@objectstack/objectql 8.0.1 → 9.0.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/dist/index.d.mts +93 -5
- package/dist/index.d.ts +93 -5
- package/dist/index.js +698 -19
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +689 -4
- package/dist/index.mjs.map +1 -1
- package/package.json +6 -6
package/dist/index.js
CHANGED
|
@@ -5,6 +5,9 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
|
5
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
6
|
var __getProtoOf = Object.getPrototypeOf;
|
|
7
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __esm = (fn, res) => function __init() {
|
|
9
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
10
|
+
};
|
|
8
11
|
var __export = (target, all) => {
|
|
9
12
|
for (var name in all)
|
|
10
13
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
@@ -27,6 +30,609 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
27
30
|
));
|
|
28
31
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
32
|
|
|
33
|
+
// src/seed-loader.ts
|
|
34
|
+
var seed_loader_exports = {};
|
|
35
|
+
__export(seed_loader_exports, {
|
|
36
|
+
SeedLoaderService: () => SeedLoaderService
|
|
37
|
+
});
|
|
38
|
+
var import_data2, import_formula, DEFAULT_EXTERNAL_ID_FIELD, _SeedLoaderService, SeedLoaderService;
|
|
39
|
+
var init_seed_loader = __esm({
|
|
40
|
+
"src/seed-loader.ts"() {
|
|
41
|
+
"use strict";
|
|
42
|
+
import_data2 = require("@objectstack/spec/data");
|
|
43
|
+
import_formula = require("@objectstack/formula");
|
|
44
|
+
DEFAULT_EXTERNAL_ID_FIELD = "name";
|
|
45
|
+
_SeedLoaderService = class _SeedLoaderService {
|
|
46
|
+
constructor(engine, metadata, logger) {
|
|
47
|
+
this.engine = engine;
|
|
48
|
+
this.metadata = metadata;
|
|
49
|
+
this.logger = logger;
|
|
50
|
+
}
|
|
51
|
+
// ==========================================================================
|
|
52
|
+
// Public API
|
|
53
|
+
// ==========================================================================
|
|
54
|
+
async load(request) {
|
|
55
|
+
const startTime = Date.now();
|
|
56
|
+
const config = request.config;
|
|
57
|
+
const allErrors = [];
|
|
58
|
+
const allResults = [];
|
|
59
|
+
const datasets = this.filterByEnv(request.seeds, config.env);
|
|
60
|
+
if (datasets.length === 0) {
|
|
61
|
+
return this.buildEmptyResult(config, Date.now() - startTime);
|
|
62
|
+
}
|
|
63
|
+
const objectNames = datasets.map((d) => d.object);
|
|
64
|
+
const graph = await this.buildDependencyGraph(objectNames);
|
|
65
|
+
this.logger.info("[SeedLoader] Dependency graph built", {
|
|
66
|
+
objects: objectNames.length,
|
|
67
|
+
insertOrder: graph.insertOrder,
|
|
68
|
+
circularDeps: graph.circularDependencies.length
|
|
69
|
+
});
|
|
70
|
+
const orderedDatasets = this.orderDatasets(datasets, graph.insertOrder);
|
|
71
|
+
const refMap = this.buildReferenceMap(graph);
|
|
72
|
+
const insertedRecords = /* @__PURE__ */ new Map();
|
|
73
|
+
const deferredUpdates = [];
|
|
74
|
+
for (const dataset of orderedDatasets) {
|
|
75
|
+
const result = await this.loadDataset(
|
|
76
|
+
dataset,
|
|
77
|
+
config,
|
|
78
|
+
refMap,
|
|
79
|
+
insertedRecords,
|
|
80
|
+
deferredUpdates,
|
|
81
|
+
allErrors
|
|
82
|
+
);
|
|
83
|
+
allResults.push(result);
|
|
84
|
+
if (config.haltOnError && result.errored > 0) {
|
|
85
|
+
this.logger.warn("[SeedLoader] Halting on first error", { object: dataset.object });
|
|
86
|
+
break;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
if (config.multiPass && deferredUpdates.length > 0 && !config.dryRun) {
|
|
90
|
+
this.logger.info("[SeedLoader] Pass 2: resolving deferred references", {
|
|
91
|
+
count: deferredUpdates.length
|
|
92
|
+
});
|
|
93
|
+
await this.resolveDeferredUpdates(deferredUpdates, insertedRecords, allResults, allErrors, config.organizationId);
|
|
94
|
+
}
|
|
95
|
+
const durationMs = Date.now() - startTime;
|
|
96
|
+
return this.buildResult(config, graph, allResults, allErrors, durationMs);
|
|
97
|
+
}
|
|
98
|
+
async buildDependencyGraph(objectNames) {
|
|
99
|
+
const nodes = [];
|
|
100
|
+
const objectSet = new Set(objectNames);
|
|
101
|
+
for (const objectName of objectNames) {
|
|
102
|
+
const objDef = await this.metadata.getObject(objectName);
|
|
103
|
+
const dependsOn = [];
|
|
104
|
+
const references = [];
|
|
105
|
+
if (objDef && objDef.fields) {
|
|
106
|
+
const fields = objDef.fields;
|
|
107
|
+
for (const [fieldName, fieldDef] of Object.entries(fields)) {
|
|
108
|
+
if ((fieldDef.type === "lookup" || fieldDef.type === "master_detail") && fieldDef.reference) {
|
|
109
|
+
const targetObject = fieldDef.reference;
|
|
110
|
+
if (objectSet.has(targetObject) && !dependsOn.includes(targetObject)) {
|
|
111
|
+
dependsOn.push(targetObject);
|
|
112
|
+
}
|
|
113
|
+
references.push({
|
|
114
|
+
field: fieldName,
|
|
115
|
+
targetObject,
|
|
116
|
+
targetField: DEFAULT_EXTERNAL_ID_FIELD,
|
|
117
|
+
fieldType: fieldDef.type
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
nodes.push({ object: objectName, dependsOn, references });
|
|
123
|
+
}
|
|
124
|
+
const { insertOrder, circularDependencies } = this.topologicalSort(nodes);
|
|
125
|
+
return { nodes, insertOrder, circularDependencies };
|
|
126
|
+
}
|
|
127
|
+
async validate(datasets, config) {
|
|
128
|
+
const parsedConfig = import_data2.SeedLoaderConfigSchema.parse({ ...config, dryRun: true });
|
|
129
|
+
return this.load({ seeds: datasets, config: parsedConfig });
|
|
130
|
+
}
|
|
131
|
+
// ==========================================================================
|
|
132
|
+
// Internal: Seed Loading
|
|
133
|
+
// ==========================================================================
|
|
134
|
+
async loadDataset(dataset, config, refMap, insertedRecords, deferredUpdates, allErrors) {
|
|
135
|
+
const objectName = dataset.object;
|
|
136
|
+
const mode = dataset.mode || config.defaultMode;
|
|
137
|
+
const externalId = dataset.externalId || "name";
|
|
138
|
+
let inserted = 0;
|
|
139
|
+
let updated = 0;
|
|
140
|
+
let skipped = 0;
|
|
141
|
+
let errored = 0;
|
|
142
|
+
let referencesResolved = 0;
|
|
143
|
+
let referencesDeferred = 0;
|
|
144
|
+
const errors = [];
|
|
145
|
+
if (!insertedRecords.has(objectName)) {
|
|
146
|
+
insertedRecords.set(objectName, /* @__PURE__ */ new Map());
|
|
147
|
+
}
|
|
148
|
+
let existingRecords;
|
|
149
|
+
if ((mode === "upsert" || mode === "update" || mode === "ignore") && !config.dryRun) {
|
|
150
|
+
existingRecords = await this.loadExistingRecords(
|
|
151
|
+
objectName,
|
|
152
|
+
externalId,
|
|
153
|
+
config.organizationId
|
|
154
|
+
);
|
|
155
|
+
}
|
|
156
|
+
const objectRefs = refMap.get(objectName) || [];
|
|
157
|
+
const seedNow = /* @__PURE__ */ new Date();
|
|
158
|
+
const seedIdentity = config.identity;
|
|
159
|
+
const baseEvalCtx = {
|
|
160
|
+
now: seedNow,
|
|
161
|
+
user: seedIdentity?.user,
|
|
162
|
+
// Fall back to the per-tenant organizationId so `os.org.id` resolves
|
|
163
|
+
// during per-org replay even without an explicit identity.org.
|
|
164
|
+
org: seedIdentity?.org ?? (config.organizationId ? { id: config.organizationId } : void 0),
|
|
165
|
+
env: config.env
|
|
166
|
+
};
|
|
167
|
+
for (let i = 0; i < dataset.records.length; i++) {
|
|
168
|
+
const seedResult = (0, import_formula.resolveSeedRecord)(
|
|
169
|
+
dataset.records[i],
|
|
170
|
+
baseEvalCtx
|
|
171
|
+
);
|
|
172
|
+
if (!seedResult.ok) {
|
|
173
|
+
errored++;
|
|
174
|
+
const error = {
|
|
175
|
+
sourceObject: objectName,
|
|
176
|
+
field: "(expression)",
|
|
177
|
+
targetObject: objectName,
|
|
178
|
+
targetField: "(expression)",
|
|
179
|
+
attemptedValue: dataset.records[i],
|
|
180
|
+
recordIndex: i,
|
|
181
|
+
message: `Cannot resolve dynamic seed values for ${objectName} record #${i}: ${seedResult.error.message}. Records using cel\`os.user.id\` / cel\`os.org.id\` require a seed identity \u2014 ensure a system/admin user exists before seeding (see SeedLoaderConfig.identity).`
|
|
182
|
+
};
|
|
183
|
+
errors.push(error);
|
|
184
|
+
allErrors.push(error);
|
|
185
|
+
this.logger.warn(`[SeedLoader] ${error.message}`);
|
|
186
|
+
continue;
|
|
187
|
+
}
|
|
188
|
+
const record = { ...seedResult.value };
|
|
189
|
+
if (config.organizationId && record["organization_id"] == null) {
|
|
190
|
+
record["organization_id"] = config.organizationId;
|
|
191
|
+
}
|
|
192
|
+
for (const ref of objectRefs) {
|
|
193
|
+
const fieldValue = record[ref.field];
|
|
194
|
+
if (fieldValue === void 0 || fieldValue === null) continue;
|
|
195
|
+
if (typeof fieldValue === "object") {
|
|
196
|
+
const wrapped = fieldValue.externalId;
|
|
197
|
+
const hint = wrapped !== void 0 ? ` Pass the natural key directly: ${ref.field}: ${JSON.stringify(wrapped)}.` : ` Pass the target's ${ref.targetField} value as a plain string.`;
|
|
198
|
+
const error = {
|
|
199
|
+
sourceObject: objectName,
|
|
200
|
+
field: ref.field,
|
|
201
|
+
targetObject: ref.targetObject,
|
|
202
|
+
targetField: ref.targetField,
|
|
203
|
+
attemptedValue: fieldValue,
|
|
204
|
+
recordIndex: i,
|
|
205
|
+
message: `Invalid reference for ${objectName}.${ref.field}: expected a ${ref.targetObject}.${ref.targetField} natural-key string but got an object.${hint}`
|
|
206
|
+
};
|
|
207
|
+
errors.push(error);
|
|
208
|
+
allErrors.push(error);
|
|
209
|
+
this.logger.warn(`[SeedLoader] ${error.message}`, { recordIndex: i });
|
|
210
|
+
record[ref.field] = null;
|
|
211
|
+
continue;
|
|
212
|
+
}
|
|
213
|
+
if (typeof fieldValue !== "string" || this.looksLikeInternalId(fieldValue)) continue;
|
|
214
|
+
const targetMap = insertedRecords.get(ref.targetObject);
|
|
215
|
+
const resolvedId = targetMap?.get(String(fieldValue));
|
|
216
|
+
if (resolvedId) {
|
|
217
|
+
record[ref.field] = resolvedId;
|
|
218
|
+
referencesResolved++;
|
|
219
|
+
} else if (!config.dryRun) {
|
|
220
|
+
const dbId = await this.resolveFromDatabase(ref.targetObject, ref.targetField, fieldValue, config.organizationId);
|
|
221
|
+
if (dbId) {
|
|
222
|
+
record[ref.field] = dbId;
|
|
223
|
+
referencesResolved++;
|
|
224
|
+
} else if (config.multiPass) {
|
|
225
|
+
record[ref.field] = null;
|
|
226
|
+
deferredUpdates.push({
|
|
227
|
+
objectName,
|
|
228
|
+
recordExternalId: String(record[externalId] ?? ""),
|
|
229
|
+
field: ref.field,
|
|
230
|
+
targetObject: ref.targetObject,
|
|
231
|
+
targetField: ref.targetField,
|
|
232
|
+
attemptedValue: fieldValue,
|
|
233
|
+
recordIndex: i
|
|
234
|
+
});
|
|
235
|
+
referencesDeferred++;
|
|
236
|
+
} else {
|
|
237
|
+
const error = {
|
|
238
|
+
sourceObject: objectName,
|
|
239
|
+
field: ref.field,
|
|
240
|
+
targetObject: ref.targetObject,
|
|
241
|
+
targetField: ref.targetField,
|
|
242
|
+
attemptedValue: fieldValue,
|
|
243
|
+
recordIndex: i,
|
|
244
|
+
message: `Cannot resolve reference: ${objectName}.${ref.field} = '${fieldValue}' \u2192 ${ref.targetObject}.${ref.targetField} not found`
|
|
245
|
+
};
|
|
246
|
+
errors.push(error);
|
|
247
|
+
allErrors.push(error);
|
|
248
|
+
}
|
|
249
|
+
} else {
|
|
250
|
+
const targetMap2 = insertedRecords.get(ref.targetObject);
|
|
251
|
+
if (!targetMap2?.has(String(fieldValue))) {
|
|
252
|
+
const error = {
|
|
253
|
+
sourceObject: objectName,
|
|
254
|
+
field: ref.field,
|
|
255
|
+
targetObject: ref.targetObject,
|
|
256
|
+
targetField: ref.targetField,
|
|
257
|
+
attemptedValue: fieldValue,
|
|
258
|
+
recordIndex: i,
|
|
259
|
+
message: `[dry-run] Reference may not resolve: ${objectName}.${ref.field} = '${fieldValue}' \u2192 ${ref.targetObject}.${ref.targetField}`
|
|
260
|
+
};
|
|
261
|
+
errors.push(error);
|
|
262
|
+
allErrors.push(error);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
if (!config.dryRun) {
|
|
267
|
+
try {
|
|
268
|
+
const result = await this.writeRecord(
|
|
269
|
+
objectName,
|
|
270
|
+
record,
|
|
271
|
+
mode,
|
|
272
|
+
externalId,
|
|
273
|
+
existingRecords
|
|
274
|
+
);
|
|
275
|
+
if (result.action === "inserted") inserted++;
|
|
276
|
+
else if (result.action === "updated") updated++;
|
|
277
|
+
else if (result.action === "skipped") skipped++;
|
|
278
|
+
const externalIdValue = String(record[externalId] ?? "");
|
|
279
|
+
const internalId = result.id;
|
|
280
|
+
if (externalIdValue && internalId) {
|
|
281
|
+
insertedRecords.get(objectName).set(externalIdValue, String(internalId));
|
|
282
|
+
}
|
|
283
|
+
} catch (err) {
|
|
284
|
+
errored++;
|
|
285
|
+
const error = {
|
|
286
|
+
sourceObject: objectName,
|
|
287
|
+
field: "(write)",
|
|
288
|
+
targetObject: objectName,
|
|
289
|
+
targetField: externalId,
|
|
290
|
+
attemptedValue: record[externalId] ?? null,
|
|
291
|
+
recordIndex: i,
|
|
292
|
+
message: `Failed to write ${objectName} record #${i} (${externalId}=${String(record[externalId] ?? "")}): ${err.message}`
|
|
293
|
+
};
|
|
294
|
+
errors.push(error);
|
|
295
|
+
allErrors.push(error);
|
|
296
|
+
this.logger.warn(`[SeedLoader] ${error.message}`, { recordIndex: i });
|
|
297
|
+
}
|
|
298
|
+
} else {
|
|
299
|
+
const externalIdValue = String(record[externalId] ?? "");
|
|
300
|
+
if (externalIdValue) {
|
|
301
|
+
insertedRecords.get(objectName).set(externalIdValue, `dry-run-id-${i}`);
|
|
302
|
+
}
|
|
303
|
+
inserted++;
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
return {
|
|
307
|
+
object: objectName,
|
|
308
|
+
mode,
|
|
309
|
+
inserted,
|
|
310
|
+
updated,
|
|
311
|
+
skipped,
|
|
312
|
+
errored,
|
|
313
|
+
total: dataset.records.length,
|
|
314
|
+
referencesResolved,
|
|
315
|
+
referencesDeferred,
|
|
316
|
+
errors
|
|
317
|
+
};
|
|
318
|
+
}
|
|
319
|
+
// ==========================================================================
|
|
320
|
+
// Internal: Reference Resolution
|
|
321
|
+
// ==========================================================================
|
|
322
|
+
async resolveFromDatabase(targetObject, targetField, value, organizationId) {
|
|
323
|
+
try {
|
|
324
|
+
const where = { [targetField]: value };
|
|
325
|
+
if (organizationId) where.organization_id = organizationId;
|
|
326
|
+
const records = await this.engine.find(targetObject, {
|
|
327
|
+
where,
|
|
328
|
+
fields: ["id"],
|
|
329
|
+
limit: 1,
|
|
330
|
+
context: { isSystem: true }
|
|
331
|
+
});
|
|
332
|
+
if (records && records.length > 0) {
|
|
333
|
+
return String(records[0].id || records[0]._id);
|
|
334
|
+
}
|
|
335
|
+
} catch {
|
|
336
|
+
}
|
|
337
|
+
return null;
|
|
338
|
+
}
|
|
339
|
+
async resolveDeferredUpdates(deferredUpdates, insertedRecords, allResults, allErrors, organizationId) {
|
|
340
|
+
for (const deferred of deferredUpdates) {
|
|
341
|
+
const targetMap = insertedRecords.get(deferred.targetObject);
|
|
342
|
+
let resolvedId = targetMap?.get(String(deferred.attemptedValue));
|
|
343
|
+
if (!resolvedId) {
|
|
344
|
+
resolvedId = await this.resolveFromDatabase(
|
|
345
|
+
deferred.targetObject,
|
|
346
|
+
deferred.targetField,
|
|
347
|
+
deferred.attemptedValue,
|
|
348
|
+
organizationId
|
|
349
|
+
) ?? void 0;
|
|
350
|
+
}
|
|
351
|
+
if (resolvedId) {
|
|
352
|
+
const objectRecordMap = insertedRecords.get(deferred.objectName);
|
|
353
|
+
const recordId = objectRecordMap?.get(deferred.recordExternalId);
|
|
354
|
+
if (recordId) {
|
|
355
|
+
try {
|
|
356
|
+
await this.engine.update(deferred.objectName, {
|
|
357
|
+
id: recordId,
|
|
358
|
+
[deferred.field]: resolvedId
|
|
359
|
+
}, { context: { isSystem: true } });
|
|
360
|
+
const resultEntry = allResults.find((r) => r.object === deferred.objectName);
|
|
361
|
+
if (resultEntry) {
|
|
362
|
+
resultEntry.referencesResolved++;
|
|
363
|
+
resultEntry.referencesDeferred--;
|
|
364
|
+
}
|
|
365
|
+
} catch (err) {
|
|
366
|
+
this.logger.warn("[SeedLoader] Failed to resolve deferred reference", {
|
|
367
|
+
object: deferred.objectName,
|
|
368
|
+
field: deferred.field,
|
|
369
|
+
error: err.message
|
|
370
|
+
});
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
} else {
|
|
374
|
+
const error = {
|
|
375
|
+
sourceObject: deferred.objectName,
|
|
376
|
+
field: deferred.field,
|
|
377
|
+
targetObject: deferred.targetObject,
|
|
378
|
+
targetField: deferred.targetField,
|
|
379
|
+
attemptedValue: deferred.attemptedValue,
|
|
380
|
+
recordIndex: deferred.recordIndex,
|
|
381
|
+
message: `Deferred reference unresolved after pass 2: ${deferred.objectName}.${deferred.field} = '${deferred.attemptedValue}' \u2192 ${deferred.targetObject}.${deferred.targetField} not found`
|
|
382
|
+
};
|
|
383
|
+
const resultEntry = allResults.find((r) => r.object === deferred.objectName);
|
|
384
|
+
if (resultEntry) {
|
|
385
|
+
resultEntry.errors.push(error);
|
|
386
|
+
}
|
|
387
|
+
allErrors.push(error);
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
async writeRecord(objectName, record, mode, externalId, existingRecords) {
|
|
392
|
+
const externalIdValue = record[externalId];
|
|
393
|
+
const existing = existingRecords?.get(String(externalIdValue ?? ""));
|
|
394
|
+
const opts = _SeedLoaderService.SEED_OPTIONS;
|
|
395
|
+
switch (mode) {
|
|
396
|
+
case "insert": {
|
|
397
|
+
const result = await this.engine.insert(objectName, record, opts);
|
|
398
|
+
return { action: "inserted", id: this.extractId(result) };
|
|
399
|
+
}
|
|
400
|
+
case "update": {
|
|
401
|
+
if (!existing) {
|
|
402
|
+
return { action: "skipped" };
|
|
403
|
+
}
|
|
404
|
+
const id = this.extractId(existing);
|
|
405
|
+
await this.engine.update(objectName, { ...record, id }, opts);
|
|
406
|
+
return { action: "updated", id };
|
|
407
|
+
}
|
|
408
|
+
case "upsert": {
|
|
409
|
+
if (existing) {
|
|
410
|
+
const id = this.extractId(existing);
|
|
411
|
+
await this.engine.update(objectName, { ...record, id }, opts);
|
|
412
|
+
return { action: "updated", id };
|
|
413
|
+
} else {
|
|
414
|
+
const result = await this.engine.insert(objectName, record, opts);
|
|
415
|
+
return { action: "inserted", id: this.extractId(result) };
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
case "ignore": {
|
|
419
|
+
if (existing) {
|
|
420
|
+
return { action: "skipped", id: this.extractId(existing) };
|
|
421
|
+
}
|
|
422
|
+
const result = await this.engine.insert(objectName, record, opts);
|
|
423
|
+
return { action: "inserted", id: this.extractId(result) };
|
|
424
|
+
}
|
|
425
|
+
case "replace": {
|
|
426
|
+
const result = await this.engine.insert(objectName, record, opts);
|
|
427
|
+
return { action: "inserted", id: this.extractId(result) };
|
|
428
|
+
}
|
|
429
|
+
default: {
|
|
430
|
+
const result = await this.engine.insert(objectName, record, opts);
|
|
431
|
+
return { action: "inserted", id: this.extractId(result) };
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
// ==========================================================================
|
|
436
|
+
// Internal: Dependency Graph
|
|
437
|
+
// ==========================================================================
|
|
438
|
+
/**
|
|
439
|
+
* Kahn's algorithm for topological sort with cycle detection.
|
|
440
|
+
*/
|
|
441
|
+
topologicalSort(nodes) {
|
|
442
|
+
const inDegree = /* @__PURE__ */ new Map();
|
|
443
|
+
const adjacency = /* @__PURE__ */ new Map();
|
|
444
|
+
const objectSet = new Set(nodes.map((n) => n.object));
|
|
445
|
+
for (const node of nodes) {
|
|
446
|
+
inDegree.set(node.object, 0);
|
|
447
|
+
adjacency.set(node.object, []);
|
|
448
|
+
}
|
|
449
|
+
for (const node of nodes) {
|
|
450
|
+
for (const dep of node.dependsOn) {
|
|
451
|
+
if (objectSet.has(dep) && dep !== node.object) {
|
|
452
|
+
adjacency.get(dep).push(node.object);
|
|
453
|
+
inDegree.set(node.object, (inDegree.get(node.object) || 0) + 1);
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
const queue = [];
|
|
458
|
+
for (const [obj, degree] of inDegree) {
|
|
459
|
+
if (degree === 0) queue.push(obj);
|
|
460
|
+
}
|
|
461
|
+
const insertOrder = [];
|
|
462
|
+
while (queue.length > 0) {
|
|
463
|
+
const current = queue.shift();
|
|
464
|
+
insertOrder.push(current);
|
|
465
|
+
for (const neighbor of adjacency.get(current) || []) {
|
|
466
|
+
const newDegree = (inDegree.get(neighbor) || 0) - 1;
|
|
467
|
+
inDegree.set(neighbor, newDegree);
|
|
468
|
+
if (newDegree === 0) {
|
|
469
|
+
queue.push(neighbor);
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
const circularDependencies = [];
|
|
474
|
+
const remaining = nodes.filter((n) => !insertOrder.includes(n.object));
|
|
475
|
+
if (remaining.length > 0) {
|
|
476
|
+
const cycles = this.findCycles(remaining);
|
|
477
|
+
circularDependencies.push(...cycles);
|
|
478
|
+
for (const node of remaining) {
|
|
479
|
+
if (!insertOrder.includes(node.object)) {
|
|
480
|
+
insertOrder.push(node.object);
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
return { insertOrder, circularDependencies };
|
|
485
|
+
}
|
|
486
|
+
findCycles(nodes) {
|
|
487
|
+
const cycles = [];
|
|
488
|
+
const nodeMap = new Map(nodes.map((n) => [n.object, n]));
|
|
489
|
+
const visited = /* @__PURE__ */ new Set();
|
|
490
|
+
const inStack = /* @__PURE__ */ new Set();
|
|
491
|
+
const dfs = (current, path) => {
|
|
492
|
+
if (inStack.has(current)) {
|
|
493
|
+
const cycleStart = path.indexOf(current);
|
|
494
|
+
if (cycleStart !== -1) {
|
|
495
|
+
cycles.push([...path.slice(cycleStart), current]);
|
|
496
|
+
}
|
|
497
|
+
return;
|
|
498
|
+
}
|
|
499
|
+
if (visited.has(current)) return;
|
|
500
|
+
visited.add(current);
|
|
501
|
+
inStack.add(current);
|
|
502
|
+
path.push(current);
|
|
503
|
+
const node = nodeMap.get(current);
|
|
504
|
+
if (node) {
|
|
505
|
+
for (const dep of node.dependsOn) {
|
|
506
|
+
if (nodeMap.has(dep)) {
|
|
507
|
+
dfs(dep, [...path]);
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
inStack.delete(current);
|
|
512
|
+
};
|
|
513
|
+
for (const node of nodes) {
|
|
514
|
+
if (!visited.has(node.object)) {
|
|
515
|
+
dfs(node.object, []);
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
return cycles;
|
|
519
|
+
}
|
|
520
|
+
// ==========================================================================
|
|
521
|
+
// Internal: Helpers
|
|
522
|
+
// ==========================================================================
|
|
523
|
+
filterByEnv(datasets, env) {
|
|
524
|
+
if (!env) return datasets;
|
|
525
|
+
return datasets.filter((d) => d.env.includes(env));
|
|
526
|
+
}
|
|
527
|
+
orderDatasets(datasets, insertOrder) {
|
|
528
|
+
const orderMap = new Map(insertOrder.map((name, i) => [name, i]));
|
|
529
|
+
return [...datasets].sort((a, b) => {
|
|
530
|
+
const orderA = orderMap.get(a.object) ?? Number.MAX_SAFE_INTEGER;
|
|
531
|
+
const orderB = orderMap.get(b.object) ?? Number.MAX_SAFE_INTEGER;
|
|
532
|
+
return orderA - orderB;
|
|
533
|
+
});
|
|
534
|
+
}
|
|
535
|
+
buildReferenceMap(graph) {
|
|
536
|
+
const map = /* @__PURE__ */ new Map();
|
|
537
|
+
for (const node of graph.nodes) {
|
|
538
|
+
if (node.references.length > 0) {
|
|
539
|
+
map.set(node.object, node.references);
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
return map;
|
|
543
|
+
}
|
|
544
|
+
async loadExistingRecords(objectName, externalId, organizationId) {
|
|
545
|
+
const map = /* @__PURE__ */ new Map();
|
|
546
|
+
try {
|
|
547
|
+
const findArgs = {
|
|
548
|
+
fields: ["id", externalId],
|
|
549
|
+
context: { isSystem: true }
|
|
550
|
+
};
|
|
551
|
+
if (organizationId) findArgs.where = { organization_id: organizationId };
|
|
552
|
+
const records = await this.engine.find(objectName, findArgs);
|
|
553
|
+
for (const record of records || []) {
|
|
554
|
+
const key = String(record[externalId] ?? "");
|
|
555
|
+
if (key) {
|
|
556
|
+
map.set(key, record);
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
} catch {
|
|
560
|
+
}
|
|
561
|
+
return map;
|
|
562
|
+
}
|
|
563
|
+
looksLikeInternalId(value) {
|
|
564
|
+
if (/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(value)) {
|
|
565
|
+
return true;
|
|
566
|
+
}
|
|
567
|
+
if (/^[0-9a-f]{24}$/i.test(value)) {
|
|
568
|
+
return true;
|
|
569
|
+
}
|
|
570
|
+
return false;
|
|
571
|
+
}
|
|
572
|
+
extractId(record) {
|
|
573
|
+
if (!record) return void 0;
|
|
574
|
+
return String(record.id || record._id || "");
|
|
575
|
+
}
|
|
576
|
+
buildEmptyResult(config, durationMs) {
|
|
577
|
+
return {
|
|
578
|
+
success: true,
|
|
579
|
+
dryRun: config.dryRun,
|
|
580
|
+
dependencyGraph: { nodes: [], insertOrder: [], circularDependencies: [] },
|
|
581
|
+
results: [],
|
|
582
|
+
errors: [],
|
|
583
|
+
summary: {
|
|
584
|
+
objectsProcessed: 0,
|
|
585
|
+
totalRecords: 0,
|
|
586
|
+
totalInserted: 0,
|
|
587
|
+
totalUpdated: 0,
|
|
588
|
+
totalSkipped: 0,
|
|
589
|
+
totalErrored: 0,
|
|
590
|
+
totalReferencesResolved: 0,
|
|
591
|
+
totalReferencesDeferred: 0,
|
|
592
|
+
circularDependencyCount: 0,
|
|
593
|
+
durationMs
|
|
594
|
+
}
|
|
595
|
+
};
|
|
596
|
+
}
|
|
597
|
+
buildResult(config, graph, results, errors, durationMs) {
|
|
598
|
+
const summary = {
|
|
599
|
+
objectsProcessed: results.length,
|
|
600
|
+
totalRecords: results.reduce((sum, r) => sum + r.total, 0),
|
|
601
|
+
totalInserted: results.reduce((sum, r) => sum + r.inserted, 0),
|
|
602
|
+
totalUpdated: results.reduce((sum, r) => sum + r.updated, 0),
|
|
603
|
+
totalSkipped: results.reduce((sum, r) => sum + r.skipped, 0),
|
|
604
|
+
totalErrored: results.reduce((sum, r) => sum + r.errored, 0),
|
|
605
|
+
totalReferencesResolved: results.reduce((sum, r) => sum + r.referencesResolved, 0),
|
|
606
|
+
totalReferencesDeferred: results.reduce((sum, r) => sum + r.referencesDeferred, 0),
|
|
607
|
+
circularDependencyCount: graph.circularDependencies.length,
|
|
608
|
+
durationMs
|
|
609
|
+
};
|
|
610
|
+
const hasErrors = errors.length > 0 || summary.totalErrored > 0;
|
|
611
|
+
return {
|
|
612
|
+
success: !hasErrors,
|
|
613
|
+
dryRun: config.dryRun,
|
|
614
|
+
dependencyGraph: graph,
|
|
615
|
+
results,
|
|
616
|
+
errors,
|
|
617
|
+
summary
|
|
618
|
+
};
|
|
619
|
+
}
|
|
620
|
+
};
|
|
621
|
+
// ==========================================================================
|
|
622
|
+
// Internal: Write Operations
|
|
623
|
+
// ==========================================================================
|
|
624
|
+
/**
|
|
625
|
+
* Seed writes always run as a privileged system context. This bypasses
|
|
626
|
+
* RBAC checks (so seeds can target system tables like `sys_*`) and
|
|
627
|
+
* disables the SecurityPlugin's auto-injection of `organization_id` /
|
|
628
|
+
* `owner_id` — seeds either declare those fields explicitly per
|
|
629
|
+
* record, or are intentionally cross-tenant / global.
|
|
630
|
+
*/
|
|
631
|
+
_SeedLoaderService.SEED_OPTIONS = { context: { isSystem: true } };
|
|
632
|
+
SeedLoaderService = _SeedLoaderService;
|
|
633
|
+
}
|
|
634
|
+
});
|
|
635
|
+
|
|
30
636
|
// src/index.ts
|
|
31
637
|
var index_exports = {};
|
|
32
638
|
__export(index_exports, {
|
|
@@ -43,6 +649,7 @@ __export(index_exports, {
|
|
|
43
649
|
SECRET_REF_PREFIX: () => SECRET_REF_PREFIX,
|
|
44
650
|
SchemaRegistry: () => SchemaRegistry,
|
|
45
651
|
ScopedContext: () => ScopedContext,
|
|
652
|
+
SeedLoaderService: () => SeedLoaderService,
|
|
46
653
|
SysMetadataRepository: () => SysMetadataRepository,
|
|
47
654
|
ValidationError: () => ValidationError,
|
|
48
655
|
applyInMemoryAggregation: () => applyInMemoryAggregation,
|
|
@@ -1568,7 +2175,7 @@ var SysMetadataRepository = class {
|
|
|
1568
2175
|
|
|
1569
2176
|
// src/protocol.ts
|
|
1570
2177
|
var import_metadata_core2 = require("@objectstack/metadata-core");
|
|
1571
|
-
var
|
|
2178
|
+
var import_data3 = require("@objectstack/spec/data");
|
|
1572
2179
|
var import_shared4 = require("@objectstack/spec/shared");
|
|
1573
2180
|
var import_ui2 = require("@objectstack/spec/ui");
|
|
1574
2181
|
var import_system = require("@objectstack/spec/system");
|
|
@@ -2937,8 +3544,8 @@ var _ObjectStackProtocolImplementation = class _ObjectStackProtocolImplementatio
|
|
|
2937
3544
|
} catch {
|
|
2938
3545
|
}
|
|
2939
3546
|
}
|
|
2940
|
-
if ((0,
|
|
2941
|
-
parsedFilter = (0,
|
|
3547
|
+
if ((0, import_data3.isFilterAST)(parsedFilter)) {
|
|
3548
|
+
parsedFilter = (0, import_data3.parseFilterAST)(parsedFilter);
|
|
2942
3549
|
}
|
|
2943
3550
|
options.where = parsedFilter;
|
|
2944
3551
|
}
|
|
@@ -4279,12 +4886,16 @@ var _ObjectStackProtocolImplementation = class _ObjectStackProtocolImplementatio
|
|
|
4279
4886
|
item: result.item.body
|
|
4280
4887
|
});
|
|
4281
4888
|
await this.ensureObjectStorage(request.type, request.name);
|
|
4282
|
-
|
|
4889
|
+
const response = {
|
|
4283
4890
|
success: true,
|
|
4284
4891
|
version: result.version,
|
|
4285
4892
|
seq: result.seq,
|
|
4286
4893
|
message: `Published draft \u2014 type=${request.type}, name=${request.name} [seq=${result.seq}]`
|
|
4287
4894
|
};
|
|
4895
|
+
if (singularType === "seed" && !request._skipSeedApply) {
|
|
4896
|
+
response.seedApplied = await this.applySeedBodies([result.item.body], orgId);
|
|
4897
|
+
}
|
|
4898
|
+
return response;
|
|
4288
4899
|
} catch (err) {
|
|
4289
4900
|
if (err instanceof import_metadata_core2.ConflictError) {
|
|
4290
4901
|
const conflict = new Error(
|
|
@@ -4299,6 +4910,58 @@ var _ObjectStackProtocolImplementation = class _ObjectStackProtocolImplementatio
|
|
|
4299
4910
|
throw err;
|
|
4300
4911
|
}
|
|
4301
4912
|
}
|
|
4913
|
+
/**
|
|
4914
|
+
* Materialize published `seed` bodies into data rows via the SeedLoaderService
|
|
4915
|
+
* (externalId-keyed upsert, multi-pass for cross-seed references). Passing ALL
|
|
4916
|
+
* of a publish's seed bodies in ONE call lets a child seed reference a parent
|
|
4917
|
+
* seed's rows regardless of publish order. Best-effort: any failure is
|
|
4918
|
+
* returned, never thrown — publishing metadata must not be blocked by a data
|
|
4919
|
+
* problem, but the caller surfaces `seedApplied` so the failure is LOUD.
|
|
4920
|
+
*/
|
|
4921
|
+
async applySeedBodies(bodies, organizationId) {
|
|
4922
|
+
try {
|
|
4923
|
+
const seeds = bodies.filter(
|
|
4924
|
+
(b) => b && typeof b.object === "string" && Array.isArray(b.records)
|
|
4925
|
+
);
|
|
4926
|
+
if (seeds.length === 0) {
|
|
4927
|
+
return { success: false, inserted: 0, updated: 0, error: "seed apply: no readable seed bodies" };
|
|
4928
|
+
}
|
|
4929
|
+
const { SeedLoaderService: SeedLoaderService2 } = await Promise.resolve().then(() => (init_seed_loader(), seed_loader_exports));
|
|
4930
|
+
const { SeedLoaderRequestSchema } = await import("@objectstack/spec/data");
|
|
4931
|
+
const metadataAdapter = {
|
|
4932
|
+
getObject: async (name) => {
|
|
4933
|
+
const wrapper = await this.getMetaItem({
|
|
4934
|
+
type: "object",
|
|
4935
|
+
name,
|
|
4936
|
+
...organizationId ? { organizationId } : {}
|
|
4937
|
+
});
|
|
4938
|
+
return wrapper?.item ?? wrapper ?? null;
|
|
4939
|
+
}
|
|
4940
|
+
};
|
|
4941
|
+
const loader = new SeedLoaderService2(
|
|
4942
|
+
this.engine,
|
|
4943
|
+
metadataAdapter,
|
|
4944
|
+
console
|
|
4945
|
+
);
|
|
4946
|
+
const request = SeedLoaderRequestSchema.parse({
|
|
4947
|
+
seeds,
|
|
4948
|
+
config: {
|
|
4949
|
+
defaultMode: "upsert",
|
|
4950
|
+
multiPass: true,
|
|
4951
|
+
...organizationId ? { organizationId } : {}
|
|
4952
|
+
}
|
|
4953
|
+
});
|
|
4954
|
+
const r = await loader.load(request);
|
|
4955
|
+
return {
|
|
4956
|
+
success: r.success,
|
|
4957
|
+
inserted: r.summary.totalInserted,
|
|
4958
|
+
updated: r.summary.totalUpdated,
|
|
4959
|
+
...r.errors?.length ? { errors: r.errors } : {}
|
|
4960
|
+
};
|
|
4961
|
+
} catch (e) {
|
|
4962
|
+
return { success: false, inserted: 0, updated: 0, error: e?.message ?? "seed apply failed" };
|
|
4963
|
+
}
|
|
4964
|
+
}
|
|
4302
4965
|
/**
|
|
4303
4966
|
* List pending DRAFT metadata (ADR-0033) for the org, optionally narrowed
|
|
4304
4967
|
* by `packageId` and/or `type`. The list reads of `getMetaItems` only see
|
|
@@ -4332,14 +4995,25 @@ var _ObjectStackProtocolImplementation = class _ObjectStackProtocolImplementatio
|
|
|
4332
4995
|
const drafts = await repo.listDrafts({ packageId: request.packageId });
|
|
4333
4996
|
const published = [];
|
|
4334
4997
|
const failed = [];
|
|
4335
|
-
|
|
4998
|
+
const ordered = [
|
|
4999
|
+
...drafts.filter((d) => d.type !== "seed"),
|
|
5000
|
+
...drafts.filter((d) => d.type === "seed")
|
|
5001
|
+
];
|
|
5002
|
+
const seedBodies = [];
|
|
5003
|
+
for (const d of ordered) {
|
|
4336
5004
|
try {
|
|
5005
|
+
if (d.type === "seed") {
|
|
5006
|
+
const ref = { type: d.type, name: d.name, org: orgId ?? "env" };
|
|
5007
|
+
const draft = await repo.get(ref, { state: "draft" });
|
|
5008
|
+
if (draft?.body) seedBodies.push(draft.body);
|
|
5009
|
+
}
|
|
4337
5010
|
const r = await this.publishMetaItem({
|
|
4338
5011
|
type: d.type,
|
|
4339
5012
|
name: d.name,
|
|
4340
5013
|
...request.organizationId ? { organizationId: request.organizationId } : {},
|
|
4341
5014
|
...request.actor ? { actor: request.actor } : {},
|
|
4342
|
-
message: `publish app package '${request.packageId}'
|
|
5015
|
+
message: `publish app package '${request.packageId}'`,
|
|
5016
|
+
_skipSeedApply: true
|
|
4343
5017
|
});
|
|
4344
5018
|
published.push({ type: d.type, name: d.name, version: r.version });
|
|
4345
5019
|
} catch (e) {
|
|
@@ -4356,7 +5030,8 @@ var _ObjectStackProtocolImplementation = class _ObjectStackProtocolImplementatio
|
|
|
4356
5030
|
publishedCount: published.length,
|
|
4357
5031
|
failedCount: failed.length,
|
|
4358
5032
|
published,
|
|
4359
|
-
failed
|
|
5033
|
+
failed,
|
|
5034
|
+
...seedBodies.length > 0 ? { seedApplied: await this.applySeedBodies(seedBodies, orgId) } : {}
|
|
4360
5035
|
};
|
|
4361
5036
|
}
|
|
4362
5037
|
/**
|
|
@@ -5132,11 +5807,11 @@ function collectSecretFields(schema) {
|
|
|
5132
5807
|
|
|
5133
5808
|
// src/engine.ts
|
|
5134
5809
|
var import_shared5 = require("@objectstack/spec/shared");
|
|
5135
|
-
var
|
|
5810
|
+
var import_formula4 = require("@objectstack/formula");
|
|
5136
5811
|
var import_spec = require("@objectstack/spec");
|
|
5137
5812
|
|
|
5138
5813
|
// src/hook-wrappers.ts
|
|
5139
|
-
var
|
|
5814
|
+
var import_formula2 = require("@objectstack/formula");
|
|
5140
5815
|
|
|
5141
5816
|
// src/hook-metrics.ts
|
|
5142
5817
|
var noopHookMetricsRecorder = {
|
|
@@ -5213,10 +5888,10 @@ function wrapDeclarativeHook(meta, handler, opts = {}) {
|
|
|
5213
5888
|
if (meta.condition) {
|
|
5214
5889
|
const expr = typeof meta.condition === "string" ? { dialect: "cel", source: meta.condition } : meta.condition;
|
|
5215
5890
|
if (expr.source && expr.source.trim()) {
|
|
5216
|
-
const check =
|
|
5891
|
+
const check = import_formula2.ExpressionEngine.compile(expr);
|
|
5217
5892
|
if (check.ok) {
|
|
5218
5893
|
conditionFn = (record) => {
|
|
5219
|
-
const r =
|
|
5894
|
+
const r = import_formula2.ExpressionEngine.evaluate(expr, { record: record ?? {} });
|
|
5220
5895
|
if (!r.ok) {
|
|
5221
5896
|
logger.warn("[hook] condition evaluation failed; treating as false", {
|
|
5222
5897
|
hook: meta.name,
|
|
@@ -5688,7 +6363,7 @@ function validateRecord(objectSchema, data, mode) {
|
|
|
5688
6363
|
}
|
|
5689
6364
|
|
|
5690
6365
|
// src/validation/rule-validator.ts
|
|
5691
|
-
var
|
|
6366
|
+
var import_formula3 = require("@objectstack/formula");
|
|
5692
6367
|
var import_ajv = __toESM(require("ajv"));
|
|
5693
6368
|
var ajv = new import_ajv.default({ allErrors: true, strict: false });
|
|
5694
6369
|
var jsonSchemaCache = /* @__PURE__ */ new WeakMap();
|
|
@@ -5704,7 +6379,7 @@ function stripReadonlyWhenFields(objectSchema, data, previous, logger) {
|
|
|
5704
6379
|
let result = data;
|
|
5705
6380
|
for (const [name, def] of Object.entries(fields)) {
|
|
5706
6381
|
if (!def?.readonlyWhen || !(name in data)) continue;
|
|
5707
|
-
const res =
|
|
6382
|
+
const res = import_formula3.ExpressionEngine.evaluate(toExpression(def.readonlyWhen), {
|
|
5708
6383
|
record: merged,
|
|
5709
6384
|
previous: previous ?? void 0
|
|
5710
6385
|
});
|
|
@@ -5759,7 +6434,7 @@ function evaluateValidationRules(objectSchema, data, mode, opts = {}) {
|
|
|
5759
6434
|
for (const [name, def] of Object.entries(fields)) {
|
|
5760
6435
|
const pred = def?.requiredWhen ?? def?.conditionalRequired;
|
|
5761
6436
|
if (!pred) continue;
|
|
5762
|
-
const res =
|
|
6437
|
+
const res = import_formula3.ExpressionEngine.evaluate(toExpression(pred), { record: merged, previous });
|
|
5763
6438
|
if (!res.ok) {
|
|
5764
6439
|
opts.logger?.warn?.(`requiredWhen for '${name}' failed to evaluate \u2014 skipped`);
|
|
5765
6440
|
continue;
|
|
@@ -5830,7 +6505,7 @@ function checkStateMachine(rule, mode, data, previous) {
|
|
|
5830
6505
|
}
|
|
5831
6506
|
function checkPredicate(rule, record, previous, logger) {
|
|
5832
6507
|
const expr = toExpression(rule.condition);
|
|
5833
|
-
const result =
|
|
6508
|
+
const result = import_formula3.ExpressionEngine.evaluate(expr, {
|
|
5834
6509
|
record,
|
|
5835
6510
|
previous: previous ?? void 0
|
|
5836
6511
|
});
|
|
@@ -5928,7 +6603,7 @@ function checkJsonSchema(rule, data, logger) {
|
|
|
5928
6603
|
return null;
|
|
5929
6604
|
}
|
|
5930
6605
|
function checkConditional(rule, ctx) {
|
|
5931
|
-
const result =
|
|
6606
|
+
const result = import_formula3.ExpressionEngine.evaluate(toExpression(rule.when), {
|
|
5932
6607
|
record: ctx.merged,
|
|
5933
6608
|
previous: ctx.previous ?? void 0
|
|
5934
6609
|
});
|
|
@@ -6109,7 +6784,7 @@ function planFormulaProjection(schema, requestedFields) {
|
|
|
6109
6784
|
if (def?.type === "formula" && def.expression) {
|
|
6110
6785
|
const expr = typeof def.expression === "string" ? { dialect: "cel", source: def.expression } : def.expression;
|
|
6111
6786
|
plan.push({ name: f, expression: expr });
|
|
6112
|
-
|
|
6787
|
+
import_formula4.ExpressionEngine.compile(expr);
|
|
6113
6788
|
} else if (Array.isArray(requestedFields) && requestedFields.length > 0) {
|
|
6114
6789
|
projected.add(f);
|
|
6115
6790
|
}
|
|
@@ -6131,7 +6806,7 @@ function applyFormulaPlan(plan, records) {
|
|
|
6131
6806
|
for (const rec of records) {
|
|
6132
6807
|
if (rec == null) continue;
|
|
6133
6808
|
for (const fp of plan) {
|
|
6134
|
-
const r =
|
|
6809
|
+
const r = import_formula4.ExpressionEngine.evaluate(fp.expression, { record: rec });
|
|
6135
6810
|
rec[fp.name] = r.ok ? r.value : null;
|
|
6136
6811
|
}
|
|
6137
6812
|
}
|
|
@@ -6556,7 +7231,7 @@ var _ObjectQL = class _ObjectQL {
|
|
|
6556
7231
|
if (f.defaultValue == null) continue;
|
|
6557
7232
|
const dv = f.defaultValue;
|
|
6558
7233
|
if (typeof dv === "object" && dv !== null && dv.dialect && typeof dv.source === "string") {
|
|
6559
|
-
const result =
|
|
7234
|
+
const result = import_formula4.ExpressionEngine.evaluate(dv, {
|
|
6560
7235
|
now,
|
|
6561
7236
|
user: execCtx?.userId ? { id: String(execCtx.userId), role: execCtx?.roles?.[0] } : void 0,
|
|
6562
7237
|
org: execCtx?.tenantId ? { id: String(execCtx.tenantId) } : void 0,
|
|
@@ -9215,6 +9890,9 @@ function convertIntrospectedSchemaToObjects(introspectedSchema, options) {
|
|
|
9215
9890
|
}
|
|
9216
9891
|
return objects;
|
|
9217
9892
|
}
|
|
9893
|
+
|
|
9894
|
+
// src/index.ts
|
|
9895
|
+
init_seed_loader();
|
|
9218
9896
|
// Annotate the CommonJS export names for ESM import in node:
|
|
9219
9897
|
0 && (module.exports = {
|
|
9220
9898
|
DEFAULT_EXTENDER_PRIORITY,
|
|
@@ -9230,6 +9908,7 @@ function convertIntrospectedSchemaToObjects(introspectedSchema, options) {
|
|
|
9230
9908
|
SECRET_REF_PREFIX,
|
|
9231
9909
|
SchemaRegistry,
|
|
9232
9910
|
ScopedContext,
|
|
9911
|
+
SeedLoaderService,
|
|
9233
9912
|
SysMetadataRepository,
|
|
9234
9913
|
ValidationError,
|
|
9235
9914
|
applyInMemoryAggregation,
|