@fjell/lib-sequelize 4.4.74 → 4.4.76
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/QueryBuilder.d.ts +31 -3
- package/dist/QueryBuilder.d.ts.map +1 -1
- package/dist/RowProcessor.d.ts +1 -1
- package/dist/RowProcessor.d.ts.map +1 -1
- package/dist/index.js +592 -114
- package/dist/index.js.map +4 -4
- package/dist/metrics/QueryMetrics.d.ts +31 -0
- package/dist/metrics/QueryMetrics.d.ts.map +1 -0
- package/dist/metrics/index.d.ts +2 -0
- package/dist/metrics/index.d.ts.map +1 -0
- package/dist/ops/all.d.ts.map +1 -1
- package/dist/ops/create.d.ts.map +1 -1
- package/dist/ops/find.d.ts.map +1 -1
- package/dist/ops/get.d.ts.map +1 -1
- package/dist/ops/remove.d.ts.map +1 -1
- package/dist/ops/update.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -173,7 +173,7 @@ var addReferenceQueries = (options, references, model) => {
|
|
|
173
173
|
});
|
|
174
174
|
return options;
|
|
175
175
|
};
|
|
176
|
-
var addCompoundCondition = (options, compoundCondition, model) => {
|
|
176
|
+
var addCompoundCondition = (options, compoundCondition, model, references, allReferences, registry) => {
|
|
177
177
|
options.where = options.where || {};
|
|
178
178
|
let compoundOp;
|
|
179
179
|
const compoundType = compoundCondition.compoundType;
|
|
@@ -186,7 +186,7 @@ var addCompoundCondition = (options, compoundCondition, model) => {
|
|
|
186
186
|
let conditions = {};
|
|
187
187
|
compoundCondition.conditions.forEach((condition) => {
|
|
188
188
|
if (isCondition(condition)) {
|
|
189
|
-
conditions = addCondition(conditions, condition, model);
|
|
189
|
+
conditions = addCondition(conditions, condition, model, options, references, allReferences, registry);
|
|
190
190
|
} else {
|
|
191
191
|
throw new Error(`Nested Compound conditions not supported. Model: '${model.name}', Compound condition: ${stringifyJSON(compoundCondition)}, Nested condition: ${stringifyJSON(condition)}`);
|
|
192
192
|
}
|
|
@@ -216,12 +216,267 @@ var getSequelizeOperator = (operator) => {
|
|
|
216
216
|
return Op.gte;
|
|
217
217
|
} else if (operator === "in") {
|
|
218
218
|
return Op.in;
|
|
219
|
+
} else if (operator === "!=") {
|
|
220
|
+
return Op.ne;
|
|
219
221
|
} else {
|
|
220
222
|
throw new Error(`Operator ${operator} not supported`);
|
|
221
223
|
}
|
|
222
224
|
};
|
|
223
|
-
var
|
|
224
|
-
|
|
225
|
+
var findReferenceByProperty = (propertyName, references) => {
|
|
226
|
+
if (!references || references.length === 0) {
|
|
227
|
+
return null;
|
|
228
|
+
}
|
|
229
|
+
return references.find((ref) => ref.property === propertyName) || null;
|
|
230
|
+
};
|
|
231
|
+
var getReferencesFromRegistry = (model, registry) => {
|
|
232
|
+
if (!registry) {
|
|
233
|
+
return;
|
|
234
|
+
}
|
|
235
|
+
const modelName = model.name.toLowerCase();
|
|
236
|
+
try {
|
|
237
|
+
const library = registry.get([modelName]);
|
|
238
|
+
if (library && library.options && library.options.references) {
|
|
239
|
+
return library.options.references;
|
|
240
|
+
}
|
|
241
|
+
} catch {
|
|
242
|
+
}
|
|
243
|
+
return;
|
|
244
|
+
};
|
|
245
|
+
var buildNestedInclude = (pathSegments, currentModel, references, allReferences, registry, isFirstSegment = true) => {
|
|
246
|
+
if (pathSegments.length === 0) {
|
|
247
|
+
return null;
|
|
248
|
+
}
|
|
249
|
+
const [firstSegment, ...remainingSegments] = pathSegments;
|
|
250
|
+
if (isFirstSegment) {
|
|
251
|
+
const refDef = findReferenceByProperty(firstSegment, references);
|
|
252
|
+
if (!refDef) {
|
|
253
|
+
logger3.debug(`[buildNestedInclude] No reference definition found for property '${firstSegment}'`, {
|
|
254
|
+
model: currentModel.name,
|
|
255
|
+
property: firstSegment,
|
|
256
|
+
availableReferences: references?.map((r) => r.property) || [],
|
|
257
|
+
referencesCount: references?.length || 0
|
|
258
|
+
});
|
|
259
|
+
return null;
|
|
260
|
+
}
|
|
261
|
+
logger3.debug(`[buildNestedInclude] Found reference definition for property '${firstSegment}'`, {
|
|
262
|
+
model: currentModel.name,
|
|
263
|
+
property: firstSegment,
|
|
264
|
+
refDef: { property: refDef.property, column: refDef.column, kta: refDef.kta }
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
const association = currentModel.associations?.[firstSegment];
|
|
268
|
+
if (!association) {
|
|
269
|
+
if (isFirstSegment) {
|
|
270
|
+
logger3.debug(`[buildNestedInclude] Reference property '${firstSegment}' found but no Sequelize association exists`, {
|
|
271
|
+
model: currentModel.name,
|
|
272
|
+
property: firstSegment,
|
|
273
|
+
availableAssociations: Object.keys(currentModel.associations || {}),
|
|
274
|
+
associationsObject: currentModel.associations ? Object.keys(currentModel.associations) : "undefined"
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
return null;
|
|
278
|
+
}
|
|
279
|
+
logger3.debug(`[buildNestedInclude] Found Sequelize association for '${firstSegment}'`, {
|
|
280
|
+
model: currentModel.name,
|
|
281
|
+
property: firstSegment,
|
|
282
|
+
associationType: association.associationType,
|
|
283
|
+
targetModel: association.target?.name
|
|
284
|
+
});
|
|
285
|
+
const targetModel = association.target;
|
|
286
|
+
const includeConfig = {
|
|
287
|
+
model: targetModel,
|
|
288
|
+
as: firstSegment,
|
|
289
|
+
required: true
|
|
290
|
+
// Use INNER JOIN for filtering conditions
|
|
291
|
+
};
|
|
292
|
+
if (remainingSegments.length === 0) {
|
|
293
|
+
return { include: includeConfig, associationName: firstSegment };
|
|
294
|
+
}
|
|
295
|
+
let nestedReferences = getReferencesFromRegistry(targetModel, registry);
|
|
296
|
+
if (!nestedReferences) {
|
|
297
|
+
nestedReferences = allReferences?.get(targetModel.name);
|
|
298
|
+
}
|
|
299
|
+
const nestedInclude = buildNestedInclude(
|
|
300
|
+
remainingSegments,
|
|
301
|
+
targetModel,
|
|
302
|
+
nestedReferences,
|
|
303
|
+
allReferences,
|
|
304
|
+
registry,
|
|
305
|
+
false
|
|
306
|
+
// Subsequent segments don't require reference definition match
|
|
307
|
+
);
|
|
308
|
+
if (nestedInclude) {
|
|
309
|
+
includeConfig.include = [nestedInclude.include];
|
|
310
|
+
return { include: includeConfig, associationName: firstSegment };
|
|
311
|
+
}
|
|
312
|
+
const [nextSegment, ...restSegments] = remainingSegments;
|
|
313
|
+
const nextAssociation = targetModel.associations?.[nextSegment];
|
|
314
|
+
if (!nextAssociation) {
|
|
315
|
+
return null;
|
|
316
|
+
}
|
|
317
|
+
if (restSegments.length === 0) {
|
|
318
|
+
includeConfig.include = [{
|
|
319
|
+
model: nextAssociation.target,
|
|
320
|
+
as: nextSegment,
|
|
321
|
+
required: true
|
|
322
|
+
}];
|
|
323
|
+
return { include: includeConfig, associationName: firstSegment };
|
|
324
|
+
}
|
|
325
|
+
const deeperInclude = buildNestedInclude(
|
|
326
|
+
remainingSegments,
|
|
327
|
+
targetModel,
|
|
328
|
+
nestedReferences,
|
|
329
|
+
allReferences,
|
|
330
|
+
registry,
|
|
331
|
+
false
|
|
332
|
+
);
|
|
333
|
+
if (!deeperInclude) {
|
|
334
|
+
return null;
|
|
335
|
+
}
|
|
336
|
+
includeConfig.include = [deeperInclude.include];
|
|
337
|
+
return { include: includeConfig, associationName: firstSegment };
|
|
338
|
+
};
|
|
339
|
+
var detectReferenceJoin = (fieldPath, model, references, allReferences, registry) => {
|
|
340
|
+
const pathSegments = fieldPath.split(".");
|
|
341
|
+
if (pathSegments.length < 2) {
|
|
342
|
+
return null;
|
|
343
|
+
}
|
|
344
|
+
for (let i = pathSegments.length - 1; i >= 1; i--) {
|
|
345
|
+
const referencePath = pathSegments.slice(0, i);
|
|
346
|
+
const attributePath = pathSegments.slice(i).join(".");
|
|
347
|
+
const includeResult = buildNestedInclude(referencePath, model, references, allReferences, registry);
|
|
348
|
+
if (!includeResult) {
|
|
349
|
+
continue;
|
|
350
|
+
}
|
|
351
|
+
let finalModel = model;
|
|
352
|
+
for (const segment of referencePath) {
|
|
353
|
+
const assoc = finalModel.associations?.[segment];
|
|
354
|
+
if (!assoc) {
|
|
355
|
+
break;
|
|
356
|
+
}
|
|
357
|
+
finalModel = assoc.target;
|
|
358
|
+
}
|
|
359
|
+
const attributeSegments = attributePath.split(".");
|
|
360
|
+
if (attributeSegments.length !== 1 || !finalModel.getAttributes()[attributePath]) {
|
|
361
|
+
continue;
|
|
362
|
+
}
|
|
363
|
+
logger3.debug(`Auto-detected reference join for condition '${fieldPath}'`, {
|
|
364
|
+
model: model.name,
|
|
365
|
+
referencePath: referencePath.join("."),
|
|
366
|
+
attributePath,
|
|
367
|
+
associationName: includeResult.associationName
|
|
368
|
+
});
|
|
369
|
+
return {
|
|
370
|
+
include: includeResult.include,
|
|
371
|
+
attributePath,
|
|
372
|
+
associationName: includeResult.associationName
|
|
373
|
+
};
|
|
374
|
+
}
|
|
375
|
+
return null;
|
|
376
|
+
};
|
|
377
|
+
var addIncludeIfNotExists = (options, newInclude) => {
|
|
378
|
+
options.include = options.include || [];
|
|
379
|
+
const exists = options.include.some((inc) => {
|
|
380
|
+
if (typeof inc === "string") {
|
|
381
|
+
return inc === newInclude.as;
|
|
382
|
+
}
|
|
383
|
+
if (inc.model === newInclude.model && inc.as === newInclude.as) {
|
|
384
|
+
if (newInclude.include && inc.include) {
|
|
385
|
+
newInclude.include.forEach((nested) => {
|
|
386
|
+
const nestedExists = inc.include.some(
|
|
387
|
+
(existingNested) => existingNested.model === nested.model && existingNested.as === nested.as
|
|
388
|
+
);
|
|
389
|
+
if (!nestedExists) {
|
|
390
|
+
inc.include.push(nested);
|
|
391
|
+
}
|
|
392
|
+
});
|
|
393
|
+
} else if (newInclude.include) {
|
|
394
|
+
inc.include = newInclude.include;
|
|
395
|
+
}
|
|
396
|
+
return true;
|
|
397
|
+
}
|
|
398
|
+
return false;
|
|
399
|
+
});
|
|
400
|
+
if (!exists) {
|
|
401
|
+
options.include.push(newInclude);
|
|
402
|
+
}
|
|
403
|
+
};
|
|
404
|
+
var addAssociationCondition = (conditions, condition, model, options, references, allReferences, registry) => {
|
|
405
|
+
const fieldPath = condition.column;
|
|
406
|
+
const pathSegments = fieldPath.split(".");
|
|
407
|
+
logger3.debug(`[addAssociationCondition] Processing condition '${fieldPath}'`, {
|
|
408
|
+
model: model.name,
|
|
409
|
+
hasReferences: !!references,
|
|
410
|
+
referencesCount: references?.length || 0,
|
|
411
|
+
pathSegmentsLength: pathSegments.length,
|
|
412
|
+
pathSegments,
|
|
413
|
+
willAttemptDetection: !!(references && pathSegments.length >= 2)
|
|
414
|
+
});
|
|
415
|
+
if (references && pathSegments.length >= 2) {
|
|
416
|
+
logger3.debug(`[addAssociationCondition] Attempting reference join detection for '${fieldPath}'`, {
|
|
417
|
+
model: model.name,
|
|
418
|
+
referencesCount: references.length,
|
|
419
|
+
references: references.map((r) => ({ property: r.property, column: r.column })),
|
|
420
|
+
pathSegments,
|
|
421
|
+
hasOptions: !!options
|
|
422
|
+
});
|
|
423
|
+
const referenceJoin = detectReferenceJoin(fieldPath, model, references, allReferences, registry);
|
|
424
|
+
if (!referenceJoin) {
|
|
425
|
+
logger3.debug(`[addAssociationCondition] Reference join detection returned null for '${fieldPath}'`, {
|
|
426
|
+
model: model.name,
|
|
427
|
+
fieldPath
|
|
428
|
+
});
|
|
429
|
+
}
|
|
430
|
+
if (referenceJoin && options) {
|
|
431
|
+
logger3.debug(`[addAssociationCondition] Reference join detected successfully for '${fieldPath}'`, {
|
|
432
|
+
model: model.name,
|
|
433
|
+
associationName: referenceJoin.associationName,
|
|
434
|
+
attributePath: referenceJoin.attributePath
|
|
435
|
+
});
|
|
436
|
+
addIncludeIfNotExists(options, referenceJoin.include);
|
|
437
|
+
const attributeName2 = referenceJoin.attributePath;
|
|
438
|
+
const associationPath = fieldPath.substring(0, fieldPath.length - attributeName2.length - 1);
|
|
439
|
+
const sequelizeAssociationColumn2 = `$${associationPath}.${attributeName2}$`;
|
|
440
|
+
const finalPathSegments = associationPath.split(".");
|
|
441
|
+
let currentModel = model;
|
|
442
|
+
let targetModel = model;
|
|
443
|
+
for (const segment of finalPathSegments) {
|
|
444
|
+
const assoc = currentModel.associations?.[segment];
|
|
445
|
+
if (!assoc) {
|
|
446
|
+
throw new Error(`Association ${segment} not found on model ${currentModel.name}`);
|
|
447
|
+
}
|
|
448
|
+
targetModel = assoc.target;
|
|
449
|
+
currentModel = targetModel;
|
|
450
|
+
}
|
|
451
|
+
if (!targetModel.getAttributes()[attributeName2]) {
|
|
452
|
+
throw new Error(`Attribute ${attributeName2} not found on associated model ${targetModel.name} for path ${associationPath}`);
|
|
453
|
+
}
|
|
454
|
+
if (condition.value === null) {
|
|
455
|
+
if (condition.operator === "==" || !condition.operator) {
|
|
456
|
+
logger3.trace(`[QueryBuilder] Setting reference condition: ${sequelizeAssociationColumn2} IS NULL`);
|
|
457
|
+
conditions[sequelizeAssociationColumn2] = {
|
|
458
|
+
[Op.is]: null
|
|
459
|
+
};
|
|
460
|
+
} else if (condition.operator === "!=") {
|
|
461
|
+
logger3.trace(`[QueryBuilder] Setting reference condition: ${sequelizeAssociationColumn2} IS NOT NULL`);
|
|
462
|
+
conditions[sequelizeAssociationColumn2] = {
|
|
463
|
+
[Op.not]: null
|
|
464
|
+
};
|
|
465
|
+
} else {
|
|
466
|
+
logger3.error(`Operator ${condition.operator} cannot be used with null value on reference`, { condition });
|
|
467
|
+
throw new Error(`Operator ${condition.operator} cannot be used with null value. Use '==' for IS NULL or '!=' for IS NOT NULL.`);
|
|
468
|
+
}
|
|
469
|
+
return conditions;
|
|
470
|
+
}
|
|
471
|
+
const conditionOp2 = getSequelizeOperator(condition.operator);
|
|
472
|
+
logger3.trace(`[QueryBuilder] Setting reference condition: ${sequelizeAssociationColumn2} = ${stringifyJSON(condition.value)} (type: ${typeof condition.value})`);
|
|
473
|
+
conditions[sequelizeAssociationColumn2] = {
|
|
474
|
+
[conditionOp2]: condition.value
|
|
475
|
+
};
|
|
476
|
+
return conditions;
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
const [associationName, attributeName] = fieldPath.split(".", 2);
|
|
225
480
|
if (!model.associations || !model.associations[associationName]) {
|
|
226
481
|
throw new Error(`Association ${associationName} not found on model ${model.name}`);
|
|
227
482
|
}
|
|
@@ -284,10 +539,10 @@ var addAttributeCondition = (conditions, condition, model) => {
|
|
|
284
539
|
};
|
|
285
540
|
return conditions;
|
|
286
541
|
};
|
|
287
|
-
var addCondition = (conditions, condition, model) => {
|
|
542
|
+
var addCondition = (conditions, condition, model, options, references, allReferences, registry) => {
|
|
288
543
|
const conditionColumn = condition.column;
|
|
289
544
|
if (conditionColumn.includes(".")) {
|
|
290
|
-
return addAssociationCondition(conditions, condition, model);
|
|
545
|
+
return addAssociationCondition(conditions, condition, model, options, references, allReferences, registry);
|
|
291
546
|
}
|
|
292
547
|
return addAttributeCondition(conditions, condition, model);
|
|
293
548
|
};
|
|
@@ -341,14 +596,105 @@ var addAssociationIncludes = (options, model) => {
|
|
|
341
596
|
}
|
|
342
597
|
return options;
|
|
343
598
|
};
|
|
344
|
-
var
|
|
599
|
+
var addReferenceIncludes = (options, model, referenceDefinitions) => {
|
|
600
|
+
if (!referenceDefinitions || referenceDefinitions.length === 0) {
|
|
601
|
+
return { options, includedReferences: [] };
|
|
602
|
+
}
|
|
603
|
+
const includedReferences = [];
|
|
604
|
+
options.include = options.include || [];
|
|
605
|
+
for (const refDef of referenceDefinitions) {
|
|
606
|
+
const association = model.associations && model.associations[refDef.property];
|
|
607
|
+
if (association) {
|
|
608
|
+
const alreadyIncluded = options.include.some(
|
|
609
|
+
(inc) => typeof inc === "string" && inc === refDef.property || typeof inc === "object" && inc.as === refDef.property
|
|
610
|
+
);
|
|
611
|
+
if (!alreadyIncluded) {
|
|
612
|
+
logger3.default(`Auto-detected association for reference '${refDef.property}' - using INCLUDE to prevent N+1`, {
|
|
613
|
+
property: refDef.property,
|
|
614
|
+
associationType: association.associationType,
|
|
615
|
+
targetModel: association.target.name
|
|
616
|
+
});
|
|
617
|
+
options.include.push({
|
|
618
|
+
model: association.target,
|
|
619
|
+
as: refDef.property,
|
|
620
|
+
required: false
|
|
621
|
+
// Use LEFT JOIN to preserve items without references
|
|
622
|
+
});
|
|
623
|
+
includedReferences.push(refDef.property);
|
|
624
|
+
} else {
|
|
625
|
+
logger3.debug(`Association '${refDef.property}' already included in query`, {
|
|
626
|
+
property: refDef.property
|
|
627
|
+
});
|
|
628
|
+
includedReferences.push(refDef.property);
|
|
629
|
+
}
|
|
630
|
+
} else {
|
|
631
|
+
logger3.debug(`No association found for reference '${refDef.property}' - will use separate query`, {
|
|
632
|
+
property: refDef.property,
|
|
633
|
+
availableAssociations: Object.keys(model.associations || {})
|
|
634
|
+
});
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
return { options, includedReferences };
|
|
638
|
+
};
|
|
639
|
+
var addAggregationIncludes = (options, model, aggregationDefinitions) => {
|
|
640
|
+
if (!aggregationDefinitions || aggregationDefinitions.length === 0) {
|
|
641
|
+
return { options, includedAggregations: [] };
|
|
642
|
+
}
|
|
643
|
+
const includedAggregations = [];
|
|
644
|
+
options.include = options.include || [];
|
|
645
|
+
for (const aggDef of aggregationDefinitions) {
|
|
646
|
+
const association = model.associations && model.associations[aggDef.property];
|
|
647
|
+
if (association) {
|
|
648
|
+
const alreadyIncluded = options.include.some(
|
|
649
|
+
(inc) => typeof inc === "string" && inc === aggDef.property || typeof inc === "object" && inc.as === aggDef.property
|
|
650
|
+
);
|
|
651
|
+
if (!alreadyIncluded) {
|
|
652
|
+
logger3.default(`Auto-detected association for aggregation '${aggDef.property}' - using INCLUDE to prevent N+1`, {
|
|
653
|
+
property: aggDef.property,
|
|
654
|
+
associationType: association.associationType,
|
|
655
|
+
targetModel: association.target.name
|
|
656
|
+
});
|
|
657
|
+
options.include.push({
|
|
658
|
+
model: association.target,
|
|
659
|
+
as: aggDef.property,
|
|
660
|
+
required: false
|
|
661
|
+
// Use LEFT JOIN to preserve items without aggregations
|
|
662
|
+
});
|
|
663
|
+
includedAggregations.push(aggDef.property);
|
|
664
|
+
} else {
|
|
665
|
+
logger3.debug(`Association '${aggDef.property}' already included in query`, {
|
|
666
|
+
property: aggDef.property
|
|
667
|
+
});
|
|
668
|
+
includedAggregations.push(aggDef.property);
|
|
669
|
+
}
|
|
670
|
+
} else {
|
|
671
|
+
logger3.debug(`No association found for aggregation '${aggDef.property}' - will use separate query`, {
|
|
672
|
+
property: aggDef.property,
|
|
673
|
+
availableAssociations: Object.keys(model.associations || {})
|
|
674
|
+
});
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
return { options, includedAggregations };
|
|
678
|
+
};
|
|
679
|
+
var buildQuery = (itemQuery, model, references, registry) => {
|
|
345
680
|
logger3.default(`QueryBuilder build called with itemQuery: ${stringifyJSON(itemQuery)}`);
|
|
681
|
+
logger3.debug(`[buildQuery] Parameters:`, {
|
|
682
|
+
modelName: model.name,
|
|
683
|
+
referencesCount: references?.length || 0,
|
|
684
|
+
references: references?.map((r) => ({ property: r.property, column: r.column })) || [],
|
|
685
|
+
hasRegistry: !!registry,
|
|
686
|
+
hasCompoundCondition: !!itemQuery.compoundCondition
|
|
687
|
+
});
|
|
346
688
|
let options = {
|
|
347
689
|
where: {}
|
|
348
690
|
};
|
|
691
|
+
const allReferences = /* @__PURE__ */ new Map();
|
|
692
|
+
if (references) {
|
|
693
|
+
allReferences.set(model.name, references);
|
|
694
|
+
}
|
|
349
695
|
if (itemQuery.compoundCondition) {
|
|
350
696
|
logger3.default(`QueryBuilder adding conditions: ${stringifyJSON(itemQuery.compoundCondition)}`);
|
|
351
|
-
options = addCompoundCondition(options, itemQuery.compoundCondition, model);
|
|
697
|
+
options = addCompoundCondition(options, itemQuery.compoundCondition, model, references, allReferences, registry);
|
|
352
698
|
}
|
|
353
699
|
if (model.getAttributes().deletedAt || model.getAttributes().isDeleted) {
|
|
354
700
|
options = addDeleteQuery(options, model);
|
|
@@ -659,12 +1005,12 @@ var buildSequelizeReference = async (item, referenceDefinition, registry, contex
|
|
|
659
1005
|
pk: columnValue,
|
|
660
1006
|
loc: []
|
|
661
1007
|
};
|
|
662
|
-
libLogger3.
|
|
1008
|
+
libLogger3.default("Using empty loc array for composite item reference", {
|
|
663
1009
|
kta: referenceDefinition.kta,
|
|
664
1010
|
property: referenceDefinition.property
|
|
665
1011
|
});
|
|
666
1012
|
}
|
|
667
|
-
libLogger3.
|
|
1013
|
+
libLogger3.default("Created reference key", {
|
|
668
1014
|
itemKey,
|
|
669
1015
|
isCompositeItem,
|
|
670
1016
|
hasLocationColumns: !!referenceDefinition.locationColumns,
|
|
@@ -676,7 +1022,7 @@ var buildSequelizeReference = async (item, referenceDefinition, registry, contex
|
|
|
676
1022
|
libLogger3.debug("Using cached reference", { itemKey, property: referenceDefinition.property });
|
|
677
1023
|
referencedItem = context.getCached(itemKey);
|
|
678
1024
|
} else if (context.isInProgress(itemKey)) {
|
|
679
|
-
libLogger3.
|
|
1025
|
+
libLogger3.default("Circular dependency detected, creating reference placeholder", {
|
|
680
1026
|
itemKey,
|
|
681
1027
|
property: referenceDefinition.property
|
|
682
1028
|
});
|
|
@@ -839,7 +1185,7 @@ function addAggsToItem(item, aggregationDefinitions) {
|
|
|
839
1185
|
if (typeof aggregationValue !== "undefined") {
|
|
840
1186
|
aggs[aggDef.property] = aggregationValue;
|
|
841
1187
|
delete result[aggDef.property];
|
|
842
|
-
libLogger2.
|
|
1188
|
+
libLogger2.default(`Moved aggregation '${aggDef.property}' to aggs structure`, {
|
|
843
1189
|
property: aggDef.property,
|
|
844
1190
|
hasValue: typeof aggregationValue !== "undefined",
|
|
845
1191
|
valueType: Array.isArray(aggregationValue) ? "array" : typeof aggregationValue
|
|
@@ -879,7 +1225,7 @@ function removeAggsFromItem(item, aggregationDefinitions) {
|
|
|
879
1225
|
|
|
880
1226
|
// src/RowProcessor.ts
|
|
881
1227
|
var logger6 = logger_default.get("sequelize", "RowProcessor");
|
|
882
|
-
var processRow = async (row, keyTypes, referenceDefinitions, aggregationDefinitions, registry, context) => {
|
|
1228
|
+
var processRow = async (row, keyTypes, referenceDefinitions, aggregationDefinitions, registry, context, includedAggregations, includedReferences) => {
|
|
883
1229
|
logger6.default("Processing Row", { row });
|
|
884
1230
|
const operationContext = context || createOperationContext();
|
|
885
1231
|
return contextManager.withContext(operationContext, async () => {
|
|
@@ -892,9 +1238,22 @@ var processRow = async (row, keyTypes, referenceDefinitions, aggregationDefiniti
|
|
|
892
1238
|
try {
|
|
893
1239
|
if (referenceDefinitions && referenceDefinitions.length > 0) {
|
|
894
1240
|
const referenceStartTime = typeof performance !== "undefined" ? performance.now() : Date.now();
|
|
895
|
-
const referencePromises = referenceDefinitions.map((referenceDefinition) => {
|
|
896
|
-
|
|
897
|
-
|
|
1241
|
+
const referencePromises = referenceDefinitions.map(async (referenceDefinition) => {
|
|
1242
|
+
const alreadyLoaded = includedReferences && includedReferences.includes(referenceDefinition.property) && typeof item[referenceDefinition.property] !== "undefined";
|
|
1243
|
+
if (alreadyLoaded) {
|
|
1244
|
+
logger6.default(
|
|
1245
|
+
`Skipping buildSequelizeReference for '${referenceDefinition.property}' - already loaded via INCLUDE (N+1 prevention)`,
|
|
1246
|
+
{
|
|
1247
|
+
property: referenceDefinition.property,
|
|
1248
|
+
itemType: item.key.kt,
|
|
1249
|
+
hasData: item[referenceDefinition.property] ? "loaded" : "undefined"
|
|
1250
|
+
}
|
|
1251
|
+
);
|
|
1252
|
+
return item;
|
|
1253
|
+
} else {
|
|
1254
|
+
logger6.default("Processing Reference for %s to %s", item.key.kt, stringifyJSON(referenceDefinition.kta));
|
|
1255
|
+
return buildSequelizeReference(item, referenceDefinition, registry, operationContext);
|
|
1256
|
+
}
|
|
898
1257
|
});
|
|
899
1258
|
await Promise.all(referencePromises);
|
|
900
1259
|
const referenceDuration = (typeof performance !== "undefined" ? performance.now() : Date.now()) - referenceStartTime;
|
|
@@ -904,8 +1263,20 @@ var processRow = async (row, keyTypes, referenceDefinitions, aggregationDefiniti
|
|
|
904
1263
|
}
|
|
905
1264
|
if (aggregationDefinitions && aggregationDefinitions.length > 0) {
|
|
906
1265
|
for (const aggregationDefinition of aggregationDefinitions) {
|
|
907
|
-
|
|
908
|
-
|
|
1266
|
+
const alreadyLoaded = includedAggregations && includedAggregations.includes(aggregationDefinition.property) && typeof item[aggregationDefinition.property] !== "undefined";
|
|
1267
|
+
if (alreadyLoaded) {
|
|
1268
|
+
logger6.default(
|
|
1269
|
+
`Skipping buildAggregation for '${aggregationDefinition.property}' - already loaded via INCLUDE (N+1 prevention)`,
|
|
1270
|
+
{
|
|
1271
|
+
property: aggregationDefinition.property,
|
|
1272
|
+
itemType: item.key.kt,
|
|
1273
|
+
hasData: Array.isArray(item[aggregationDefinition.property]) ? `${item[aggregationDefinition.property].length} items` : "single item"
|
|
1274
|
+
}
|
|
1275
|
+
);
|
|
1276
|
+
} else {
|
|
1277
|
+
logger6.default("Processing Aggregation for %s from %s", item.key.kt, stringifyJSON(aggregationDefinition.kta));
|
|
1278
|
+
item = await buildAggregation(item, aggregationDefinition, registry, operationContext);
|
|
1279
|
+
}
|
|
909
1280
|
}
|
|
910
1281
|
}
|
|
911
1282
|
operationContext.setCached(item.key, item);
|
|
@@ -914,11 +1285,11 @@ var processRow = async (row, keyTypes, referenceDefinitions, aggregationDefiniti
|
|
|
914
1285
|
}
|
|
915
1286
|
if (referenceDefinitions && referenceDefinitions.length > 0) {
|
|
916
1287
|
item = addRefsToSequelizeItem(item, referenceDefinitions);
|
|
917
|
-
logger6.
|
|
1288
|
+
logger6.default("Added refs structure to item (transparent wrapper)", { key: item.key });
|
|
918
1289
|
}
|
|
919
1290
|
if (aggregationDefinitions && aggregationDefinitions.length > 0) {
|
|
920
1291
|
item = addAggsToItem(item, aggregationDefinitions);
|
|
921
|
-
logger6.
|
|
1292
|
+
logger6.default("Added aggs structure to item (transparent wrapper)", { key: item.key });
|
|
922
1293
|
}
|
|
923
1294
|
logger6.default("Processed Row: %j", stringifyJSON(item));
|
|
924
1295
|
return item;
|
|
@@ -1117,8 +1488,57 @@ function transformSequelizeError(error, itemType, key, modelName, itemData) {
|
|
|
1117
1488
|
return error;
|
|
1118
1489
|
}
|
|
1119
1490
|
|
|
1491
|
+
// src/metrics/QueryMetrics.ts
|
|
1492
|
+
var logger7 = logger_default.get("sequelize", "metrics", "QueryMetrics");
|
|
1493
|
+
var QueryMetrics = class {
|
|
1494
|
+
totalQueryCount = 0;
|
|
1495
|
+
queriesByModel = /* @__PURE__ */ new Map();
|
|
1496
|
+
LOG_INTERVAL = 10;
|
|
1497
|
+
/**
|
|
1498
|
+
* Records a query execution for a given model
|
|
1499
|
+
* @param modelName - The name of the Sequelize model the query was executed against
|
|
1500
|
+
*/
|
|
1501
|
+
recordQuery(modelName) {
|
|
1502
|
+
this.totalQueryCount++;
|
|
1503
|
+
const currentCount = this.queriesByModel.get(modelName) || 0;
|
|
1504
|
+
this.queriesByModel.set(modelName, currentCount + 1);
|
|
1505
|
+
if (this.totalQueryCount % this.LOG_INTERVAL === 0) {
|
|
1506
|
+
const modelBreakdown = Array.from(this.queriesByModel.entries()).map(([model, count]) => `${model}: ${count}`).join(", ");
|
|
1507
|
+
logger7.debug(
|
|
1508
|
+
`Query execution count: ${this.totalQueryCount} total queries. Breakdown by model: ${modelBreakdown || "none"}`
|
|
1509
|
+
);
|
|
1510
|
+
}
|
|
1511
|
+
}
|
|
1512
|
+
/**
|
|
1513
|
+
* Gets the total number of queries executed
|
|
1514
|
+
*/
|
|
1515
|
+
getTotalQueryCount() {
|
|
1516
|
+
return this.totalQueryCount;
|
|
1517
|
+
}
|
|
1518
|
+
/**
|
|
1519
|
+
* Gets the number of queries executed for a specific model
|
|
1520
|
+
*/
|
|
1521
|
+
getQueryCountForModel(modelName) {
|
|
1522
|
+
return this.queriesByModel.get(modelName) || 0;
|
|
1523
|
+
}
|
|
1524
|
+
/**
|
|
1525
|
+
* Gets a map of all model query counts
|
|
1526
|
+
*/
|
|
1527
|
+
getQueriesByModel() {
|
|
1528
|
+
return new Map(this.queriesByModel);
|
|
1529
|
+
}
|
|
1530
|
+
/**
|
|
1531
|
+
* Resets all metrics (useful for testing)
|
|
1532
|
+
*/
|
|
1533
|
+
reset() {
|
|
1534
|
+
this.totalQueryCount = 0;
|
|
1535
|
+
this.queriesByModel.clear();
|
|
1536
|
+
}
|
|
1537
|
+
};
|
|
1538
|
+
var queryMetrics = new QueryMetrics();
|
|
1539
|
+
|
|
1120
1540
|
// src/ops/all.ts
|
|
1121
|
-
var
|
|
1541
|
+
var logger8 = logger_default.get("sequelize", "ops", "all");
|
|
1122
1542
|
var mergeIncludes = (existingIncludes, newIncludes) => {
|
|
1123
1543
|
const mergedIncludes = [...existingIncludes];
|
|
1124
1544
|
for (const newInclude of newIncludes) {
|
|
@@ -1145,10 +1565,22 @@ var getAllOperation = (models, definition, registry) => {
|
|
|
1145
1565
|
async (itemQuery, locations, allOptions) => {
|
|
1146
1566
|
try {
|
|
1147
1567
|
const locs = locations ?? [];
|
|
1148
|
-
|
|
1568
|
+
logger8.debug(`ALL operation called on ${models[0].name} with ${locs.length} location filters: ${locs.map((loc2) => `${loc2.kt}=${loc2.lk}`).join(", ") || "none"}`);
|
|
1149
1569
|
const loc = locs;
|
|
1150
1570
|
const model = models[0];
|
|
1151
|
-
|
|
1571
|
+
let options = buildQuery(itemQuery ?? {}, model, references, registry);
|
|
1572
|
+
const { options: optionsWithRefs, includedReferences } = addReferenceIncludes(
|
|
1573
|
+
options,
|
|
1574
|
+
model,
|
|
1575
|
+
references || []
|
|
1576
|
+
);
|
|
1577
|
+
options = optionsWithRefs;
|
|
1578
|
+
const { options: optionsWithAggs, includedAggregations } = addAggregationIncludes(
|
|
1579
|
+
options,
|
|
1580
|
+
model,
|
|
1581
|
+
aggregations || []
|
|
1582
|
+
);
|
|
1583
|
+
options = optionsWithAggs;
|
|
1152
1584
|
if (loc.length > 0) {
|
|
1153
1585
|
const { kta } = coordinate;
|
|
1154
1586
|
const directLocations = [];
|
|
@@ -1158,7 +1590,7 @@ var getAllOperation = (models, definition, registry) => {
|
|
|
1158
1590
|
const relationshipInfo = buildRelationshipPath(model, locKey.kt, kta, true);
|
|
1159
1591
|
if (!relationshipInfo.found) {
|
|
1160
1592
|
const errorMessage = `Location key '${locKey.kt}' cannot be resolved on model '${model.name}' or through its relationships.`;
|
|
1161
|
-
|
|
1593
|
+
logger8.error(errorMessage, { locations: loc, kta });
|
|
1162
1594
|
throw new Error(errorMessage);
|
|
1163
1595
|
}
|
|
1164
1596
|
if (relationshipInfo.isDirect) {
|
|
@@ -1169,31 +1601,31 @@ var getAllOperation = (models, definition, registry) => {
|
|
|
1169
1601
|
}
|
|
1170
1602
|
for (const locKey of directLocations) {
|
|
1171
1603
|
if (locKey.lk === void 0 || locKey.lk == null || locKey.lk === "" || typeof locKey.lk === "object" && Object.keys(locKey.lk).length === 0) {
|
|
1172
|
-
|
|
1604
|
+
logger8.error(`Location key '${locKey.kt}' has invalid lk value: ${stringifyJSON(locKey.lk)}`, { locKey, locations: loc });
|
|
1173
1605
|
throw new Error(`Location key '${locKey.kt}' has invalid lk value: ${stringifyJSON(locKey.lk)}`);
|
|
1174
1606
|
}
|
|
1175
1607
|
const foreignKeyField = locKey.kt + "Id";
|
|
1176
1608
|
if (options.where[foreignKeyField]) {
|
|
1177
|
-
|
|
1609
|
+
logger8.debug(`[ALL] Field ${foreignKeyField} already constrained by itemQuery, skipping location constraint to avoid conflicts`);
|
|
1178
1610
|
continue;
|
|
1179
1611
|
}
|
|
1180
|
-
|
|
1612
|
+
logger8.trace(`[ALL] Setting direct location where clause: ${foreignKeyField} = ${stringifyJSON(locKey.lk)} (type: ${typeof locKey.lk})`);
|
|
1181
1613
|
options.where[foreignKeyField] = {
|
|
1182
1614
|
[Op2.eq]: locKey.lk
|
|
1183
1615
|
};
|
|
1184
1616
|
}
|
|
1185
1617
|
for (const locKey of hierarchicalLocations) {
|
|
1186
1618
|
if (locKey.lk === void 0 || locKey.lk == null || locKey.lk === "" || typeof locKey.lk === "object" && Object.keys(locKey.lk).length === 0) {
|
|
1187
|
-
|
|
1619
|
+
logger8.error(`Hierarchical location key '${locKey.kt}' has invalid lk value: ${stringifyJSON(locKey.lk)}`, { locKey, locations: loc });
|
|
1188
1620
|
throw new Error(`Hierarchical location key '${locKey.kt}' has invalid lk value: ${stringifyJSON(locKey.lk)}`);
|
|
1189
1621
|
}
|
|
1190
1622
|
const relationshipInfo = buildRelationshipPath(model, locKey.kt, kta);
|
|
1191
1623
|
if (relationshipInfo.found && relationshipInfo.path) {
|
|
1192
1624
|
if (options.where[relationshipInfo.path]) {
|
|
1193
|
-
|
|
1625
|
+
logger8.debug(`[ALL] Field ${relationshipInfo.path} already constrained by itemQuery, skipping hierarchical location constraint to avoid conflicts`);
|
|
1194
1626
|
continue;
|
|
1195
1627
|
}
|
|
1196
|
-
|
|
1628
|
+
logger8.trace(`[ALL] Setting hierarchical location where clause: ${relationshipInfo.path} = ${stringifyJSON(locKey.lk)} (type: ${typeof locKey.lk})`);
|
|
1197
1629
|
options.where[relationshipInfo.path] = {
|
|
1198
1630
|
[Op2.eq]: locKey.lk
|
|
1199
1631
|
};
|
|
@@ -1211,7 +1643,7 @@ var getAllOperation = (models, definition, registry) => {
|
|
|
1211
1643
|
const effectiveOffset = allOptions?.offset ?? itemQuery?.offset ?? 0;
|
|
1212
1644
|
const whereFields = options.where ? Object.keys(options.where).join(", ") : "none";
|
|
1213
1645
|
const includeCount = options.include?.length || 0;
|
|
1214
|
-
|
|
1646
|
+
logger8.default(
|
|
1215
1647
|
`All query configured for ${model.name} with where fields: ${whereFields}, includes: ${includeCount}, limit: ${effectiveLimit}, offset: ${effectiveOffset}`
|
|
1216
1648
|
);
|
|
1217
1649
|
const countOptions = {
|
|
@@ -1221,9 +1653,10 @@ var getAllOperation = (models, definition, registry) => {
|
|
|
1221
1653
|
if (options.include) {
|
|
1222
1654
|
countOptions.include = options.include;
|
|
1223
1655
|
}
|
|
1656
|
+
queryMetrics.recordQuery(model.name);
|
|
1224
1657
|
const countResult = await model.count(countOptions);
|
|
1225
1658
|
const total = Array.isArray(countResult) ? countResult.length : countResult;
|
|
1226
|
-
|
|
1659
|
+
logger8.debug(`[ALL] Total count for ${model.name}: ${total}`);
|
|
1227
1660
|
delete options.limit;
|
|
1228
1661
|
delete options.offset;
|
|
1229
1662
|
if (effectiveLimit !== void 0) {
|
|
@@ -1233,17 +1666,27 @@ var getAllOperation = (models, definition, registry) => {
|
|
|
1233
1666
|
options.offset = effectiveOffset;
|
|
1234
1667
|
}
|
|
1235
1668
|
try {
|
|
1236
|
-
|
|
1669
|
+
logger8.trace(`[ALL] Executing ${model.name}.findAll() with options: ${JSON.stringify(options, null, 2)}`);
|
|
1237
1670
|
} catch {
|
|
1238
|
-
|
|
1671
|
+
logger8.trace(`[ALL] Executing ${model.name}.findAll() with options containing non-serializable operators (${Object.keys(options.where || {}).length} where conditions)`);
|
|
1239
1672
|
}
|
|
1673
|
+
queryMetrics.recordQuery(model.name);
|
|
1240
1674
|
const matchingItems = await model.findAll(options);
|
|
1241
1675
|
const currentContext = contextManager.getCurrentContext();
|
|
1242
1676
|
const items = await Promise.all(matchingItems.map(async (row) => {
|
|
1243
|
-
const processedRow = await processRow(
|
|
1677
|
+
const processedRow = await processRow(
|
|
1678
|
+
row,
|
|
1679
|
+
coordinate.kta,
|
|
1680
|
+
references || [],
|
|
1681
|
+
aggregations || [],
|
|
1682
|
+
registry,
|
|
1683
|
+
currentContext,
|
|
1684
|
+
includedAggregations,
|
|
1685
|
+
includedReferences
|
|
1686
|
+
);
|
|
1244
1687
|
return validateKeys(processedRow, coordinate.kta);
|
|
1245
1688
|
}));
|
|
1246
|
-
|
|
1689
|
+
logger8.debug(`[ALL] Returning ${items.length} of ${total} ${model.name} records`);
|
|
1247
1690
|
return {
|
|
1248
1691
|
items,
|
|
1249
1692
|
metadata: {
|
|
@@ -1264,7 +1707,7 @@ var getAllOperation = (models, definition, registry) => {
|
|
|
1264
1707
|
// src/ops/create.ts
|
|
1265
1708
|
import { createCreateWrapper, isComKey as isComKey3, isPriKey as isPriKey3 } from "@fjell/core";
|
|
1266
1709
|
import { validateKeys as validateKeys2 } from "@fjell/core/validation";
|
|
1267
|
-
var
|
|
1710
|
+
var logger9 = logger_default.get("sequelize", "ops", "create");
|
|
1268
1711
|
async function validateHierarchicalChain(models, locKey, kta) {
|
|
1269
1712
|
const locatorIndex = kta.indexOf(locKey.kt);
|
|
1270
1713
|
if (locatorIndex === -1) {
|
|
@@ -1274,6 +1717,7 @@ async function validateHierarchicalChain(models, locKey, kta) {
|
|
|
1274
1717
|
try {
|
|
1275
1718
|
const chainResult = buildRelationshipChain(locatorModel, kta, locatorIndex, kta.length - 1);
|
|
1276
1719
|
if (!chainResult.success) {
|
|
1720
|
+
queryMetrics.recordQuery(locatorModel.name);
|
|
1277
1721
|
const record2 = await locatorModel.findByPk(locKey.lk);
|
|
1278
1722
|
if (!record2) {
|
|
1279
1723
|
throw new Error(`Referenced ${locKey.kt} with id ${locKey.lk} does not exist`);
|
|
@@ -1286,6 +1730,7 @@ async function validateHierarchicalChain(models, locKey, kta) {
|
|
|
1286
1730
|
if (chainResult.includes && chainResult.includes.length > 0) {
|
|
1287
1731
|
queryOptions.include = chainResult.includes;
|
|
1288
1732
|
}
|
|
1733
|
+
queryMetrics.recordQuery(locatorModel.name);
|
|
1289
1734
|
const record = await locatorModel.findOne(queryOptions);
|
|
1290
1735
|
if (!record) {
|
|
1291
1736
|
throw new Error(`Referenced ${locKey.kt} with id ${locKey.lk} does not exist or chain is invalid`);
|
|
@@ -1304,8 +1749,8 @@ var getCreateOperation = (models, definition, registry) => {
|
|
|
1304
1749
|
coordinate,
|
|
1305
1750
|
async (item, options) => {
|
|
1306
1751
|
const constraints = options?.key ? `key: pk=${options.key.pk}, loc=[${isComKey3(options.key) ? options.key.loc.map((l) => `${l.kt}=${l.lk}`).join(", ") : ""}]` : options?.locations ? `locations: ${options.locations.map((loc) => `${loc.kt}=${loc.lk}`).join(", ")}` : "no constraints";
|
|
1307
|
-
|
|
1308
|
-
|
|
1752
|
+
logger9.debug(`CREATE operation called on ${models[0].name} with ${constraints}`);
|
|
1753
|
+
logger9.default(`Create configured for ${models[0].name} with ${Object.keys(item).length} item fields`);
|
|
1309
1754
|
const model = models[0];
|
|
1310
1755
|
const modelAttributes = model.getAttributes();
|
|
1311
1756
|
let itemData = { ...item };
|
|
@@ -1343,7 +1788,7 @@ var getCreateOperation = (models, definition, registry) => {
|
|
|
1343
1788
|
if (!relationshipInfo.found) {
|
|
1344
1789
|
const associations = model.associations ? Object.keys(model.associations) : [];
|
|
1345
1790
|
const errorMessage = `Composite key locator '${locKey.kt}' cannot be resolved on model '${model.name}' or through its relationships. Available associations: [${associations.join(", ")}]. KTA: [${kta.join(", ")}]. Composite key: ${JSON.stringify(comKey, null, 2)}`;
|
|
1346
|
-
|
|
1791
|
+
logger9.error(errorMessage, { key: comKey, kta, associations });
|
|
1347
1792
|
throw new Error(errorMessage);
|
|
1348
1793
|
}
|
|
1349
1794
|
if (relationshipInfo.isDirect) {
|
|
@@ -1354,7 +1799,7 @@ var getCreateOperation = (models, definition, registry) => {
|
|
|
1354
1799
|
}
|
|
1355
1800
|
for (const locKey of directLocations) {
|
|
1356
1801
|
if (locKey.lk == null || locKey.lk === "") {
|
|
1357
|
-
|
|
1802
|
+
logger9.error(`Composite key location '${locKey.kt}' has undefined/null lk value`, { locKey, key: comKey });
|
|
1358
1803
|
throw new Error(`Composite key location '${locKey.kt}' has undefined/null lk value`);
|
|
1359
1804
|
}
|
|
1360
1805
|
const foreignKeyField = locKey.kt + "Id";
|
|
@@ -1373,7 +1818,7 @@ var getCreateOperation = (models, definition, registry) => {
|
|
|
1373
1818
|
if (!relationshipInfo.found) {
|
|
1374
1819
|
const associations = model.associations ? Object.keys(model.associations) : [];
|
|
1375
1820
|
const errorMessage = `Location key '${locKey.kt}' cannot be resolved on model '${model.name}' or through its relationships. Available associations: [${associations.join(", ")}]. KTA: [${kta.join(", ")}]. Locations: ${JSON.stringify(options.locations, null, 2)}`;
|
|
1376
|
-
|
|
1821
|
+
logger9.error(errorMessage, { locations: options.locations, kta, associations });
|
|
1377
1822
|
throw new Error(errorMessage);
|
|
1378
1823
|
}
|
|
1379
1824
|
if (relationshipInfo.isDirect) {
|
|
@@ -1384,7 +1829,7 @@ var getCreateOperation = (models, definition, registry) => {
|
|
|
1384
1829
|
}
|
|
1385
1830
|
for (const locKey of directLocations) {
|
|
1386
1831
|
if (locKey.lk == null || locKey.lk === "") {
|
|
1387
|
-
|
|
1832
|
+
logger9.error(`Location option '${locKey.kt}' has undefined/null lk value`, { locKey, locations: options.locations });
|
|
1388
1833
|
throw new Error(`Location option '${locKey.kt}' has undefined/null lk value`);
|
|
1389
1834
|
}
|
|
1390
1835
|
const foreignKeyField = locKey.kt + "Id";
|
|
@@ -1395,11 +1840,12 @@ var getCreateOperation = (models, definition, registry) => {
|
|
|
1395
1840
|
}
|
|
1396
1841
|
}
|
|
1397
1842
|
try {
|
|
1398
|
-
|
|
1843
|
+
logger9.trace(`[CREATE] Executing ${model.name}.create() with data: ${stringifyJSON(itemData)}`);
|
|
1844
|
+
queryMetrics.recordQuery(model.name);
|
|
1399
1845
|
const createdRecord = await model.create(itemData);
|
|
1400
|
-
const processedRecord = await processRow(createdRecord, kta, references || [], aggregations || [], registry);
|
|
1846
|
+
const processedRecord = await processRow(createdRecord, kta, references || [], aggregations || [], registry, void 0, void 0);
|
|
1401
1847
|
const result = validateKeys2(processedRecord, kta);
|
|
1402
|
-
|
|
1848
|
+
logger9.debug(`[CREATE] Created ${model.name} with key: ${result.key ? JSON.stringify(result.key) : `id=${createdRecord.id}`}`);
|
|
1403
1849
|
return result;
|
|
1404
1850
|
} catch (error) {
|
|
1405
1851
|
throw transformSequelizeError(error, kta[0], options?.key, model.name, itemData);
|
|
@@ -1411,7 +1857,7 @@ var getCreateOperation = (models, definition, registry) => {
|
|
|
1411
1857
|
// src/ops/find.ts
|
|
1412
1858
|
import { createFindWrapper } from "@fjell/core";
|
|
1413
1859
|
import { validateKeys as validateKeys3 } from "@fjell/core/validation";
|
|
1414
|
-
var
|
|
1860
|
+
var logger10 = logger_default.get("sequelize", "ops", "find");
|
|
1415
1861
|
var getFindOperation = (models, definition, registry) => {
|
|
1416
1862
|
const { options: { finders, references, aggregations } } = definition;
|
|
1417
1863
|
return createFindWrapper(
|
|
@@ -1421,24 +1867,24 @@ var getFindOperation = (models, definition, registry) => {
|
|
|
1421
1867
|
const locs = locations ?? [];
|
|
1422
1868
|
const params = finderParams ?? {};
|
|
1423
1869
|
const locationFilters = locs.map((loc) => `${loc.kt}=${loc.lk}`).join(", ") || "none";
|
|
1424
|
-
|
|
1870
|
+
logger10.debug(
|
|
1425
1871
|
`FIND operation called on ${models[0].name} with finder '${finder}' and ${locs.length} location filters: ${locationFilters}`
|
|
1426
1872
|
);
|
|
1427
|
-
|
|
1873
|
+
logger10.default(`Find configured for ${models[0].name} using finder '${finder}' with ${Object.keys(params).length} params`);
|
|
1428
1874
|
if (!finders || !finders[finder]) {
|
|
1429
|
-
|
|
1875
|
+
logger10.error(`No finders have been defined for this lib`);
|
|
1430
1876
|
throw new Error(`No finders found`);
|
|
1431
1877
|
}
|
|
1432
1878
|
const finderMethod = finders[finder];
|
|
1433
1879
|
if (!finderMethod) {
|
|
1434
|
-
|
|
1880
|
+
logger10.error(`Finder %s not found`, finder);
|
|
1435
1881
|
throw new Error(`Finder ${finder} not found`);
|
|
1436
1882
|
}
|
|
1437
|
-
|
|
1883
|
+
logger10.trace(`[FIND] Executing finder '${finder}' on ${models[0].name} with params: ${stringifyJSON(params)}, locations: ${stringifyJSON(locs)}, options: ${stringifyJSON(findOptions)}`);
|
|
1438
1884
|
const finderResult = await finderMethod(params, locs, findOptions);
|
|
1439
1885
|
const processItems = async (items) => {
|
|
1440
1886
|
return await Promise.all(items.map(async (row) => {
|
|
1441
|
-
const processedRow = await processRow(row, definition.coordinate.kta, references || [], aggregations || [], registry);
|
|
1887
|
+
const processedRow = await processRow(row, definition.coordinate.kta, references || [], aggregations || [], registry, void 0, void 0);
|
|
1442
1888
|
return validateKeys3(processedRow, definition.coordinate.kta);
|
|
1443
1889
|
}));
|
|
1444
1890
|
};
|
|
@@ -1446,7 +1892,7 @@ var getFindOperation = (models, definition, registry) => {
|
|
|
1446
1892
|
if (isOptInResult) {
|
|
1447
1893
|
const optInResult = finderResult;
|
|
1448
1894
|
const processedResults2 = optInResult.items && optInResult.items.length > 0 ? await processItems(optInResult.items) : [];
|
|
1449
|
-
|
|
1895
|
+
logger10.debug(`[FIND] Finder opted-in, found ${processedResults2.length} ${models[0].name} records using finder '${finder}' (total: ${optInResult.metadata.total})`);
|
|
1450
1896
|
return {
|
|
1451
1897
|
items: processedResults2,
|
|
1452
1898
|
metadata: optInResult.metadata
|
|
@@ -1454,7 +1900,7 @@ var getFindOperation = (models, definition, registry) => {
|
|
|
1454
1900
|
}
|
|
1455
1901
|
const results = finderResult;
|
|
1456
1902
|
const processedResults = results && results.length > 0 ? await processItems(results) : [];
|
|
1457
|
-
|
|
1903
|
+
logger10.debug(`[FIND] Legacy finder, found ${processedResults.length} ${models[0].name} records using finder '${finder}'`);
|
|
1458
1904
|
return {
|
|
1459
1905
|
items: processedResults,
|
|
1460
1906
|
metadata: {
|
|
@@ -1465,7 +1911,7 @@ var getFindOperation = (models, definition, registry) => {
|
|
|
1465
1911
|
}
|
|
1466
1912
|
};
|
|
1467
1913
|
} catch (error) {
|
|
1468
|
-
|
|
1914
|
+
logger10.error("Error in find operation", {
|
|
1469
1915
|
finder,
|
|
1470
1916
|
finderParams,
|
|
1471
1917
|
locations,
|
|
@@ -1497,7 +1943,7 @@ import {
|
|
|
1497
1943
|
validateKeys as validateKeys4
|
|
1498
1944
|
} from "@fjell/core";
|
|
1499
1945
|
import { NotFoundError } from "@fjell/core";
|
|
1500
|
-
var
|
|
1946
|
+
var logger11 = logger_default.get("sequelize", "ops", "get");
|
|
1501
1947
|
var processCompositeKey = (comKey, model, kta) => {
|
|
1502
1948
|
const where = { id: comKey.pk };
|
|
1503
1949
|
const includes = [];
|
|
@@ -1505,7 +1951,7 @@ var processCompositeKey = (comKey, model, kta) => {
|
|
|
1505
1951
|
const relationshipInfo = buildRelationshipPath(model, locator.kt, kta);
|
|
1506
1952
|
if (!relationshipInfo.found) {
|
|
1507
1953
|
const errorMessage = `Composite key locator '${locator.kt}' cannot be resolved on model '${model.name}' or through its relationships. Key type array: [${kta.join(", ")}], Composite key: ${stringifyJSON(comKey)}, Available associations: [${Object.keys(model.associations || {}).join(", ")}]`;
|
|
1508
|
-
|
|
1954
|
+
logger11.error(errorMessage, { key: comKey, kta });
|
|
1509
1955
|
throw new Error(errorMessage);
|
|
1510
1956
|
}
|
|
1511
1957
|
if (relationshipInfo.path) {
|
|
@@ -1532,28 +1978,53 @@ var getGetOperation = (models, definition, registry) => {
|
|
|
1532
1978
|
async (key) => {
|
|
1533
1979
|
try {
|
|
1534
1980
|
if (!isValidItemKey(key)) {
|
|
1535
|
-
|
|
1981
|
+
logger11.error("Key for Get is not a valid ItemKey: %j", key);
|
|
1536
1982
|
throw new Error("Key for Get is not a valid ItemKey");
|
|
1537
1983
|
}
|
|
1538
1984
|
const keyDescription = isPriKey4(key) ? `primary key: pk=${key.pk}` : `composite key: pk=${key.pk}, loc=[${key.loc.map((l) => `${l.kt}=${l.lk}`).join(", ")}]`;
|
|
1539
|
-
|
|
1540
|
-
|
|
1985
|
+
logger11.debug(`GET operation called on ${models[0].name} with ${keyDescription}`);
|
|
1986
|
+
logger11.default(`Get configured for ${models[0].name} with ${isPriKey4(key) ? "primary" : "composite"} key`);
|
|
1541
1987
|
const itemKey = key;
|
|
1542
1988
|
const model = models[0];
|
|
1543
1989
|
let item;
|
|
1990
|
+
let includedAggregations = [];
|
|
1991
|
+
let includedReferences = [];
|
|
1544
1992
|
if (isPriKey4(itemKey)) {
|
|
1545
|
-
|
|
1546
|
-
|
|
1993
|
+
let options = {};
|
|
1994
|
+
const refResult = addReferenceIncludes(options, model, references || []);
|
|
1995
|
+
includedReferences = refResult.includedReferences;
|
|
1996
|
+
options = refResult.options;
|
|
1997
|
+
const aggResult = addAggregationIncludes(options, model, aggregations || []);
|
|
1998
|
+
includedAggregations = aggResult.includedAggregations;
|
|
1999
|
+
options = aggResult.options;
|
|
2000
|
+
logger11.trace(`[GET] Executing ${model.name}.findByPk() with pk: ${itemKey.pk}, ${includedReferences.length} reference includes, and ${includedAggregations.length} aggregation includes`);
|
|
2001
|
+
queryMetrics.recordQuery(model.name);
|
|
2002
|
+
item = options.include && options.include.length > 0 ? await model.findByPk(itemKey.pk, { include: options.include }) : await model.findByPk(itemKey.pk);
|
|
1547
2003
|
} else if (isComKey4(itemKey)) {
|
|
1548
2004
|
const comKey = itemKey;
|
|
1549
2005
|
if (comKey.loc.length === 0) {
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
2006
|
+
let options = {};
|
|
2007
|
+
const refResult = addReferenceIncludes(options, model, references || []);
|
|
2008
|
+
includedReferences = refResult.includedReferences;
|
|
2009
|
+
options = refResult.options;
|
|
2010
|
+
const aggResult = addAggregationIncludes(options, model, aggregations || []);
|
|
2011
|
+
includedAggregations = aggResult.includedAggregations;
|
|
2012
|
+
options = aggResult.options;
|
|
2013
|
+
logger11.debug(`[GET] Empty loc array detected - finding by primary key across all locations: ${comKey.pk}`);
|
|
2014
|
+
logger11.trace(`[GET] Executing ${model.name}.findByPk() with pk: ${comKey.pk}, ${includedReferences.length} reference includes, and ${includedAggregations.length} aggregation includes`);
|
|
2015
|
+
queryMetrics.recordQuery(model.name);
|
|
2016
|
+
item = options.include && options.include.length > 0 ? await model.findByPk(comKey.pk, { include: options.include }) : await model.findByPk(comKey.pk);
|
|
1553
2017
|
} else {
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
2018
|
+
let queryOptions = processCompositeKey(comKey, model, kta);
|
|
2019
|
+
const refResult = addReferenceIncludes(queryOptions, model, references || []);
|
|
2020
|
+
includedReferences = refResult.includedReferences;
|
|
2021
|
+
queryOptions = refResult.options;
|
|
2022
|
+
const aggResult = addAggregationIncludes(queryOptions, model, aggregations || []);
|
|
2023
|
+
includedAggregations = aggResult.includedAggregations;
|
|
2024
|
+
queryOptions = aggResult.options;
|
|
2025
|
+
logger11.default("Composite key query", { queryOptions });
|
|
2026
|
+
logger11.trace(`[GET] Executing ${model.name}.findOne() with options: ${stringifyJSON(queryOptions)}, ${includedReferences.length} reference includes, and ${includedAggregations.length} aggregation includes`);
|
|
2027
|
+
queryMetrics.recordQuery(model.name);
|
|
1557
2028
|
item = await model.findOne(queryOptions);
|
|
1558
2029
|
}
|
|
1559
2030
|
}
|
|
@@ -1565,8 +2036,8 @@ var getGetOperation = (models, definition, registry) => {
|
|
|
1565
2036
|
);
|
|
1566
2037
|
}
|
|
1567
2038
|
const currentContext = contextManager.getCurrentContext();
|
|
1568
|
-
const result = validateKeys4(await processRow(item, kta, references || [], aggregations || [], registry, currentContext), kta);
|
|
1569
|
-
|
|
2039
|
+
const result = validateKeys4(await processRow(item, kta, references || [], aggregations || [], registry, currentContext, includedAggregations, includedReferences), kta);
|
|
2040
|
+
logger11.debug(`[GET] Retrieved ${model.name} with key: ${result.key ? JSON.stringify(result.key) : `id=${item.id}`}`);
|
|
1570
2041
|
return result;
|
|
1571
2042
|
} catch (error) {
|
|
1572
2043
|
if (error instanceof NotFoundError) throw error;
|
|
@@ -1578,21 +2049,21 @@ var getGetOperation = (models, definition, registry) => {
|
|
|
1578
2049
|
|
|
1579
2050
|
// src/ops/one.ts
|
|
1580
2051
|
import { createOneWrapper } from "@fjell/core";
|
|
1581
|
-
var
|
|
2052
|
+
var logger12 = logger_default.get("sequelize", "ops", "one");
|
|
1582
2053
|
var getOneOperation = (models, definition, registry) => {
|
|
1583
2054
|
return createOneWrapper(
|
|
1584
2055
|
definition.coordinate,
|
|
1585
2056
|
async (itemQuery, locations) => {
|
|
1586
2057
|
const locs = locations ?? [];
|
|
1587
|
-
|
|
1588
|
-
|
|
2058
|
+
logger12.debug(`ONE operation called on ${models[0].name} with ${locs.length} location filters: ${locs.map((loc) => `${loc.kt}=${loc.lk}`).join(", ") || "none"}`);
|
|
2059
|
+
logger12.default(`One configured for ${models[0].name} delegating to all operation`);
|
|
1589
2060
|
const result = await getAllOperation(models, definition, registry)(itemQuery ?? {}, locs, { limit: 1 });
|
|
1590
2061
|
if (result.items.length > 0) {
|
|
1591
2062
|
const item = result.items[0];
|
|
1592
|
-
|
|
2063
|
+
logger12.debug(`[ONE] Found ${models[0].name} record with key: ${item.key ? JSON.stringify(item.key) : "unknown"}`);
|
|
1593
2064
|
return item;
|
|
1594
2065
|
} else {
|
|
1595
|
-
|
|
2066
|
+
logger12.debug(`[ONE] No ${models[0].name} record found`);
|
|
1596
2067
|
return null;
|
|
1597
2068
|
}
|
|
1598
2069
|
}
|
|
@@ -1602,7 +2073,7 @@ var getOneOperation = (models, definition, registry) => {
|
|
|
1602
2073
|
// src/ops/remove.ts
|
|
1603
2074
|
import { abbrevIK, isComKey as isComKey5, isPriKey as isPriKey5, isValidItemKey as isValidItemKey2, createRemoveWrapper } from "@fjell/core";
|
|
1604
2075
|
import { NotFoundError as NotFoundError2 } from "@fjell/core";
|
|
1605
|
-
var
|
|
2076
|
+
var logger13 = logger_default.get("sequelize", "ops", "remove");
|
|
1606
2077
|
var processCompositeKey2 = (comKey, model, kta) => {
|
|
1607
2078
|
const where = { id: comKey.pk };
|
|
1608
2079
|
const includes = [];
|
|
@@ -1610,7 +2081,7 @@ var processCompositeKey2 = (comKey, model, kta) => {
|
|
|
1610
2081
|
const relationshipInfo = buildRelationshipPath(model, locator.kt, kta);
|
|
1611
2082
|
if (!relationshipInfo.found) {
|
|
1612
2083
|
const errorMessage = `Composite key locator '${locator.kt}' cannot be resolved on model '${model.name}' or through its relationships.`;
|
|
1613
|
-
|
|
2084
|
+
logger13.error(errorMessage, { key: comKey, kta });
|
|
1614
2085
|
throw new Error(errorMessage);
|
|
1615
2086
|
}
|
|
1616
2087
|
if (relationshipInfo.path) {
|
|
@@ -1637,24 +2108,26 @@ var getRemoveOperation = (models, definition, _registry) => {
|
|
|
1637
2108
|
async (key) => {
|
|
1638
2109
|
try {
|
|
1639
2110
|
if (!isValidItemKey2(key)) {
|
|
1640
|
-
|
|
2111
|
+
logger13.error("Key for Remove is not a valid ItemKey: %j", key);
|
|
1641
2112
|
throw new Error("Key for Remove is not a valid ItemKey");
|
|
1642
2113
|
}
|
|
1643
2114
|
const keyDescription = isPriKey5(key) ? `primary key: pk=${key.pk}` : `composite key: pk=${key.pk}, loc=[${key.loc.map((l) => `${l.kt}=${l.lk}`).join(", ")}]`;
|
|
1644
|
-
|
|
1645
|
-
|
|
2115
|
+
logger13.debug(`REMOVE operation called on ${models[0].name} with ${keyDescription}`);
|
|
2116
|
+
logger13.default(`Remove configured for ${models[0].name} with ${isPriKey5(key) ? "primary" : "composite"} key`);
|
|
1646
2117
|
const model = models[0];
|
|
1647
2118
|
let item;
|
|
1648
2119
|
let returnItem;
|
|
1649
|
-
|
|
2120
|
+
logger13.debug("remove: %s", abbrevIK(key));
|
|
1650
2121
|
if (isPriKey5(key)) {
|
|
1651
|
-
|
|
2122
|
+
logger13.debug(`[REMOVE] Executing ${model.name}.findByPk() with pk: ${key.pk}`);
|
|
2123
|
+
queryMetrics.recordQuery(model.name);
|
|
1652
2124
|
item = await model.findByPk(key.pk);
|
|
1653
2125
|
} else if (isComKey5(key)) {
|
|
1654
2126
|
const comKey = key;
|
|
1655
2127
|
const queryOptions = processCompositeKey2(comKey, model, kta);
|
|
1656
|
-
|
|
1657
|
-
|
|
2128
|
+
logger13.default(`Remove composite key query for ${model.name} with where fields: ${queryOptions.where ? Object.keys(queryOptions.where).join(", ") : "none"}`);
|
|
2129
|
+
logger13.debug(`[REMOVE] Executing ${model.name}.findOne() with options: ${stringifyJSON(queryOptions)}`);
|
|
2130
|
+
queryMetrics.recordQuery(model.name);
|
|
1658
2131
|
item = await model.findOne(queryOptions);
|
|
1659
2132
|
}
|
|
1660
2133
|
if (!item) {
|
|
@@ -1673,13 +2146,15 @@ var getRemoveOperation = (models, definition, _registry) => {
|
|
|
1673
2146
|
if (model.getAttributes().deletedAt) {
|
|
1674
2147
|
item.deletedAt = /* @__PURE__ */ new Date();
|
|
1675
2148
|
}
|
|
1676
|
-
|
|
2149
|
+
logger13.debug(`[REMOVE] Executing ${model.name}.save() for soft delete`);
|
|
2150
|
+
queryMetrics.recordQuery(model.name);
|
|
1677
2151
|
await item?.save();
|
|
1678
2152
|
returnItem = item?.get({ plain: true });
|
|
1679
2153
|
returnItem = addKey(item, returnItem, kta);
|
|
1680
2154
|
returnItem = populateEvents(returnItem);
|
|
1681
2155
|
} else if (options.deleteOnRemove) {
|
|
1682
|
-
|
|
2156
|
+
logger13.debug(`[REMOVE] Executing ${model.name}.destroy() for hard delete`);
|
|
2157
|
+
queryMetrics.recordQuery(model.name);
|
|
1683
2158
|
await item?.destroy();
|
|
1684
2159
|
returnItem = item?.get({ plain: true });
|
|
1685
2160
|
returnItem = addKey(item, returnItem, kta);
|
|
@@ -1687,7 +2162,7 @@ var getRemoveOperation = (models, definition, _registry) => {
|
|
|
1687
2162
|
} else {
|
|
1688
2163
|
throw new Error("No deletedAt or isDeleted attribute found in model, and deleteOnRemove is not set");
|
|
1689
2164
|
}
|
|
1690
|
-
|
|
2165
|
+
logger13.debug(`[REMOVE] Removed ${model.name} with key: ${returnItem.key ? JSON.stringify(returnItem.key) : `id=${item.id}`}`);
|
|
1691
2166
|
const { references } = options;
|
|
1692
2167
|
if (references && references.length > 0) {
|
|
1693
2168
|
returnItem = addRefsToSequelizeItem(returnItem, references);
|
|
@@ -1711,7 +2186,7 @@ import {
|
|
|
1711
2186
|
import { validateKeys as validateKeys5 } from "@fjell/core/validation";
|
|
1712
2187
|
import { NotFoundError as NotFoundError3 } from "@fjell/core";
|
|
1713
2188
|
import { Op as Op3 } from "sequelize";
|
|
1714
|
-
var
|
|
2189
|
+
var logger14 = logger_default.get("sequelize", "ops", "update");
|
|
1715
2190
|
var mergeIncludes2 = (existingIncludes, newIncludes) => {
|
|
1716
2191
|
const mergedIncludes = [...existingIncludes];
|
|
1717
2192
|
for (const newInclude of newIncludes) {
|
|
@@ -1743,15 +2218,16 @@ var getUpdateOperation = (models, definition, registry) => {
|
|
|
1743
2218
|
);
|
|
1744
2219
|
}
|
|
1745
2220
|
const keyDescription = isPriKey6(key) ? `primary key: pk=${key.pk}` : `composite key: pk=${key.pk}, loc=[${key.loc.map((l) => `${l.kt}=${l.lk}`).join(", ")}]`;
|
|
1746
|
-
|
|
2221
|
+
logger14.debug(`UPDATE operation called on ${models[0].name} with ${keyDescription}`, { options });
|
|
1747
2222
|
const { coordinate } = definition;
|
|
1748
2223
|
const { kta } = coordinate;
|
|
1749
|
-
|
|
2224
|
+
logger14.debug("update: %s, %j", abbrevIK2(key), item);
|
|
1750
2225
|
const model = models[0];
|
|
1751
2226
|
let response;
|
|
1752
2227
|
if (isPriKey6(key)) {
|
|
1753
2228
|
const priKey = key;
|
|
1754
|
-
|
|
2229
|
+
logger14.trace(`[UPDATE] Executing ${model.name}.findByPk() with pk: ${priKey.pk}`);
|
|
2230
|
+
queryMetrics.recordQuery(model.name);
|
|
1755
2231
|
response = await model.findByPk(priKey.pk);
|
|
1756
2232
|
} else if (isComKey6(key)) {
|
|
1757
2233
|
const comKey = key;
|
|
@@ -1761,7 +2237,7 @@ var getUpdateOperation = (models, definition, registry) => {
|
|
|
1761
2237
|
const relationshipInfo = buildRelationshipPath(model, locator.kt, kta, true);
|
|
1762
2238
|
if (!relationshipInfo.found) {
|
|
1763
2239
|
const errorMessage = `Composite key locator '${locator.kt}' cannot be resolved on model '${model.name}' or through its relationships.`;
|
|
1764
|
-
|
|
2240
|
+
logger14.error(errorMessage, { key: comKey, kta });
|
|
1765
2241
|
throw new Error(errorMessage);
|
|
1766
2242
|
}
|
|
1767
2243
|
if (relationshipInfo.isDirect) {
|
|
@@ -1780,8 +2256,9 @@ var getUpdateOperation = (models, definition, registry) => {
|
|
|
1780
2256
|
if (additionalIncludes.length > 0) {
|
|
1781
2257
|
queryOptions.include = mergeIncludes2([], additionalIncludes);
|
|
1782
2258
|
}
|
|
1783
|
-
|
|
1784
|
-
|
|
2259
|
+
logger14.default(`Update composite key query for ${model.name} with where fields: ${queryOptions.where ? Object.keys(queryOptions.where).join(", ") : "none"}`);
|
|
2260
|
+
logger14.trace(`[UPDATE] Executing ${model.name}.findOne() with options: ${stringifyJSON(queryOptions)}`);
|
|
2261
|
+
queryMetrics.recordQuery(model.name);
|
|
1785
2262
|
response = await model.findOne(queryOptions);
|
|
1786
2263
|
}
|
|
1787
2264
|
if (!response) {
|
|
@@ -1800,13 +2277,14 @@ var getUpdateOperation = (models, definition, registry) => {
|
|
|
1800
2277
|
if (aggregations && aggregations.length > 0) {
|
|
1801
2278
|
updateProps = removeAggsFromItem(updateProps, aggregations);
|
|
1802
2279
|
}
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
2280
|
+
logger14.default(`Update found ${model.name} record to modify`);
|
|
2281
|
+
logger14.default(`Update properties configured: ${Object.keys(updateProps).join(", ")}`);
|
|
2282
|
+
logger14.trace(`[UPDATE] Executing ${model.name}.update() with properties: ${stringifyJSON(updateProps)}`);
|
|
2283
|
+
queryMetrics.recordQuery(model.name);
|
|
1806
2284
|
response = await response.update(updateProps);
|
|
1807
|
-
const processedItem = await processRow(response, kta, references || [], aggregations || [], registry);
|
|
2285
|
+
const processedItem = await processRow(response, kta, references || [], aggregations || [], registry, void 0, void 0);
|
|
1808
2286
|
const returnItem = validateKeys5(processedItem, kta);
|
|
1809
|
-
|
|
2287
|
+
logger14.debug(`[UPDATE] Updated ${model.name} with key: ${returnItem.key ? JSON.stringify(returnItem.key) : `id=${response.id}`}`);
|
|
1810
2288
|
return returnItem;
|
|
1811
2289
|
} catch (error) {
|
|
1812
2290
|
if (error instanceof NotFoundError3) throw error;
|
|
@@ -1818,7 +2296,7 @@ var getUpdateOperation = (models, definition, registry) => {
|
|
|
1818
2296
|
|
|
1819
2297
|
// src/ops/upsert.ts
|
|
1820
2298
|
import { createUpsertWrapper, isValidItemKey as isValidItemKey3, NotFoundError as NotFoundError4 } from "@fjell/core";
|
|
1821
|
-
var
|
|
2299
|
+
var logger15 = logger_default.get("sequelize", "ops", "upsert");
|
|
1822
2300
|
var getUpsertOperation = (models, definition, registry) => {
|
|
1823
2301
|
const get = getGetOperation(models, definition, registry);
|
|
1824
2302
|
const update = getUpdateOperation(models, definition, registry);
|
|
@@ -1827,31 +2305,31 @@ var getUpsertOperation = (models, definition, registry) => {
|
|
|
1827
2305
|
definition.coordinate,
|
|
1828
2306
|
async (key, item, locations, options) => {
|
|
1829
2307
|
if (!isValidItemKey3(key)) {
|
|
1830
|
-
|
|
2308
|
+
logger15.error("Key for Upsert is not a valid ItemKey: %j", key);
|
|
1831
2309
|
throw new Error(`Key for Upsert is not a valid ItemKey: ${stringifyJSON(key)}`);
|
|
1832
2310
|
}
|
|
1833
|
-
|
|
2311
|
+
logger15.debug(`[UPSERT] Attempting upsert with key: ${stringifyJSON(key)}`, { options });
|
|
1834
2312
|
let resultItem = null;
|
|
1835
2313
|
try {
|
|
1836
|
-
|
|
2314
|
+
logger15.debug(`[UPSERT] Retrieving item by key: ${stringifyJSON(key)}`);
|
|
1837
2315
|
resultItem = await get(key);
|
|
1838
2316
|
} catch (error) {
|
|
1839
2317
|
const isNotFound = error instanceof NotFoundError4 || error?.name === "NotFoundError" || error?.errorInfo?.code === "NOT_FOUND";
|
|
1840
2318
|
if (isNotFound) {
|
|
1841
|
-
|
|
2319
|
+
logger15.debug(`[UPSERT] Item not found, creating new item with key: ${stringifyJSON(key)}, errorType: ${error?.name}, errorCode: ${error?.errorInfo?.code}`);
|
|
1842
2320
|
const createOptions3 = locations ? { locations } : { key };
|
|
1843
2321
|
resultItem = await create(item, createOptions3);
|
|
1844
2322
|
} else {
|
|
1845
|
-
|
|
2323
|
+
logger15.error(`[UPSERT] Unexpected error during get operation`, { error: error?.message, name: error?.name, code: error?.errorInfo?.code });
|
|
1846
2324
|
throw error;
|
|
1847
2325
|
}
|
|
1848
2326
|
}
|
|
1849
2327
|
if (!resultItem) {
|
|
1850
2328
|
throw new Error(`Failed to retrieve or create item for key: ${stringifyJSON(key)}`);
|
|
1851
2329
|
}
|
|
1852
|
-
|
|
2330
|
+
logger15.debug(`[UPSERT] Updating item with properties, key: ${stringifyJSON(key)}`, { options });
|
|
1853
2331
|
resultItem = await update(resultItem.key, item, options);
|
|
1854
|
-
|
|
2332
|
+
logger15.debug(`[UPSERT] Item upserted successfully: ${stringifyJSON(resultItem)}`);
|
|
1855
2333
|
return resultItem;
|
|
1856
2334
|
}
|
|
1857
2335
|
);
|
|
@@ -1880,9 +2358,9 @@ var createOperations = (models, coordinate, registry, options) => {
|
|
|
1880
2358
|
};
|
|
1881
2359
|
|
|
1882
2360
|
// src/SequelizeLibrary.ts
|
|
1883
|
-
var
|
|
2361
|
+
var logger16 = logger_default.get("SequelizeLibrary");
|
|
1884
2362
|
var createSequelizeLibrary = (registry, coordinate, models, options) => {
|
|
1885
|
-
|
|
2363
|
+
logger16.debug("createSequelizeLibrary", { coordinate, models, registry, options });
|
|
1886
2364
|
const operations = createOperations(models, coordinate, registry, options);
|
|
1887
2365
|
const wrappedOperations = Library3.wrapOperations(operations, options, coordinate, registry);
|
|
1888
2366
|
const libLibrary = Library3.createLibrary(registry, coordinate, wrappedOperations, options);
|
|
@@ -1896,10 +2374,10 @@ var isSequelizeLibrary = (library) => {
|
|
|
1896
2374
|
};
|
|
1897
2375
|
|
|
1898
2376
|
// src/SequelizeLibraryFactory.ts
|
|
1899
|
-
var
|
|
2377
|
+
var logger17 = logger_default.get("InstanceFactory");
|
|
1900
2378
|
var createSequelizeLibraryFactory = (models, options) => {
|
|
1901
2379
|
return (coordinate, context) => {
|
|
1902
|
-
|
|
2380
|
+
logger17.debug("Creating Sequelize instance", {
|
|
1903
2381
|
coordinate,
|
|
1904
2382
|
registry: context.registry,
|
|
1905
2383
|
models: models.map((m) => m.name),
|
|
@@ -1944,9 +2422,9 @@ __export(primary_exports, {
|
|
|
1944
2422
|
|
|
1945
2423
|
// src/primary/SequelizeLibrary.ts
|
|
1946
2424
|
import { Primary } from "@fjell/lib";
|
|
1947
|
-
var
|
|
2425
|
+
var logger18 = logger_default.get("lib-sequelize", "primary", "library");
|
|
1948
2426
|
function createSequelizeLibrary3(keyType, models, libOptions = {}, scopes = [], registry) {
|
|
1949
|
-
|
|
2427
|
+
logger18.debug("createSequelizeLibrary", { keyType, models, libOptions, scopes });
|
|
1950
2428
|
const coordinate = createCoordinate([keyType], scopes);
|
|
1951
2429
|
const options = createOptions2(libOptions);
|
|
1952
2430
|
const operations = createOperations(models, coordinate, registry, options);
|