@e22m4u/js-repository 0.0.31

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 (183) hide show
  1. package/.c8rc +9 -0
  2. package/.commitlintrc +5 -0
  3. package/.editorconfig +13 -0
  4. package/.eslintignore +1 -0
  5. package/.eslintrc.cjs +27 -0
  6. package/.husky/commit-msg +4 -0
  7. package/.husky/pre-commit +9 -0
  8. package/.mocharc.cjs +7 -0
  9. package/.prettierrc +7 -0
  10. package/LICENSE +21 -0
  11. package/README.md +523 -0
  12. package/mocha.setup.js +10 -0
  13. package/package.json +57 -0
  14. package/src/adapter/adapter-loader.d.ts +16 -0
  15. package/src/adapter/adapter-loader.js +63 -0
  16. package/src/adapter/adapter-loader.spec.js +31 -0
  17. package/src/adapter/adapter-registry.d.ts +14 -0
  18. package/src/adapter/adapter-registry.js +36 -0
  19. package/src/adapter/adapter-registry.spec.js +36 -0
  20. package/src/adapter/adapter.d.ts +118 -0
  21. package/src/adapter/adapter.js +181 -0
  22. package/src/adapter/adapter.spec.js +144 -0
  23. package/src/adapter/builtin/memory-adapter.d.ts +118 -0
  24. package/src/adapter/builtin/memory-adapter.js +342 -0
  25. package/src/adapter/builtin/memory-adapter.spec.js +2925 -0
  26. package/src/adapter/decorator/data-sanitizing-decorator.d.ts +13 -0
  27. package/src/adapter/decorator/data-sanitizing-decorator.js +44 -0
  28. package/src/adapter/decorator/data-sanitizing-decorator.spec.js +59 -0
  29. package/src/adapter/decorator/data-validation-decorator.d.ts +13 -0
  30. package/src/adapter/decorator/data-validation-decorator.js +41 -0
  31. package/src/adapter/decorator/data-validation-decorator.spec.js +59 -0
  32. package/src/adapter/decorator/default-values-decorator.d.ts +13 -0
  33. package/src/adapter/decorator/default-values-decorator.js +57 -0
  34. package/src/adapter/decorator/default-values-decorator.spec.js +141 -0
  35. package/src/adapter/decorator/fields-filtering-decorator.d.ts +13 -0
  36. package/src/adapter/decorator/fields-filtering-decorator.js +72 -0
  37. package/src/adapter/decorator/fields-filtering-decorator.spec.js +119 -0
  38. package/src/adapter/decorator/inclusion-decorator.d.ts +13 -0
  39. package/src/adapter/decorator/inclusion-decorator.js +78 -0
  40. package/src/adapter/decorator/inclusion-decorator.spec.js +117 -0
  41. package/src/adapter/decorator/index.d.ts +5 -0
  42. package/src/adapter/decorator/index.js +5 -0
  43. package/src/adapter/index.d.ts +3 -0
  44. package/src/adapter/index.js +3 -0
  45. package/src/definition/datasource/datasource-definition-validator.d.ts +14 -0
  46. package/src/definition/datasource/datasource-definition-validator.js +33 -0
  47. package/src/definition/datasource/datasource-definition-validator.spec.js +63 -0
  48. package/src/definition/datasource/datasource-definition.d.ts +7 -0
  49. package/src/definition/datasource/index.d.ts +2 -0
  50. package/src/definition/datasource/index.js +1 -0
  51. package/src/definition/definition-registry.d.ts +50 -0
  52. package/src/definition/definition-registry.js +98 -0
  53. package/src/definition/definition-registry.spec.js +78 -0
  54. package/src/definition/index.d.ts +3 -0
  55. package/src/definition/index.js +3 -0
  56. package/src/definition/model/index.d.ts +7 -0
  57. package/src/definition/model/index.js +6 -0
  58. package/src/definition/model/model-data-sanitizer.d.ts +15 -0
  59. package/src/definition/model/model-data-sanitizer.js +33 -0
  60. package/src/definition/model/model-data-validator.d.ts +32 -0
  61. package/src/definition/model/model-data-validator.js +144 -0
  62. package/src/definition/model/model-data-validator.spec.js +1889 -0
  63. package/src/definition/model/model-definition-utils.d.ts +161 -0
  64. package/src/definition/model/model-definition-utils.js +371 -0
  65. package/src/definition/model/model-definition-utils.spec.js +1474 -0
  66. package/src/definition/model/model-definition-validator.d.ts +14 -0
  67. package/src/definition/model/model-definition-validator.js +83 -0
  68. package/src/definition/model/model-definition-validator.spec.js +143 -0
  69. package/src/definition/model/model-definition.d.ts +28 -0
  70. package/src/definition/model/properties/data-type.d.ts +11 -0
  71. package/src/definition/model/properties/data-type.js +11 -0
  72. package/src/definition/model/properties/default-values-definition-validator.d.ts +15 -0
  73. package/src/definition/model/properties/default-values-definition-validator.js +53 -0
  74. package/src/definition/model/properties/default-values-definition-validator.spec.js +136 -0
  75. package/src/definition/model/properties/index.d.ts +5 -0
  76. package/src/definition/model/properties/index.js +4 -0
  77. package/src/definition/model/properties/primary-keys-definition-validator.d.ts +15 -0
  78. package/src/definition/model/properties/primary-keys-definition-validator.js +55 -0
  79. package/src/definition/model/properties/primary-keys-definition-validator.spec.js +145 -0
  80. package/src/definition/model/properties/properties-definition-validator.d.ts +15 -0
  81. package/src/definition/model/properties/properties-definition-validator.js +194 -0
  82. package/src/definition/model/properties/properties-definition-validator.spec.js +373 -0
  83. package/src/definition/model/properties/property-definition.d.ts +20 -0
  84. package/src/definition/model/relations/index.d.ts +3 -0
  85. package/src/definition/model/relations/index.js +2 -0
  86. package/src/definition/model/relations/relation-definition.d.ts +254 -0
  87. package/src/definition/model/relations/relation-type.d.ts +9 -0
  88. package/src/definition/model/relations/relation-type.js +9 -0
  89. package/src/definition/model/relations/relations-definition-validator.d.ts +15 -0
  90. package/src/definition/model/relations/relations-definition-validator.js +449 -0
  91. package/src/definition/model/relations/relations-definition-validator.spec.js +772 -0
  92. package/src/errors/index.d.ts +3 -0
  93. package/src/errors/index.js +3 -0
  94. package/src/errors/invalid-argument-error.d.ts +6 -0
  95. package/src/errors/invalid-argument-error.js +6 -0
  96. package/src/errors/invalid-argument-error.spec.js +33 -0
  97. package/src/errors/invalid-operator-value-error.d.ts +13 -0
  98. package/src/errors/invalid-operator-value-error.js +24 -0
  99. package/src/errors/invalid-operator-value-error.spec.js +11 -0
  100. package/src/errors/not-implemented-error.d.ts +6 -0
  101. package/src/errors/not-implemented-error.js +6 -0
  102. package/src/errors/not-implemented-error.spec.js +33 -0
  103. package/src/filter/fields-clause-tool.d.ts +38 -0
  104. package/src/filter/fields-clause-tool.js +88 -0
  105. package/src/filter/fields-clause-tool.spec.js +133 -0
  106. package/src/filter/filter.d.ts +335 -0
  107. package/src/filter/include-clause-tool.d.ts +53 -0
  108. package/src/filter/include-clause-tool.js +364 -0
  109. package/src/filter/include-clause-tool.spec.js +653 -0
  110. package/src/filter/index.d.ts +7 -0
  111. package/src/filter/index.js +6 -0
  112. package/src/filter/operator-clause-tool.d.ts +223 -0
  113. package/src/filter/operator-clause-tool.js +515 -0
  114. package/src/filter/operator-clause-tool.spec.js +1064 -0
  115. package/src/filter/order-clause-tool.d.ts +32 -0
  116. package/src/filter/order-clause-tool.js +97 -0
  117. package/src/filter/order-clause-tool.spec.js +438 -0
  118. package/src/filter/slice-clause-tool.d.ts +30 -0
  119. package/src/filter/slice-clause-tool.js +65 -0
  120. package/src/filter/slice-clause-tool.spec.js +117 -0
  121. package/src/filter/where-clause-tool.d.ts +23 -0
  122. package/src/filter/where-clause-tool.js +165 -0
  123. package/src/filter/where-clause-tool.spec.js +280 -0
  124. package/src/index.d.ts +9 -0
  125. package/src/index.js +8 -0
  126. package/src/relations/belongs-to-resolver.d.ts +46 -0
  127. package/src/relations/belongs-to-resolver.js +242 -0
  128. package/src/relations/belongs-to-resolver.spec.js +1047 -0
  129. package/src/relations/has-many-resolver.d.ts +67 -0
  130. package/src/relations/has-many-resolver.js +317 -0
  131. package/src/relations/has-many-resolver.spec.js +2911 -0
  132. package/src/relations/has-one-resolver.d.ts +67 -0
  133. package/src/relations/has-one-resolver.js +311 -0
  134. package/src/relations/has-one-resolver.spec.js +2274 -0
  135. package/src/relations/index.d.ts +4 -0
  136. package/src/relations/index.js +4 -0
  137. package/src/relations/references-many-resolver.d.ts +27 -0
  138. package/src/relations/references-many-resolver.js +113 -0
  139. package/src/relations/references-many-resolver.spec.js +631 -0
  140. package/src/repository/index.d.ts +2 -0
  141. package/src/repository/index.js +2 -0
  142. package/src/repository/repository-registry.d.ts +29 -0
  143. package/src/repository/repository-registry.js +57 -0
  144. package/src/repository/repository-registry.spec.js +38 -0
  145. package/src/repository/repository.d.ts +164 -0
  146. package/src/repository/repository.js +207 -0
  147. package/src/repository/repository.spec.js +202 -0
  148. package/src/schema.d.ts +37 -0
  149. package/src/schema.js +41 -0
  150. package/src/types.d.ts +30 -0
  151. package/src/utils/capitalize.d.ts +6 -0
  152. package/src/utils/capitalize.js +10 -0
  153. package/src/utils/capitalize.spec.js +14 -0
  154. package/src/utils/clone-deep.d.ts +6 -0
  155. package/src/utils/clone-deep.js +61 -0
  156. package/src/utils/clone-deep.spec.js +28 -0
  157. package/src/utils/exclude-object-keys.d.ts +10 -0
  158. package/src/utils/exclude-object-keys.js +20 -0
  159. package/src/utils/exclude-object-keys.spec.js +49 -0
  160. package/src/utils/get-ctor-name.d.ts +6 -0
  161. package/src/utils/get-ctor-name.js +11 -0
  162. package/src/utils/get-ctor-name.spec.js +17 -0
  163. package/src/utils/get-value-by-path.d.ts +12 -0
  164. package/src/utils/get-value-by-path.js +23 -0
  165. package/src/utils/get-value-by-path.spec.js +36 -0
  166. package/src/utils/index.d.ts +10 -0
  167. package/src/utils/index.js +10 -0
  168. package/src/utils/is-ctor.d.ts +7 -0
  169. package/src/utils/is-ctor.js +10 -0
  170. package/src/utils/is-ctor.spec.js +26 -0
  171. package/src/utils/is-pure-object.d.ts +6 -0
  172. package/src/utils/is-pure-object.js +15 -0
  173. package/src/utils/is-pure-object.spec.js +25 -0
  174. package/src/utils/select-object-keys.d.ts +10 -0
  175. package/src/utils/select-object-keys.js +37 -0
  176. package/src/utils/select-object-keys.spec.js +40 -0
  177. package/src/utils/singularize.d.ts +6 -0
  178. package/src/utils/singularize.js +22 -0
  179. package/src/utils/singularize.spec.js +23 -0
  180. package/src/utils/string-to-regexp.d.ts +10 -0
  181. package/src/utils/string-to-regexp.js +22 -0
  182. package/src/utils/string-to-regexp.spec.js +35 -0
  183. package/tsconfig.json +9 -0
@@ -0,0 +1,242 @@
1
+ import {Service} from '@e22m4u/js-service';
2
+ import {cloneDeep} from '../utils/index.js';
3
+ import {singularize} from '../utils/index.js';
4
+ import {InvalidArgumentError} from '../errors/index.js';
5
+ import {RepositoryRegistry} from '../repository/index.js';
6
+ import {ModelDefinitionUtils} from '../definition/index.js';
7
+
8
+ /**
9
+ * Belongs to resolver.
10
+ */
11
+ export class BelongsToResolver extends Service {
12
+ /**
13
+ * Include to.
14
+ *
15
+ * @param {object[]} entities
16
+ * @param {string} sourceName
17
+ * @param {string} targetName
18
+ * @param {string} relationName
19
+ * @param {string|undefined} foreignKey
20
+ * @param {object|undefined} scope
21
+ * @returns {Promise<void>}
22
+ */
23
+ async includeTo(
24
+ entities,
25
+ sourceName,
26
+ targetName,
27
+ relationName,
28
+ foreignKey = undefined,
29
+ scope = undefined,
30
+ ) {
31
+ if (!entities || !Array.isArray(entities))
32
+ throw new InvalidArgumentError(
33
+ 'The parameter "entities" of BelongsToResolver.includeTo requires ' +
34
+ 'an Array of Object, but %v given.',
35
+ entities,
36
+ );
37
+ if (!sourceName || typeof sourceName !== 'string')
38
+ throw new InvalidArgumentError(
39
+ 'The parameter "sourceName" of BelongsToResolver.includeTo requires ' +
40
+ 'a non-empty String, but %v given.',
41
+ sourceName,
42
+ );
43
+ if (!targetName || typeof targetName !== 'string')
44
+ throw new InvalidArgumentError(
45
+ 'The parameter "targetName" of BelongsToResolver.includeTo requires ' +
46
+ 'a non-empty String, but %v given.',
47
+ targetName,
48
+ );
49
+ if (!relationName || typeof relationName !== 'string')
50
+ throw new InvalidArgumentError(
51
+ 'The parameter "relationName" of BelongsToResolver.includeTo requires ' +
52
+ 'a non-empty String, but %v given.',
53
+ relationName,
54
+ );
55
+ if (foreignKey && typeof foreignKey !== 'string')
56
+ throw new InvalidArgumentError(
57
+ 'The provided parameter "foreignKey" of BelongsToResolver.includeTo ' +
58
+ 'should be a String, but %v given.',
59
+ foreignKey,
60
+ );
61
+ if (scope && (typeof scope !== 'object' || Array.isArray(scope)))
62
+ throw new InvalidArgumentError(
63
+ 'The provided parameter "scope" of BelongsToResolver.includeTo ' +
64
+ 'should be an Object, but %v given.',
65
+ scope,
66
+ );
67
+ if (foreignKey == null) foreignKey = `${relationName}Id`;
68
+ const targetIds = entities.reduce((acc, entity) => {
69
+ if (!entity || typeof entity !== 'object' || Array.isArray(entity))
70
+ throw new InvalidArgumentError(
71
+ 'The parameter "entities" of BelongsToResolver.includeTo requires ' +
72
+ 'an Array of Object, but %v given.',
73
+ entity,
74
+ );
75
+ const targetId = entity[foreignKey];
76
+ return targetId != null ? [...acc, targetId] : acc;
77
+ }, []);
78
+ const targetRepository =
79
+ this.getService(RepositoryRegistry).getRepository(targetName);
80
+ const targetPkPropName =
81
+ this.getService(ModelDefinitionUtils).getPrimaryKeyAsPropertyName(
82
+ targetName,
83
+ );
84
+ scope = scope ? cloneDeep(scope) : {};
85
+ const filter = cloneDeep(scope);
86
+ filter.where = {
87
+ and: [
88
+ {[targetPkPropName]: {inq: targetIds}},
89
+ ...(scope.where ? [scope.where] : []),
90
+ ],
91
+ };
92
+ const targets = await targetRepository.find(filter);
93
+ entities.forEach(entity => {
94
+ const target = targets.find(
95
+ e => e[targetPkPropName] === entity[foreignKey],
96
+ );
97
+ if (target) entity[relationName] = target;
98
+ });
99
+ }
100
+
101
+ /**
102
+ * Include polymorphic to.
103
+ *
104
+ * @param {object[]} entities
105
+ * @param {string} sourceName
106
+ * @param {string} relationName
107
+ * @param {string|undefined} foreignKey
108
+ * @param {string|undefined} discriminator
109
+ * @param {object|undefined} scope
110
+ * @returns {Promise<void>}
111
+ */
112
+ async includePolymorphicTo(
113
+ entities,
114
+ sourceName,
115
+ relationName,
116
+ foreignKey = undefined,
117
+ discriminator = undefined,
118
+ scope = undefined,
119
+ ) {
120
+ if (!entities || !Array.isArray(entities))
121
+ throw new InvalidArgumentError(
122
+ 'The parameter "entities" of BelongsToResolver.includePolymorphicTo ' +
123
+ 'requires an Array of Object, but %v given.',
124
+ entities,
125
+ );
126
+ if (!sourceName || typeof sourceName !== 'string')
127
+ throw new InvalidArgumentError(
128
+ 'The parameter "sourceName" of BelongsToResolver.includePolymorphicTo ' +
129
+ 'requires a non-empty String, but %v given.',
130
+ sourceName,
131
+ );
132
+ if (!relationName || typeof relationName !== 'string')
133
+ throw new InvalidArgumentError(
134
+ 'The parameter "relationName" of BelongsToResolver.includePolymorphicTo ' +
135
+ 'requires a non-empty String, but %v given.',
136
+ relationName,
137
+ );
138
+ if (foreignKey && typeof foreignKey !== 'string')
139
+ throw new InvalidArgumentError(
140
+ 'The provided parameter "foreignKey" of BelongsToResolver.includePolymorphicTo ' +
141
+ 'should be a String, but %v given.',
142
+ foreignKey,
143
+ );
144
+ if (discriminator && typeof discriminator !== 'string')
145
+ throw new InvalidArgumentError(
146
+ 'The provided parameter "discriminator" of BelongsToResolver.includePolymorphicTo ' +
147
+ 'should be a String, but %v given.',
148
+ discriminator,
149
+ );
150
+ if (scope && (typeof scope !== 'object' || Array.isArray(scope)))
151
+ throw new InvalidArgumentError(
152
+ 'The provided parameter "scope" of BelongsToResolver.includePolymorphicTo ' +
153
+ 'should be an Object, but %v given.',
154
+ scope,
155
+ );
156
+ if (foreignKey == null) {
157
+ const singularRelationName = singularize(relationName);
158
+ foreignKey = `${singularRelationName}Id`;
159
+ }
160
+ if (discriminator == null) {
161
+ const singularRelationName = singularize(relationName);
162
+ discriminator = `${singularRelationName}Type`;
163
+ }
164
+ const targetIdsByTargetName = {};
165
+ entities.forEach(entity => {
166
+ if (!entity || typeof entity !== 'object' || Array.isArray(entity))
167
+ throw new InvalidArgumentError(
168
+ 'The parameter "entities" of BelongsToResolver.includePolymorphicTo requires ' +
169
+ 'an Array of Object, but %v given.',
170
+ entity,
171
+ );
172
+ const targetId = entity[foreignKey];
173
+ const targetName = entity[discriminator];
174
+ if (targetId == null || targetName == null) return;
175
+ if (targetIdsByTargetName[targetName] == null)
176
+ targetIdsByTargetName[targetName] = [];
177
+ if (!targetIdsByTargetName[targetName].includes(targetId))
178
+ targetIdsByTargetName[targetName].push(targetId);
179
+ });
180
+ const promises = [];
181
+ const targetNames = Object.keys(targetIdsByTargetName);
182
+ scope = scope ? cloneDeep(scope) : {};
183
+ const targetEntitiesByTargetNames = {};
184
+ targetNames.forEach(targetName => {
185
+ let targetRepository;
186
+ try {
187
+ targetRepository =
188
+ this.getService(RepositoryRegistry).getRepository(targetName);
189
+ } catch (error) {
190
+ if (error instanceof InvalidArgumentError) {
191
+ if (
192
+ error.message === `The model "${targetName}" is not defined.` ||
193
+ error.message ===
194
+ `The model "${targetName}" does not have a specified datasource.`
195
+ ) {
196
+ return;
197
+ }
198
+ } else {
199
+ throw error;
200
+ }
201
+ }
202
+ const targetPkPropName =
203
+ this.getService(ModelDefinitionUtils).getPrimaryKeyAsPropertyName(
204
+ targetName,
205
+ );
206
+ const targetFilter = cloneDeep(scope);
207
+ const targetIds = targetIdsByTargetName[targetName];
208
+ targetFilter.where = {
209
+ and: [
210
+ {[targetPkPropName]: {inq: targetIds}},
211
+ ...(scope.where ? [scope.where] : []),
212
+ ],
213
+ };
214
+ const promise = targetRepository.find(targetFilter).then(result => {
215
+ targetEntitiesByTargetNames[targetName] = [
216
+ ...(targetEntitiesByTargetNames[targetName] ?? []),
217
+ ...result,
218
+ ];
219
+ });
220
+ promises.push(promise);
221
+ });
222
+ await Promise.all(promises);
223
+ entities.forEach(entity => {
224
+ const targetId = entity[foreignKey];
225
+ const targetName = entity[discriminator];
226
+ if (
227
+ targetId == null ||
228
+ targetName == null ||
229
+ targetEntitiesByTargetNames[targetName] == null
230
+ ) {
231
+ return;
232
+ }
233
+ const targetEntities = targetEntitiesByTargetNames[targetName] ?? [];
234
+ const targetPkPropName =
235
+ this.getService(ModelDefinitionUtils).getPrimaryKeyAsPropertyName(
236
+ targetName,
237
+ );
238
+ const target = targetEntities.find(e => e[targetPkPropName] === targetId);
239
+ if (target) entity[relationName] = target;
240
+ });
241
+ }
242
+ }