@fjell/core 4.4.48 → 4.4.49

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 (82) hide show
  1. package/README.md +92 -0
  2. package/dist/Coordinate.d.ts +7 -0
  3. package/dist/errors/ActionError.d.ts +51 -0
  4. package/dist/errors/BusinessLogicError.d.ts +4 -0
  5. package/dist/errors/DuplicateError.d.ts +4 -0
  6. package/dist/errors/NotFoundError.d.ts +4 -0
  7. package/dist/errors/PermissionError.d.ts +4 -0
  8. package/dist/errors/ValidationError.d.ts +4 -0
  9. package/dist/errors/index.d.ts +6 -0
  10. package/dist/index.d.ts +11 -0
  11. package/dist/index.js +1312 -47
  12. package/dist/item/IUtils.d.ts +6 -3
  13. package/dist/operations/OperationContext.d.ts +10 -0
  14. package/dist/operations/Operations.d.ts +259 -0
  15. package/dist/operations/contained.d.ts +65 -0
  16. package/dist/operations/errorEnhancer.d.ts +79 -0
  17. package/dist/operations/index.d.ts +2 -0
  18. package/dist/operations/methods.d.ts +134 -0
  19. package/dist/operations/primary.d.ts +57 -0
  20. package/dist/operations/specialized.d.ts +41 -0
  21. package/dist/operations/wrappers/createActionWrapper.d.ts +28 -0
  22. package/dist/operations/wrappers/createAllActionWrapper.d.ts +28 -0
  23. package/dist/operations/wrappers/createAllFacetWrapper.d.ts +27 -0
  24. package/dist/operations/wrappers/createAllWrapper.d.ts +28 -0
  25. package/dist/operations/wrappers/createCreateWrapper.d.ts +28 -0
  26. package/dist/operations/wrappers/createFacetWrapper.d.ts +27 -0
  27. package/dist/operations/wrappers/createFindOneWrapper.d.ts +28 -0
  28. package/dist/operations/wrappers/createFindWrapper.d.ts +28 -0
  29. package/dist/operations/wrappers/createGetWrapper.d.ts +28 -0
  30. package/dist/operations/wrappers/createOneWrapper.d.ts +38 -0
  31. package/dist/operations/wrappers/createRemoveWrapper.d.ts +28 -0
  32. package/dist/operations/wrappers/createUpdateWrapper.d.ts +28 -0
  33. package/dist/operations/wrappers/createUpsertWrapper.d.ts +28 -0
  34. package/dist/operations/wrappers/index.d.ts +34 -0
  35. package/dist/operations/wrappers/types.d.ts +48 -0
  36. package/dist/validation/ItemValidator.d.ts +43 -0
  37. package/dist/validation/KeyValidator.d.ts +56 -0
  38. package/dist/validation/LocationValidator.d.ts +39 -0
  39. package/dist/validation/QueryValidator.d.ts +57 -0
  40. package/dist/validation/index.d.ts +15 -0
  41. package/dist/validation/index.js +501 -0
  42. package/dist/validation/types.d.ts +38 -0
  43. package/package.json +7 -2
  44. package/src/Coordinate.ts +35 -0
  45. package/src/errors/ActionError.ts +69 -0
  46. package/src/errors/BusinessLogicError.ts +24 -0
  47. package/src/errors/DuplicateError.ts +57 -0
  48. package/src/errors/NotFoundError.ts +24 -0
  49. package/src/errors/PermissionError.ts +31 -0
  50. package/src/errors/ValidationError.ts +27 -0
  51. package/src/errors/index.ts +7 -0
  52. package/src/index.ts +53 -0
  53. package/src/item/IUtils.ts +9 -80
  54. package/src/operations/OperationContext.ts +12 -0
  55. package/src/operations/Operations.ts +357 -0
  56. package/src/operations/contained.ts +134 -0
  57. package/src/operations/errorEnhancer.ts +204 -0
  58. package/src/operations/index.ts +2 -0
  59. package/src/operations/methods.ts +363 -0
  60. package/src/operations/primary.ts +101 -0
  61. package/src/operations/specialized.ts +71 -0
  62. package/src/operations/wrappers/createActionWrapper.ts +108 -0
  63. package/src/operations/wrappers/createAllActionWrapper.ts +109 -0
  64. package/src/operations/wrappers/createAllFacetWrapper.ts +98 -0
  65. package/src/operations/wrappers/createAllWrapper.ts +103 -0
  66. package/src/operations/wrappers/createCreateWrapper.ts +117 -0
  67. package/src/operations/wrappers/createFacetWrapper.ts +97 -0
  68. package/src/operations/wrappers/createFindOneWrapper.ts +105 -0
  69. package/src/operations/wrappers/createFindWrapper.ts +105 -0
  70. package/src/operations/wrappers/createGetWrapper.ts +96 -0
  71. package/src/operations/wrappers/createOneWrapper.ts +128 -0
  72. package/src/operations/wrappers/createRemoveWrapper.ts +91 -0
  73. package/src/operations/wrappers/createUpdateWrapper.ts +106 -0
  74. package/src/operations/wrappers/createUpsertWrapper.ts +108 -0
  75. package/src/operations/wrappers/index.ts +39 -0
  76. package/src/operations/wrappers/types.ts +63 -0
  77. package/src/validation/ItemValidator.ts +131 -0
  78. package/src/validation/KeyValidator.ts +365 -0
  79. package/src/validation/LocationValidator.ts +136 -0
  80. package/src/validation/QueryValidator.ts +250 -0
  81. package/src/validation/index.ts +32 -0
  82. package/src/validation/types.ts +45 -0
@@ -0,0 +1,109 @@
1
+ /**
2
+ * Wrapper for allAction() operation
3
+ *
4
+ * Provides automatic validation for allAction() operation parameters.
5
+ */
6
+
7
+ import type { Item } from "../../items";
8
+ import type { LocKeyArray } from "../../keys";
9
+ import type { Coordinate } from "../../Coordinate";
10
+ import type { AffectedKeys, OperationParams } from "../Operations";
11
+ import { validateActionName, validateLocations, validateOperationParams, validatePK } from "../../validation";
12
+ import type { AllActionOperationMethod } from "../methods";
13
+ import type { ErrorContext, WrapperOptions } from "./types";
14
+ import LibLogger from "../../logger";
15
+
16
+ const logger = LibLogger.get('operations', 'wrappers', 'allAction');
17
+
18
+ /**
19
+ * Creates a wrapped allAction() method with automatic parameter validation.
20
+ *
21
+ * @param coordinate - The coordinate defining the item hierarchy
22
+ * @param implementation - The core logic for the operation
23
+ * @param options - Optional configuration
24
+ * @returns A fully validated allAction() method
25
+ *
26
+ * @example
27
+ * ```typescript
28
+ * const allAction = createAllActionWrapper(
29
+ * coordinate,
30
+ * async (action, params, locations) => {
31
+ * return await database.executeAllAction(action, params, locations);
32
+ * }
33
+ * );
34
+ * ```
35
+ */
36
+ export function createAllActionWrapper<
37
+ V extends Item<S, L1, L2, L3, L4, L5>,
38
+ S extends string,
39
+ L1 extends string = never,
40
+ L2 extends string = never,
41
+ L3 extends string = never,
42
+ L4 extends string = never,
43
+ L5 extends string = never
44
+ >(
45
+ coordinate: Coordinate<S, L1, L2, L3, L4, L5>,
46
+ implementation: AllActionOperationMethod<V, S, L1, L2, L3, L4, L5>,
47
+ options: WrapperOptions = {}
48
+ ): AllActionOperationMethod<V, S, L1, L2, L3, L4, L5> {
49
+
50
+ const operationName = options.operationName || 'allAction';
51
+
52
+ return async (
53
+ action: string,
54
+ params?: OperationParams,
55
+ locations?: LocKeyArray<L1, L2, L3, L4, L5> | []
56
+ ): Promise<[V[], AffectedKeys]> => {
57
+
58
+ if (options.debug) {
59
+ logger.debug(`[${operationName}] Called:`, { action, params, locations });
60
+ }
61
+
62
+ // Validate
63
+ if (!options.skipValidation) {
64
+ validateActionName(action, operationName);
65
+ validateOperationParams(params, operationName);
66
+ validateLocations(locations, coordinate, operationName);
67
+ }
68
+
69
+ // Normalize
70
+ const normalizedParams = params ?? {};
71
+ const normalizedLocations = (locations ?? []) as LocKeyArray<L1, L2, L3, L4, L5> | [];
72
+
73
+ // Execute
74
+ try {
75
+ const result = await implementation(action, normalizedParams, normalizedLocations);
76
+
77
+ if (options.debug) {
78
+ logger.debug(`[${operationName}] Action "${action}" completed:`, {
79
+ itemsAffected: result[0].length,
80
+ affectedKeys: result[1].length
81
+ });
82
+ }
83
+
84
+ // Validate primary key types for all returned items
85
+ if (!options.skipValidation) {
86
+ const validatedItems = validatePK(result[0], coordinate.kta[0]) as V[];
87
+ return [validatedItems, result[1]];
88
+ }
89
+
90
+ return result;
91
+
92
+ } catch (error) {
93
+ if (options.onError) {
94
+ const context: ErrorContext = {
95
+ operationName,
96
+ params: [action, params, locations],
97
+ coordinate
98
+ };
99
+ throw options.onError(error as Error, context);
100
+ }
101
+
102
+ throw new Error(
103
+ `[${operationName}] Action "${action}" failed: ${(error as Error).message}`,
104
+ { cause: error }
105
+ );
106
+ }
107
+ };
108
+ }
109
+
@@ -0,0 +1,98 @@
1
+ /**
2
+ * Wrapper for allFacet() operation
3
+ *
4
+ * Provides automatic validation for allFacet() operation parameters.
5
+ */
6
+
7
+ import type { LocKeyArray } from "../../keys";
8
+ import type { Coordinate } from "../../Coordinate";
9
+ import type { OperationParams } from "../Operations";
10
+ import { validateFacetName, validateLocations, validateOperationParams } from "../../validation";
11
+ import type { AllFacetOperationMethod } from "../methods";
12
+ import type { ErrorContext, WrapperOptions } from "./types";
13
+ import LibLogger from "../../logger";
14
+
15
+ const logger = LibLogger.get('operations', 'wrappers', 'allFacet');
16
+
17
+ /**
18
+ * Creates a wrapped allFacet() method with automatic parameter validation.
19
+ *
20
+ * @param coordinate - The coordinate defining the item hierarchy
21
+ * @param implementation - The core logic for the operation
22
+ * @param options - Optional configuration
23
+ * @returns A fully validated allFacet() method
24
+ *
25
+ * @example
26
+ * ```typescript
27
+ * const allFacet = createAllFacetWrapper(
28
+ * coordinate,
29
+ * async (facet, params, locations) => {
30
+ * return await database.executeAllFacet(facet, params, locations);
31
+ * }
32
+ * );
33
+ * ```
34
+ */
35
+ export function createAllFacetWrapper<
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
+ coordinate: Coordinate<S, L1, L2, L3, L4, L5>,
44
+ implementation: AllFacetOperationMethod<L1, L2, L3, L4, L5>,
45
+ options: WrapperOptions = {}
46
+ ): AllFacetOperationMethod<L1, L2, L3, L4, L5> {
47
+
48
+ const operationName = options.operationName || 'allFacet';
49
+
50
+ return async (
51
+ facet: string,
52
+ params?: OperationParams,
53
+ locations?: LocKeyArray<L1, L2, L3, L4, L5> | []
54
+ ): Promise<any> => {
55
+
56
+ if (options.debug) {
57
+ logger.debug(`[${operationName}] Called:`, { facet, params, locations });
58
+ }
59
+
60
+ // Validate
61
+ if (!options.skipValidation) {
62
+ validateFacetName(facet, operationName);
63
+ validateOperationParams(params, operationName);
64
+ validateLocations(locations, coordinate, operationName);
65
+ }
66
+
67
+ // Normalize
68
+ const normalizedParams = params ?? {};
69
+ const normalizedLocations = (locations ?? []) as LocKeyArray<L1, L2, L3, L4, L5> | [];
70
+
71
+ // Execute
72
+ try {
73
+ const result = await implementation(facet, normalizedParams, normalizedLocations);
74
+
75
+ if (options.debug) {
76
+ logger.debug(`[${operationName}] Facet "${facet}" completed`);
77
+ }
78
+
79
+ return result;
80
+
81
+ } catch (error) {
82
+ if (options.onError) {
83
+ const context: ErrorContext = {
84
+ operationName,
85
+ params: [facet, params, locations],
86
+ coordinate
87
+ };
88
+ throw options.onError(error as Error, context);
89
+ }
90
+
91
+ throw new Error(
92
+ `[${operationName}] Facet "${facet}" failed: ${(error as Error).message}`,
93
+ { cause: error }
94
+ );
95
+ }
96
+ };
97
+ }
98
+
@@ -0,0 +1,103 @@
1
+ /**
2
+ * Wrapper for all() operation
3
+ *
4
+ * Provides automatic validation for all() operation parameters.
5
+ */
6
+
7
+ import type { Item } from "../../items";
8
+ import type { ItemQuery } from "../../item/ItemQuery";
9
+ import type { LocKeyArray } from "../../keys";
10
+ import type { Coordinate } from "../../Coordinate";
11
+ import { validateLocations, validatePK, validateQuery } from "../../validation";
12
+ import type { AllMethod } from "../methods";
13
+ import type { ErrorContext, WrapperOptions } from "./types";
14
+ import LibLogger from "../../logger";
15
+
16
+ const logger = LibLogger.get('operations', 'wrappers', 'all');
17
+
18
+ /**
19
+ * Creates a wrapped all() method with automatic parameter validation.
20
+ *
21
+ * @param coordinate - The coordinate defining the item hierarchy
22
+ * @param implementation - The core logic for the operation
23
+ * @param options - Optional configuration
24
+ * @returns A fully validated all() method
25
+ *
26
+ * @example
27
+ * ```typescript
28
+ * const all = createAllWrapper(
29
+ * coordinate,
30
+ * async (query, locations) => {
31
+ * return await database.findAll(query, locations);
32
+ * }
33
+ * );
34
+ * ```
35
+ */
36
+ export function createAllWrapper<
37
+ V extends Item<S, L1, L2, L3, L4, L5>,
38
+ S extends string,
39
+ L1 extends string = never,
40
+ L2 extends string = never,
41
+ L3 extends string = never,
42
+ L4 extends string = never,
43
+ L5 extends string = never
44
+ >(
45
+ coordinate: Coordinate<S, L1, L2, L3, L4, L5>,
46
+ implementation: AllMethod<V, S, L1, L2, L3, L4, L5>,
47
+ options: WrapperOptions = {}
48
+ ): AllMethod<V, S, L1, L2, L3, L4, L5> {
49
+
50
+ const operationName = options.operationName || 'all';
51
+
52
+ return async (
53
+ query?: ItemQuery,
54
+ locations?: LocKeyArray<L1, L2, L3, L4, L5> | []
55
+ ): Promise<V[]> => {
56
+
57
+ if (options.debug) {
58
+ logger.debug(`[${operationName}] Called with:`, { query, locations });
59
+ }
60
+
61
+ // Validate
62
+ if (!options.skipValidation) {
63
+ validateQuery(query, operationName);
64
+ validateLocations(locations, coordinate, operationName);
65
+ }
66
+
67
+ // Normalize
68
+ const normalizedQuery = query ?? {};
69
+ const normalizedLocations = (locations ?? []) as LocKeyArray<L1, L2, L3, L4, L5> | [];
70
+
71
+ // Execute
72
+ try {
73
+ const result = await implementation(normalizedQuery, normalizedLocations);
74
+
75
+ if (options.debug) {
76
+ logger.debug(`[${operationName}] Result: ${result.length} items`);
77
+ }
78
+
79
+ // Validate primary key types for all items
80
+ if (!options.skipValidation) {
81
+ return validatePK(result, coordinate.kta[0]) as V[];
82
+ }
83
+
84
+ return result;
85
+
86
+ } catch (error) {
87
+ if (options.onError) {
88
+ const context: ErrorContext = {
89
+ operationName,
90
+ params: [query, locations],
91
+ coordinate
92
+ };
93
+ throw options.onError(error as Error, context);
94
+ }
95
+
96
+ throw new Error(
97
+ `[${operationName}] Operation failed: ${(error as Error).message}`,
98
+ { cause: error }
99
+ );
100
+ }
101
+ };
102
+ }
103
+
@@ -0,0 +1,117 @@
1
+ /**
2
+ * Wrapper for create() operation
3
+ *
4
+ * Provides automatic validation for create() operation parameters.
5
+ */
6
+
7
+ import type { Item } from "../../items";
8
+ import type { Coordinate } from "../../Coordinate";
9
+ import { validateKey, validateLocations, validatePK } from "../../validation";
10
+ import type { CreateMethod } from "../methods";
11
+ import type { CreateOptions } from "../Operations";
12
+ import type { ErrorContext, WrapperOptions } from "./types";
13
+ import LibLogger from "../../logger";
14
+
15
+ const logger = LibLogger.get('operations', 'wrappers', 'create');
16
+
17
+ /**
18
+ * Creates a wrapped create() method with automatic parameter validation.
19
+ *
20
+ * @param coordinate - The coordinate defining the item hierarchy
21
+ * @param implementation - The core logic for the operation
22
+ * @param options - Optional wrapper configuration
23
+ * @returns A fully validated create() method
24
+ *
25
+ * @example
26
+ * ```typescript
27
+ * const create = createCreateWrapper(
28
+ * coordinate,
29
+ * async (item, options) => {
30
+ * return await database.create(item, options);
31
+ * }
32
+ * );
33
+ * ```
34
+ */
35
+ export function createCreateWrapper<
36
+ V extends Item<S, L1, L2, L3, L4, L5>,
37
+ S extends string,
38
+ L1 extends string = never,
39
+ L2 extends string = never,
40
+ L3 extends string = never,
41
+ L4 extends string = never,
42
+ L5 extends string = never
43
+ >(
44
+ coordinate: Coordinate<S, L1, L2, L3, L4, L5>,
45
+ implementation: CreateMethod<V, S, L1, L2, L3, L4, L5>,
46
+ wrapperOptions: WrapperOptions = {}
47
+ ): CreateMethod<V, S, L1, L2, L3, L4, L5> {
48
+
49
+ const operationName = wrapperOptions.operationName || 'create';
50
+
51
+ return async (
52
+ item: Partial<Item<S, L1, L2, L3, L4, L5>>,
53
+ createOptions?: CreateOptions<S, L1, L2, L3, L4, L5>
54
+ ): Promise<V> => {
55
+
56
+ if (wrapperOptions.debug) {
57
+ logger.debug(`[${operationName}] Called with:`, { item, options: createOptions });
58
+ }
59
+
60
+ // Validate
61
+ if (!wrapperOptions.skipValidation) {
62
+ // Validate item is an object
63
+ if (!item || typeof item !== 'object' || Array.isArray(item)) {
64
+ throw new Error(
65
+ `[${operationName}] Invalid item parameter.\n` +
66
+ `\n` +
67
+ `Expected: object\n` +
68
+ `Received: ${Array.isArray(item) ? 'array' : typeof item}`
69
+ );
70
+ }
71
+
72
+ // Validate create options
73
+ if (createOptions) {
74
+ if ('key' in createOptions) {
75
+ // Validate the key (even if null, let validateKey handle it)
76
+ validateKey(createOptions.key as any, coordinate, operationName);
77
+ }
78
+ if ('locations' in createOptions) {
79
+ // Validate the locations (even if undefined, let validateLocations handle it)
80
+ validateLocations(createOptions.locations, coordinate, operationName);
81
+ }
82
+ }
83
+ }
84
+
85
+ // Execute
86
+ try {
87
+ const result = await implementation(item, createOptions);
88
+
89
+ if (wrapperOptions.debug) {
90
+ logger.debug(`[${operationName}] Created item:`, result.key);
91
+ }
92
+
93
+ // Validate primary key type
94
+ if (!wrapperOptions.skipValidation) {
95
+ return validatePK(result, coordinate.kta[0]) as V;
96
+ }
97
+
98
+ return result;
99
+
100
+ } catch (error) {
101
+ if (wrapperOptions.onError) {
102
+ const context: ErrorContext = {
103
+ operationName,
104
+ params: [item, createOptions],
105
+ coordinate
106
+ };
107
+ throw wrapperOptions.onError(error as Error, context);
108
+ }
109
+
110
+ throw new Error(
111
+ `[${operationName}] Operation failed: ${(error as Error).message}`,
112
+ { cause: error }
113
+ );
114
+ }
115
+ };
116
+ }
117
+
@@ -0,0 +1,97 @@
1
+ /**
2
+ * Wrapper for facet() operation
3
+ *
4
+ * Provides automatic validation for facet() operation parameters.
5
+ */
6
+
7
+ import type { ComKey, PriKey } from "../../keys";
8
+ import type { Coordinate } from "../../Coordinate";
9
+ import type { OperationParams } from "../Operations";
10
+ import { validateFacetName, validateKey, validateOperationParams } from "../../validation";
11
+ import type { FacetOperationMethod } from "../methods";
12
+ import type { ErrorContext, WrapperOptions } from "./types";
13
+ import LibLogger from "../../logger";
14
+
15
+ const logger = LibLogger.get('operations', 'wrappers', 'facet');
16
+
17
+ /**
18
+ * Creates a wrapped facet() method with automatic parameter validation.
19
+ *
20
+ * @param coordinate - The coordinate defining the item hierarchy
21
+ * @param implementation - The core logic for the operation
22
+ * @param options - Optional configuration
23
+ * @returns A fully validated facet() method
24
+ *
25
+ * @example
26
+ * ```typescript
27
+ * const facet = createFacetWrapper(
28
+ * coordinate,
29
+ * async (key, facet, params) => {
30
+ * return await database.executeFacet(key, facet, params);
31
+ * }
32
+ * );
33
+ * ```
34
+ */
35
+ export function createFacetWrapper<
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
+ coordinate: Coordinate<S, L1, L2, L3, L4, L5>,
44
+ implementation: FacetOperationMethod<S, L1, L2, L3, L4, L5>,
45
+ options: WrapperOptions = {}
46
+ ): FacetOperationMethod<S, L1, L2, L3, L4, L5> {
47
+
48
+ const operationName = options.operationName || 'facet';
49
+
50
+ return async (
51
+ key: PriKey<S> | ComKey<S, L1, L2, L3, L4, L5>,
52
+ facet: string,
53
+ params?: OperationParams
54
+ ): Promise<any> => {
55
+
56
+ if (options.debug) {
57
+ logger.debug(`[${operationName}] Called:`, { key, facet, params });
58
+ }
59
+
60
+ // Validate
61
+ if (!options.skipValidation) {
62
+ validateKey(key, coordinate, operationName);
63
+ validateFacetName(facet, operationName);
64
+ validateOperationParams(params, operationName);
65
+ }
66
+
67
+ // Normalize
68
+ const normalizedParams = params ?? {};
69
+
70
+ // Execute
71
+ try {
72
+ const result = await implementation(key, facet, normalizedParams);
73
+
74
+ if (options.debug) {
75
+ logger.debug(`[${operationName}] Facet "${facet}" completed`);
76
+ }
77
+
78
+ return result;
79
+
80
+ } catch (error) {
81
+ if (options.onError) {
82
+ const context: ErrorContext = {
83
+ operationName,
84
+ params: [key, facet, params],
85
+ coordinate
86
+ };
87
+ throw options.onError(error as Error, context);
88
+ }
89
+
90
+ throw new Error(
91
+ `[${operationName}] Facet "${facet}" failed: ${(error as Error).message}`,
92
+ { cause: error }
93
+ );
94
+ }
95
+ };
96
+ }
97
+
@@ -0,0 +1,105 @@
1
+ /**
2
+ * Wrapper for findOne() operation
3
+ *
4
+ * Provides automatic validation for findOne() operation parameters.
5
+ */
6
+
7
+ import type { Item } from "../../items";
8
+ import type { LocKeyArray } from "../../keys";
9
+ import type { Coordinate } from "../../Coordinate";
10
+ import type { OperationParams } from "../Operations";
11
+ import { validateFinderName, validateLocations, validateOperationParams, validatePK } from "../../validation";
12
+ import type { FindOneMethod } from "../methods";
13
+ import type { ErrorContext, WrapperOptions } from "./types";
14
+ import LibLogger from "../../logger";
15
+
16
+ const logger = LibLogger.get('operations', 'wrappers', 'findOne');
17
+
18
+ /**
19
+ * Creates a wrapped findOne() method with automatic parameter validation.
20
+ *
21
+ * @param coordinate - The coordinate defining the item hierarchy
22
+ * @param implementation - The core logic for the operation
23
+ * @param options - Optional configuration
24
+ * @returns A fully validated findOne() method
25
+ *
26
+ * @example
27
+ * ```typescript
28
+ * const findOne = createFindOneWrapper(
29
+ * coordinate,
30
+ * async (finder, params, locations) => {
31
+ * return await database.executeFinderOne(finder, params, locations);
32
+ * }
33
+ * );
34
+ * ```
35
+ */
36
+ export function createFindOneWrapper<
37
+ V extends Item<S, L1, L2, L3, L4, L5>,
38
+ S extends string,
39
+ L1 extends string = never,
40
+ L2 extends string = never,
41
+ L3 extends string = never,
42
+ L4 extends string = never,
43
+ L5 extends string = never
44
+ >(
45
+ coordinate: Coordinate<S, L1, L2, L3, L4, L5>,
46
+ implementation: FindOneMethod<V, S, L1, L2, L3, L4, L5>,
47
+ options: WrapperOptions = {}
48
+ ): FindOneMethod<V, S, L1, L2, L3, L4, L5> {
49
+
50
+ const operationName = options.operationName || 'findOne';
51
+
52
+ return async (
53
+ finder: string,
54
+ params?: OperationParams,
55
+ locations?: LocKeyArray<L1, L2, L3, L4, L5> | []
56
+ ): Promise<V | null> => {
57
+
58
+ if (options.debug) {
59
+ logger.debug(`[${operationName}] Called:`, { finder, params, locations });
60
+ }
61
+
62
+ // Validate
63
+ if (!options.skipValidation) {
64
+ validateFinderName(finder, operationName);
65
+ validateOperationParams(params, operationName);
66
+ validateLocations(locations, coordinate, operationName);
67
+ }
68
+
69
+ // Normalize
70
+ const normalizedParams = params ?? {};
71
+ const normalizedLocations = (locations ?? []) as LocKeyArray<L1, L2, L3, L4, L5> | [];
72
+
73
+ // Execute
74
+ try {
75
+ const result = await implementation(finder, normalizedParams, normalizedLocations);
76
+
77
+ if (options.debug) {
78
+ logger.debug(`[${operationName}] Result for finder "${finder}":`, result ? 'found' : 'not found');
79
+ }
80
+
81
+ // Validate primary key type if result exists
82
+ if (result && !options.skipValidation) {
83
+ return validatePK(result, coordinate.kta[0]) as V;
84
+ }
85
+
86
+ return result;
87
+
88
+ } catch (error) {
89
+ if (options.onError) {
90
+ const context: ErrorContext = {
91
+ operationName,
92
+ params: [finder, params, locations],
93
+ coordinate
94
+ };
95
+ throw options.onError(error as Error, context);
96
+ }
97
+
98
+ throw new Error(
99
+ `[${operationName}] Operation failed for finder "${finder}": ${(error as Error).message}`,
100
+ { cause: error }
101
+ );
102
+ }
103
+ };
104
+ }
105
+