@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.
- package/package.json +3 -3
- package/src/AItemService.ts +0 -38
- package/src/Coordinate.ts +0 -35
- package/src/dictionary.ts +0 -84
- package/src/errors/ActionError.ts +0 -69
- package/src/errors/BusinessLogicError.ts +0 -24
- package/src/errors/DuplicateError.ts +0 -57
- package/src/errors/NotFoundError.ts +0 -24
- package/src/errors/PermissionError.ts +0 -31
- package/src/errors/ValidationError.ts +0 -27
- package/src/errors/index.ts +0 -7
- package/src/event/emitter.ts +0 -247
- package/src/event/events.ts +0 -178
- package/src/event/index.ts +0 -130
- package/src/event/matching.ts +0 -264
- package/src/event/subscription.ts +0 -181
- package/src/event/types.ts +0 -282
- package/src/index.ts +0 -70
- package/src/item/IFactory.ts +0 -122
- package/src/item/IQFactory.ts +0 -163
- package/src/item/IQUtils.ts +0 -392
- package/src/item/IUtils.ts +0 -40
- package/src/item/ItemQuery.ts +0 -88
- package/src/items.ts +0 -120
- package/src/key/KUtils.ts +0 -484
- package/src/keys.ts +0 -95
- package/src/logger.ts +0 -5
- package/src/operations/OperationContext.ts +0 -12
- package/src/operations/Operations.ts +0 -357
- package/src/operations/contained.ts +0 -134
- package/src/operations/errorEnhancer.ts +0 -204
- package/src/operations/index.ts +0 -2
- package/src/operations/methods.ts +0 -363
- package/src/operations/primary.ts +0 -101
- package/src/operations/specialized.ts +0 -71
- package/src/operations/wrappers/createActionWrapper.ts +0 -108
- package/src/operations/wrappers/createAllActionWrapper.ts +0 -109
- package/src/operations/wrappers/createAllFacetWrapper.ts +0 -98
- package/src/operations/wrappers/createAllWrapper.ts +0 -103
- package/src/operations/wrappers/createCreateWrapper.ts +0 -117
- package/src/operations/wrappers/createFacetWrapper.ts +0 -97
- package/src/operations/wrappers/createFindOneWrapper.ts +0 -105
- package/src/operations/wrappers/createFindWrapper.ts +0 -105
- package/src/operations/wrappers/createGetWrapper.ts +0 -96
- package/src/operations/wrappers/createOneWrapper.ts +0 -128
- package/src/operations/wrappers/createRemoveWrapper.ts +0 -91
- package/src/operations/wrappers/createUpdateWrapper.ts +0 -106
- package/src/operations/wrappers/createUpsertWrapper.ts +0 -108
- package/src/operations/wrappers/index.ts +0 -39
- package/src/operations/wrappers/types.ts +0 -63
- package/src/validation/ItemValidator.ts +0 -131
- package/src/validation/KeyValidator.ts +0 -365
- package/src/validation/LocationValidator.ts +0 -136
- package/src/validation/QueryValidator.ts +0 -250
- package/src/validation/index.ts +0 -32
- 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
|
-
|