Skip to content

Commit 3434219

Browse files
committed
feat: Add database utility functions for transforming MixDB objects and CSV handling
1 parent 4f4f79b commit 3434219

File tree

2 files changed

+184
-0
lines changed

2 files changed

+184
-0
lines changed
Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
import type {
2+
TableInfo,
3+
ColumnDefinition,
4+
FilterCondition,
5+
RecordData
6+
} from './types';
7+
8+
/**
9+
* Transform a MixDB database API object to TableInfo
10+
*/
11+
export function transformMixDbDatabaseToTable(db: any): TableInfo {
12+
return {
13+
id: db.id?.toString() || db.systemName,
14+
name: db.systemName || db.displayName,
15+
displayName: db.displayName || db.systemName,
16+
description: `${db.databaseProvider} database - ${db.namingConvention}`,
17+
recordCount: 0, // MixDbDatabase doesn't provide record count directly
18+
createdDate: db.createdDateTime || new Date().toISOString(),
19+
lastModified: db.modifiedDateTime || db.createdDateTime || new Date().toISOString(),
20+
isSystemTable: db.systemName === 'master' || db.isSystem || false,
21+
schema: {
22+
columns: [
23+
{ name: 'id', type: 'bigint', isRequired: true, isUnique: true, description: 'Primary key' }
24+
],
25+
primaryKey: 'id',
26+
indexes: [],
27+
relationships: []
28+
}
29+
};
30+
}
31+
32+
export function transformMixDbTableToTable(table: any): TableInfo {
33+
return {
34+
id: table.id?.toString() || table.systemName,
35+
name: table.systemName || table.displayName,
36+
displayName: table.displayName || table.systemName,
37+
description: table.description || `Database table in ${table.mixDbDatabaseName}`,
38+
recordCount: table.recordCount || 0,
39+
createdDate: table.createdDateTime || new Date().toISOString(),
40+
lastModified: table.modifiedDateTime || table.createdDateTime || new Date().toISOString(),
41+
isSystemTable: table.isSystem || false,
42+
schema: {
43+
columns: transformColumns(table.columns || table.fields || [
44+
{ name: 'id', type: 'bigint', isRequired: true, isUnique: true, description: 'Primary key' }
45+
]),
46+
primaryKey: table.primaryKey || 'id',
47+
indexes: table.indexes || [],
48+
relationships: table.relationships || table.relations || []
49+
}
50+
};
51+
}
52+
53+
export function transformDatabasesToTables(databases: any[]): TableInfo[] {
54+
return databases.map(db => ({
55+
id: db.id || db.name,
56+
name: db.name || db.id,
57+
displayName: db.displayName || db.title || db.name,
58+
description: db.description || '',
59+
recordCount: db.recordCount || db.totalRecords || 0,
60+
createdDate: db.createdDate || db.createdDateTime || new Date().toISOString(),
61+
lastModified: db.lastModified || db.modifiedDate || db.modifiedDateTime || new Date().toISOString(),
62+
isSystemTable: db.isSystemTable || db.isSystem || false,
63+
schema: {
64+
columns: transformColumns(db.columns || db.fields || []),
65+
primaryKey: db.primaryKey || 'id',
66+
indexes: db.indexes || [],
67+
relationships: db.relationships || db.relations || []
68+
}
69+
}));
70+
}
71+
72+
export function transformModuleItemToTable(item: any): TableInfo {
73+
return {
74+
id: item.id || item.name,
75+
name: item.name || item.id,
76+
displayName: item.displayName || item.title || item.name,
77+
description: item.description || '',
78+
recordCount: item.recordCount || item.totalRecords || 0,
79+
createdDate: item.createdDate || item.createdDateTime || new Date().toISOString(),
80+
lastModified: item.lastModified || item.modifiedDate || item.modifiedDateTime || new Date().toISOString(),
81+
isSystemTable: item.isSystemTable || item.isSystem || false,
82+
schema: {
83+
columns: transformColumns(item.columns || item.fields || [
84+
{ name: 'id', type: 'bigint', isRequired: true, isUnique: true, description: 'Primary key' }
85+
]),
86+
primaryKey: item.primaryKey || 'id',
87+
indexes: item.indexes || [],
88+
relationships: item.relationships || item.relations || []
89+
}
90+
};
91+
}
92+
93+
export function transformColumns(columns: any[]): ColumnDefinition[] {
94+
return columns.map(col => ({
95+
name: col.name || col.fieldName,
96+
type: col.type || col.datatype || col.dataType || 'varchar',
97+
isRequired: col.isRequired || col.required || false,
98+
isUnique: col.isUnique || col.unique || false,
99+
defaultValue: col.defaultValue || col.default,
100+
maxLength: col.maxLength || col.length,
101+
description: col.description || col.note
102+
}));
103+
}
104+
105+
/**
106+
* CSV Utilities
107+
*/
108+
export function convertToCSV(data: RecordData[]): string {
109+
if (data.length === 0) return '';
110+
const headers = Object.keys(data[0]);
111+
const csvRows = [
112+
headers.join(','),
113+
...data.map(row =>
114+
headers.map(header => {
115+
const value = row[header];
116+
return typeof value === 'string' ? `"${value.replace(/"/g, '""')}"` : value;
117+
}).join(',')
118+
)
119+
];
120+
return csvRows.join('\n');
121+
}
122+
123+
export function parseCSV(content: string): RecordData[] {
124+
const lines = content.split('\n').filter(line => line.trim());
125+
if (lines.length === 0) return [];
126+
const headers = lines[0].split(',').map(h => h.trim().replace(/"/g, ''));
127+
return lines.slice(1).map(line => {
128+
const values = line.split(',').map(v => v.trim().replace(/"/g, ''));
129+
const record: RecordData = {};
130+
headers.forEach((header, index) => {
131+
record[header] = values[index] || '';
132+
});
133+
return record;
134+
});
135+
}
136+
137+
/**
138+
* Generic record filter logic
139+
*/
140+
export function applyFilter(record: RecordData, filter: FilterCondition): boolean {
141+
const value = record[filter.column];
142+
switch (filter.operator) {
143+
case 'eq':
144+
return value === filter.value;
145+
case 'neq':
146+
return value !== filter.value;
147+
case 'gt':
148+
return value > filter.value;
149+
case 'gte':
150+
return value >= filter.value;
151+
case 'lt':
152+
return value < filter.value;
153+
case 'lte':
154+
return value <= filter.value;
155+
case 'like':
156+
return value?.toString().toLowerCase().includes(filter.value.toLowerCase());
157+
case 'in':
158+
return Array.isArray(filter.value) && filter.value.includes(value);
159+
case 'notin':
160+
return Array.isArray(filter.value) && !filter.value.includes(value);
161+
case 'isnull':
162+
return value === null || value === undefined;
163+
case 'isnotnull':
164+
return value !== null && value !== undefined;
165+
default:
166+
return true;
167+
}
168+
}

packages/database/src/mix-db-client.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,22 @@
11
import { MixDatabaseRestPortalService } from './mix-database-rest-portal-service';
22
import { MixDatabaseDataRestPortalService } from './mix-database-data-rest-portal-service';
33
import type { ApiService, ApiResult } from '@mixcore/api';
4+
import type {
5+
MixQuery,
6+
TableInfo,
7+
TableSchema,
8+
ColumnDefinition,
9+
IndexDefinition,
10+
RelationshipDefinition,
11+
RecordData,
12+
QueryResult,
13+
DatabaseStats,
14+
CreateTableRequest,
15+
UpdateTableRequest,
16+
QueryOptions,
17+
FilterCondition,
18+
DatabaseOperationResult
19+
} from './types';
420

521
// Optionally: Define types for params for better DX
622
export interface ListDatabasesParams {

0 commit comments

Comments
 (0)