@openmdm/core 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/dist/index.d.ts +90 -0
- package/dist/index.js +1368 -0
- package/dist/index.js.map +1 -0
- package/dist/schema.d.ts +78 -0
- package/dist/schema.js +415 -0
- package/dist/schema.js.map +1 -0
- package/dist/types.d.ts +899 -0
- package/dist/types.js +49 -0
- package/dist/types.js.map +1 -0
- package/package.json +67 -0
- package/src/index.ts +1145 -0
- package/src/schema.ts +533 -0
- package/src/types.ts +1161 -0
- package/src/webhooks.ts +314 -0
package/src/schema.ts
ADDED
|
@@ -0,0 +1,533 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenMDM Database Schema Definition
|
|
3
|
+
*
|
|
4
|
+
* This schema defines the structure for MDM data storage.
|
|
5
|
+
* Database adapters implement this schema for their specific ORM/database.
|
|
6
|
+
*
|
|
7
|
+
* Tables:
|
|
8
|
+
* - mdm_devices: Enrolled devices and their state
|
|
9
|
+
* - mdm_policies: Device policies and configurations
|
|
10
|
+
* - mdm_applications: Registered applications for deployment
|
|
11
|
+
* - mdm_commands: Command queue for device operations
|
|
12
|
+
* - mdm_events: Event log for device activities
|
|
13
|
+
* - mdm_groups: Device grouping for bulk operations
|
|
14
|
+
* - mdm_device_groups: Many-to-many device-group relationships
|
|
15
|
+
* - mdm_push_tokens: FCM/MQTT push notification tokens
|
|
16
|
+
* - mdm_app_deployments: App-to-policy/group deployment mappings
|
|
17
|
+
* - mdm_app_versions: App version history for rollback support
|
|
18
|
+
* - mdm_rollbacks: Rollback operation history and status
|
|
19
|
+
* - mdm_webhook_endpoints: Outbound webhook configuration
|
|
20
|
+
* - mdm_webhook_deliveries: Webhook delivery history
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
// ============================================
|
|
24
|
+
// Schema Column Types
|
|
25
|
+
// ============================================
|
|
26
|
+
|
|
27
|
+
export type ColumnType =
|
|
28
|
+
| 'string'
|
|
29
|
+
| 'text'
|
|
30
|
+
| 'integer'
|
|
31
|
+
| 'bigint'
|
|
32
|
+
| 'boolean'
|
|
33
|
+
| 'datetime'
|
|
34
|
+
| 'json'
|
|
35
|
+
| 'enum';
|
|
36
|
+
|
|
37
|
+
export interface ColumnDefinition {
|
|
38
|
+
type: ColumnType;
|
|
39
|
+
nullable?: boolean;
|
|
40
|
+
primaryKey?: boolean;
|
|
41
|
+
unique?: boolean;
|
|
42
|
+
default?: unknown;
|
|
43
|
+
enumValues?: string[];
|
|
44
|
+
references?: {
|
|
45
|
+
table: string;
|
|
46
|
+
column: string;
|
|
47
|
+
onDelete?: 'cascade' | 'set null' | 'restrict';
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export interface IndexDefinition {
|
|
52
|
+
columns: string[];
|
|
53
|
+
unique?: boolean;
|
|
54
|
+
name?: string;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export interface TableDefinition {
|
|
58
|
+
columns: Record<string, ColumnDefinition>;
|
|
59
|
+
indexes?: IndexDefinition[];
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export interface SchemaDefinition {
|
|
63
|
+
tables: Record<string, TableDefinition>;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// ============================================
|
|
67
|
+
// OpenMDM Schema
|
|
68
|
+
// ============================================
|
|
69
|
+
|
|
70
|
+
export const mdmSchema: SchemaDefinition = {
|
|
71
|
+
tables: {
|
|
72
|
+
// ----------------------------------------
|
|
73
|
+
// Devices Table
|
|
74
|
+
// ----------------------------------------
|
|
75
|
+
mdm_devices: {
|
|
76
|
+
columns: {
|
|
77
|
+
id: { type: 'string', primaryKey: true },
|
|
78
|
+
external_id: { type: 'string', nullable: true },
|
|
79
|
+
enrollment_id: { type: 'string', unique: true },
|
|
80
|
+
status: {
|
|
81
|
+
type: 'enum',
|
|
82
|
+
enumValues: ['pending', 'enrolled', 'unenrolled', 'blocked'],
|
|
83
|
+
default: 'pending',
|
|
84
|
+
},
|
|
85
|
+
|
|
86
|
+
// Device Info
|
|
87
|
+
model: { type: 'string', nullable: true },
|
|
88
|
+
manufacturer: { type: 'string', nullable: true },
|
|
89
|
+
os_version: { type: 'string', nullable: true },
|
|
90
|
+
serial_number: { type: 'string', nullable: true },
|
|
91
|
+
imei: { type: 'string', nullable: true },
|
|
92
|
+
mac_address: { type: 'string', nullable: true },
|
|
93
|
+
android_id: { type: 'string', nullable: true },
|
|
94
|
+
|
|
95
|
+
// MDM State
|
|
96
|
+
policy_id: {
|
|
97
|
+
type: 'string',
|
|
98
|
+
nullable: true,
|
|
99
|
+
references: { table: 'mdm_policies', column: 'id', onDelete: 'set null' },
|
|
100
|
+
},
|
|
101
|
+
last_heartbeat: { type: 'datetime', nullable: true },
|
|
102
|
+
last_sync: { type: 'datetime', nullable: true },
|
|
103
|
+
|
|
104
|
+
// Telemetry (denormalized for quick access)
|
|
105
|
+
battery_level: { type: 'integer', nullable: true },
|
|
106
|
+
storage_used: { type: 'bigint', nullable: true },
|
|
107
|
+
storage_total: { type: 'bigint', nullable: true },
|
|
108
|
+
latitude: { type: 'string', nullable: true }, // Stored as string for precision
|
|
109
|
+
longitude: { type: 'string', nullable: true },
|
|
110
|
+
location_timestamp: { type: 'datetime', nullable: true },
|
|
111
|
+
|
|
112
|
+
// JSON fields
|
|
113
|
+
installed_apps: { type: 'json', nullable: true },
|
|
114
|
+
tags: { type: 'json', nullable: true },
|
|
115
|
+
metadata: { type: 'json', nullable: true },
|
|
116
|
+
|
|
117
|
+
// Timestamps
|
|
118
|
+
created_at: { type: 'datetime', default: 'now' },
|
|
119
|
+
updated_at: { type: 'datetime', default: 'now' },
|
|
120
|
+
},
|
|
121
|
+
indexes: [
|
|
122
|
+
{ columns: ['enrollment_id'], unique: true },
|
|
123
|
+
{ columns: ['status'] },
|
|
124
|
+
{ columns: ['policy_id'] },
|
|
125
|
+
{ columns: ['last_heartbeat'] },
|
|
126
|
+
{ columns: ['mac_address'] },
|
|
127
|
+
{ columns: ['serial_number'] },
|
|
128
|
+
],
|
|
129
|
+
},
|
|
130
|
+
|
|
131
|
+
// ----------------------------------------
|
|
132
|
+
// Policies Table
|
|
133
|
+
// ----------------------------------------
|
|
134
|
+
mdm_policies: {
|
|
135
|
+
columns: {
|
|
136
|
+
id: { type: 'string', primaryKey: true },
|
|
137
|
+
name: { type: 'string' },
|
|
138
|
+
description: { type: 'text', nullable: true },
|
|
139
|
+
is_default: { type: 'boolean', default: false },
|
|
140
|
+
settings: { type: 'json' },
|
|
141
|
+
created_at: { type: 'datetime', default: 'now' },
|
|
142
|
+
updated_at: { type: 'datetime', default: 'now' },
|
|
143
|
+
},
|
|
144
|
+
indexes: [
|
|
145
|
+
{ columns: ['name'] },
|
|
146
|
+
{ columns: ['is_default'] },
|
|
147
|
+
],
|
|
148
|
+
},
|
|
149
|
+
|
|
150
|
+
// ----------------------------------------
|
|
151
|
+
// Applications Table
|
|
152
|
+
// ----------------------------------------
|
|
153
|
+
mdm_applications: {
|
|
154
|
+
columns: {
|
|
155
|
+
id: { type: 'string', primaryKey: true },
|
|
156
|
+
name: { type: 'string' },
|
|
157
|
+
package_name: { type: 'string' },
|
|
158
|
+
version: { type: 'string' },
|
|
159
|
+
version_code: { type: 'integer' },
|
|
160
|
+
url: { type: 'string' },
|
|
161
|
+
hash: { type: 'string', nullable: true }, // SHA-256
|
|
162
|
+
size: { type: 'bigint', nullable: true },
|
|
163
|
+
min_sdk_version: { type: 'integer', nullable: true },
|
|
164
|
+
|
|
165
|
+
// Deployment settings
|
|
166
|
+
show_icon: { type: 'boolean', default: true },
|
|
167
|
+
run_after_install: { type: 'boolean', default: false },
|
|
168
|
+
run_at_boot: { type: 'boolean', default: false },
|
|
169
|
+
is_system: { type: 'boolean', default: false },
|
|
170
|
+
|
|
171
|
+
// State
|
|
172
|
+
is_active: { type: 'boolean', default: true },
|
|
173
|
+
|
|
174
|
+
// Metadata
|
|
175
|
+
metadata: { type: 'json', nullable: true },
|
|
176
|
+
created_at: { type: 'datetime', default: 'now' },
|
|
177
|
+
updated_at: { type: 'datetime', default: 'now' },
|
|
178
|
+
},
|
|
179
|
+
indexes: [
|
|
180
|
+
{ columns: ['package_name'] },
|
|
181
|
+
{ columns: ['package_name', 'version'], unique: true },
|
|
182
|
+
{ columns: ['is_active'] },
|
|
183
|
+
],
|
|
184
|
+
},
|
|
185
|
+
|
|
186
|
+
// ----------------------------------------
|
|
187
|
+
// Commands Table
|
|
188
|
+
// ----------------------------------------
|
|
189
|
+
mdm_commands: {
|
|
190
|
+
columns: {
|
|
191
|
+
id: { type: 'string', primaryKey: true },
|
|
192
|
+
device_id: {
|
|
193
|
+
type: 'string',
|
|
194
|
+
references: { table: 'mdm_devices', column: 'id', onDelete: 'cascade' },
|
|
195
|
+
},
|
|
196
|
+
type: { type: 'string' },
|
|
197
|
+
payload: { type: 'json', nullable: true },
|
|
198
|
+
status: {
|
|
199
|
+
type: 'enum',
|
|
200
|
+
enumValues: ['pending', 'sent', 'acknowledged', 'completed', 'failed', 'cancelled'],
|
|
201
|
+
default: 'pending',
|
|
202
|
+
},
|
|
203
|
+
result: { type: 'json', nullable: true },
|
|
204
|
+
error: { type: 'text', nullable: true },
|
|
205
|
+
created_at: { type: 'datetime', default: 'now' },
|
|
206
|
+
sent_at: { type: 'datetime', nullable: true },
|
|
207
|
+
acknowledged_at: { type: 'datetime', nullable: true },
|
|
208
|
+
completed_at: { type: 'datetime', nullable: true },
|
|
209
|
+
},
|
|
210
|
+
indexes: [
|
|
211
|
+
{ columns: ['device_id'] },
|
|
212
|
+
{ columns: ['status'] },
|
|
213
|
+
{ columns: ['device_id', 'status'] },
|
|
214
|
+
{ columns: ['created_at'] },
|
|
215
|
+
],
|
|
216
|
+
},
|
|
217
|
+
|
|
218
|
+
// ----------------------------------------
|
|
219
|
+
// Events Table
|
|
220
|
+
// ----------------------------------------
|
|
221
|
+
mdm_events: {
|
|
222
|
+
columns: {
|
|
223
|
+
id: { type: 'string', primaryKey: true },
|
|
224
|
+
device_id: {
|
|
225
|
+
type: 'string',
|
|
226
|
+
references: { table: 'mdm_devices', column: 'id', onDelete: 'cascade' },
|
|
227
|
+
},
|
|
228
|
+
type: { type: 'string' },
|
|
229
|
+
payload: { type: 'json' },
|
|
230
|
+
created_at: { type: 'datetime', default: 'now' },
|
|
231
|
+
},
|
|
232
|
+
indexes: [
|
|
233
|
+
{ columns: ['device_id'] },
|
|
234
|
+
{ columns: ['type'] },
|
|
235
|
+
{ columns: ['device_id', 'type'] },
|
|
236
|
+
{ columns: ['created_at'] },
|
|
237
|
+
],
|
|
238
|
+
},
|
|
239
|
+
|
|
240
|
+
// ----------------------------------------
|
|
241
|
+
// Groups Table
|
|
242
|
+
// ----------------------------------------
|
|
243
|
+
mdm_groups: {
|
|
244
|
+
columns: {
|
|
245
|
+
id: { type: 'string', primaryKey: true },
|
|
246
|
+
name: { type: 'string' },
|
|
247
|
+
description: { type: 'text', nullable: true },
|
|
248
|
+
policy_id: {
|
|
249
|
+
type: 'string',
|
|
250
|
+
nullable: true,
|
|
251
|
+
references: { table: 'mdm_policies', column: 'id', onDelete: 'set null' },
|
|
252
|
+
},
|
|
253
|
+
parent_id: {
|
|
254
|
+
type: 'string',
|
|
255
|
+
nullable: true,
|
|
256
|
+
references: { table: 'mdm_groups', column: 'id', onDelete: 'set null' },
|
|
257
|
+
},
|
|
258
|
+
metadata: { type: 'json', nullable: true },
|
|
259
|
+
created_at: { type: 'datetime', default: 'now' },
|
|
260
|
+
updated_at: { type: 'datetime', default: 'now' },
|
|
261
|
+
},
|
|
262
|
+
indexes: [
|
|
263
|
+
{ columns: ['name'] },
|
|
264
|
+
{ columns: ['policy_id'] },
|
|
265
|
+
{ columns: ['parent_id'] },
|
|
266
|
+
],
|
|
267
|
+
},
|
|
268
|
+
|
|
269
|
+
// ----------------------------------------
|
|
270
|
+
// Device Groups (Many-to-Many)
|
|
271
|
+
// ----------------------------------------
|
|
272
|
+
mdm_device_groups: {
|
|
273
|
+
columns: {
|
|
274
|
+
device_id: {
|
|
275
|
+
type: 'string',
|
|
276
|
+
references: { table: 'mdm_devices', column: 'id', onDelete: 'cascade' },
|
|
277
|
+
},
|
|
278
|
+
group_id: {
|
|
279
|
+
type: 'string',
|
|
280
|
+
references: { table: 'mdm_groups', column: 'id', onDelete: 'cascade' },
|
|
281
|
+
},
|
|
282
|
+
created_at: { type: 'datetime', default: 'now' },
|
|
283
|
+
},
|
|
284
|
+
indexes: [
|
|
285
|
+
{ columns: ['device_id', 'group_id'], unique: true },
|
|
286
|
+
{ columns: ['group_id'] },
|
|
287
|
+
],
|
|
288
|
+
},
|
|
289
|
+
|
|
290
|
+
// ----------------------------------------
|
|
291
|
+
// Push Tokens (for FCM/MQTT registration)
|
|
292
|
+
// ----------------------------------------
|
|
293
|
+
mdm_push_tokens: {
|
|
294
|
+
columns: {
|
|
295
|
+
id: { type: 'string', primaryKey: true },
|
|
296
|
+
device_id: {
|
|
297
|
+
type: 'string',
|
|
298
|
+
references: { table: 'mdm_devices', column: 'id', onDelete: 'cascade' },
|
|
299
|
+
},
|
|
300
|
+
provider: {
|
|
301
|
+
type: 'enum',
|
|
302
|
+
enumValues: ['fcm', 'mqtt', 'websocket'],
|
|
303
|
+
},
|
|
304
|
+
token: { type: 'string' },
|
|
305
|
+
is_active: { type: 'boolean', default: true },
|
|
306
|
+
created_at: { type: 'datetime', default: 'now' },
|
|
307
|
+
updated_at: { type: 'datetime', default: 'now' },
|
|
308
|
+
},
|
|
309
|
+
indexes: [
|
|
310
|
+
{ columns: ['device_id'] },
|
|
311
|
+
{ columns: ['provider', 'token'], unique: true },
|
|
312
|
+
{ columns: ['is_active'] },
|
|
313
|
+
],
|
|
314
|
+
},
|
|
315
|
+
|
|
316
|
+
// ----------------------------------------
|
|
317
|
+
// Application Deployments (Which apps go to which policies/groups)
|
|
318
|
+
// ----------------------------------------
|
|
319
|
+
mdm_app_deployments: {
|
|
320
|
+
columns: {
|
|
321
|
+
id: { type: 'string', primaryKey: true },
|
|
322
|
+
application_id: {
|
|
323
|
+
type: 'string',
|
|
324
|
+
references: { table: 'mdm_applications', column: 'id', onDelete: 'cascade' },
|
|
325
|
+
},
|
|
326
|
+
// Target can be policy or group
|
|
327
|
+
target_type: {
|
|
328
|
+
type: 'enum',
|
|
329
|
+
enumValues: ['policy', 'group'],
|
|
330
|
+
},
|
|
331
|
+
target_id: { type: 'string' },
|
|
332
|
+
action: {
|
|
333
|
+
type: 'enum',
|
|
334
|
+
enumValues: ['install', 'update', 'uninstall'],
|
|
335
|
+
default: 'install',
|
|
336
|
+
},
|
|
337
|
+
is_required: { type: 'boolean', default: false },
|
|
338
|
+
created_at: { type: 'datetime', default: 'now' },
|
|
339
|
+
},
|
|
340
|
+
indexes: [
|
|
341
|
+
{ columns: ['application_id'] },
|
|
342
|
+
{ columns: ['target_type', 'target_id'] },
|
|
343
|
+
],
|
|
344
|
+
},
|
|
345
|
+
|
|
346
|
+
// ----------------------------------------
|
|
347
|
+
// App Versions (Version history for rollback support)
|
|
348
|
+
// ----------------------------------------
|
|
349
|
+
mdm_app_versions: {
|
|
350
|
+
columns: {
|
|
351
|
+
id: { type: 'string', primaryKey: true },
|
|
352
|
+
application_id: {
|
|
353
|
+
type: 'string',
|
|
354
|
+
references: { table: 'mdm_applications', column: 'id', onDelete: 'cascade' },
|
|
355
|
+
},
|
|
356
|
+
package_name: { type: 'string' },
|
|
357
|
+
version: { type: 'string' },
|
|
358
|
+
version_code: { type: 'integer' },
|
|
359
|
+
url: { type: 'string' },
|
|
360
|
+
hash: { type: 'string', nullable: true },
|
|
361
|
+
size: { type: 'bigint', nullable: true },
|
|
362
|
+
release_notes: { type: 'text', nullable: true },
|
|
363
|
+
is_minimum_version: { type: 'boolean', default: false },
|
|
364
|
+
created_at: { type: 'datetime', default: 'now' },
|
|
365
|
+
},
|
|
366
|
+
indexes: [
|
|
367
|
+
{ columns: ['application_id'] },
|
|
368
|
+
{ columns: ['package_name'] },
|
|
369
|
+
{ columns: ['package_name', 'version_code'], unique: true },
|
|
370
|
+
{ columns: ['is_minimum_version'] },
|
|
371
|
+
],
|
|
372
|
+
},
|
|
373
|
+
|
|
374
|
+
// ----------------------------------------
|
|
375
|
+
// App Rollbacks (Rollback history and status)
|
|
376
|
+
// ----------------------------------------
|
|
377
|
+
mdm_rollbacks: {
|
|
378
|
+
columns: {
|
|
379
|
+
id: { type: 'string', primaryKey: true },
|
|
380
|
+
device_id: {
|
|
381
|
+
type: 'string',
|
|
382
|
+
references: { table: 'mdm_devices', column: 'id', onDelete: 'cascade' },
|
|
383
|
+
},
|
|
384
|
+
package_name: { type: 'string' },
|
|
385
|
+
from_version: { type: 'string' },
|
|
386
|
+
from_version_code: { type: 'integer' },
|
|
387
|
+
to_version: { type: 'string' },
|
|
388
|
+
to_version_code: { type: 'integer' },
|
|
389
|
+
reason: { type: 'text', nullable: true },
|
|
390
|
+
status: {
|
|
391
|
+
type: 'enum',
|
|
392
|
+
enumValues: ['pending', 'in_progress', 'completed', 'failed'],
|
|
393
|
+
default: 'pending',
|
|
394
|
+
},
|
|
395
|
+
error: { type: 'text', nullable: true },
|
|
396
|
+
initiated_by: { type: 'string', nullable: true },
|
|
397
|
+
created_at: { type: 'datetime', default: 'now' },
|
|
398
|
+
completed_at: { type: 'datetime', nullable: true },
|
|
399
|
+
},
|
|
400
|
+
indexes: [
|
|
401
|
+
{ columns: ['device_id'] },
|
|
402
|
+
{ columns: ['package_name'] },
|
|
403
|
+
{ columns: ['device_id', 'package_name'] },
|
|
404
|
+
{ columns: ['status'] },
|
|
405
|
+
{ columns: ['created_at'] },
|
|
406
|
+
],
|
|
407
|
+
},
|
|
408
|
+
|
|
409
|
+
// ----------------------------------------
|
|
410
|
+
// Webhook Endpoints (For outbound webhook configuration storage)
|
|
411
|
+
// ----------------------------------------
|
|
412
|
+
mdm_webhook_endpoints: {
|
|
413
|
+
columns: {
|
|
414
|
+
id: { type: 'string', primaryKey: true },
|
|
415
|
+
url: { type: 'string' },
|
|
416
|
+
events: { type: 'json' }, // Array of event types or ['*']
|
|
417
|
+
headers: { type: 'json', nullable: true },
|
|
418
|
+
enabled: { type: 'boolean', default: true },
|
|
419
|
+
description: { type: 'text', nullable: true },
|
|
420
|
+
created_at: { type: 'datetime', default: 'now' },
|
|
421
|
+
updated_at: { type: 'datetime', default: 'now' },
|
|
422
|
+
},
|
|
423
|
+
indexes: [
|
|
424
|
+
{ columns: ['enabled'] },
|
|
425
|
+
],
|
|
426
|
+
},
|
|
427
|
+
|
|
428
|
+
// ----------------------------------------
|
|
429
|
+
// Webhook Deliveries (Delivery history and status)
|
|
430
|
+
// ----------------------------------------
|
|
431
|
+
mdm_webhook_deliveries: {
|
|
432
|
+
columns: {
|
|
433
|
+
id: { type: 'string', primaryKey: true },
|
|
434
|
+
endpoint_id: {
|
|
435
|
+
type: 'string',
|
|
436
|
+
references: { table: 'mdm_webhook_endpoints', column: 'id', onDelete: 'cascade' },
|
|
437
|
+
},
|
|
438
|
+
event_id: { type: 'string' },
|
|
439
|
+
event_type: { type: 'string' },
|
|
440
|
+
payload: { type: 'json' },
|
|
441
|
+
status: {
|
|
442
|
+
type: 'enum',
|
|
443
|
+
enumValues: ['pending', 'success', 'failed'],
|
|
444
|
+
default: 'pending',
|
|
445
|
+
},
|
|
446
|
+
status_code: { type: 'integer', nullable: true },
|
|
447
|
+
error: { type: 'text', nullable: true },
|
|
448
|
+
retry_count: { type: 'integer', default: 0 },
|
|
449
|
+
created_at: { type: 'datetime', default: 'now' },
|
|
450
|
+
delivered_at: { type: 'datetime', nullable: true },
|
|
451
|
+
},
|
|
452
|
+
indexes: [
|
|
453
|
+
{ columns: ['endpoint_id'] },
|
|
454
|
+
{ columns: ['event_type'] },
|
|
455
|
+
{ columns: ['status'] },
|
|
456
|
+
{ columns: ['created_at'] },
|
|
457
|
+
],
|
|
458
|
+
},
|
|
459
|
+
},
|
|
460
|
+
};
|
|
461
|
+
|
|
462
|
+
// ============================================
|
|
463
|
+
// Schema Helper Functions
|
|
464
|
+
// ============================================
|
|
465
|
+
|
|
466
|
+
/**
|
|
467
|
+
* Get all table names from the schema
|
|
468
|
+
*/
|
|
469
|
+
export function getTableNames(): string[] {
|
|
470
|
+
return Object.keys(mdmSchema.tables);
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
/**
|
|
474
|
+
* Get column names for a table
|
|
475
|
+
*/
|
|
476
|
+
export function getColumnNames(tableName: string): string[] {
|
|
477
|
+
const table = mdmSchema.tables[tableName];
|
|
478
|
+
if (!table) throw new Error(`Table ${tableName} not found in schema`);
|
|
479
|
+
return Object.keys(table.columns);
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
/**
|
|
483
|
+
* Get the primary key column for a table
|
|
484
|
+
*/
|
|
485
|
+
export function getPrimaryKey(tableName: string): string | null {
|
|
486
|
+
const table = mdmSchema.tables[tableName];
|
|
487
|
+
if (!table) throw new Error(`Table ${tableName} not found in schema`);
|
|
488
|
+
|
|
489
|
+
for (const [name, def] of Object.entries(table.columns)) {
|
|
490
|
+
if (def.primaryKey) return name;
|
|
491
|
+
}
|
|
492
|
+
return null;
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
/**
|
|
496
|
+
* Convert snake_case column name to camelCase
|
|
497
|
+
*/
|
|
498
|
+
export function snakeToCamel(str: string): string {
|
|
499
|
+
return str.replace(/_([a-z])/g, (_, letter) => letter.toUpperCase());
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
/**
|
|
503
|
+
* Convert camelCase to snake_case
|
|
504
|
+
*/
|
|
505
|
+
export function camelToSnake(str: string): string {
|
|
506
|
+
return str.replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`);
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
/**
|
|
510
|
+
* Transform object keys from snake_case to camelCase
|
|
511
|
+
*/
|
|
512
|
+
export function transformToCamelCase<T extends Record<string, unknown>>(
|
|
513
|
+
obj: T
|
|
514
|
+
): Record<string, unknown> {
|
|
515
|
+
const result: Record<string, unknown> = {};
|
|
516
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
517
|
+
result[snakeToCamel(key)] = value;
|
|
518
|
+
}
|
|
519
|
+
return result;
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
/**
|
|
523
|
+
* Transform object keys from camelCase to snake_case
|
|
524
|
+
*/
|
|
525
|
+
export function transformToSnakeCase<T extends Record<string, unknown>>(
|
|
526
|
+
obj: T
|
|
527
|
+
): Record<string, unknown> {
|
|
528
|
+
const result: Record<string, unknown> = {};
|
|
529
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
530
|
+
result[camelToSnake(key)] = value;
|
|
531
|
+
}
|
|
532
|
+
return result;
|
|
533
|
+
}
|