@fjell/core 4.4.50 → 4.4.51

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 (56) hide show
  1. package/package.json +3 -3
  2. package/src/AItemService.ts +0 -38
  3. package/src/Coordinate.ts +0 -35
  4. package/src/dictionary.ts +0 -84
  5. package/src/errors/ActionError.ts +0 -69
  6. package/src/errors/BusinessLogicError.ts +0 -24
  7. package/src/errors/DuplicateError.ts +0 -57
  8. package/src/errors/NotFoundError.ts +0 -24
  9. package/src/errors/PermissionError.ts +0 -31
  10. package/src/errors/ValidationError.ts +0 -27
  11. package/src/errors/index.ts +0 -7
  12. package/src/event/emitter.ts +0 -247
  13. package/src/event/events.ts +0 -178
  14. package/src/event/index.ts +0 -130
  15. package/src/event/matching.ts +0 -264
  16. package/src/event/subscription.ts +0 -181
  17. package/src/event/types.ts +0 -282
  18. package/src/index.ts +0 -70
  19. package/src/item/IFactory.ts +0 -122
  20. package/src/item/IQFactory.ts +0 -163
  21. package/src/item/IQUtils.ts +0 -392
  22. package/src/item/IUtils.ts +0 -40
  23. package/src/item/ItemQuery.ts +0 -88
  24. package/src/items.ts +0 -120
  25. package/src/key/KUtils.ts +0 -484
  26. package/src/keys.ts +0 -95
  27. package/src/logger.ts +0 -5
  28. package/src/operations/OperationContext.ts +0 -12
  29. package/src/operations/Operations.ts +0 -357
  30. package/src/operations/contained.ts +0 -134
  31. package/src/operations/errorEnhancer.ts +0 -204
  32. package/src/operations/index.ts +0 -2
  33. package/src/operations/methods.ts +0 -363
  34. package/src/operations/primary.ts +0 -101
  35. package/src/operations/specialized.ts +0 -71
  36. package/src/operations/wrappers/createActionWrapper.ts +0 -108
  37. package/src/operations/wrappers/createAllActionWrapper.ts +0 -109
  38. package/src/operations/wrappers/createAllFacetWrapper.ts +0 -98
  39. package/src/operations/wrappers/createAllWrapper.ts +0 -103
  40. package/src/operations/wrappers/createCreateWrapper.ts +0 -117
  41. package/src/operations/wrappers/createFacetWrapper.ts +0 -97
  42. package/src/operations/wrappers/createFindOneWrapper.ts +0 -105
  43. package/src/operations/wrappers/createFindWrapper.ts +0 -105
  44. package/src/operations/wrappers/createGetWrapper.ts +0 -96
  45. package/src/operations/wrappers/createOneWrapper.ts +0 -128
  46. package/src/operations/wrappers/createRemoveWrapper.ts +0 -91
  47. package/src/operations/wrappers/createUpdateWrapper.ts +0 -106
  48. package/src/operations/wrappers/createUpsertWrapper.ts +0 -108
  49. package/src/operations/wrappers/index.ts +0 -39
  50. package/src/operations/wrappers/types.ts +0 -63
  51. package/src/validation/ItemValidator.ts +0 -131
  52. package/src/validation/KeyValidator.ts +0 -365
  53. package/src/validation/LocationValidator.ts +0 -136
  54. package/src/validation/QueryValidator.ts +0 -250
  55. package/src/validation/index.ts +0 -32
  56. package/src/validation/types.ts +0 -45
@@ -1,63 +0,0 @@
1
- /**
2
- * Types for operation wrappers
3
- *
4
- * These wrappers provide automatic parameter validation for all Operations methods.
5
- */
6
-
7
- import type { Coordinate } from "../../Coordinate";
8
-
9
- /**
10
- * Options for configuring wrapper behavior
11
- */
12
- export interface WrapperOptions {
13
- /**
14
- * Skip automatic parameter validation.
15
- * Use this if you're handling validation elsewhere.
16
- * @default false
17
- */
18
- skipValidation?: boolean;
19
-
20
- /**
21
- * Custom operation name for error messages.
22
- * If not provided, uses the wrapper's default name.
23
- */
24
- operationName?: string;
25
-
26
- /**
27
- * Enable debug logging for wrapper calls.
28
- * @default false
29
- */
30
- debug?: boolean;
31
-
32
- /**
33
- * Custom error handler.
34
- * If provided, catches and transforms errors from the implementation.
35
- */
36
- onError?: (error: Error, context: ErrorContext) => Error | never;
37
- }
38
-
39
- /**
40
- * Context provided to error handlers
41
- */
42
- export interface ErrorContext {
43
- operationName: string;
44
- params: any[];
45
- coordinate: Coordinate<any, any, any, any, any, any>;
46
- }
47
-
48
- /**
49
- * Internal context passed through wrapper execution
50
- */
51
- export interface WrapperContext<
52
- S extends string,
53
- L1 extends string = never,
54
- L2 extends string = never,
55
- L3 extends string = never,
56
- L4 extends string = never,
57
- L5 extends string = never
58
- > {
59
- coordinate: Coordinate<S, L1, L2, L3, L4, L5>;
60
- operationName: string;
61
- options: WrapperOptions;
62
- }
63
-
@@ -1,131 +0,0 @@
1
- /**
2
- * Item validation
3
- *
4
- * Validates that Item objects have correct key types and structures.
5
- */
6
-
7
- import type { Item } from "../items";
8
- import { toKeyTypeArray } from "../key/KUtils";
9
- import type { AllItemTypeArrays, ComKey, PriKey } from "../keys";
10
- import LibLogger from '../logger';
11
-
12
- const logger = LibLogger.get('validation', 'ItemValidator');
13
-
14
- /**
15
- * Validates that a single item has the correct primary key type
16
- *
17
- * @param item - The item to validate
18
- * @param pkType - The expected primary key type
19
- * @returns The validated item
20
- * @throws Error if item is invalid or has wrong key type
21
- */
22
- const validatePKForItem = <
23
- S extends string,
24
- L1 extends string = never,
25
- L2 extends string = never,
26
- L3 extends string = never,
27
- L4 extends string = never,
28
- L5 extends string = never,
29
- >(item: Item<S, L1, L2, L3, L4, L5>, pkType: S): Item<S, L1, L2, L3, L4, L5> => {
30
- if (!item) {
31
- logger.error('Validating PK, Item is undefined', { item });
32
- throw new Error('Validating PK, Item is undefined');
33
- }
34
- if (!item.key) {
35
- logger.error('Validating PK, Item does not have a key', { item });
36
- throw new Error('Validating PK, Item does not have a key');
37
- }
38
-
39
- const keyTypeArray = toKeyTypeArray(item.key as ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>);
40
- if (keyTypeArray[0] !== pkType) {
41
- logger.error('Key Type Array Mismatch', { keyTypeArray, pkType });
42
- throw new Error(`Item does not have the correct primary key type. Expected ${pkType}, got ${keyTypeArray[0]}`);
43
- }
44
- return item;
45
- };
46
-
47
- /**
48
- * Validates that an item or array of items have the correct primary key type
49
- *
50
- * @param input - The item or array of items to validate
51
- * @param pkType - The expected primary key type
52
- * @returns The validated item(s)
53
- * @throws Error if any item is invalid or has wrong key type
54
- *
55
- * @example
56
- * ```typescript
57
- * // Validate single item
58
- * const item = validatePK(fetchedItem, 'product');
59
- *
60
- * // Validate array of items
61
- * const items = validatePK(fetchedItems, 'product');
62
- * ```
63
- */
64
- export const validatePK = <
65
- S extends string,
66
- L1 extends string = never,
67
- L2 extends string = never,
68
- L3 extends string = never,
69
- L4 extends string = never,
70
- L5 extends string = never,
71
- >(
72
- input: Item<S, L1, L2, L3, L4, L5> | Item<S, L1, L2, L3, L4, L5>[],
73
- pkType: S,
74
- ): Item<S, L1, L2, L3, L4, L5> | Item<S, L1, L2, L3, L4, L5>[] => {
75
- logger.trace('Checking Return Type', { input });
76
-
77
- if (Array.isArray(input)) {
78
- return input.map((item) => validatePKForItem(item, pkType));
79
- }
80
- return validatePKForItem(input, pkType);
81
- };
82
-
83
- /**
84
- * Validates that an item's key matches the expected key type array
85
- *
86
- * This is used to validate composite items where the key structure must match
87
- * the complete hierarchy (e.g., [product, store, region])
88
- *
89
- * @param item - The item to validate
90
- * @param keyTypes - The expected key type array
91
- * @returns The validated item
92
- * @throws Error if item is invalid or key types don't match
93
- *
94
- * @example
95
- * ```typescript
96
- * // Validate item has correct key structure
97
- * const item = validateKeys(fetchedItem, ['product', 'store']);
98
- * ```
99
- */
100
- export const validateKeys = <
101
- S extends string,
102
- L1 extends string = never,
103
- L2 extends string = never,
104
- L3 extends string = never,
105
- L4 extends string = never,
106
- L5 extends string = never,
107
- >(
108
- item: Item<S, L1, L2, L3, L4, L5>,
109
- keyTypes: AllItemTypeArrays<S, L1, L2, L3, L4, L5>,
110
- ): Item<S, L1, L2, L3, L4, L5> => {
111
- logger.trace('Checking Return Type', { item });
112
- if (!item) {
113
- throw new Error('validating keys, item is undefined');
114
- }
115
- if (!item.key) {
116
- throw new Error('validating keys, item does not have a key: ' + JSON.stringify(item));
117
- }
118
-
119
- const keyTypeArray = toKeyTypeArray(item.key as ComKey<S, L1, L2, L3, L4, L5> | PriKey<S>);
120
- if (keyTypeArray.length !== keyTypes.length) {
121
- throw new Error(`Item does not have the correct number of keys. Expected ${keyTypes.length}, but got ${keyTypeArray.length}`);
122
- }
123
-
124
- const match: boolean = JSON.stringify(keyTypeArray) === JSON.stringify(keyTypes);
125
- if (!match) {
126
- logger.error('Key Type Array Mismatch', { keyTypeArray, thisKeyTypes: keyTypes });
127
- throw new Error(`Item does not have the correct key types. Expected [${keyTypes.join(', ')}], but got [${keyTypeArray.join(', ')}]`);
128
- }
129
- return item;
130
- };
131
-
@@ -1,365 +0,0 @@
1
- /**
2
- * Key validation (PriKey, ComKey)
3
- *
4
- * Validates key structures and ensures keys match the expected library type.
5
- */
6
-
7
- import type { ComKey, PriKey } from "../keys";
8
- import type { Coordinate } from "../Coordinate";
9
- import { isComKey, isPriKey } from "../key/KUtils";
10
- import LibLogger from "../logger";
11
-
12
- const logger = LibLogger.get('validation', 'KeyValidator');
13
-
14
- /**
15
- * Validates that the location key array in a ComKey matches the expected hierarchy
16
- * defined by the coordinate's key type array (kta).
17
- *
18
- * @param key - The composite key to validate
19
- * @param coordinate - The coordinate defining the library's key type hierarchy
20
- * @param operation - The operation name (for error messages)
21
- * @throws Error if location key array order is incorrect
22
- */
23
- const validateLocationKeyOrder = <
24
- S extends string,
25
- L1 extends string = never,
26
- L2 extends string = never,
27
- L3 extends string = never,
28
- L4 extends string = never,
29
- L5 extends string = never
30
- >(
31
- key: ComKey<S, L1, L2, L3, L4, L5>,
32
- coordinate: Coordinate<S, L1, L2, L3, L4, L5>,
33
- operation: string
34
- ): void => {
35
- const keyTypeArray = coordinate.kta;
36
- const expectedLocationTypes = keyTypeArray.slice(1); // Remove primary key type
37
- const actualLocationTypes = key.loc.map(loc => loc.kt);
38
-
39
- // Check if lengths match
40
- if (expectedLocationTypes.length !== actualLocationTypes.length) {
41
- logger.error('Location key array length mismatch', {
42
- expected: expectedLocationTypes.length,
43
- actual: actualLocationTypes.length,
44
- key,
45
- coordinate,
46
- operation
47
- });
48
-
49
- // Build detailed error message
50
- const expectedOrder = expectedLocationTypes.map((kt, i) =>
51
- ` [${i}] { kt: '${kt}', lk: <value> }`
52
- ).join('\n');
53
-
54
- const actualOrder = key.loc.map((loc, i) =>
55
- ` [${i}] { kt: '${loc.kt}', lk: ${JSON.stringify(loc.lk)} }`
56
- ).join('\n');
57
-
58
- throw new Error(
59
- `Location key array length mismatch for ${operation} operation.\n` +
60
- `\n` +
61
- `Expected ${expectedLocationTypes.length} location keys but received ${actualLocationTypes.length}.\n` +
62
- `\n` +
63
- `Expected location key order for '${keyTypeArray[0]}':\n` +
64
- `${expectedOrder}\n` +
65
- `\n` +
66
- `Received location key order:\n` +
67
- `${actualOrder}`
68
- );
69
- }
70
-
71
- // Check if each position matches
72
- for (let i = 0; i < expectedLocationTypes.length; i++) {
73
- if (expectedLocationTypes[i] !== actualLocationTypes[i]) {
74
- logger.error('Location key array order mismatch', {
75
- position: i,
76
- expected: expectedLocationTypes[i],
77
- actual: actualLocationTypes[i],
78
- key,
79
- coordinate,
80
- operation
81
- });
82
-
83
- // Build detailed error message
84
- const expectedOrder = expectedLocationTypes.map((kt, i) =>
85
- ` [${i}] { kt: '${kt}', lk: <value> }`
86
- ).join('\n');
87
-
88
- const actualOrder = key.loc.map((loc, i) =>
89
- ` [${i}] { kt: '${loc.kt}', lk: ${JSON.stringify(loc.lk)} }`
90
- ).join('\n');
91
-
92
- throw new Error(
93
- `Location key array order mismatch for ${operation} operation.\n` +
94
- `\n` +
95
- `At position ${i}, expected key type "${expectedLocationTypes[i]}" but received "${actualLocationTypes[i]}".\n` +
96
- `\n` +
97
- `Expected location key order for '${keyTypeArray[0]}':\n` +
98
- `${expectedOrder}\n` +
99
- `\n` +
100
- `Received location key order:\n` +
101
- `${actualOrder}\n` +
102
- `\n` +
103
- `Tip: Location keys must be ordered according to the hierarchy: [${expectedLocationTypes.join(', ')}]`
104
- );
105
- }
106
- }
107
- };
108
-
109
- /**
110
- * Validates that a key is valid and matches the expected library type.
111
- *
112
- * This function performs comprehensive validation:
113
- * 1. Validates key type (PriKey vs ComKey) matches library type (primary vs composite)
114
- * 2. For composite keys, validates location key array order matches hierarchy
115
- * 3. Validates key structure is correct
116
- *
117
- * @param key - The key to validate
118
- * @param coordinate - The coordinate defining the library's key type hierarchy
119
- * @param operation - The operation name (for error messages)
120
- * @throws Error if key type doesn't match library type or location key array order is incorrect
121
- *
122
- * @example
123
- * ```typescript
124
- * // Validate a PriKey for a primary library
125
- * validateKey(
126
- * { kt: 'product', pk: '123' },
127
- * coordinate,
128
- * 'get'
129
- * );
130
- *
131
- * // Validate a ComKey for a composite library
132
- * validateKey(
133
- * { kt: 'product', pk: '123', loc: [{ kt: 'store', lk: '456' }] },
134
- * coordinate,
135
- * 'get'
136
- * );
137
- * ```
138
- */
139
- export const validateKey = <
140
- S extends string,
141
- L1 extends string = never,
142
- L2 extends string = never,
143
- L3 extends string = never,
144
- L4 extends string = never,
145
- L5 extends string = never
146
- >(
147
- key: PriKey<S> | ComKey<S, L1, L2, L3, L4, L5>,
148
- coordinate: Coordinate<S, L1, L2, L3, L4, L5>,
149
- operation: string
150
- ): void => {
151
- logger.debug(`Validating key for ${operation}`, { key, coordinate: coordinate.kta });
152
-
153
- // Check for null/undefined early
154
- if (!key || key === null) {
155
- throw new Error(
156
- `Invalid key structure for ${operation} operation.\n` +
157
- `\n` +
158
- `The provided key is null or undefined.\n` +
159
- `\n` +
160
- `Valid key formats:\n` +
161
- ` PriKey: { kt: string, pk: string|number }\n` +
162
- ` ComKey: { kt: string, pk: string|number, loc: Array<{ kt: string, lk: string|number }> }`
163
- );
164
- }
165
-
166
- // Runtime validation: Check if the key type matches the library type
167
- const isCompositeLibrary = coordinate.kta.length > 1;
168
- const keyIsComposite = isComKey(key);
169
- const keyIsPrimary = isPriKey(key);
170
-
171
- // Validate that the key type matches the library type
172
- if (isCompositeLibrary && !keyIsComposite) {
173
- // This is a composite library but received a primary key
174
- logger.error(`Composite library received primary key in ${operation}`, { key, coordinate });
175
-
176
- const keyTypeArray = coordinate.kta;
177
-
178
- throw new Error(
179
- `Invalid key type for ${operation} operation.\n` +
180
- `\n` +
181
- `This is a composite item library. You must provide a ComKey with location keys.\n` +
182
- `\n` +
183
- `Expected: ComKey with format:\n` +
184
- ` {\n` +
185
- ` kt: '${keyTypeArray[0]}',\n` +
186
- ` pk: string|number,\n` +
187
- ` loc: [\n` +
188
- keyTypeArray.slice(1).map(kt => ` { kt: '${kt}', lk: string|number }`).join(',\n') + '\n' +
189
- ` ]\n` +
190
- ` }\n` +
191
- `\n` +
192
- `Received: PriKey with format:\n` +
193
- ` ${JSON.stringify(key, null, 2)}\n` +
194
- `\n` +
195
- `Example correct usage:\n` +
196
- ` library.operations.${operation}({\n` +
197
- ` kt: '${keyTypeArray[0]}',\n` +
198
- ` pk: 'item-id',\n` +
199
- ` loc: [${keyTypeArray.slice(1).map(kt => `{ kt: '${kt}', lk: 'parent-id' }`).join(', ')}]\n` +
200
- ` })`
201
- );
202
- }
203
-
204
- if (!isCompositeLibrary && keyIsComposite) {
205
- // This is a primary library but received a composite key
206
- logger.error(`Primary library received composite key in ${operation}`, { key, coordinate });
207
-
208
- const keyTypeArray = coordinate.kta;
209
-
210
- throw new Error(
211
- `Invalid key type for ${operation} operation.\n` +
212
- `\n` +
213
- `This is a primary item library. You should provide a PriKey without location keys.\n` +
214
- `\n` +
215
- `Expected: PriKey with format:\n` +
216
- ` { kt: '${keyTypeArray[0]}', pk: string|number }\n` +
217
- `\n` +
218
- `Received: ComKey with format:\n` +
219
- ` ${JSON.stringify(key, null, 2)}\n` +
220
- `\n` +
221
- `Example correct usage:\n` +
222
- ` library.operations.${operation}({ kt: '${keyTypeArray[0]}', pk: 'item-id' })`
223
- );
224
- }
225
-
226
- if (!keyIsPrimary && !keyIsComposite) {
227
- // Invalid key structure
228
- logger.error(`Invalid key structure in ${operation}`, { key, coordinate });
229
-
230
- throw new Error(
231
- `Invalid key structure for ${operation} operation.\n` +
232
- `\n` +
233
- `The provided key does not match PriKey or ComKey format.\n` +
234
- `\n` +
235
- `Received:\n` +
236
- ` ${JSON.stringify(key, null, 2)}\n` +
237
- `\n` +
238
- `Valid key formats:\n` +
239
- ` PriKey: { kt: string, pk: string|number }\n` +
240
- ` ComKey: { kt: string, pk: string|number, loc: Array<{ kt: string, lk: string|number }> }`
241
- );
242
- }
243
-
244
- // Validate that the key's kt field matches the expected primary key type
245
- const expectedKeyType = coordinate.kta[0];
246
- if ((key as any).kt !== expectedKeyType) {
247
- logger.error(`Key type mismatch in ${operation}`, {
248
- expected: expectedKeyType,
249
- received: (key as any).kt,
250
- key,
251
- coordinate
252
- });
253
-
254
- throw new Error(
255
- `Invalid key type for ${operation} operation.\n` +
256
- `\n` +
257
- `Expected key type: '${expectedKeyType}'\n` +
258
- `Received key type: '${(key as any).kt}'\n` +
259
- `\n` +
260
- `Example correct usage:\n` +
261
- ` library.operations.${operation}({ kt: '${expectedKeyType}', pk: 'item-id', ... })`
262
- );
263
- }
264
-
265
- // For composite keys, validate the location key array order
266
- if (keyIsComposite) {
267
- const comKey = key as ComKey<S, L1, L2, L3, L4, L5>;
268
-
269
- // Empty loc array is a special case: it means "find by primary key across all locations"
270
- // This is used for foreign key references to composite items where the location context is unknown
271
- if (comKey.loc.length === 0) {
272
- logger.debug(`Empty loc array detected in ${operation} - will search across all locations`, { key });
273
- } else {
274
- // For non-empty loc arrays, validate the order matches the expected hierarchy
275
- validateLocationKeyOrder(comKey, coordinate, operation);
276
- }
277
- }
278
-
279
- logger.debug(`Key validation passed for ${operation}`, { key });
280
- };
281
-
282
- /**
283
- * Validates a PriKey structure
284
- *
285
- * @param key - The primary key to validate
286
- * @param expectedType - The expected key type
287
- * @param operation - The operation name (for error messages)
288
- * @throws Error if key is invalid
289
- */
290
- export const validatePriKey = <S extends string>(
291
- key: PriKey<S>,
292
- expectedType: S,
293
- operation: string
294
- ): void => {
295
- if (!key || key === null) {
296
- throw new Error(`[${operation}] PriKey is undefined or null`);
297
- }
298
-
299
- if (!key.kt) {
300
- throw new Error(`[${operation}] PriKey is missing 'kt' field`);
301
- }
302
-
303
- if (key.kt !== expectedType) {
304
- throw new Error(
305
- `[${operation}] PriKey has incorrect type.\n` +
306
- `Expected: '${expectedType}'\n` +
307
- `Received: '${key.kt}'`
308
- );
309
- }
310
-
311
- if (typeof key.pk === 'undefined' || key.pk === null) {
312
- throw new Error(`[${operation}] PriKey is missing 'pk' field`);
313
- }
314
- };
315
-
316
- /**
317
- * Validates a ComKey structure
318
- *
319
- * @param key - The composite key to validate
320
- * @param coordinate - The coordinate defining the expected hierarchy
321
- * @param operation - The operation name (for error messages)
322
- * @throws Error if key is invalid
323
- */
324
- export const validateComKey = <
325
- S extends string,
326
- L1 extends string = never,
327
- L2 extends string = never,
328
- L3 extends string = never,
329
- L4 extends string = never,
330
- L5 extends string = never
331
- >(
332
- key: ComKey<S, L1, L2, L3, L4, L5>,
333
- coordinate: Coordinate<S, L1, L2, L3, L4, L5>,
334
- operation: string
335
- ): void => {
336
- if (!key || key === null) {
337
- throw new Error(`[${operation}] ComKey is undefined or null`);
338
- }
339
-
340
- if (!key.kt) {
341
- throw new Error(`[${operation}] ComKey is missing 'kt' field`);
342
- }
343
-
344
- if (key.kt !== coordinate.kta[0]) {
345
- throw new Error(
346
- `[${operation}] ComKey has incorrect type.\n` +
347
- `Expected: '${coordinate.kta[0]}'\n` +
348
- `Received: '${key.kt}'`
349
- );
350
- }
351
-
352
- if (typeof key.pk === 'undefined' || key.pk === null) {
353
- throw new Error(`[${operation}] ComKey is missing 'pk' field`);
354
- }
355
-
356
- if (!Array.isArray(key.loc)) {
357
- throw new Error(`[${operation}] ComKey is missing or invalid 'loc' field (must be an array)`);
358
- }
359
-
360
- // Validate location key order if loc is not empty
361
- if (key.loc.length > 0) {
362
- validateLocationKeyOrder(key, coordinate, operation);
363
- }
364
- };
365
-
@@ -1,136 +0,0 @@
1
- /**
2
- * Location array validation
3
- *
4
- * Validates that LocKeyArray parameters match the expected Coordinate hierarchy.
5
- */
6
-
7
- import type { LocKey, LocKeyArray } from "../keys";
8
- import type { Coordinate } from "../Coordinate";
9
- import LibLogger from "../logger";
10
- import type { ValidationResult } from "./types";
11
-
12
- const logger = LibLogger.get('validation', 'LocationValidator');
13
-
14
- /**
15
- * Validates that a standalone LocKeyArray parameter matches the expected hierarchy
16
- * defined by the coordinate's key type array (kta).
17
- *
18
- * This is used to validate the `locations` parameter passed to operations like
19
- * all(), find(), create(), etc.
20
- *
21
- * @param locations - The location key array to validate
22
- * @param coordinate - The coordinate defining the library's key type hierarchy
23
- * @param operation - The operation name (for error messages)
24
- * @throws Error if location key array order is incorrect
25
- *
26
- * @example
27
- * ```typescript
28
- * validateLocations(
29
- * [{kt: 'store', lk: '123'}],
30
- * coordinate,
31
- * 'find'
32
- * );
33
- * ```
34
- */
35
- export const validateLocations = <
36
- S extends string,
37
- L1 extends string = never,
38
- L2 extends string = never,
39
- L3 extends string = never,
40
- L4 extends string = never,
41
- L5 extends string = never
42
- >(
43
- locations: LocKeyArray<L1, L2, L3, L4, L5> | [] | undefined,
44
- coordinate: Coordinate<S, L1, L2, L3, L4, L5>,
45
- operation: string
46
- ): void => {
47
- // Skip validation if locations is empty or undefined
48
- if (!locations || locations.length === 0) {
49
- return;
50
- }
51
-
52
- const keyTypeArray = coordinate.kta;
53
- const expectedLocationTypes = keyTypeArray.slice(1); // Remove primary key type
54
- const actualLocationTypes = (locations as Array<LocKey<L1 | L2 | L3 | L4 | L5>>).map(loc => loc.kt);
55
-
56
- logger.debug(`Validating locations for ${operation}`, {
57
- expected: expectedLocationTypes,
58
- actual: actualLocationTypes,
59
- coordinate: keyTypeArray
60
- });
61
-
62
- // Check if lengths match
63
- if (actualLocationTypes.length > expectedLocationTypes.length) {
64
- logger.error('Location key array has too many elements', {
65
- expected: expectedLocationTypes.length,
66
- actual: actualLocationTypes.length,
67
- expectedTypes: expectedLocationTypes,
68
- actualTypes: actualLocationTypes,
69
- coordinate,
70
- operation
71
- });
72
- throw new Error(
73
- `Invalid location key array for ${operation}: ` +
74
- `Expected at most ${expectedLocationTypes.length} location keys ` +
75
- `(hierarchy: [${expectedLocationTypes.join(', ')}]), ` +
76
- `but received ${actualLocationTypes.length} ` +
77
- `(types: [${actualLocationTypes.join(', ')}])`
78
- );
79
- }
80
-
81
- // Check if each position matches the expected hierarchy
82
- for (let i = 0; i < actualLocationTypes.length; i++) {
83
- if (expectedLocationTypes[i] !== actualLocationTypes[i]) {
84
- logger.error('Location key array order mismatch', {
85
- position: i,
86
- expected: expectedLocationTypes[i],
87
- actual: actualLocationTypes[i],
88
- expectedHierarchy: expectedLocationTypes,
89
- actualOrder: actualLocationTypes,
90
- coordinate,
91
- operation
92
- });
93
- throw new Error(
94
- `Invalid location key array order for ${operation}: ` +
95
- `At position ${i}, expected key type "${expectedLocationTypes[i]}" ` +
96
- `but received "${actualLocationTypes[i]}". ` +
97
- `Location keys must be ordered according to the hierarchy: [${expectedLocationTypes.join(', ')}]. ` +
98
- `Received order: [${actualLocationTypes.join(', ')}]`
99
- );
100
- }
101
- }
102
-
103
- logger.debug(`Location key array validation passed for ${operation}`, { locations });
104
- };
105
-
106
- /**
107
- * Non-throwing version of validateLocations that returns a ValidationResult
108
- *
109
- * @param locations - The location key array to validate
110
- * @param coordinate - The coordinate defining the library's key type hierarchy
111
- * @param operation - The operation name (for error messages)
112
- * @returns ValidationResult with valid flag and optional error message
113
- */
114
- export const isValidLocations = <
115
- S extends string,
116
- L1 extends string = never,
117
- L2 extends string = never,
118
- L3 extends string = never,
119
- L4 extends string = never,
120
- L5 extends string = never
121
- >(
122
- locations: LocKeyArray<L1, L2, L3, L4, L5> | [] | undefined,
123
- coordinate: Coordinate<S, L1, L2, L3, L4, L5>,
124
- operation: string
125
- ): ValidationResult => {
126
- try {
127
- validateLocations(locations, coordinate, operation);
128
- return { valid: true };
129
- } catch (error) {
130
- return {
131
- valid: false,
132
- error: error instanceof Error ? error.message : String(error)
133
- };
134
- }
135
- };
136
-