@loopback/repository 4.1.1 → 5.0.1

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 (250) hide show
  1. package/LICENSE +1 -1
  2. package/dist/connectors/connector.js +1 -1
  3. package/dist/connectors/connector.js.map +1 -1
  4. package/dist/connectors/crud.connector.js +1 -1
  5. package/dist/connectors/crud.connector.js.map +1 -1
  6. package/dist/connectors/index.js +4 -4
  7. package/dist/connectors/index.js.map +1 -1
  8. package/dist/connectors/kv.connector.js +1 -1
  9. package/dist/connectors/kv.connector.js.map +1 -1
  10. package/dist/datasource.js +1 -1
  11. package/dist/datasource.js.map +1 -1
  12. package/dist/decorators/index.js +4 -4
  13. package/dist/decorators/index.js.map +1 -1
  14. package/dist/decorators/metadata.js +1 -1
  15. package/dist/decorators/metadata.js.map +1 -1
  16. package/dist/decorators/model.decorator.js +1 -1
  17. package/dist/decorators/model.decorator.js.map +1 -1
  18. package/dist/decorators/repository.decorator.js +2 -2
  19. package/dist/decorators/repository.decorator.js.map +1 -1
  20. package/dist/define-model-class.js +2 -2
  21. package/dist/define-model-class.js.map +1 -1
  22. package/dist/define-repository-class.js +2 -2
  23. package/dist/define-repository-class.js.map +1 -1
  24. package/dist/errors/entity-not-found.error.js +1 -1
  25. package/dist/errors/entity-not-found.error.js.map +1 -1
  26. package/dist/errors/index.d.ts +1 -0
  27. package/dist/errors/index.js +4 -3
  28. package/dist/errors/index.js.map +1 -1
  29. package/dist/errors/invalid-polymorphism.error.d.ts +5 -0
  30. package/dist/errors/invalid-polymorphism.error.js +22 -0
  31. package/dist/errors/invalid-polymorphism.error.js.map +1 -0
  32. package/dist/errors/invalid-relation.error.d.ts +1 -1
  33. package/dist/errors/invalid-relation.error.js +1 -1
  34. package/dist/errors/invalid-relation.error.js.map +1 -1
  35. package/dist/index.js +17 -17
  36. package/dist/index.js.map +1 -1
  37. package/dist/mixins/index.js +2 -2
  38. package/dist/mixins/index.js.map +1 -1
  39. package/dist/mixins/repository.mixin.d.ts +49 -50
  40. package/dist/mixins/repository.mixin.js +2 -2
  41. package/dist/mixins/repository.mixin.js.map +1 -1
  42. package/dist/model.d.ts +7 -1
  43. package/dist/model.js +15 -1
  44. package/dist/model.js.map +1 -1
  45. package/dist/relations/belongs-to/belongs-to.accessor.d.ts +6 -2
  46. package/dist/relations/belongs-to/belongs-to.accessor.js +20 -7
  47. package/dist/relations/belongs-to/belongs-to.accessor.js.map +1 -1
  48. package/dist/relations/belongs-to/belongs-to.decorator.js +1 -1
  49. package/dist/relations/belongs-to/belongs-to.decorator.js.map +1 -1
  50. package/dist/relations/belongs-to/belongs-to.helpers.d.ts +3 -0
  51. package/dist/relations/belongs-to/belongs-to.helpers.js +34 -10
  52. package/dist/relations/belongs-to/belongs-to.helpers.js.map +1 -1
  53. package/dist/relations/belongs-to/belongs-to.inclusion-resolver.d.ts +5 -2
  54. package/dist/relations/belongs-to/belongs-to.inclusion-resolver.js +82 -9
  55. package/dist/relations/belongs-to/belongs-to.inclusion-resolver.js.map +1 -1
  56. package/dist/relations/belongs-to/belongs-to.repository.d.ts +28 -5
  57. package/dist/relations/belongs-to/belongs-to.repository.js +50 -11
  58. package/dist/relations/belongs-to/belongs-to.repository.js.map +1 -1
  59. package/dist/relations/belongs-to/index.d.ts +2 -2
  60. package/dist/relations/belongs-to/index.js +5 -5
  61. package/dist/relations/belongs-to/index.js.map +1 -1
  62. package/dist/relations/has-many/has-many-through.helpers.d.ts +3 -0
  63. package/dist/relations/has-many/has-many-through.helpers.js +27 -3
  64. package/dist/relations/has-many/has-many-through.helpers.js.map +1 -1
  65. package/dist/relations/has-many/has-many-through.inclusion-resolver.d.ts +3 -1
  66. package/dist/relations/has-many/has-many-through.inclusion-resolver.js +94 -23
  67. package/dist/relations/has-many/has-many-through.inclusion-resolver.js.map +1 -1
  68. package/dist/relations/has-many/has-many-through.repository-factory.d.ts +3 -1
  69. package/dist/relations/has-many/has-many-through.repository-factory.js +8 -2
  70. package/dist/relations/has-many/has-many-through.repository-factory.js.map +1 -1
  71. package/dist/relations/has-many/has-many-through.repository.d.ts +66 -11
  72. package/dist/relations/has-many/has-many-through.repository.js +212 -36
  73. package/dist/relations/has-many/has-many-through.repository.js.map +1 -1
  74. package/dist/relations/has-many/has-many.decorator.js +1 -1
  75. package/dist/relations/has-many/has-many.decorator.js.map +1 -1
  76. package/dist/relations/has-many/has-many.helpers.js +2 -2
  77. package/dist/relations/has-many/has-many.helpers.js.map +1 -1
  78. package/dist/relations/has-many/has-many.inclusion-resolver.js +2 -2
  79. package/dist/relations/has-many/has-many.inclusion-resolver.js.map +1 -1
  80. package/dist/relations/has-many/has-many.repository-factory.js +2 -2
  81. package/dist/relations/has-many/has-many.repository-factory.js.map +1 -1
  82. package/dist/relations/has-many/has-many.repository.js +1 -1
  83. package/dist/relations/has-many/has-many.repository.js.map +1 -1
  84. package/dist/relations/has-many/index.d.ts +2 -2
  85. package/dist/relations/has-many/index.js +7 -7
  86. package/dist/relations/has-many/index.js.map +1 -1
  87. package/dist/relations/has-one/has-one.decorator.js +1 -1
  88. package/dist/relations/has-one/has-one.decorator.js.map +1 -1
  89. package/dist/relations/has-one/has-one.helpers.d.ts +3 -0
  90. package/dist/relations/has-one/has-one.helpers.js +36 -10
  91. package/dist/relations/has-one/has-one.helpers.js.map +1 -1
  92. package/dist/relations/has-one/has-one.inclusion-resolver.d.ts +6 -3
  93. package/dist/relations/has-one/has-one.inclusion-resolver.js +83 -8
  94. package/dist/relations/has-one/has-one.inclusion-resolver.js.map +1 -1
  95. package/dist/relations/has-one/has-one.repository-factory.d.ts +9 -3
  96. package/dist/relations/has-one/has-one.repository-factory.js +15 -5
  97. package/dist/relations/has-one/has-one.repository-factory.js.map +1 -1
  98. package/dist/relations/has-one/has-one.repository.d.ts +58 -11
  99. package/dist/relations/has-one/has-one.repository.js +119 -16
  100. package/dist/relations/has-one/has-one.repository.js.map +1 -1
  101. package/dist/relations/has-one/index.js +4 -4
  102. package/dist/relations/has-one/index.js.map +1 -1
  103. package/dist/relations/index.d.ts +2 -0
  104. package/dist/relations/index.js +9 -7
  105. package/dist/relations/index.js.map +1 -1
  106. package/dist/relations/references-many/index.d.ts +4 -0
  107. package/dist/relations/references-many/index.js +12 -0
  108. package/dist/relations/references-many/index.js.map +1 -0
  109. package/dist/relations/references-many/references-many.accessor.d.ts +17 -0
  110. package/dist/relations/references-many/references-many.accessor.js +40 -0
  111. package/dist/relations/references-many/references-many.accessor.js.map +1 -0
  112. package/dist/relations/references-many/references-many.decorator.d.ts +11 -0
  113. package/dist/relations/references-many/references-many.decorator.js +73 -0
  114. package/dist/relations/references-many/references-many.decorator.js.map +1 -0
  115. package/dist/relations/references-many/references-many.helpers.d.ts +17 -0
  116. package/dist/relations/references-many/references-many.helpers.js +63 -0
  117. package/dist/relations/references-many/references-many.helpers.js.map +1 -0
  118. package/dist/relations/references-many/references-many.inclusion-resolver.d.ts +14 -0
  119. package/dist/relations/references-many/references-many.inclusion-resolver.js +42 -0
  120. package/dist/relations/references-many/references-many.inclusion-resolver.js.map +1 -0
  121. package/dist/relations/references-many/references-many.repository.d.ts +28 -0
  122. package/dist/relations/references-many/references-many.repository.js +33 -0
  123. package/dist/relations/references-many/references-many.repository.js.map +1 -0
  124. package/dist/relations/relation.decorator.d.ts +0 -6
  125. package/dist/relations/relation.decorator.js +2 -14
  126. package/dist/relations/relation.decorator.js.map +1 -1
  127. package/dist/relations/relation.filter.solver.d.ts +2 -0
  128. package/dist/relations/relation.filter.solver.js +57 -0
  129. package/dist/relations/relation.filter.solver.js.map +1 -0
  130. package/dist/relations/relation.helpers.js +20 -5
  131. package/dist/relations/relation.helpers.js.map +1 -1
  132. package/dist/relations/relation.types.d.ts +52 -1
  133. package/dist/relations/relation.types.js +1 -1
  134. package/dist/relations/relation.types.js.map +1 -1
  135. package/dist/repositories/constraint-utils.js +1 -1
  136. package/dist/repositories/constraint-utils.js.map +1 -1
  137. package/dist/repositories/index.d.ts +2 -2
  138. package/dist/repositories/index.js +6 -6
  139. package/dist/repositories/index.js.map +1 -1
  140. package/dist/repositories/kv.repository.bridge.js +1 -1
  141. package/dist/repositories/kv.repository.bridge.js.map +1 -1
  142. package/dist/repositories/kv.repository.d.ts +2 -2
  143. package/dist/repositories/kv.repository.js +1 -1
  144. package/dist/repositories/kv.repository.js.map +1 -1
  145. package/dist/repositories/legacy-juggler-bridge.d.ts +35 -8
  146. package/dist/repositories/legacy-juggler-bridge.js +39 -17
  147. package/dist/repositories/legacy-juggler-bridge.js.map +1 -1
  148. package/dist/repositories/repository.js +1 -1
  149. package/dist/repositories/repository.js.map +1 -1
  150. package/dist/type-resolver.js +1 -1
  151. package/dist/type-resolver.js.map +1 -1
  152. package/dist/types/any.js +1 -1
  153. package/dist/types/any.js.map +1 -1
  154. package/dist/types/array.js +2 -2
  155. package/dist/types/array.js.map +1 -1
  156. package/dist/types/boolean.js +1 -1
  157. package/dist/types/boolean.js.map +1 -1
  158. package/dist/types/buffer.js +2 -2
  159. package/dist/types/buffer.js.map +1 -1
  160. package/dist/types/date.js +2 -2
  161. package/dist/types/date.js.map +1 -1
  162. package/dist/types/index.js +1 -1
  163. package/dist/types/index.js.map +1 -1
  164. package/dist/types/model.js +1 -1
  165. package/dist/types/model.js.map +1 -1
  166. package/dist/types/null.js +1 -1
  167. package/dist/types/null.js.map +1 -1
  168. package/dist/types/number.js +2 -2
  169. package/dist/types/number.js.map +1 -1
  170. package/dist/types/object.js +2 -2
  171. package/dist/types/object.js.map +1 -1
  172. package/dist/types/string.js +1 -1
  173. package/dist/types/string.js.map +1 -1
  174. package/dist/types/type.js +1 -1
  175. package/dist/types/type.js.map +1 -1
  176. package/dist/types/union.js +2 -2
  177. package/dist/types/union.js.map +1 -1
  178. package/package.json +17 -17
  179. package/src/connectors/connector.ts +1 -1
  180. package/src/connectors/crud.connector.ts +1 -1
  181. package/src/connectors/index.ts +1 -1
  182. package/src/connectors/kv.connector.ts +1 -1
  183. package/src/datasource.ts +1 -1
  184. package/src/decorators/index.ts +1 -1
  185. package/src/decorators/metadata.ts +1 -1
  186. package/src/decorators/model.decorator.ts +1 -1
  187. package/src/decorators/repository.decorator.ts +1 -1
  188. package/src/define-model-class.ts +1 -1
  189. package/src/define-repository-class.ts +1 -1
  190. package/src/errors/entity-not-found.error.ts +1 -1
  191. package/src/errors/index.ts +2 -1
  192. package/src/errors/invalid-polymorphism.error.ts +28 -0
  193. package/src/errors/invalid-relation.error.ts +2 -2
  194. package/src/index.ts +1 -1
  195. package/src/mixins/index.ts +1 -1
  196. package/src/mixins/repository.mixin.ts +1 -6
  197. package/src/model.ts +20 -1
  198. package/src/relations/belongs-to/belongs-to.accessor.ts +36 -7
  199. package/src/relations/belongs-to/belongs-to.decorator.ts +2 -2
  200. package/src/relations/belongs-to/belongs-to.helpers.ts +37 -10
  201. package/src/relations/belongs-to/belongs-to.inclusion-resolver.ts +109 -18
  202. package/src/relations/belongs-to/belongs-to.repository.ts +78 -18
  203. package/src/relations/belongs-to/index.ts +3 -3
  204. package/src/relations/has-many/has-many-through.helpers.ts +28 -2
  205. package/src/relations/has-many/has-many-through.inclusion-resolver.ts +118 -27
  206. package/src/relations/has-many/has-many-through.repository-factory.ts +22 -4
  207. package/src/relations/has-many/has-many-through.repository.ts +344 -77
  208. package/src/relations/has-many/has-many.decorator.ts +1 -1
  209. package/src/relations/has-many/has-many.helpers.ts +1 -1
  210. package/src/relations/has-many/has-many.inclusion-resolver.ts +1 -1
  211. package/src/relations/has-many/has-many.repository-factory.ts +1 -1
  212. package/src/relations/has-many/has-many.repository.ts +1 -1
  213. package/src/relations/has-many/index.ts +3 -3
  214. package/src/relations/has-one/has-one.decorator.ts +1 -1
  215. package/src/relations/has-one/has-one.helpers.ts +41 -14
  216. package/src/relations/has-one/has-one.inclusion-resolver.ts +110 -16
  217. package/src/relations/has-one/has-one.repository-factory.ts +35 -7
  218. package/src/relations/has-one/has-one.repository.ts +189 -36
  219. package/src/relations/has-one/index.ts +1 -1
  220. package/src/relations/index.ts +3 -1
  221. package/src/relations/references-many/index.ts +9 -0
  222. package/src/relations/references-many/references-many.accessor.ts +76 -0
  223. package/src/relations/references-many/references-many.decorator.ts +100 -0
  224. package/src/relations/references-many/references-many.helpers.ts +82 -0
  225. package/src/relations/references-many/references-many.inclusion-resolver.ts +80 -0
  226. package/src/relations/references-many/references-many.repository.ts +55 -0
  227. package/src/relations/relation.decorator.ts +1 -13
  228. package/src/relations/relation.filter.solver.ts +56 -0
  229. package/src/relations/relation.helpers.ts +17 -2
  230. package/src/relations/relation.types.ts +52 -1
  231. package/src/repositories/constraint-utils.ts +1 -1
  232. package/src/repositories/index.ts +3 -3
  233. package/src/repositories/kv.repository.bridge.ts +1 -1
  234. package/src/repositories/kv.repository.ts +3 -3
  235. package/src/repositories/legacy-juggler-bridge.ts +79 -15
  236. package/src/repositories/repository.ts +1 -1
  237. package/src/type-resolver.ts +1 -1
  238. package/src/types/any.ts +1 -1
  239. package/src/types/array.ts +1 -1
  240. package/src/types/boolean.ts +1 -1
  241. package/src/types/buffer.ts +1 -1
  242. package/src/types/date.ts +1 -1
  243. package/src/types/index.ts +1 -1
  244. package/src/types/model.ts +1 -1
  245. package/src/types/null.ts +1 -1
  246. package/src/types/number.ts +1 -1
  247. package/src/types/object.ts +1 -1
  248. package/src/types/string.ts +1 -1
  249. package/src/types/type.ts +1 -1
  250. package/src/types/union.ts +1 -1
@@ -1,4 +1,4 @@
1
- // Copyright IBM Corp. 2020. All Rights Reserved.
1
+ // Copyright IBM Corp. and LoopBack contributors 2020. All Rights Reserved.
2
2
  // Node module: @loopback/repository
3
3
  // This file is licensed under the MIT License.
4
4
  // License text available at https://opensource.org/licenses/MIT
@@ -59,10 +59,22 @@ export function createHasManyThroughRepositoryFactory<
59
59
  SourceID,
60
60
  >(
61
61
  relationMetadata: HasManyDefinition,
62
- targetRepositoryGetter: Getter<EntityCrudRepository<Target, TargetID>>,
62
+ targetRepositoryGetter:
63
+ | Getter<EntityCrudRepository<Target, TargetID>>
64
+ | {
65
+ [repoType: string]: Getter<EntityCrudRepository<Target, TargetID>>;
66
+ },
63
67
  throughRepositoryGetter: Getter<EntityCrudRepository<Through, ThroughID>>,
64
68
  ): HasManyThroughRepositoryFactory<Target, TargetID, Through, SourceID> {
65
69
  const meta = resolveHasManyThroughMetadata(relationMetadata);
70
+ // resolve the repositoryGetter into a dictionary
71
+ if (typeof targetRepositoryGetter === 'function') {
72
+ targetRepositoryGetter = {
73
+ [meta.target().name]: targetRepositoryGetter as Getter<
74
+ EntityCrudRepository<Target, TargetID>
75
+ >,
76
+ };
77
+ }
66
78
  const result = function (fkValue: SourceID) {
67
79
  function getTargetConstraintFromThroughModels(
68
80
  throughInstances: Through[],
@@ -103,19 +115,25 @@ export function createHasManyThroughRepositoryFactory<
103
115
  ThroughID,
104
116
  EntityCrudRepository<Through, ThroughID>
105
117
  >(
106
- targetRepositoryGetter,
118
+ targetRepositoryGetter as {
119
+ [repoType: string]: Getter<EntityCrudRepository<Target, TargetID>>;
120
+ },
107
121
  throughRepositoryGetter,
108
122
  getTargetConstraintFromThroughModels,
109
123
  getTargetKeys,
110
124
  getThroughConstraintFromSource,
111
125
  getTargetIds,
112
126
  getThroughConstraintFromTarget,
127
+ relationMetadata.target,
128
+ relationMetadata.through!.model,
113
129
  );
114
130
  };
115
131
  result.inclusionResolver = createHasManyThroughInclusionResolver(
116
132
  meta,
117
133
  throughRepositoryGetter,
118
- targetRepositoryGetter,
134
+ targetRepositoryGetter as {
135
+ [repoType: string]: Getter<EntityCrudRepository<Target, TargetID>>;
136
+ },
119
137
  );
120
138
  return result;
121
139
  }
@@ -1,8 +1,9 @@
1
- // Copyright IBM Corp. 2019,2020. All Rights Reserved.
1
+ // Copyright IBM Corp. and LoopBack contributors 2019,2020. All Rights Reserved.
2
2
  // Node module: @loopback/repository
3
3
  // This file is licensed under the MIT License.
4
4
  // License text available at https://opensource.org/licenses/MIT
5
5
 
6
+ import {cloneDeep} from 'lodash';
6
7
  import {
7
8
  constrainDataObject,
8
9
  constrainFilter,
@@ -14,7 +15,10 @@ import {
14
15
  EntityCrudRepository,
15
16
  Filter,
16
17
  Getter,
18
+ InvalidPolymorphismError,
17
19
  Options,
20
+ StringKeyOf,
21
+ TypeResolver,
18
22
  Where,
19
23
  } from '../..';
20
24
 
@@ -33,6 +37,8 @@ export interface HasManyThroughRepository<
33
37
  * Create a target model instance
34
38
  * @param targetModelData - The target model data
35
39
  * @param options - Options for the operation
40
+ * options.polymorphicType a string or a string array of polymorphic type names
41
+ * specify of which concrete model the created instance should be
36
42
  * @returns A promise which resolves to the newly created target model instance
37
43
  */
38
44
  create(
@@ -40,33 +46,43 @@ export interface HasManyThroughRepository<
40
46
  options?: Options & {
41
47
  throughData?: DataObject<Through>;
42
48
  throughOptions?: Options;
43
- },
49
+ } & {polymorphicType?: string},
44
50
  ): Promise<Target>;
45
51
 
46
52
  /**
47
53
  * Find target model instance(s)
48
54
  * @param filter - A filter object for where, order, limit, etc.
49
55
  * @param options - Options for the operation
56
+ * options.throughOptions.discriminator - target discriminator field on through
57
+ * options.polymorphicType a string or a string array of polymorphic type names
58
+ * to specify which repositories should are expected to be searched
59
+ * It is highly recommended to contain this param especially for
60
+ * datasources using deplicated ids across tables
50
61
  * @returns A promise which resolves with the found target instance(s)
51
62
  */
52
63
  find(
53
64
  filter?: Filter<Target>,
54
65
  options?: Options & {
55
- throughOptions?: Options;
56
- },
66
+ throughOptions?: Options & {discriminator?: string};
67
+ } & {polymorphicType?: string | string[]},
57
68
  ): Promise<Target[]>;
58
69
 
59
70
  /**
60
71
  * Delete multiple target model instances
61
72
  * @param where - Instances within the where scope are deleted
62
73
  * @param options
74
+ * options.throughOptions.discriminator - target discriminator field on through
75
+ * options.polymorphicType a string or a string array of polymorphic type names
76
+ * to specify which repositories should are expected to be searched
77
+ * It is highly recommended to contain this param especially for
78
+ * datasources using deplicated ids across tables
63
79
  * @returns A promise which resolves the deleted target model instances
64
80
  */
65
81
  delete(
66
82
  where?: Where<Target>,
67
83
  options?: Options & {
68
- throughOptions?: Options;
69
- },
84
+ throughOptions?: Options & {discriminator?: string};
85
+ } & {polymorphicType?: string | string[]},
70
86
  ): Promise<Count>;
71
87
 
72
88
  /**
@@ -74,14 +90,18 @@ export interface HasManyThroughRepository<
74
90
  * @param dataObject - The fields and their new values to patch
75
91
  * @param where - Instances within the where scope are patched
76
92
  * @param options
93
+ * options.throughOptions.discriminator - target discriminator field on through
94
+ * options.isPolymorphic - whether dataObject is a dictionary
77
95
  * @returns A promise which resolves the patched target model instances
78
96
  */
79
97
  patch(
80
- dataObject: DataObject<Target>,
98
+ dataObject:
99
+ | DataObject<Target>
100
+ | {[polymorphicType: string]: DataObject<Target>},
81
101
  where?: Where<Target>,
82
102
  options?: Options & {
83
- throughOptions?: Options;
84
- },
103
+ throughOptions?: Options & {discriminator?: string};
104
+ } & {isPolymorphic?: boolean},
85
105
  ): Promise<Count>;
86
106
 
87
107
  /**
@@ -140,7 +160,11 @@ export class DefaultHasManyThroughRepository<
140
160
  > implements HasManyThroughRepository<TargetEntity, TargetID, ThroughEntity>
141
161
  {
142
162
  constructor(
143
- public getTargetRepository: Getter<TargetRepository>,
163
+ public getTargetRepository:
164
+ | Getter<TargetRepository>
165
+ | {
166
+ [repoType: string]: Getter<TargetRepository>;
167
+ },
144
168
  public getThroughRepository: Getter<ThroughRepository>,
145
169
  public getTargetConstraintFromThroughModels: (
146
170
  throughInstances: ThroughEntity[],
@@ -151,16 +175,52 @@ export class DefaultHasManyThroughRepository<
151
175
  public getThroughConstraintFromTarget: (
152
176
  targetID: TargetID[],
153
177
  ) => DataObject<ThroughEntity>,
154
- ) {}
178
+ public targetResolver: TypeResolver<Entity, typeof Entity>,
179
+ public throughResolver: TypeResolver<Entity, typeof Entity>,
180
+ ) {
181
+ if (typeof getTargetRepository === 'function') {
182
+ this.getTargetRepositoryDict = {
183
+ [targetResolver().name]:
184
+ getTargetRepository as Getter<TargetRepository>,
185
+ };
186
+ } else {
187
+ this.getTargetRepositoryDict = getTargetRepository as {
188
+ [repoType: string]: Getter<TargetRepository>;
189
+ };
190
+ }
191
+ }
192
+
193
+ public getTargetRepositoryDict: {
194
+ [repoType: string]: Getter<TargetRepository>;
195
+ };
155
196
 
156
197
  async create(
157
198
  targetModelData: DataObject<TargetEntity>,
158
199
  options?: Options & {
159
200
  throughData?: DataObject<ThroughEntity>;
160
201
  throughOptions?: Options;
161
- },
202
+ } & {polymorphicType?: string},
162
203
  ): Promise<TargetEntity> {
163
- const targetRepository = await this.getTargetRepository();
204
+ let targetPolymorphicTypeName = options?.polymorphicType;
205
+ if (targetPolymorphicTypeName) {
206
+ if (!this.getTargetRepositoryDict[targetPolymorphicTypeName]) {
207
+ throw new InvalidPolymorphismError(targetPolymorphicTypeName);
208
+ }
209
+ } else {
210
+ if (Object.keys(this.getTargetRepositoryDict).length > 1) {
211
+ console.warn(
212
+ 'It is highly recommended to specify the polymorphicTypes param when using polymorphic types.',
213
+ );
214
+ }
215
+ targetPolymorphicTypeName = this.targetResolver().name;
216
+ if (!this.getTargetRepositoryDict[targetPolymorphicTypeName]) {
217
+ throw new InvalidPolymorphismError(targetPolymorphicTypeName);
218
+ }
219
+ }
220
+
221
+ const targetRepository = await this.getTargetRepositoryDict[
222
+ targetPolymorphicTypeName
223
+ ]();
164
224
  const targetInstance = await targetRepository.create(
165
225
  targetModelData,
166
226
  options,
@@ -172,91 +232,298 @@ export class DefaultHasManyThroughRepository<
172
232
  async find(
173
233
  filter?: Filter<TargetEntity>,
174
234
  options?: Options & {
175
- throughOptions?: Options;
176
- },
235
+ throughOptions?: Options & {discriminator?: string};
236
+ } & {polymorphicType?: string | string[]},
177
237
  ): Promise<TargetEntity[]> {
178
- const targetRepository = await this.getTargetRepository();
179
- const throughRepository = await this.getThroughRepository();
238
+ const targetDiscriminatorOnThrough = options?.throughOptions?.discriminator;
239
+ let targetPolymorphicTypes = options?.polymorphicType;
240
+ let allKeys: string[];
241
+ if (Object.keys(this.getTargetRepositoryDict).length <= 1) {
242
+ allKeys = Object.keys(this.getTargetRepositoryDict);
243
+ } else {
244
+ if (!targetDiscriminatorOnThrough) {
245
+ console.warn(
246
+ 'It is highly recommended to specify the targetDiscriminatorOnThrough param when using polymorphic types.',
247
+ );
248
+ }
249
+ if (!targetPolymorphicTypes || targetPolymorphicTypes.length === 0) {
250
+ console.warn(
251
+ 'It is highly recommended to specify the polymorphicTypes param when using polymorphic types.',
252
+ );
253
+ allKeys = Object.keys(this.getTargetRepositoryDict);
254
+ } else {
255
+ if (typeof targetPolymorphicTypes === 'string') {
256
+ targetPolymorphicTypes = [targetPolymorphicTypes];
257
+ }
258
+ allKeys = [];
259
+ new Set(targetPolymorphicTypes!).forEach(element => {
260
+ if (Object.keys(this.getTargetRepositoryDict).includes(element)) {
261
+ allKeys.push(element);
262
+ }
263
+ });
264
+ }
265
+ }
266
+
180
267
  const sourceConstraint = this.getThroughConstraintFromSource();
181
- const throughInstances = await throughRepository.find(
182
- constrainFilter(undefined, sourceConstraint),
183
- options?.throughOptions,
184
- );
185
- const targetConstraint =
186
- this.getTargetConstraintFromThroughModels(throughInstances);
187
- return targetRepository.find(
188
- constrainFilter(filter, targetConstraint),
189
- options,
190
- );
268
+
269
+ const throughCategorized: {[concreteType: string]: (ThroughEntity & {})[]} =
270
+ {};
271
+ const throughRepository = await this.getThroughRepository();
272
+ (
273
+ await throughRepository.find(
274
+ constrainFilter(undefined, sourceConstraint),
275
+ options?.throughOptions,
276
+ )
277
+ ).forEach(element => {
278
+ let concreteTargetType;
279
+ if (!targetDiscriminatorOnThrough) {
280
+ concreteTargetType = this.targetResolver().name;
281
+ } else {
282
+ concreteTargetType = String(
283
+ element[targetDiscriminatorOnThrough as StringKeyOf<ThroughEntity>],
284
+ );
285
+ }
286
+ if (!allKeys.includes(concreteTargetType)) {
287
+ return;
288
+ }
289
+ if (!this.getTargetRepositoryDict[concreteTargetType]) {
290
+ throw new InvalidPolymorphismError(
291
+ concreteTargetType,
292
+ targetDiscriminatorOnThrough,
293
+ );
294
+ }
295
+ if (!throughCategorized[concreteTargetType]) {
296
+ throughCategorized[concreteTargetType] = [];
297
+ }
298
+ throughCategorized[concreteTargetType].push(element);
299
+ });
300
+
301
+ let allTargets: TargetEntity[] = [];
302
+ for (const key of Object.keys(throughCategorized)) {
303
+ const targetRepository = await this.getTargetRepositoryDict[key]();
304
+ const targetConstraint = this.getTargetConstraintFromThroughModels(
305
+ throughCategorized[key],
306
+ );
307
+ allTargets = allTargets.concat(
308
+ await targetRepository.find(
309
+ constrainFilter(filter, targetConstraint),
310
+ Object.assign(cloneDeep(options ?? {}), {polymorphicType: key}),
311
+ ),
312
+ );
313
+ }
314
+
315
+ return allTargets;
191
316
  }
192
317
 
193
318
  async delete(
194
319
  where?: Where<TargetEntity>,
195
320
  options?: Options & {
196
- throughOptions?: Options;
197
- },
321
+ throughOptions?: Options & {discriminator?: string};
322
+ } & {polymorphicType?: string | string[]},
198
323
  ): Promise<Count> {
199
- const targetRepository = await this.getTargetRepository();
200
- const throughRepository = await this.getThroughRepository();
324
+ const targetDiscriminatorOnThrough = options?.throughOptions?.discriminator;
325
+ let targetPolymorphicTypes = options?.polymorphicType;
326
+ let allKeys: string[];
327
+ if (Object.keys(this.getTargetRepositoryDict).length <= 1) {
328
+ allKeys = Object.keys(this.getTargetRepositoryDict);
329
+ } else {
330
+ if (!targetDiscriminatorOnThrough) {
331
+ console.warn(
332
+ 'It is highly recommended to specify the targetDiscriminatorOnThrough param when using polymorphic types.',
333
+ );
334
+ }
335
+ if (!targetPolymorphicTypes || targetPolymorphicTypes.length === 0) {
336
+ console.warn(
337
+ 'It is highly recommended to specify the polymorphicTypes param when using polymorphic types.',
338
+ );
339
+ allKeys = Object.keys(this.getTargetRepositoryDict);
340
+ } else {
341
+ if (typeof targetPolymorphicTypes === 'string') {
342
+ targetPolymorphicTypes = [targetPolymorphicTypes];
343
+ }
344
+ allKeys = [];
345
+ new Set(targetPolymorphicTypes!).forEach(element => {
346
+ if (Object.keys(this.getTargetRepositoryDict).includes(element)) {
347
+ allKeys.push(element);
348
+ }
349
+ });
350
+ }
351
+ }
352
+
201
353
  const sourceConstraint = this.getThroughConstraintFromSource();
202
- const throughInstances = await throughRepository.find(
203
- constrainFilter(undefined, sourceConstraint),
204
- options?.throughOptions,
205
- );
206
- if (where) {
207
- // only delete related through models
208
- // TODO(Agnes): this performance can be improved by only fetching related data
209
- // TODO: add target ids to the `where` constraint
210
- const targets = await targetRepository.find({where});
211
- const targetIds = this.getTargetIds(targets);
212
- if (targetIds.length > 0) {
213
- const targetConstraint = this.getThroughConstraintFromTarget(targetIds);
214
- const constraints = {...targetConstraint, ...sourceConstraint};
354
+ let totalCount = 0;
355
+ const throughCategorized: {[concreteType: string]: (ThroughEntity & {})[]} =
356
+ {};
357
+ const throughRepository = await this.getThroughRepository();
358
+ (
359
+ await throughRepository.find(
360
+ constrainFilter(undefined, sourceConstraint),
361
+ options?.throughOptions,
362
+ )
363
+ ).forEach(element => {
364
+ let concreteTargetType;
365
+ if (!targetDiscriminatorOnThrough) {
366
+ concreteTargetType = this.targetResolver().name;
367
+ } else {
368
+ concreteTargetType = String(
369
+ element[targetDiscriminatorOnThrough as StringKeyOf<ThroughEntity>],
370
+ );
371
+ }
372
+ if (!allKeys.includes(concreteTargetType)) {
373
+ return;
374
+ }
375
+ if (!this.getTargetRepositoryDict[concreteTargetType]) {
376
+ throw new InvalidPolymorphismError(
377
+ concreteTargetType,
378
+ targetDiscriminatorOnThrough,
379
+ );
380
+ }
381
+ if (!throughCategorized[concreteTargetType]) {
382
+ throughCategorized[concreteTargetType] = [];
383
+ }
384
+ throughCategorized[concreteTargetType].push(element);
385
+ });
386
+
387
+ for (const targetKey of Object.keys(throughCategorized)) {
388
+ const targetRepository = await this.getTargetRepositoryDict[targetKey]();
389
+ if (where) {
390
+ // only delete related through models
391
+ // TODO(Agnes): this performance can be improved by only fetching related data
392
+ // TODO: add target ids to the `where` constraint
393
+ const targets = await targetRepository.find({where});
394
+ const targetIds = this.getTargetIds(targets);
395
+ if (targetIds.length > 0) {
396
+ const targetConstraint =
397
+ this.getThroughConstraintFromTarget(targetIds);
398
+ const constraints = {...targetConstraint, ...sourceConstraint};
399
+ await throughRepository.deleteAll(
400
+ constrainDataObject({}, constraints as DataObject<ThroughEntity>),
401
+ options?.throughOptions,
402
+ );
403
+ }
404
+ } else {
405
+ // otherwise, delete through models that relate to the sourceId
406
+ const targetFkValues = this.getTargetKeys(
407
+ throughCategorized[targetKey],
408
+ );
409
+ // delete through instances that have the targets that are going to be deleted
410
+ const throughFkConstraint =
411
+ this.getThroughConstraintFromTarget(targetFkValues);
215
412
  await throughRepository.deleteAll(
216
- constrainDataObject({}, constraints as DataObject<ThroughEntity>),
217
- options?.throughOptions,
413
+ constrainWhereOr({}, [sourceConstraint, throughFkConstraint]),
218
414
  );
219
415
  }
220
- } else {
221
- // otherwise, delete through models that relate to the sourceId
222
- const targetFkValues = this.getTargetKeys(throughInstances);
223
- // delete through instances that have the targets that are going to be deleted
224
- const throughFkConstraint =
225
- this.getThroughConstraintFromTarget(targetFkValues);
226
- await throughRepository.deleteAll(
227
- constrainWhereOr({}, [sourceConstraint, throughFkConstraint]),
416
+ // delete target(s)
417
+ const targetConstraint = this.getTargetConstraintFromThroughModels(
418
+ throughCategorized[targetKey],
228
419
  );
420
+ totalCount +=
421
+ (
422
+ await targetRepository.deleteAll(
423
+ constrainWhere(where, targetConstraint as Where<TargetEntity>),
424
+ options,
425
+ )
426
+ )?.count ?? 0;
229
427
  }
230
- // delete target(s)
231
- const targetConstraint =
232
- this.getTargetConstraintFromThroughModels(throughInstances);
233
- return targetRepository.deleteAll(
234
- constrainWhere(where, targetConstraint as Where<TargetEntity>),
235
- options,
236
- );
428
+ return {count: totalCount};
237
429
  }
430
+
238
431
  // only allows patch target instances for now
239
432
  async patch(
240
- dataObject: DataObject<TargetEntity>,
433
+ dataObject:
434
+ | DataObject<TargetEntity>
435
+ | {[polymorphicType: string]: DataObject<TargetEntity>},
241
436
  where?: Where<TargetEntity>,
242
437
  options?: Options & {
243
- throughOptions?: Options;
244
- },
438
+ throughOptions?: Options & {discriminator?: string};
439
+ } & {isPolymorphic?: boolean},
245
440
  ): Promise<Count> {
246
- const targetRepository = await this.getTargetRepository();
247
- const throughRepository = await this.getThroughRepository();
441
+ const targetDiscriminatorOnThrough = options?.throughOptions?.discriminator;
442
+ const isMultipleTypes = options?.isPolymorphic;
443
+ let allKeys: string[];
444
+ if (!targetDiscriminatorOnThrough) {
445
+ if (Object.keys(this.getTargetRepositoryDict).length > 1) {
446
+ console.warn(
447
+ 'It is highly recommended to specify the targetDiscriminatorOnThrough param when using polymorphic types.',
448
+ );
449
+ }
450
+ }
451
+ if (!isMultipleTypes) {
452
+ if (Object.keys(this.getTargetRepositoryDict).length > 1) {
453
+ console.warn(
454
+ 'It is highly recommended to specify the isMultipleTypes param and pass in a dictionary of dataobjects when using polymorphic types.',
455
+ );
456
+ }
457
+ allKeys = Object.keys(this.getTargetRepositoryDict);
458
+ } else {
459
+ allKeys = [];
460
+ new Set(Object.keys(dataObject)).forEach(element => {
461
+ if (Object.keys(this.getTargetRepositoryDict).includes(element)) {
462
+ allKeys.push(element);
463
+ }
464
+ });
465
+ }
466
+
248
467
  const sourceConstraint = this.getThroughConstraintFromSource();
249
- const throughInstances = await throughRepository.find(
250
- constrainFilter(undefined, sourceConstraint),
251
- options?.throughOptions,
252
- );
253
- const targetConstraint =
254
- this.getTargetConstraintFromThroughModels(throughInstances);
255
- return targetRepository.updateAll(
256
- constrainDataObject(dataObject, targetConstraint),
257
- constrainWhere(where, targetConstraint as Where<TargetEntity>),
258
- options,
259
- );
468
+
469
+ const throughCategorized: {[concreteType: string]: (ThroughEntity & {})[]} =
470
+ {};
471
+ const throughRepository = await this.getThroughRepository();
472
+ (
473
+ await throughRepository.find(
474
+ constrainFilter(undefined, sourceConstraint),
475
+ options?.throughOptions,
476
+ )
477
+ ).forEach(element => {
478
+ let concreteTargetType;
479
+ if (!targetDiscriminatorOnThrough) {
480
+ concreteTargetType = this.targetResolver().name;
481
+ } else {
482
+ concreteTargetType = String(
483
+ element[targetDiscriminatorOnThrough as StringKeyOf<ThroughEntity>],
484
+ );
485
+ }
486
+ if (!allKeys.includes(concreteTargetType)) {
487
+ return;
488
+ }
489
+ if (!this.getTargetRepositoryDict[concreteTargetType]) {
490
+ throw new InvalidPolymorphismError(
491
+ concreteTargetType,
492
+ targetDiscriminatorOnThrough,
493
+ );
494
+ }
495
+ if (!throughCategorized[concreteTargetType]) {
496
+ throughCategorized[concreteTargetType] = [];
497
+ }
498
+ throughCategorized[concreteTargetType].push(element);
499
+ });
500
+
501
+ let updatedCount = 0;
502
+ for (const key of Object.keys(throughCategorized)) {
503
+ const targetRepository = await this.getTargetRepositoryDict[key]();
504
+ const targetConstraint = this.getTargetConstraintFromThroughModels(
505
+ throughCategorized[key],
506
+ );
507
+ updatedCount +=
508
+ (
509
+ await targetRepository.updateAll(
510
+ constrainDataObject(
511
+ isMultipleTypes
512
+ ? (
513
+ dataObject as {
514
+ [polymorphicType: string]: DataObject<TargetEntity>;
515
+ }
516
+ )[key]
517
+ : (dataObject as DataObject<TargetEntity>),
518
+ targetConstraint,
519
+ ),
520
+ constrainWhere(where, targetConstraint as Where<TargetEntity>),
521
+ options,
522
+ )
523
+ )?.count ?? 0;
524
+ }
525
+
526
+ return {count: updatedCount};
260
527
  }
261
528
 
262
529
  async link(
@@ -1,4 +1,4 @@
1
- // Copyright IBM Corp. 2018,2020. All Rights Reserved.
1
+ // Copyright IBM Corp. and LoopBack contributors 2018,2020. All Rights Reserved.
2
2
  // Node module: @loopback/repository
3
3
  // This file is licensed under the MIT License.
4
4
  // License text available at https://opensource.org/licenses/MIT
@@ -1,4 +1,4 @@
1
- // Copyright IBM Corp. 2019,2020. All Rights Reserved.
1
+ // Copyright IBM Corp. and LoopBack contributors 2019,2020. All Rights Reserved.
2
2
  // Node module: @loopback/repository
3
3
  // This file is licensed under the MIT License.
4
4
  // License text available at https://opensource.org/licenses/MIT
@@ -1,4 +1,4 @@
1
- // Copyright IBM Corp. 2019,2020. All Rights Reserved.
1
+ // Copyright IBM Corp. and LoopBack contributors 2019,2020. All Rights Reserved.
2
2
  // Node module: @loopback/repository
3
3
  // This file is licensed under the MIT License.
4
4
  // License text available at https://opensource.org/licenses/MIT
@@ -1,4 +1,4 @@
1
- // Copyright IBM Corp. 2018,2020. All Rights Reserved.
1
+ // Copyright IBM Corp. and LoopBack contributors 2018,2020. All Rights Reserved.
2
2
  // Node module: @loopback/repository
3
3
  // This file is licensed under the MIT License.
4
4
  // License text available at https://opensource.org/licenses/MIT
@@ -1,4 +1,4 @@
1
- // Copyright IBM Corp. 2018,2020. All Rights Reserved.
1
+ // Copyright IBM Corp. and LoopBack contributors 2018,2020. All Rights Reserved.
2
2
  // Node module: @loopback/repository
3
3
  // This file is licensed under the MIT License.
4
4
  // License text available at https://opensource.org/licenses/MIT
@@ -1,11 +1,11 @@
1
- // Copyright IBM Corp. 2018,2020. All Rights Reserved.
1
+ // Copyright IBM Corp. and LoopBack contributors 2018,2020. All Rights Reserved.
2
2
  // Node module: @loopback/repository
3
3
  // This file is licensed under the MIT License.
4
4
  // License text available at https://opensource.org/licenses/MIT
5
5
 
6
- export * from './has-many.repository-factory';
7
- export * from './has-many-through.repository-factory';
8
6
  export * from './has-many-through.repository';
7
+ export * from './has-many-through.repository-factory';
9
8
  export * from './has-many.decorator';
10
9
  export * from './has-many.inclusion-resolver';
11
10
  export * from './has-many.repository';
11
+ export * from './has-many.repository-factory';
@@ -1,4 +1,4 @@
1
- // Copyright IBM Corp. 2018,2020. All Rights Reserved.
1
+ // Copyright IBM Corp. and LoopBack contributors 2018,2020. All Rights Reserved.
2
2
  // Node module: @loopback/repository
3
3
  // This file is licensed under the MIT License.
4
4
  // License text available at https://opensource.org/licenses/MIT