@objectql/core 1.4.0 → 1.5.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/CHANGELOG.md +12 -0
- package/README.md +287 -0
- package/dist/app.d.ts +1 -0
- package/dist/app.js +41 -0
- package/dist/app.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/loader.js +42 -0
- package/dist/loader.js.map +1 -1
- package/dist/validator.d.ts +69 -0
- package/dist/validator.js +461 -0
- package/dist/validator.js.map +1 -0
- package/package.json +3 -3
- package/src/app.ts +49 -0
- package/src/index.ts +1 -0
- package/src/loader.ts +45 -0
- package/src/validator.ts +553 -0
- package/test/fixtures/project-with-validation.object.yml +124 -0
- package/test/validation.test.ts +486 -0
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -0,0 +1,461 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Validation engine for ObjectQL.
|
|
4
|
+
* Executes validation rules based on metadata configuration.
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.Validator = void 0;
|
|
8
|
+
/**
|
|
9
|
+
* Validator class that executes validation rules.
|
|
10
|
+
*/
|
|
11
|
+
class Validator {
|
|
12
|
+
constructor(options = {}) {
|
|
13
|
+
this.options = {
|
|
14
|
+
language: options.language || 'en',
|
|
15
|
+
languageFallback: options.languageFallback || ['en', 'zh-CN'],
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Validate a record against a set of rules.
|
|
20
|
+
*/
|
|
21
|
+
async validate(rules, context) {
|
|
22
|
+
const results = [];
|
|
23
|
+
for (const rule of rules) {
|
|
24
|
+
// Check if rule should be applied
|
|
25
|
+
if (!this.shouldApplyRule(rule, context)) {
|
|
26
|
+
continue;
|
|
27
|
+
}
|
|
28
|
+
// Execute validation based on rule type
|
|
29
|
+
let result;
|
|
30
|
+
try {
|
|
31
|
+
switch (rule.type) {
|
|
32
|
+
case 'cross_field':
|
|
33
|
+
result = await this.validateCrossField(rule, context);
|
|
34
|
+
break;
|
|
35
|
+
case 'state_machine':
|
|
36
|
+
result = await this.validateStateMachine(rule, context);
|
|
37
|
+
break;
|
|
38
|
+
case 'unique':
|
|
39
|
+
result = await this.validateUniqueness(rule, context);
|
|
40
|
+
break;
|
|
41
|
+
case 'business_rule':
|
|
42
|
+
result = await this.validateBusinessRule(rule, context);
|
|
43
|
+
break;
|
|
44
|
+
case 'custom':
|
|
45
|
+
result = await this.validateCustom(rule, context);
|
|
46
|
+
break;
|
|
47
|
+
default:
|
|
48
|
+
// Generic validation
|
|
49
|
+
result = {
|
|
50
|
+
rule: rule.name,
|
|
51
|
+
valid: true,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
catch (error) {
|
|
56
|
+
result = {
|
|
57
|
+
rule: rule.name,
|
|
58
|
+
valid: false,
|
|
59
|
+
message: error instanceof Error ? error.message : 'Validation error',
|
|
60
|
+
severity: rule.severity || 'error',
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
results.push(result);
|
|
64
|
+
}
|
|
65
|
+
// Categorize results
|
|
66
|
+
const errors = results.filter(r => !r.valid && r.severity === 'error');
|
|
67
|
+
const warnings = results.filter(r => !r.valid && r.severity === 'warning');
|
|
68
|
+
const info = results.filter(r => !r.valid && r.severity === 'info');
|
|
69
|
+
return {
|
|
70
|
+
valid: errors.length === 0,
|
|
71
|
+
results,
|
|
72
|
+
errors,
|
|
73
|
+
warnings,
|
|
74
|
+
info,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Validate field-level rules.
|
|
79
|
+
*/
|
|
80
|
+
async validateField(fieldName, fieldConfig, value, context) {
|
|
81
|
+
const results = [];
|
|
82
|
+
// Required field validation
|
|
83
|
+
if (fieldConfig.required && (value === null || value === undefined || value === '')) {
|
|
84
|
+
results.push({
|
|
85
|
+
rule: `${fieldName}_required`,
|
|
86
|
+
valid: false,
|
|
87
|
+
message: fieldConfig.validation?.message || `${fieldConfig.label || fieldName} is required`,
|
|
88
|
+
severity: 'error',
|
|
89
|
+
fields: [fieldName],
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
// Skip further validation if value is empty and not required
|
|
93
|
+
if (value === null || value === undefined || value === '') {
|
|
94
|
+
return results;
|
|
95
|
+
}
|
|
96
|
+
// Type-specific validation
|
|
97
|
+
if (fieldConfig.validation) {
|
|
98
|
+
const validation = fieldConfig.validation;
|
|
99
|
+
// Email format
|
|
100
|
+
if (validation.format === 'email') {
|
|
101
|
+
// NOTE: This is a basic email validation regex. For production use,
|
|
102
|
+
// consider using a more comprehensive email validation library or regex
|
|
103
|
+
// that handles international domains, quoted strings, etc.
|
|
104
|
+
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
105
|
+
if (!emailRegex.test(value)) {
|
|
106
|
+
results.push({
|
|
107
|
+
rule: `${fieldName}_email_format`,
|
|
108
|
+
valid: false,
|
|
109
|
+
message: validation.message || 'Invalid email format',
|
|
110
|
+
severity: 'error',
|
|
111
|
+
fields: [fieldName],
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
// URL format
|
|
116
|
+
if (validation.format === 'url') {
|
|
117
|
+
try {
|
|
118
|
+
const url = new URL(value);
|
|
119
|
+
if (validation.protocols && !validation.protocols.includes(url.protocol.replace(':', ''))) {
|
|
120
|
+
results.push({
|
|
121
|
+
rule: `${fieldName}_url_protocol`,
|
|
122
|
+
valid: false,
|
|
123
|
+
message: validation.message || `URL must use one of: ${validation.protocols.join(', ')}`,
|
|
124
|
+
severity: 'error',
|
|
125
|
+
fields: [fieldName],
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
catch {
|
|
130
|
+
results.push({
|
|
131
|
+
rule: `${fieldName}_url_format`,
|
|
132
|
+
valid: false,
|
|
133
|
+
message: validation.message || 'Invalid URL format',
|
|
134
|
+
severity: 'error',
|
|
135
|
+
fields: [fieldName],
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
// Pattern validation (supports both pattern and deprecated regex)
|
|
140
|
+
const patternValue = validation.pattern ?? validation.regex;
|
|
141
|
+
if (patternValue) {
|
|
142
|
+
try {
|
|
143
|
+
const pattern = new RegExp(patternValue);
|
|
144
|
+
if (!pattern.test(String(value))) {
|
|
145
|
+
results.push({
|
|
146
|
+
rule: `${fieldName}_pattern`,
|
|
147
|
+
valid: false,
|
|
148
|
+
message: validation.message || 'Value does not match required pattern',
|
|
149
|
+
severity: 'error',
|
|
150
|
+
fields: [fieldName],
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
catch (error) {
|
|
155
|
+
results.push({
|
|
156
|
+
rule: `${fieldName}_pattern`,
|
|
157
|
+
valid: false,
|
|
158
|
+
message: `Invalid regex pattern: ${patternValue}`,
|
|
159
|
+
severity: 'error',
|
|
160
|
+
fields: [fieldName],
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
// Min/Max validation
|
|
165
|
+
if (validation.min !== undefined && value < validation.min) {
|
|
166
|
+
results.push({
|
|
167
|
+
rule: `${fieldName}_min`,
|
|
168
|
+
valid: false,
|
|
169
|
+
message: validation.message || `Value must be at least ${validation.min}`,
|
|
170
|
+
severity: 'error',
|
|
171
|
+
fields: [fieldName],
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
if (validation.max !== undefined && value > validation.max) {
|
|
175
|
+
results.push({
|
|
176
|
+
rule: `${fieldName}_max`,
|
|
177
|
+
valid: false,
|
|
178
|
+
message: validation.message || `Value must be at most ${validation.max}`,
|
|
179
|
+
severity: 'error',
|
|
180
|
+
fields: [fieldName],
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
// Length validation
|
|
184
|
+
const strValue = String(value);
|
|
185
|
+
if (validation.min_length !== undefined && strValue.length < validation.min_length) {
|
|
186
|
+
results.push({
|
|
187
|
+
rule: `${fieldName}_min_length`,
|
|
188
|
+
valid: false,
|
|
189
|
+
message: validation.message || `Must be at least ${validation.min_length} characters`,
|
|
190
|
+
severity: 'error',
|
|
191
|
+
fields: [fieldName],
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
if (validation.max_length !== undefined && strValue.length > validation.max_length) {
|
|
195
|
+
results.push({
|
|
196
|
+
rule: `${fieldName}_max_length`,
|
|
197
|
+
valid: false,
|
|
198
|
+
message: validation.message || `Must be at most ${validation.max_length} characters`,
|
|
199
|
+
severity: 'error',
|
|
200
|
+
fields: [fieldName],
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
// Legacy min/max from fieldConfig
|
|
205
|
+
if (fieldConfig.min !== undefined && value < fieldConfig.min) {
|
|
206
|
+
results.push({
|
|
207
|
+
rule: `${fieldName}_min`,
|
|
208
|
+
valid: false,
|
|
209
|
+
message: `Value must be at least ${fieldConfig.min}`,
|
|
210
|
+
severity: 'error',
|
|
211
|
+
fields: [fieldName],
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
if (fieldConfig.max !== undefined && value > fieldConfig.max) {
|
|
215
|
+
results.push({
|
|
216
|
+
rule: `${fieldName}_max`,
|
|
217
|
+
valid: false,
|
|
218
|
+
message: `Value must be at most ${fieldConfig.max}`,
|
|
219
|
+
severity: 'error',
|
|
220
|
+
fields: [fieldName],
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
return results;
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Check if a rule should be applied based on triggers and conditions.
|
|
227
|
+
*/
|
|
228
|
+
shouldApplyRule(rule, context) {
|
|
229
|
+
// Check trigger
|
|
230
|
+
if (rule.trigger && !rule.trigger.includes(context.operation)) {
|
|
231
|
+
return false;
|
|
232
|
+
}
|
|
233
|
+
// Check fields (for updates)
|
|
234
|
+
if (rule.fields && rule.fields.length > 0 && context.changedFields) {
|
|
235
|
+
const hasChangedField = rule.fields.some(f => context.changedFields.includes(f));
|
|
236
|
+
if (!hasChangedField) {
|
|
237
|
+
return false;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
// Check apply_when condition
|
|
241
|
+
if (rule.apply_when) {
|
|
242
|
+
return this.evaluateCondition(rule.apply_when, context.record);
|
|
243
|
+
}
|
|
244
|
+
return true;
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* Validate cross-field rule.
|
|
248
|
+
*/
|
|
249
|
+
async validateCrossField(rule, context) {
|
|
250
|
+
if (!rule.rule) {
|
|
251
|
+
return { rule: rule.name, valid: true };
|
|
252
|
+
}
|
|
253
|
+
const valid = this.evaluateCondition(rule.rule, context.record);
|
|
254
|
+
return {
|
|
255
|
+
rule: rule.name,
|
|
256
|
+
valid,
|
|
257
|
+
message: valid ? undefined : this.formatMessage(rule.message, context.record),
|
|
258
|
+
error_code: rule.error_code,
|
|
259
|
+
severity: rule.severity || 'error',
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
263
|
+
* Validate state machine transitions.
|
|
264
|
+
*/
|
|
265
|
+
async validateStateMachine(rule, context) {
|
|
266
|
+
// Only validate on update
|
|
267
|
+
if (context.operation !== 'update' || !context.previousRecord) {
|
|
268
|
+
return { rule: rule.name, valid: true };
|
|
269
|
+
}
|
|
270
|
+
const oldState = context.previousRecord[rule.field];
|
|
271
|
+
const newState = context.record[rule.field];
|
|
272
|
+
// If state hasn't changed, validation passes
|
|
273
|
+
if (oldState === newState) {
|
|
274
|
+
return { rule: rule.name, valid: true };
|
|
275
|
+
}
|
|
276
|
+
// Check if transition is allowed
|
|
277
|
+
const transitions = rule.transitions?.[oldState];
|
|
278
|
+
if (!transitions) {
|
|
279
|
+
return {
|
|
280
|
+
rule: rule.name,
|
|
281
|
+
valid: false,
|
|
282
|
+
message: this.formatMessage(rule.message, { old_status: oldState, new_status: newState }),
|
|
283
|
+
error_code: rule.error_code,
|
|
284
|
+
severity: rule.severity || 'error',
|
|
285
|
+
fields: [rule.field],
|
|
286
|
+
};
|
|
287
|
+
}
|
|
288
|
+
// Handle both array and object format
|
|
289
|
+
let allowedNext = [];
|
|
290
|
+
if (Array.isArray(transitions)) {
|
|
291
|
+
allowedNext = transitions;
|
|
292
|
+
}
|
|
293
|
+
else if (typeof transitions === 'object' && 'allowed_next' in transitions) {
|
|
294
|
+
allowedNext = transitions.allowed_next || [];
|
|
295
|
+
}
|
|
296
|
+
const isAllowed = allowedNext.includes(newState);
|
|
297
|
+
return {
|
|
298
|
+
rule: rule.name,
|
|
299
|
+
valid: isAllowed,
|
|
300
|
+
message: isAllowed ? undefined : this.formatMessage(rule.message, { old_status: oldState, new_status: newState }),
|
|
301
|
+
error_code: rule.error_code,
|
|
302
|
+
severity: rule.severity || 'error',
|
|
303
|
+
fields: [rule.field],
|
|
304
|
+
};
|
|
305
|
+
}
|
|
306
|
+
/**
|
|
307
|
+
* Validate uniqueness (stub - requires database access).
|
|
308
|
+
*/
|
|
309
|
+
async validateUniqueness(rule, context) {
|
|
310
|
+
// TODO: Implement database query for uniqueness check
|
|
311
|
+
// This requires access to the data layer (driver/repository)
|
|
312
|
+
// Stub: Pass silently until implementation is complete
|
|
313
|
+
return {
|
|
314
|
+
rule: rule.name,
|
|
315
|
+
valid: true,
|
|
316
|
+
};
|
|
317
|
+
}
|
|
318
|
+
/**
|
|
319
|
+
* Validate business rule (stub - requires complex logic).
|
|
320
|
+
*/
|
|
321
|
+
async validateBusinessRule(rule, context) {
|
|
322
|
+
// TODO: Implement business rule evaluation
|
|
323
|
+
// This requires expression parsing and relationship resolution
|
|
324
|
+
// Stub: Pass silently until implementation is complete
|
|
325
|
+
return {
|
|
326
|
+
rule: rule.name,
|
|
327
|
+
valid: true,
|
|
328
|
+
};
|
|
329
|
+
}
|
|
330
|
+
/**
|
|
331
|
+
* Validate custom rule (stub - requires function execution).
|
|
332
|
+
*/
|
|
333
|
+
async validateCustom(rule, context) {
|
|
334
|
+
// TODO: Implement custom validator execution
|
|
335
|
+
// This requires safe function evaluation
|
|
336
|
+
// Stub: Pass silently until implementation is complete
|
|
337
|
+
return {
|
|
338
|
+
rule: rule.name,
|
|
339
|
+
valid: true,
|
|
340
|
+
};
|
|
341
|
+
}
|
|
342
|
+
/**
|
|
343
|
+
* Evaluate a validation condition.
|
|
344
|
+
*/
|
|
345
|
+
evaluateCondition(condition, record) {
|
|
346
|
+
// Handle logical operators
|
|
347
|
+
if (condition.all_of) {
|
|
348
|
+
return condition.all_of.every(c => this.evaluateCondition(c, record));
|
|
349
|
+
}
|
|
350
|
+
if (condition.any_of) {
|
|
351
|
+
return condition.any_of.some(c => this.evaluateCondition(c, record));
|
|
352
|
+
}
|
|
353
|
+
// Handle expression
|
|
354
|
+
if (condition.expression) {
|
|
355
|
+
// TODO: Implement safe expression evaluation
|
|
356
|
+
return true;
|
|
357
|
+
}
|
|
358
|
+
// Handle field comparison
|
|
359
|
+
if (condition.field && condition.operator !== undefined) {
|
|
360
|
+
const fieldValue = record[condition.field];
|
|
361
|
+
// Use compare_to if specified (cross-field comparison), otherwise use value
|
|
362
|
+
const compareValue = condition.compare_to !== undefined
|
|
363
|
+
? record[condition.compare_to]
|
|
364
|
+
: condition.value;
|
|
365
|
+
return this.compareValues(fieldValue, condition.operator, compareValue);
|
|
366
|
+
}
|
|
367
|
+
return true;
|
|
368
|
+
}
|
|
369
|
+
/**
|
|
370
|
+
* Compare two values using an operator.
|
|
371
|
+
*/
|
|
372
|
+
compareValues(a, operator, b) {
|
|
373
|
+
switch (operator) {
|
|
374
|
+
case '=':
|
|
375
|
+
return a === b;
|
|
376
|
+
case '!=':
|
|
377
|
+
return a !== b;
|
|
378
|
+
case '>':
|
|
379
|
+
return a > b;
|
|
380
|
+
case '>=':
|
|
381
|
+
return a >= b;
|
|
382
|
+
case '<':
|
|
383
|
+
return a < b;
|
|
384
|
+
case '<=':
|
|
385
|
+
return a <= b;
|
|
386
|
+
case 'in':
|
|
387
|
+
return Array.isArray(b) && b.includes(a);
|
|
388
|
+
case 'not_in':
|
|
389
|
+
return Array.isArray(b) && !b.includes(a);
|
|
390
|
+
case 'contains': {
|
|
391
|
+
if (a == null || b == null) {
|
|
392
|
+
return false;
|
|
393
|
+
}
|
|
394
|
+
const strA = String(a);
|
|
395
|
+
const strB = String(b);
|
|
396
|
+
return strA.includes(strB);
|
|
397
|
+
}
|
|
398
|
+
case 'not_contains': {
|
|
399
|
+
if (a == null || b == null) {
|
|
400
|
+
return false;
|
|
401
|
+
}
|
|
402
|
+
const strA = String(a);
|
|
403
|
+
const strB = String(b);
|
|
404
|
+
return !strA.includes(strB);
|
|
405
|
+
}
|
|
406
|
+
case 'starts_with': {
|
|
407
|
+
if (a == null || b == null) {
|
|
408
|
+
return false;
|
|
409
|
+
}
|
|
410
|
+
const strA = String(a);
|
|
411
|
+
const strB = String(b);
|
|
412
|
+
return strA.startsWith(strB);
|
|
413
|
+
}
|
|
414
|
+
case 'ends_with': {
|
|
415
|
+
if (a == null || b == null) {
|
|
416
|
+
return false;
|
|
417
|
+
}
|
|
418
|
+
const strA = String(a);
|
|
419
|
+
const strB = String(b);
|
|
420
|
+
return strA.endsWith(strB);
|
|
421
|
+
}
|
|
422
|
+
default:
|
|
423
|
+
return false;
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
/**
|
|
427
|
+
* Format validation message with template variables.
|
|
428
|
+
*/
|
|
429
|
+
formatMessage(message, context) {
|
|
430
|
+
// Handle i18n messages
|
|
431
|
+
if (typeof message === 'object') {
|
|
432
|
+
// Try preferred language first
|
|
433
|
+
const preferredLanguage = this.options.language ?? 'en';
|
|
434
|
+
let messageText = message[preferredLanguage];
|
|
435
|
+
// Try fallback languages if preferred not available
|
|
436
|
+
if (!messageText && this.options.languageFallback) {
|
|
437
|
+
for (const lang of this.options.languageFallback) {
|
|
438
|
+
if (message[lang]) {
|
|
439
|
+
messageText = message[lang];
|
|
440
|
+
break;
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
// Fallback to first available message
|
|
445
|
+
message = messageText || Object.values(message)[0];
|
|
446
|
+
}
|
|
447
|
+
// Replace template variables
|
|
448
|
+
return message.replace(/\{\{(\w+(?:\.\w+)*)\}\}/g, (match, path) => {
|
|
449
|
+
const value = this.getNestedValue(context, path);
|
|
450
|
+
return value !== undefined ? String(value) : match;
|
|
451
|
+
});
|
|
452
|
+
}
|
|
453
|
+
/**
|
|
454
|
+
* Get nested value from object by path.
|
|
455
|
+
*/
|
|
456
|
+
getNestedValue(obj, path) {
|
|
457
|
+
return path.split('.').reduce((current, key) => current?.[key], obj);
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
exports.Validator = Validator;
|
|
461
|
+
//# sourceMappingURL=validator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validator.js","sourceRoot":"","sources":["../src/validator.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@objectql/core",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.5.0",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"types": "dist/index.d.ts",
|
|
6
6
|
"dependencies": {
|
|
7
7
|
"fast-glob": "^3.3.2",
|
|
8
8
|
"js-yaml": "^4.1.1",
|
|
9
|
-
"@objectql/types": "1.
|
|
10
|
-
"@objectql/driver-remote": "1.
|
|
9
|
+
"@objectql/types": "1.5.0",
|
|
10
|
+
"@objectql/driver-remote": "1.5.0"
|
|
11
11
|
},
|
|
12
12
|
"devDependencies": {
|
|
13
13
|
"typescript": "^5.3.0"
|
package/src/app.ts
CHANGED
|
@@ -300,5 +300,54 @@ export class ObjectQL implements IObjectQL {
|
|
|
300
300
|
await driver.init(objects);
|
|
301
301
|
}
|
|
302
302
|
}
|
|
303
|
+
|
|
304
|
+
// 6. Process Initial Data
|
|
305
|
+
await this.processInitialData();
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
private async processInitialData() {
|
|
309
|
+
const dataEntries = this.metadata.list<any>('data');
|
|
310
|
+
if (dataEntries.length === 0) return;
|
|
311
|
+
|
|
312
|
+
console.log(`Processing ${dataEntries.length} initial data files...`);
|
|
313
|
+
|
|
314
|
+
// We need a system context to write data
|
|
315
|
+
const ctx = this.createContext({ isSystem: true });
|
|
316
|
+
|
|
317
|
+
for (const entry of dataEntries) {
|
|
318
|
+
// Expected format:
|
|
319
|
+
// object: User
|
|
320
|
+
// records:
|
|
321
|
+
// - name: Admin
|
|
322
|
+
// email: admin@example.com
|
|
323
|
+
|
|
324
|
+
const objectName = entry.object;
|
|
325
|
+
const records = entry.records;
|
|
326
|
+
|
|
327
|
+
if (!objectName || !records || !Array.isArray(records)) {
|
|
328
|
+
console.warn(`Skipping invalid data entry:`, entry);
|
|
329
|
+
continue;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
const repo = ctx.object(objectName);
|
|
333
|
+
|
|
334
|
+
for (const record of records) {
|
|
335
|
+
try {
|
|
336
|
+
// Check existence if a unique key is provided?
|
|
337
|
+
// For now, let's assume if it has an ID, we check it.
|
|
338
|
+
// Or we could try to find existing record by some key matching logic.
|
|
339
|
+
// Simple approach: create. If it fails (constraint), ignore.
|
|
340
|
+
|
|
341
|
+
// Actually, a better approach for initial data is "upsert" or "create if not exists".
|
|
342
|
+
// But without unique keys defined in data, we can't reliably dedup.
|
|
343
|
+
// Let's try to 'create' and catch errors.
|
|
344
|
+
await repo.create(record);
|
|
345
|
+
console.log(`Initialized record for ${objectName}`);
|
|
346
|
+
} catch (e: any) {
|
|
347
|
+
// Ignore duplicate key errors silently-ish
|
|
348
|
+
// console.warn(`Failed to insert initial data for ${objectName}: ${e.message}`);
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
}
|
|
303
352
|
}
|
|
304
353
|
}
|
package/src/index.ts
CHANGED
package/src/loader.ts
CHANGED
|
@@ -101,6 +101,51 @@ export class ObjectLoader {
|
|
|
101
101
|
}
|
|
102
102
|
}
|
|
103
103
|
});
|
|
104
|
+
|
|
105
|
+
// Generic YAML Metadata Loaders
|
|
106
|
+
const metaTypes = ['view', 'form', 'menu', 'permission', 'report', 'workflow', 'validation', 'data'];
|
|
107
|
+
|
|
108
|
+
for (const type of metaTypes) {
|
|
109
|
+
this.use({
|
|
110
|
+
name: type,
|
|
111
|
+
glob: [`**/*.${type}.yml`, `**/*.${type}.yaml`],
|
|
112
|
+
handler: (ctx) => {
|
|
113
|
+
try {
|
|
114
|
+
const doc = yaml.load(ctx.content) as any;
|
|
115
|
+
if (!doc) return;
|
|
116
|
+
|
|
117
|
+
// Use 'name' from doc, or filename base (without extension)
|
|
118
|
+
let id = doc.name;
|
|
119
|
+
if (!id && type !== 'data') {
|
|
120
|
+
const basename = path.basename(ctx.file);
|
|
121
|
+
// e.g. "my-view.view.yml" -> "my-view"
|
|
122
|
+
// Regex: remove .type.yml or .type.yaml
|
|
123
|
+
const re = new RegExp(`\\.${type}\\.(yml|yaml)$`);
|
|
124
|
+
id = basename.replace(re, '');
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Data entries might not need a name, but for registry we need an ID.
|
|
128
|
+
// For data, we can use filename if not present.
|
|
129
|
+
if (!id && type === 'data') {
|
|
130
|
+
id = path.basename(ctx.file);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Ensure name is in the doc for consistency
|
|
134
|
+
if (!doc.name) doc.name = id;
|
|
135
|
+
|
|
136
|
+
ctx.registry.register(type, {
|
|
137
|
+
type: type,
|
|
138
|
+
id: id,
|
|
139
|
+
path: ctx.file,
|
|
140
|
+
package: ctx.packageName,
|
|
141
|
+
content: doc
|
|
142
|
+
});
|
|
143
|
+
} catch (e) {
|
|
144
|
+
console.error(`Error loading ${type} from ${ctx.file}:`, e);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
})
|
|
148
|
+
}
|
|
104
149
|
}
|
|
105
150
|
|
|
106
151
|
use(plugin: LoaderPlugin) {
|