@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/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 addAssociationCondition = (conditions, condition, model) => {
224
- const [associationName, attributeName] = condition.column.split(".", 2);
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 buildQuery = (itemQuery, model) => {
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.debug("Using empty loc array for composite item reference", {
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.debug("Created reference key", {
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.debug("Circular dependency detected, creating reference placeholder", {
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.debug(`Moved aggregation '${aggDef.property}' to aggs structure`, {
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
- logger6.default("Processing Reference for %s to %s", item.key.kt, stringifyJSON(referenceDefinition.kta));
897
- return buildSequelizeReference(item, referenceDefinition, registry, operationContext);
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
- logger6.default("Processing Aggregation for %s from %s", item.key.kt, stringifyJSON(aggregationDefinition.kta));
908
- item = await buildAggregation(item, aggregationDefinition, registry, operationContext);
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.debug("Added refs structure to item (transparent wrapper)", { key: item.key });
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.debug("Added aggs structure to item (transparent wrapper)", { key: item.key });
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 logger7 = logger_default.get("sequelize", "ops", "all");
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
- logger7.debug(`ALL operation called on ${models[0].name} with ${locs.length} location filters: ${locs.map((loc2) => `${loc2.kt}=${loc2.lk}`).join(", ") || "none"}`);
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
- const options = buildQuery(itemQuery ?? {}, model);
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
- logger7.error(errorMessage, { locations: loc, kta });
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
- logger7.error(`Location key '${locKey.kt}' has invalid lk value: ${stringifyJSON(locKey.lk)}`, { locKey, locations: loc });
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
- logger7.debug(`[ALL] Field ${foreignKeyField} already constrained by itemQuery, skipping location constraint to avoid conflicts`);
1609
+ logger8.debug(`[ALL] Field ${foreignKeyField} already constrained by itemQuery, skipping location constraint to avoid conflicts`);
1178
1610
  continue;
1179
1611
  }
1180
- logger7.trace(`[ALL] Setting direct location where clause: ${foreignKeyField} = ${stringifyJSON(locKey.lk)} (type: ${typeof locKey.lk})`);
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
- logger7.error(`Hierarchical location key '${locKey.kt}' has invalid lk value: ${stringifyJSON(locKey.lk)}`, { locKey, locations: loc });
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
- logger7.debug(`[ALL] Field ${relationshipInfo.path} already constrained by itemQuery, skipping hierarchical location constraint to avoid conflicts`);
1625
+ logger8.debug(`[ALL] Field ${relationshipInfo.path} already constrained by itemQuery, skipping hierarchical location constraint to avoid conflicts`);
1194
1626
  continue;
1195
1627
  }
1196
- logger7.trace(`[ALL] Setting hierarchical location where clause: ${relationshipInfo.path} = ${stringifyJSON(locKey.lk)} (type: ${typeof locKey.lk})`);
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
- logger7.default(
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
- logger7.debug(`[ALL] Total count for ${model.name}: ${total}`);
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
- logger7.trace(`[ALL] Executing ${model.name}.findAll() with options: ${JSON.stringify(options, null, 2)}`);
1669
+ logger8.trace(`[ALL] Executing ${model.name}.findAll() with options: ${JSON.stringify(options, null, 2)}`);
1237
1670
  } catch {
1238
- logger7.trace(`[ALL] Executing ${model.name}.findAll() with options containing non-serializable operators (${Object.keys(options.where || {}).length} where conditions)`);
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(row, coordinate.kta, references || [], aggregations || [], registry, currentContext);
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
- logger7.debug(`[ALL] Returning ${items.length} of ${total} ${model.name} records`);
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 logger8 = logger_default.get("sequelize", "ops", "create");
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
- logger8.debug(`CREATE operation called on ${models[0].name} with ${constraints}`);
1308
- logger8.default(`Create configured for ${models[0].name} with ${Object.keys(item).length} item fields`);
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
- logger8.error(errorMessage, { key: comKey, kta, associations });
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
- logger8.error(`Composite key location '${locKey.kt}' has undefined/null lk value`, { locKey, key: comKey });
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
- logger8.error(errorMessage, { locations: options.locations, kta, associations });
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
- logger8.error(`Location option '${locKey.kt}' has undefined/null lk value`, { locKey, locations: options.locations });
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
- logger8.trace(`[CREATE] Executing ${model.name}.create() with data: ${stringifyJSON(itemData)}`);
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
- logger8.debug(`[CREATE] Created ${model.name} with key: ${result.key ? JSON.stringify(result.key) : `id=${createdRecord.id}`}`);
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 logger9 = logger_default.get("sequelize", "ops", "find");
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
- logger9.debug(
1870
+ logger10.debug(
1425
1871
  `FIND operation called on ${models[0].name} with finder '${finder}' and ${locs.length} location filters: ${locationFilters}`
1426
1872
  );
1427
- logger9.default(`Find configured for ${models[0].name} using finder '${finder}' with ${Object.keys(params).length} params`);
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
- logger9.error(`No finders have been defined for this lib`);
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
- logger9.error(`Finder %s not found`, finder);
1880
+ logger10.error(`Finder %s not found`, finder);
1435
1881
  throw new Error(`Finder ${finder} not found`);
1436
1882
  }
1437
- logger9.trace(`[FIND] Executing finder '${finder}' on ${models[0].name} with params: ${stringifyJSON(params)}, locations: ${stringifyJSON(locs)}, options: ${stringifyJSON(findOptions)}`);
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
- logger9.debug(`[FIND] Finder opted-in, found ${processedResults2.length} ${models[0].name} records using finder '${finder}' (total: ${optInResult.metadata.total})`);
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
- logger9.debug(`[FIND] Legacy finder, found ${processedResults.length} ${models[0].name} records using finder '${finder}'`);
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
- logger9.error("Error in find operation", {
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 logger10 = logger_default.get("sequelize", "ops", "get");
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
- logger10.error(errorMessage, { key: comKey, kta });
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
- logger10.error("Key for Get is not a valid ItemKey: %j", key);
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
- logger10.debug(`GET operation called on ${models[0].name} with ${keyDescription}`);
1540
- logger10.default(`Get configured for ${models[0].name} with ${isPriKey4(key) ? "primary" : "composite"} key`);
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
- logger10.trace(`[GET] Executing ${model.name}.findByPk() with pk: ${itemKey.pk}`);
1546
- item = await model.findByPk(itemKey.pk);
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
- logger10.debug(`[GET] Empty loc array detected - finding by primary key across all locations: ${comKey.pk}`);
1551
- logger10.trace(`[GET] Executing ${model.name}.findByPk() with pk: ${comKey.pk}`);
1552
- item = await model.findByPk(comKey.pk);
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
- const queryOptions = processCompositeKey(comKey, model, kta);
1555
- logger10.default("Composite key query", { queryOptions });
1556
- logger10.trace(`[GET] Executing ${model.name}.findOne() with options: ${stringifyJSON(queryOptions)}`);
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
- logger10.debug(`[GET] Retrieved ${model.name} with key: ${result.key ? JSON.stringify(result.key) : `id=${item.id}`}`);
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 logger11 = logger_default.get("sequelize", "ops", "one");
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
- logger11.debug(`ONE operation called on ${models[0].name} with ${locs.length} location filters: ${locs.map((loc) => `${loc.kt}=${loc.lk}`).join(", ") || "none"}`);
1588
- logger11.default(`One configured for ${models[0].name} delegating to all operation`);
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
- logger11.debug(`[ONE] Found ${models[0].name} record with key: ${item.key ? JSON.stringify(item.key) : "unknown"}`);
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
- logger11.debug(`[ONE] No ${models[0].name} record found`);
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 logger12 = logger_default.get("sequelize", "ops", "remove");
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
- logger12.error(errorMessage, { key: comKey, kta });
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
- logger12.error("Key for Remove is not a valid ItemKey: %j", key);
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
- logger12.debug(`REMOVE operation called on ${models[0].name} with ${keyDescription}`);
1645
- logger12.default(`Remove configured for ${models[0].name} with ${isPriKey5(key) ? "primary" : "composite"} key`);
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
- logger12.debug("remove: %s", abbrevIK(key));
2120
+ logger13.debug("remove: %s", abbrevIK(key));
1650
2121
  if (isPriKey5(key)) {
1651
- logger12.debug(`[REMOVE] Executing ${model.name}.findByPk() with pk: ${key.pk}`);
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
- logger12.default(`Remove composite key query for ${model.name} with where fields: ${queryOptions.where ? Object.keys(queryOptions.where).join(", ") : "none"}`);
1657
- logger12.debug(`[REMOVE] Executing ${model.name}.findOne() with options: ${stringifyJSON(queryOptions)}`);
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
- logger12.debug(`[REMOVE] Executing ${model.name}.save() for soft delete`);
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
- logger12.debug(`[REMOVE] Executing ${model.name}.destroy() for hard delete`);
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
- logger12.debug(`[REMOVE] Removed ${model.name} with key: ${returnItem.key ? JSON.stringify(returnItem.key) : `id=${item.id}`}`);
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 logger13 = logger_default.get("sequelize", "ops", "update");
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
- logger13.debug(`UPDATE operation called on ${models[0].name} with ${keyDescription}`, { options });
2221
+ logger14.debug(`UPDATE operation called on ${models[0].name} with ${keyDescription}`, { options });
1747
2222
  const { coordinate } = definition;
1748
2223
  const { kta } = coordinate;
1749
- logger13.debug("update: %s, %j", abbrevIK2(key), item);
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
- logger13.trace(`[UPDATE] Executing ${model.name}.findByPk() with pk: ${priKey.pk}`);
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
- logger13.error(errorMessage, { key: comKey, kta });
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
- logger13.default(`Update composite key query for ${model.name} with where fields: ${queryOptions.where ? Object.keys(queryOptions.where).join(", ") : "none"}`);
1784
- logger13.trace(`[UPDATE] Executing ${model.name}.findOne() with options: ${stringifyJSON(queryOptions)}`);
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
- logger13.default(`Update found ${model.name} record to modify`);
1804
- logger13.default(`Update properties configured: ${Object.keys(updateProps).join(", ")}`);
1805
- logger13.trace(`[UPDATE] Executing ${model.name}.update() with properties: ${stringifyJSON(updateProps)}`);
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
- logger13.debug(`[UPDATE] Updated ${model.name} with key: ${returnItem.key ? JSON.stringify(returnItem.key) : `id=${response.id}`}`);
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 logger14 = logger_default.get("sequelize", "ops", "upsert");
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
- logger14.error("Key for Upsert is not a valid ItemKey: %j", key);
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
- logger14.debug(`[UPSERT] Attempting upsert with key: ${stringifyJSON(key)}`, { options });
2311
+ logger15.debug(`[UPSERT] Attempting upsert with key: ${stringifyJSON(key)}`, { options });
1834
2312
  let resultItem = null;
1835
2313
  try {
1836
- logger14.debug(`[UPSERT] Retrieving item by key: ${stringifyJSON(key)}`);
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
- logger14.debug(`[UPSERT] Item not found, creating new item with key: ${stringifyJSON(key)}, errorType: ${error?.name}, errorCode: ${error?.errorInfo?.code}`);
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
- logger14.error(`[UPSERT] Unexpected error during get operation`, { error: error?.message, name: error?.name, code: error?.errorInfo?.code });
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
- logger14.debug(`[UPSERT] Updating item with properties, key: ${stringifyJSON(key)}`, { options });
2330
+ logger15.debug(`[UPSERT] Updating item with properties, key: ${stringifyJSON(key)}`, { options });
1853
2331
  resultItem = await update(resultItem.key, item, options);
1854
- logger14.debug(`[UPSERT] Item upserted successfully: ${stringifyJSON(resultItem)}`);
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 logger15 = logger_default.get("SequelizeLibrary");
2361
+ var logger16 = logger_default.get("SequelizeLibrary");
1884
2362
  var createSequelizeLibrary = (registry, coordinate, models, options) => {
1885
- logger15.debug("createSequelizeLibrary", { coordinate, models, registry, options });
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 logger16 = logger_default.get("InstanceFactory");
2377
+ var logger17 = logger_default.get("InstanceFactory");
1900
2378
  var createSequelizeLibraryFactory = (models, options) => {
1901
2379
  return (coordinate, context) => {
1902
- logger16.debug("Creating Sequelize instance", {
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 logger17 = logger_default.get("lib-sequelize", "primary", "library");
2425
+ var logger18 = logger_default.get("lib-sequelize", "primary", "library");
1948
2426
  function createSequelizeLibrary3(keyType, models, libOptions = {}, scopes = [], registry) {
1949
- logger17.debug("createSequelizeLibrary", { keyType, models, libOptions, scopes });
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);