@fjell/lib-sequelize 4.4.5 → 4.4.10

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.
Files changed (50) hide show
  1. package/dist/cjs/Coordinate.cjs +9 -22
  2. package/dist/cjs/Definition.cjs +5 -26
  3. package/dist/cjs/Instance.cjs +26 -10
  4. package/dist/cjs/InstanceFactory.cjs +25 -0
  5. package/dist/cjs/Operations.cjs +7 -2
  6. package/dist/cjs/Options.cjs +14 -7
  7. package/dist/cjs/QueryBuilder.cjs +31 -25
  8. package/dist/cjs/contained/Instance.cjs +15 -8
  9. package/dist/cjs/index.cjs +7 -4
  10. package/dist/cjs/ops/all.cjs +44 -20
  11. package/dist/cjs/ops/create.cjs +138 -40
  12. package/dist/cjs/ops/find.cjs +9 -7
  13. package/dist/cjs/ops/get.cjs +9 -5
  14. package/dist/cjs/ops/one.cjs +7 -6
  15. package/dist/cjs/ops/remove.cjs +10 -7
  16. package/dist/cjs/ops/update.cjs +10 -7
  17. package/dist/cjs/primary/Instance.cjs +16 -9
  18. package/dist/cjs/util/general.cjs +1 -5
  19. package/dist/es/Coordinate.js +9 -3
  20. package/dist/es/Definition.js +5 -7
  21. package/dist/es/Instance.js +26 -11
  22. package/dist/es/InstanceFactory.js +21 -0
  23. package/dist/es/Operations.js +7 -2
  24. package/dist/es/Options.js +14 -7
  25. package/dist/es/QueryBuilder.js +31 -25
  26. package/dist/es/contained/Instance.js +15 -8
  27. package/dist/es/index.js +4 -3
  28. package/dist/es/ops/all.js +44 -20
  29. package/dist/es/ops/create.js +139 -41
  30. package/dist/es/ops/find.js +9 -7
  31. package/dist/es/ops/get.js +9 -5
  32. package/dist/es/ops/one.js +7 -6
  33. package/dist/es/ops/remove.js +11 -8
  34. package/dist/es/ops/update.js +11 -8
  35. package/dist/es/primary/Instance.js +16 -9
  36. package/dist/es/util/general.js +2 -5
  37. package/dist/index.cjs +412 -216
  38. package/dist/index.cjs.map +1 -1
  39. package/dist/types/AggregationBuilder.d.ts +1 -1
  40. package/dist/types/Coordinate.d.ts +3 -2
  41. package/dist/types/Definition.d.ts +3 -3
  42. package/dist/types/Instance.d.ts +22 -2
  43. package/dist/types/InstanceFactory.d.ts +14 -0
  44. package/dist/types/Operations.d.ts +3 -2
  45. package/dist/types/Options.d.ts +1 -1
  46. package/dist/types/Registry.d.ts +6 -0
  47. package/dist/types/contained/Instance.d.ts +3 -3
  48. package/dist/types/index.d.ts +4 -1
  49. package/dist/types/primary/Instance.d.ts +2 -2
  50. package/package.json +23 -23
@@ -1,49 +1,116 @@
1
- import { isPriKey, isComKey, validateKeys } from '@fjell/core';
1
+ import { isComKey, isPriKey, validateKeys } from '@fjell/core';
2
2
  import LibLogger from '../logger.js';
3
3
  import { processRow } from '../RowProcessor.js';
4
4
  import { extractEvents, removeEvents } from '../EventCoordinator.js';
5
5
  import { buildRelationshipPath, buildRelationshipChain } from '../util/relationshipUtils.js';
6
+ import { stringifyJSON } from '../util/general.js';
6
7
 
7
8
  const logger = LibLogger.get('sequelize', 'ops', 'create');
9
+ // Helper function to translate PostgreSQL errors to meaningful messages
10
+ function translateDatabaseError(error, itemData, modelName) {
11
+ var _error_original, _error_original1, _error_original2;
12
+ const originalMessage = error.message || '';
13
+ const errorCode = (_error_original = error.original) === null || _error_original === void 0 ? void 0 : _error_original.code;
14
+ const constraint = (_error_original1 = error.original) === null || _error_original1 === void 0 ? void 0 : _error_original1.constraint;
15
+ const detail = (_error_original2 = error.original) === null || _error_original2 === void 0 ? void 0 : _error_original2.detail;
16
+ logger.error('Database error during create operation', {
17
+ errorCode,
18
+ constraint,
19
+ detail,
20
+ originalMessage,
21
+ modelName,
22
+ itemData: JSON.stringify(itemData, null, 2)
23
+ });
24
+ // Handle specific PostgreSQL error codes
25
+ switch(errorCode){
26
+ case '23505':
27
+ if (constraint) {
28
+ return new Error(`Duplicate value violates unique constraint '${constraint}'. ${detail || ''}`);
29
+ }
30
+ return new Error(`Duplicate value detected. This record already exists. ${detail || ''}`);
31
+ case '23503':
32
+ if (constraint) {
33
+ return new Error(`Foreign key constraint '${constraint}' violated. Referenced record does not exist. ${detail || ''}`);
34
+ }
35
+ return new Error(`Referenced record does not exist. Check that all related records are valid. ${detail || ''}`);
36
+ case '23502':
37
+ var _error_original3;
38
+ const column = (_error_original3 = error.original) === null || _error_original3 === void 0 ? void 0 : _error_original3.column;
39
+ if (column) {
40
+ return new Error(`Required field '${column}' cannot be null`);
41
+ }
42
+ return new Error(`Required field is missing or null`);
43
+ case '23514':
44
+ if (constraint) {
45
+ return new Error(`Check constraint '${constraint}' violated. ${detail || ''}`);
46
+ }
47
+ return new Error(`Data validation failed. Check constraint violated. ${detail || ''}`);
48
+ case '22001':
49
+ return new Error(`Data too long for field. Check string lengths. ${detail || ''}`);
50
+ case '22003':
51
+ return new Error(`Numeric value out of range. Check number values. ${detail || ''}`);
52
+ case '42703':
53
+ var _error_original4;
54
+ const undefinedColumn = (_error_original4 = error.original) === null || _error_original4 === void 0 ? void 0 : _error_original4.column;
55
+ if (undefinedColumn) {
56
+ return new Error(`Column '${undefinedColumn}' does not exist in table '${modelName}'`);
57
+ }
58
+ return new Error(`Referenced column does not exist`);
59
+ case '42P01':
60
+ return new Error(`Table '${modelName}' does not exist`);
61
+ default:
62
+ // For unknown errors, provide the original message with context
63
+ return new Error(`Database error in ${modelName}.create(): ${originalMessage}. Item data: ${JSON.stringify(itemData, null, 2)}`);
64
+ }
65
+ }
8
66
  // Helper function to validate hierarchical chain exists
9
67
  async function validateHierarchicalChain(models, locKey, kta) {
10
- // Find the direct parent model that contains this locator
11
- const locatorIndex = kta.indexOf(locKey.kt);
12
- if (locatorIndex === -1) {
13
- throw new Error(`Locator type '${locKey.kt}' not found in kta array`);
14
- }
15
- // Get the model for this locator
16
- const locatorModel = models[locatorIndex] || models[0]; // Fallback to primary model
17
- // Build a query to validate the chain exists
18
- const chainResult = buildRelationshipChain(locatorModel, kta, locatorIndex, kta.length - 1);
19
- if (!chainResult.success) {
20
- // If we can't build a chain, just validate the record exists
21
- const record = await locatorModel.findByPk(locKey.lk);
68
+ try {
69
+ // Find the direct parent model that contains this locator
70
+ const locatorIndex = kta.indexOf(locKey.kt);
71
+ if (locatorIndex === -1) {
72
+ throw new Error(`Locator type '${locKey.kt}' not found in kta array`);
73
+ }
74
+ // Get the model for this locator
75
+ const locatorModel = models[locatorIndex] || models[0]; // Fallback to primary model
76
+ // Build a query to validate the chain exists
77
+ const chainResult = buildRelationshipChain(locatorModel, kta, locatorIndex, kta.length - 1);
78
+ if (!chainResult.success) {
79
+ // If we can't build a chain, just validate the record exists
80
+ const record = await locatorModel.findByPk(locKey.lk);
81
+ if (!record) {
82
+ throw new Error(`Referenced ${locKey.kt} with id ${locKey.lk} does not exist`);
83
+ }
84
+ return;
85
+ }
86
+ // Validate that the chain exists
87
+ const queryOptions = {
88
+ where: {
89
+ id: locKey.lk
90
+ }
91
+ };
92
+ if (chainResult.includes && chainResult.includes.length > 0) {
93
+ queryOptions.include = chainResult.includes;
94
+ }
95
+ const record = await locatorModel.findOne(queryOptions);
22
96
  if (!record) {
23
- throw new Error(`Referenced ${locKey.kt} with id ${locKey.lk} does not exist`);
97
+ throw new Error(`Referenced ${locKey.kt} with id ${locKey.lk} does not exist or chain is invalid`);
24
98
  }
25
- return;
26
- }
27
- // Validate that the chain exists
28
- const queryOptions = {
29
- where: {
30
- id: locKey.lk
99
+ } catch (error) {
100
+ // Add context to validation errors
101
+ if (error.original) {
102
+ throw translateDatabaseError(error, {
103
+ locKey,
104
+ kta
105
+ }, locKey.kt);
31
106
  }
32
- };
33
- if (chainResult.includes && chainResult.includes.length > 0) {
34
- queryOptions.include = chainResult.includes;
35
- }
36
- const record = await locatorModel.findOne(queryOptions);
37
- if (!record) {
38
- throw new Error(`Referenced ${locKey.kt} with id ${locKey.lk} does not exist or chain is invalid`);
107
+ throw error;
39
108
  }
40
109
  }
41
110
  const getCreateOperation = (models, definition, registry)=>{
42
111
  const create = async (item, options)=>{
43
- logger.default('Create', {
44
- item,
45
- options
46
- });
112
+ logger.debug(`CREATE operation called on ${models[0].name} with ${(options === null || options === void 0 ? void 0 : options.key) ? `key: pk=${options.key.pk}, loc=[${isComKey(options.key) ? options.key.loc.map((l)=>`${l.kt}=${l.lk}`).join(', ') : ''}]` : (options === null || options === void 0 ? void 0 : options.locations) ? `locations: ${options.locations.map((loc)=>`${loc.kt}=${loc.lk}`).join(', ')}` : 'no constraints'}`);
113
+ logger.default(`Create configured for ${models[0].name} with ${Object.keys(item).length} item fields`);
47
114
  const { coordinate, options: { references, aggregations } } = definition;
48
115
  const { kta } = coordinate;
49
116
  // Get the primary model (first model in array)
@@ -56,11 +123,17 @@ const getCreateOperation = (models, definition, registry)=>{
56
123
  // TODO: We need the opposite of processRow, something to step down from fjell to database.
57
124
  itemData = extractEvents(itemData);
58
125
  itemData = removeEvents(itemData);
126
+ // Validate that all item attributes exist on the model
127
+ const invalidAttributes = [];
59
128
  for (const key of Object.keys(itemData)){
60
129
  if (!modelAttributes[key]) {
61
- throw new Error(`Attribute '${key}' does not exist on model ${model.name}`);
130
+ invalidAttributes.push(key);
62
131
  }
63
132
  }
133
+ if (invalidAttributes.length > 0) {
134
+ const availableAttributes = Object.keys(modelAttributes).join(', ');
135
+ throw new Error(`Invalid attributes for model '${model.name}': [${invalidAttributes.join(', ')}]. ` + `Available attributes: [${availableAttributes}]. ` + `Item data: ${JSON.stringify(itemData, null, 2)}`);
136
+ }
64
137
  // Handle key options
65
138
  // If a key is supplied, assume its contents are to be assigned to the appropriate ids.
66
139
  // For most cases this will be null as key generation is often through autoIncrement.
@@ -81,10 +154,12 @@ const getCreateOperation = (models, definition, registry)=>{
81
154
  for (const locKey of comKey.loc){
82
155
  const relationshipInfo = buildRelationshipPath(model, locKey.kt, kta, true);
83
156
  if (!relationshipInfo.found) {
84
- const errorMessage = `Composite key locator '${locKey.kt}' cannot be resolved on model '${model.name}' or through its relationships.`;
157
+ const associations = model.associations ? Object.keys(model.associations) : [];
158
+ 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)}`;
85
159
  logger.error(errorMessage, {
86
160
  key: comKey,
87
- kta
161
+ kta,
162
+ associations
88
163
  });
89
164
  throw new Error(errorMessage);
90
165
  }
@@ -96,6 +171,13 @@ const getCreateOperation = (models, definition, registry)=>{
96
171
  }
97
172
  // Set direct foreign keys
98
173
  for (const locKey of directLocations){
174
+ if (locKey.lk == null || locKey.lk === '') {
175
+ logger.error(`Composite key location '${locKey.kt}' has undefined/null lk value`, {
176
+ locKey,
177
+ key: comKey
178
+ });
179
+ throw new Error(`Composite key location '${locKey.kt}' has undefined/null lk value`);
180
+ }
99
181
  const foreignKeyField = locKey.kt + 'Id';
100
182
  itemData[foreignKeyField] = locKey.lk;
101
183
  }
@@ -114,10 +196,12 @@ const getCreateOperation = (models, definition, registry)=>{
114
196
  for (const locKey of options.locations){
115
197
  const relationshipInfo = buildRelationshipPath(model, locKey.kt, kta, true);
116
198
  if (!relationshipInfo.found) {
117
- const errorMessage = `Location key '${locKey.kt}' cannot be resolved on model '${model.name}' or through its relationships.`;
199
+ const associations = model.associations ? Object.keys(model.associations) : [];
200
+ 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)}`;
118
201
  logger.error(errorMessage, {
119
202
  locations: options.locations,
120
- kta
203
+ kta,
204
+ associations
121
205
  });
122
206
  throw new Error(errorMessage);
123
207
  }
@@ -129,6 +213,13 @@ const getCreateOperation = (models, definition, registry)=>{
129
213
  }
130
214
  // Set direct foreign keys
131
215
  for (const locKey of directLocations){
216
+ if (locKey.lk == null || locKey.lk === '') {
217
+ logger.error(`Location option '${locKey.kt}' has undefined/null lk value`, {
218
+ locKey,
219
+ locations: options.locations
220
+ });
221
+ throw new Error(`Location option '${locKey.kt}' has undefined/null lk value`);
222
+ }
132
223
  const foreignKeyField = locKey.kt + 'Id';
133
224
  itemData[foreignKeyField] = locKey.lk;
134
225
  }
@@ -138,13 +229,20 @@ const getCreateOperation = (models, definition, registry)=>{
138
229
  }
139
230
  }
140
231
  // Create the record
141
- const createdRecord = await model.create(itemData);
142
- // Add key and events
143
- const processedRecord = await processRow(createdRecord, kta, references, aggregations, registry);
144
- return validateKeys(processedRecord, kta);
232
+ try {
233
+ logger.trace(`[CREATE] Executing ${model.name}.create() with data: ${stringifyJSON(itemData)}`);
234
+ const createdRecord = await model.create(itemData);
235
+ // Add key and events
236
+ const processedRecord = await processRow(createdRecord, kta, references, aggregations, registry);
237
+ const result = validateKeys(processedRecord, kta);
238
+ logger.debug(`[CREATE] Created ${model.name} with key: ${result.key ? JSON.stringify(result.key) : `id=${createdRecord.id}`}`);
239
+ return result;
240
+ } catch (error) {
241
+ throw translateDatabaseError(error, itemData, model.name);
242
+ }
145
243
  };
146
244
  return create;
147
245
  };
148
246
 
149
247
  export { getCreateOperation };
150
- //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY3JlYXRlLmpzIiwic291cmNlcyI6W10sInNvdXJjZXNDb250ZW50IjpbXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OyJ9
248
+ //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY3JlYXRlLmpzIiwic291cmNlcyI6W10sInNvdXJjZXNDb250ZW50IjpbXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7In0=
@@ -1,28 +1,30 @@
1
1
  import { validateKeys } from '@fjell/core';
2
2
  import LibLogger from '../logger.js';
3
3
  import { processRow } from '../RowProcessor.js';
4
+ import { stringifyJSON } from '../util/general.js';
4
5
 
5
6
  const logger = LibLogger.get('sequelize', 'ops', 'find');
6
7
  const getFindOperation = (models, definition, registry)=>{
7
8
  const { options: { finders, references, aggregations } } = definition;
8
9
  const find = async (finder, finderParams, locations)=>{
9
- logger.default('Find', {
10
- finder,
11
- finderParams,
12
- locations
13
- });
10
+ logger.debug(`FIND operation called on ${models[0].name} with finder '${finder}' and ${(locations === null || locations === void 0 ? void 0 : locations.length) || 0} location filters: ${(locations === null || locations === void 0 ? void 0 : locations.map((loc)=>`${loc.kt}=${loc.lk}`).join(', ')) || 'none'}`);
11
+ logger.default(`Find configured for ${models[0].name} using finder '${finder}' with ${Object.keys(finderParams).length} params`);
14
12
  // Note that we execute the createFinders function here because we want to make sure we're always getting the
15
13
  // most up to date methods.
16
14
  if (finders && finders[finder]) {
17
15
  const finderMethod = finders[finder];
18
16
  if (finderMethod) {
17
+ logger.trace(`[FIND] Executing finder '${finder}' on ${models[0].name} with params: ${stringifyJSON(finderParams)}, locations: ${stringifyJSON(locations)}`);
19
18
  const results = await finderMethod(finderParams, locations);
20
19
  if (results && results.length > 0) {
21
- return await Promise.all(results.map(async (row)=>{
20
+ const processedResults = await Promise.all(results.map(async (row)=>{
22
21
  const processedRow = await processRow(row, definition.coordinate.kta, references, aggregations, registry);
23
22
  return validateKeys(processedRow, definition.coordinate.kta);
24
23
  }));
24
+ logger.debug(`[FIND] Found ${processedResults.length} ${models[0].name} records using finder '${finder}'`);
25
+ return processedResults;
25
26
  } else {
27
+ logger.debug(`[FIND] Found 0 ${models[0].name} records using finder '${finder}'`);
26
28
  return [];
27
29
  }
28
30
  } else {
@@ -38,4 +40,4 @@ const getFindOperation = (models, definition, registry)=>{
38
40
  };
39
41
 
40
42
  export { getFindOperation };
41
- //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZmluZC5qcyIsInNvdXJjZXMiOltdLCJzb3VyY2VzQ29udGVudCI6W10sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OyJ9
43
+ //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZmluZC5qcyIsInNvdXJjZXMiOltdLCJzb3VyY2VzQ29udGVudCI6W10sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7In0=
@@ -4,6 +4,7 @@ import { processRow } from '../RowProcessor.js';
4
4
  import { NotFoundError } from '@fjell/lib';
5
5
  import { buildRelationshipPath } from '../util/relationshipUtils.js';
6
6
  import { contextManager } from '../OperationContext.js';
7
+ import { stringifyJSON } from '../util/general.js';
7
8
 
8
9
  const logger = LibLogger.get('sequelize', 'ops', 'get');
9
10
  // Helper function to process composite key and build query options
@@ -46,19 +47,19 @@ const getGetOperation = (models, definition, registry)=>{
46
47
  const { coordinate, options: { references, aggregations } } = definition;
47
48
  const { kta } = coordinate;
48
49
  const get = async (key)=>{
49
- logger.default('Get', {
50
- key
51
- });
52
50
  if (!isValidItemKey(key)) {
53
51
  logger.error('Key for Get is not a valid ItemKey: %j', key);
54
52
  throw new Error('Key for Get is not a valid ItemKey');
55
53
  }
54
+ logger.debug(`GET operation called on ${models[0].name} with ${isPriKey(key) ? `primary key: pk=${key.pk}` : `composite key: pk=${key.pk}, loc=[${key.loc.map((l)=>`${l.kt}=${l.lk}`).join(', ')}]`}`);
55
+ logger.default(`Get configured for ${models[0].name} with ${isPriKey(key) ? 'primary' : 'composite'} key`);
56
56
  const itemKey = key;
57
57
  // @ts-ignore
58
58
  const model = models[0];
59
59
  let item;
60
60
  if (isPriKey(itemKey)) {
61
61
  // This is the easy case because we can just find the item by its primary key
62
+ logger.trace(`[GET] Executing ${model.name}.findByPk() with pk: ${itemKey.pk}`);
62
63
  item = await model.findByPk(itemKey.pk);
63
64
  } else if (isComKey(itemKey)) {
64
65
  // This is a composite key, so we need to build a where clause based on the composite key's locators
@@ -67,6 +68,7 @@ const getGetOperation = (models, definition, registry)=>{
67
68
  logger.default('Composite key query', {
68
69
  queryOptions
69
70
  });
71
+ logger.trace(`[GET] Executing ${model.name}.findOne() with options: ${stringifyJSON(queryOptions)}`);
70
72
  item = await model.findOne(queryOptions);
71
73
  }
72
74
  if (!item) {
@@ -74,11 +76,13 @@ const getGetOperation = (models, definition, registry)=>{
74
76
  } else {
75
77
  // Get the current context from context manager
76
78
  const context = contextManager.getCurrentContext();
77
- return validateKeys(await processRow(item, kta, references, aggregations, registry, context), kta);
79
+ const result = validateKeys(await processRow(item, kta, references, aggregations, registry, context), kta);
80
+ logger.debug(`[GET] Retrieved ${model.name} with key: ${result.key ? JSON.stringify(result.key) : `id=${item.id}`}`);
81
+ return result;
78
82
  }
79
83
  };
80
84
  return get;
81
85
  };
82
86
 
83
87
  export { getGetOperation };
84
- //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZ2V0LmpzIiwic291cmNlcyI6W10sInNvdXJjZXNDb250ZW50IjpbXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OyJ9
88
+ //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZ2V0LmpzIiwic291cmNlcyI6W10sInNvdXJjZXNDb250ZW50IjpbXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OzsifQ==
@@ -4,14 +4,15 @@ import { getAllOperation } from './all.js';
4
4
  const logger = LibLogger.get('sequelize', 'ops', 'one');
5
5
  const getOneOperation = (models, definition, registry)=>{
6
6
  const one = async (itemQuery, locations = [])=>{
7
- logger.default('One', {
8
- itemQuery,
9
- locations
10
- });
7
+ logger.debug(`ONE operation called on ${models[0].name} with ${locations.length} location filters: ${locations.map((loc)=>`${loc.kt}=${loc.lk}`).join(', ') || 'none'}`);
8
+ logger.default(`One configured for ${models[0].name} delegating to all operation`);
11
9
  const items = await getAllOperation(models, definition, registry)(itemQuery, locations);
12
10
  if (items.length > 0) {
13
- return items[0];
11
+ const result = items[0];
12
+ logger.debug(`[ONE] Found ${models[0].name} record with key: ${result.key ? JSON.stringify(result.key) : 'unknown'}`);
13
+ return result;
14
14
  } else {
15
+ logger.debug(`[ONE] No ${models[0].name} record found`);
15
16
  return null;
16
17
  }
17
18
  };
@@ -19,4 +20,4 @@ const getOneOperation = (models, definition, registry)=>{
19
20
  };
20
21
 
21
22
  export { getOneOperation };
22
- //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoib25lLmpzIiwic291cmNlcyI6W10sInNvdXJjZXNDb250ZW50IjpbXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OzsifQ==
23
+ //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoib25lLmpzIiwic291cmNlcyI6W10sInNvdXJjZXNDb250ZW50IjpbXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7In0=
@@ -1,8 +1,9 @@
1
- import { isValidItemKey, abbrevIK, isPriKey, isComKey } from '@fjell/core';
1
+ import { isValidItemKey, isPriKey, abbrevIK, isComKey } from '@fjell/core';
2
2
  import { populateEvents } from '../EventCoordinator.js';
3
3
  import { addKey } from '../KeyMaster.js';
4
4
  import LibLogger from '../logger.js';
5
5
  import { buildRelationshipPath } from '../util/relationshipUtils.js';
6
+ import { stringifyJSON } from '../util/general.js';
6
7
 
7
8
  const logger = LibLogger.get('sequelize', 'ops', 'remove');
8
9
  // Helper function to process composite key and build query options
@@ -46,27 +47,26 @@ registry)=>{
46
47
  const { coordinate, options } = definition;
47
48
  const { kta } = coordinate;
48
49
  const remove = async (key)=>{
49
- logger.default('Remove', {
50
- key
51
- });
52
50
  if (!isValidItemKey(key)) {
53
51
  logger.error('Key for Remove is not a valid ItemKey: %j', key);
54
52
  throw new Error('Key for Remove is not a valid ItemKey');
55
53
  }
54
+ logger.debug(`REMOVE operation called on ${models[0].name} with ${isPriKey(key) ? `primary key: pk=${key.pk}` : `composite key: pk=${key.pk}, loc=[${key.loc.map((l)=>`${l.kt}=${l.lk}`).join(', ')}]`}`);
55
+ logger.default(`Remove configured for ${models[0].name} with ${isPriKey(key) ? 'primary' : 'composite'} key`);
56
56
  // @ts-ignore
57
57
  const model = models[0];
58
58
  let item;
59
59
  let returnItem;
60
60
  logger.debug('remove: %s', abbrevIK(key));
61
61
  if (isPriKey(key)) {
62
+ logger.debug(`[REMOVE] Executing ${model.name}.findByPk() with pk: ${key.pk}`);
62
63
  item = await model.findByPk(key.pk);
63
64
  } else if (isComKey(key)) {
64
65
  // This is a composite key, so we need to build a where clause based on the composite key's locators
65
66
  const comKey = key;
66
67
  const queryOptions = processCompositeKey(comKey, model, kta);
67
- logger.default('Composite key query', {
68
- queryOptions
69
- });
68
+ logger.default(`Remove composite key query for ${model.name} with where fields: ${queryOptions.where ? Object.keys(queryOptions.where).join(', ') : 'none'}`);
69
+ logger.debug(`[REMOVE] Executing ${model.name}.findOne() with options: ${stringifyJSON(queryOptions)}`);
70
70
  item = await model.findOne(queryOptions);
71
71
  }
72
72
  if (!item) {
@@ -82,6 +82,7 @@ registry)=>{
82
82
  item.deletedAt = new Date();
83
83
  }
84
84
  // Save the object
85
+ logger.debug(`[REMOVE] Executing ${model.name}.save() for soft delete`);
85
86
  await (item === null || item === void 0 ? void 0 : item.save());
86
87
  returnItem = item === null || item === void 0 ? void 0 : item.get({
87
88
  plain: true
@@ -89,6 +90,7 @@ registry)=>{
89
90
  returnItem = addKey(item, returnItem, kta);
90
91
  returnItem = populateEvents(returnItem);
91
92
  } else if (options.deleteOnRemove) {
93
+ logger.debug(`[REMOVE] Executing ${model.name}.destroy() for hard delete`);
92
94
  await (item === null || item === void 0 ? void 0 : item.destroy());
93
95
  returnItem = item === null || item === void 0 ? void 0 : item.get({
94
96
  plain: true
@@ -98,10 +100,11 @@ registry)=>{
98
100
  } else {
99
101
  throw new Error('No deletedAt or isDeleted attribute found in model, and deleteOnRemove is not set');
100
102
  }
103
+ logger.debug(`[REMOVE] Removed ${model.name} with key: ${returnItem.key ? JSON.stringify(returnItem.key) : `id=${item.id}`}`);
101
104
  return returnItem;
102
105
  };
103
106
  return remove;
104
107
  };
105
108
 
106
109
  export { getRemoveOperation };
107
- //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVtb3ZlLmpzIiwic291cmNlcyI6W10sInNvdXJjZXNDb250ZW50IjpbXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7In0=
110
+ //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVtb3ZlLmpzIiwic291cmNlcyI6W10sInNvdXJjZXNDb250ZW50IjpbXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7In0=
@@ -1,12 +1,12 @@
1
- import { abbrevIK, isPriKey, isComKey, validateKeys } from '@fjell/core';
1
+ import { isPriKey, abbrevIK, isComKey, validateKeys } from '@fjell/core';
2
2
  import { extractEvents, removeEvents } from '../EventCoordinator.js';
3
3
  import { removeKey } from '../KeyMaster.js';
4
4
  import LibLogger from '../logger.js';
5
5
  import { processRow } from '../RowProcessor.js';
6
- import { stringifyJSON } from '../util/general.js';
7
6
  import { NotFoundError } from '@fjell/lib';
8
7
  import { Op } from 'sequelize';
9
8
  import { buildRelationshipPath } from '../util/relationshipUtils.js';
9
+ import { stringifyJSON } from '../util/general.js';
10
10
 
11
11
  const logger = LibLogger.get('sequelize', 'ops', 'update');
12
12
  // Helper function to merge includes avoiding duplicates
@@ -32,6 +32,7 @@ const mergeIncludes = (existingIncludes, newIncludes)=>{
32
32
  const getUpdateOperation = (models, definition, registry)=>{
33
33
  const { options: { references, aggregations } } = definition;
34
34
  const update = async (key, item)=>{
35
+ logger.debug(`UPDATE operation called on ${models[0].name} with ${isPriKey(key) ? `primary key: pk=${key.pk}` : `composite key: pk=${key.pk}, loc=[${key.loc.map((l)=>`${l.kt}=${l.lk}`).join(', ')}]`}`);
35
36
  const { coordinate } = definition;
36
37
  const { kta } = coordinate;
37
38
  logger.debug('update: %s, %j', abbrevIK(key), item);
@@ -42,6 +43,7 @@ const getUpdateOperation = (models, definition, registry)=>{
42
43
  if (isPriKey(key)) {
43
44
  // Find the model by using the PK
44
45
  const priKey = key;
46
+ logger.trace(`[UPDATE] Executing ${model.name}.findByPk() with pk: ${priKey.pk}`);
45
47
  response = await model.findByPk(priKey.pk);
46
48
  } else if (isComKey(key)) {
47
49
  const comKey = key;
@@ -83,9 +85,8 @@ const getUpdateOperation = (models, definition, registry)=>{
83
85
  if (additionalIncludes.length > 0) {
84
86
  queryOptions.include = mergeIncludes([], additionalIncludes);
85
87
  }
86
- logger.default('Composite key query for update', {
87
- queryOptions
88
- });
88
+ logger.default(`Update composite key query for ${model.name} with where fields: ${queryOptions.where ? Object.keys(queryOptions.where).join(', ') : 'none'}`);
89
+ logger.trace(`[UPDATE] Executing ${model.name}.findOne() with options: ${stringifyJSON(queryOptions)}`);
89
90
  response = await model.findOne(queryOptions);
90
91
  }
91
92
  if (response) {
@@ -94,13 +95,15 @@ const getUpdateOperation = (models, definition, registry)=>{
94
95
  // TODO: We need the opposite of processRow, something to step down from fjell to database.
95
96
  updateProps = extractEvents(updateProps);
96
97
  updateProps = removeEvents(updateProps);
97
- logger.default('Response: %s', stringifyJSON(response));
98
- logger.default('Update Properties: %s', stringifyJSON(updateProps));
98
+ logger.default(`Update found ${model.name} record to modify`);
99
+ logger.default(`Update properties configured: ${Object.keys(updateProps).join(', ')}`);
99
100
  // Update the object
101
+ logger.trace(`[UPDATE] Executing ${model.name}.update() with properties: ${stringifyJSON(updateProps)}`);
100
102
  response = await response.update(updateProps);
101
103
  // Populate the key and events
102
104
  const processedItem = await processRow(response, kta, references, aggregations, registry);
103
105
  const returnItem = validateKeys(processedItem, kta);
106
+ logger.debug(`[UPDATE] Updated ${model.name} with key: ${returnItem.key ? JSON.stringify(returnItem.key) : `id=${response.id}`}`);
104
107
  return returnItem;
105
108
  } else {
106
109
  throw new NotFoundError('update', coordinate, key);
@@ -110,4 +113,4 @@ const getUpdateOperation = (models, definition, registry)=>{
110
113
  };
111
114
 
112
115
  export { getUpdateOperation };
113
- //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXBkYXRlLmpzIiwic291cmNlcyI6W10sInNvdXJjZXNDb250ZW50IjpbXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7In0=
116
+ //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXBkYXRlLmpzIiwic291cmNlcyI6W10sInNvdXJjZXNDb250ZW50IjpbXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7In0=
@@ -1,6 +1,7 @@
1
1
  import { Primary } from '@fjell/lib';
2
- import { createDefinition } from '../Definition.js';
3
2
  import { createOperations } from '../Operations.js';
3
+ import { createOptions } from '../Options.js';
4
+ import { createCoordinate } from '../Coordinate.js';
4
5
  import LibLogger from '../logger.js';
5
6
 
6
7
  const logger = LibLogger.get('lib-sequelize', 'primary', 'instance');
@@ -11,17 +12,23 @@ function createInstance(keyType, models, libOptions = {}, scopes = [], registry)
11
12
  libOptions,
12
13
  scopes
13
14
  });
14
- const definition = createDefinition([
15
+ // Create coordinate and options separately following new pattern
16
+ const coordinate = createCoordinate([
15
17
  keyType
16
- ], scopes, libOptions);
17
- const operations = createOperations(models, definition, registry);
18
+ ], scopes);
19
+ const options = createOptions(libOptions);
20
+ // Create operations with the new signature
21
+ const operations = createOperations(models, coordinate, registry, options);
22
+ // Wrap operations for primary pattern
23
+ const wrappedOperations = Primary.wrapOperations(operations, options, coordinate, registry);
18
24
  return {
19
- definition,
20
- operations: Primary.wrapOperations(operations, definition, registry),
21
- models,
22
- registry
25
+ coordinate,
26
+ registry,
27
+ operations: wrappedOperations,
28
+ options,
29
+ models
23
30
  };
24
31
  }
25
32
 
26
33
  export { createInstance };
27
- //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiSW5zdGFuY2UuanMiLCJzb3VyY2VzIjpbXSwic291cmNlc0NvbnRlbnQiOltdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7In0=
34
+ //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiSW5zdGFuY2UuanMiLCJzb3VyY2VzIjpbXSwic291cmNlc0NvbnRlbnQiOltdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OyJ9
@@ -1,6 +1,3 @@
1
- /* eslint-disable @typescript-eslint/no-unused-vars */ /* eslint-disable no-undefined */ const clean = (obj)=>{
2
- return Object.fromEntries(Object.entries(obj).filter(([_, v])=>v !== undefined));
3
- };
4
1
  //Recursive implementation of jSON.stringify;
5
2
  const stringifyJSON = function(obj, visited = new Set()) {
6
3
  const arrOfKeyVals = [];
@@ -43,5 +40,5 @@ const stringifyJSON = function(obj, visited = new Set()) {
43
40
  return '';
44
41
  };
45
42
 
46
- export { clean, stringifyJSON };
47
- //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZ2VuZXJhbC5qcyIsInNvdXJjZXMiOltdLCJzb3VyY2VzQ29udGVudCI6W10sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OyJ9
43
+ export { stringifyJSON };
44
+ //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZ2VuZXJhbC5qcyIsInNvdXJjZXMiOltdLCJzb3VyY2VzQ29udGVudCI6W10sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OyJ9