@loopback/repository 4.1.2 → 5.0.0

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 (107) hide show
  1. package/dist/errors/index.d.ts +1 -0
  2. package/dist/errors/index.js +1 -0
  3. package/dist/errors/index.js.map +1 -1
  4. package/dist/errors/invalid-polymorphism.error.d.ts +5 -0
  5. package/dist/errors/invalid-polymorphism.error.js +22 -0
  6. package/dist/errors/invalid-polymorphism.error.js.map +1 -0
  7. package/dist/model.d.ts +7 -1
  8. package/dist/model.js +14 -0
  9. package/dist/model.js.map +1 -1
  10. package/dist/relations/belongs-to/belongs-to.accessor.d.ts +6 -2
  11. package/dist/relations/belongs-to/belongs-to.accessor.js +18 -5
  12. package/dist/relations/belongs-to/belongs-to.accessor.js.map +1 -1
  13. package/dist/relations/belongs-to/belongs-to.helpers.d.ts +3 -0
  14. package/dist/relations/belongs-to/belongs-to.helpers.js +32 -8
  15. package/dist/relations/belongs-to/belongs-to.helpers.js.map +1 -1
  16. package/dist/relations/belongs-to/belongs-to.inclusion-resolver.d.ts +5 -2
  17. package/dist/relations/belongs-to/belongs-to.inclusion-resolver.js +81 -8
  18. package/dist/relations/belongs-to/belongs-to.inclusion-resolver.js.map +1 -1
  19. package/dist/relations/belongs-to/belongs-to.repository.d.ts +28 -5
  20. package/dist/relations/belongs-to/belongs-to.repository.js +49 -10
  21. package/dist/relations/belongs-to/belongs-to.repository.js.map +1 -1
  22. package/dist/relations/has-many/has-many-through.helpers.d.ts +3 -0
  23. package/dist/relations/has-many/has-many-through.helpers.js +25 -1
  24. package/dist/relations/has-many/has-many-through.helpers.js.map +1 -1
  25. package/dist/relations/has-many/has-many-through.inclusion-resolver.d.ts +3 -1
  26. package/dist/relations/has-many/has-many-through.inclusion-resolver.js +92 -21
  27. package/dist/relations/has-many/has-many-through.inclusion-resolver.js.map +1 -1
  28. package/dist/relations/has-many/has-many-through.repository-factory.d.ts +3 -1
  29. package/dist/relations/has-many/has-many-through.repository-factory.js +7 -1
  30. package/dist/relations/has-many/has-many-through.repository-factory.js.map +1 -1
  31. package/dist/relations/has-many/has-many-through.repository.d.ts +66 -11
  32. package/dist/relations/has-many/has-many-through.repository.js +211 -35
  33. package/dist/relations/has-many/has-many-through.repository.js.map +1 -1
  34. package/dist/relations/has-one/has-one.helpers.d.ts +3 -0
  35. package/dist/relations/has-one/has-one.helpers.js +34 -8
  36. package/dist/relations/has-one/has-one.helpers.js.map +1 -1
  37. package/dist/relations/has-one/has-one.inclusion-resolver.d.ts +6 -3
  38. package/dist/relations/has-one/has-one.inclusion-resolver.js +82 -7
  39. package/dist/relations/has-one/has-one.inclusion-resolver.js.map +1 -1
  40. package/dist/relations/has-one/has-one.repository-factory.d.ts +9 -3
  41. package/dist/relations/has-one/has-one.repository-factory.js +13 -3
  42. package/dist/relations/has-one/has-one.repository-factory.js.map +1 -1
  43. package/dist/relations/has-one/has-one.repository.d.ts +58 -11
  44. package/dist/relations/has-one/has-one.repository.js +118 -15
  45. package/dist/relations/has-one/has-one.repository.js.map +1 -1
  46. package/dist/relations/index.d.ts +2 -0
  47. package/dist/relations/index.js +2 -0
  48. package/dist/relations/index.js.map +1 -1
  49. package/dist/relations/references-many/index.d.ts +4 -0
  50. package/dist/relations/references-many/index.js +12 -0
  51. package/dist/relations/references-many/index.js.map +1 -0
  52. package/dist/relations/references-many/references-many.accessor.d.ts +17 -0
  53. package/dist/relations/references-many/references-many.accessor.js +40 -0
  54. package/dist/relations/references-many/references-many.accessor.js.map +1 -0
  55. package/dist/relations/references-many/references-many.decorator.d.ts +11 -0
  56. package/dist/relations/references-many/references-many.decorator.js +73 -0
  57. package/dist/relations/references-many/references-many.decorator.js.map +1 -0
  58. package/dist/relations/references-many/references-many.helpers.d.ts +17 -0
  59. package/dist/relations/references-many/references-many.helpers.js +63 -0
  60. package/dist/relations/references-many/references-many.helpers.js.map +1 -0
  61. package/dist/relations/references-many/references-many.inclusion-resolver.d.ts +14 -0
  62. package/dist/relations/references-many/references-many.inclusion-resolver.js +42 -0
  63. package/dist/relations/references-many/references-many.inclusion-resolver.js.map +1 -0
  64. package/dist/relations/references-many/references-many.repository.d.ts +28 -0
  65. package/dist/relations/references-many/references-many.repository.js +33 -0
  66. package/dist/relations/references-many/references-many.repository.js.map +1 -0
  67. package/dist/relations/relation.decorator.d.ts +0 -6
  68. package/dist/relations/relation.decorator.js +1 -13
  69. package/dist/relations/relation.decorator.js.map +1 -1
  70. package/dist/relations/relation.filter.solver.d.ts +2 -0
  71. package/dist/relations/relation.filter.solver.js +57 -0
  72. package/dist/relations/relation.filter.solver.js.map +1 -0
  73. package/dist/relations/relation.helpers.js +16 -1
  74. package/dist/relations/relation.helpers.js.map +1 -1
  75. package/dist/relations/relation.types.d.ts +52 -1
  76. package/dist/relations/relation.types.js.map +1 -1
  77. package/dist/repositories/legacy-juggler-bridge.d.ts +35 -8
  78. package/dist/repositories/legacy-juggler-bridge.js +36 -14
  79. package/dist/repositories/legacy-juggler-bridge.js.map +1 -1
  80. package/package.json +13 -13
  81. package/src/errors/index.ts +1 -0
  82. package/src/errors/invalid-polymorphism.error.ts +28 -0
  83. package/src/model.ts +19 -0
  84. package/src/relations/belongs-to/belongs-to.accessor.ts +35 -6
  85. package/src/relations/belongs-to/belongs-to.helpers.ts +36 -9
  86. package/src/relations/belongs-to/belongs-to.inclusion-resolver.ts +108 -17
  87. package/src/relations/belongs-to/belongs-to.repository.ts +77 -17
  88. package/src/relations/has-many/has-many-through.helpers.ts +27 -1
  89. package/src/relations/has-many/has-many-through.inclusion-resolver.ts +117 -26
  90. package/src/relations/has-many/has-many-through.repository-factory.ts +21 -3
  91. package/src/relations/has-many/has-many-through.repository.ts +343 -76
  92. package/src/relations/has-one/has-one.helpers.ts +40 -13
  93. package/src/relations/has-one/has-one.inclusion-resolver.ts +109 -15
  94. package/src/relations/has-one/has-one.repository-factory.ts +34 -6
  95. package/src/relations/has-one/has-one.repository.ts +188 -35
  96. package/src/relations/index.ts +2 -0
  97. package/src/relations/references-many/index.ts +9 -0
  98. package/src/relations/references-many/references-many.accessor.ts +76 -0
  99. package/src/relations/references-many/references-many.decorator.ts +100 -0
  100. package/src/relations/references-many/references-many.helpers.ts +82 -0
  101. package/src/relations/references-many/references-many.inclusion-resolver.ts +80 -0
  102. package/src/relations/references-many/references-many.repository.ts +55 -0
  103. package/src/relations/relation.decorator.ts +0 -12
  104. package/src/relations/relation.filter.solver.ts +56 -0
  105. package/src/relations/relation.helpers.ts +16 -1
  106. package/src/relations/relation.types.ts +51 -0
  107. package/src/repositories/legacy-juggler-bridge.ts +78 -14
@@ -5,6 +5,7 @@
5
5
 
6
6
  import {Filter, InclusionFilter} from '@loopback/filter';
7
7
  import debugFactory from 'debug';
8
+ import {InvalidPolymorphismError} from '../..';
8
9
  import {AnyObject, Options} from '../../common-types';
9
10
  import {Entity} from '../../model';
10
11
  import {EntityCrudRepository} from '../../repositories';
@@ -14,7 +15,7 @@ import {
14
15
  StringKeyOf,
15
16
  } from '../relation.helpers';
16
17
  import {Getter, HasManyDefinition, InclusionResolver} from '../relation.types';
17
- import {resolveHasManyMetadata} from './has-many.helpers';
18
+ import {resolveHasManyThroughMetadata} from './has-many-through.helpers';
18
19
 
19
20
  const debug = debugFactory(
20
21
  'loopback:repository:relations:has-many-through:inclusion-resolver',
@@ -44,17 +45,25 @@ export function createHasManyThroughInclusionResolver<
44
45
  getThroughRepo: Getter<
45
46
  EntityCrudRepository<Through, ThroughID, ThroughRelations>
46
47
  >,
47
- getTargetRepo: Getter<
48
- EntityCrudRepository<Target, TargetID, TargetRelations>
49
- >,
48
+ getTargetRepoDict: {
49
+ [repoType: string]: Getter<
50
+ EntityCrudRepository<Target, TargetID, TargetRelations>
51
+ >;
52
+ },
50
53
  ): InclusionResolver<Entity, Target> {
51
- const relationMeta = resolveHasManyMetadata(meta);
54
+ const relationMeta = resolveHasManyThroughMetadata(meta);
52
55
 
53
56
  return async function fetchHasManyThroughModels(
54
57
  entities: Entity[],
55
58
  inclusion: InclusionFilter,
56
59
  options?: Options,
57
60
  ): Promise<((Target & TargetRelations)[] | undefined)[]> {
61
+ if (!relationMeta.through) {
62
+ throw new Error(
63
+ `relationMeta.through must be defined on ${relationMeta}`,
64
+ );
65
+ }
66
+
58
67
  if (!entities.length) return [];
59
68
 
60
69
  debug('Fetching target models for entities:', entities);
@@ -85,7 +94,6 @@ export function createHasManyThroughInclusionResolver<
85
94
  );
86
95
 
87
96
  const throughRepo = await getThroughRepo();
88
- const targetRepo = await getTargetRepo();
89
97
 
90
98
  // find through models
91
99
  const throughFound = await findByForeignKeys(
@@ -102,34 +110,117 @@ export function createHasManyThroughInclusionResolver<
102
110
  throughKeyFrom,
103
111
  );
104
112
 
105
- const result = [];
106
-
107
113
  const scope =
108
114
  typeof inclusion === 'string' ? {} : (inclusion.scope as Filter<Target>);
109
115
 
110
- // convert from through entities to the target entities
111
- for (const entityList of throughResult) {
112
- if (entityList) {
113
- // get target ids from the through entities by foreign key
114
- const targetIds = entityList.map(entity => entity[throughKeyTo]);
115
-
116
- // the explicit types and casts are needed
116
+ // whether the polymorphism is configured
117
+ const targetDiscriminator: keyof (Through & ThroughRelations) | undefined =
118
+ relationMeta.through!.polymorphic
119
+ ? (relationMeta.through!.polymorphic.discriminator as keyof (Through &
120
+ ThroughRelations))
121
+ : undefined;
122
+ if (targetDiscriminator) {
123
+ // put through results into arrays based on the target polymorphic types
124
+ const throughArrayByTargetType: {
125
+ [targetType: string]: (Through & ThroughRelations)[];
126
+ } = {};
127
+ for (const throughArray of throughResult) {
128
+ if (throughArray) {
129
+ for (const throughItem of throughArray) {
130
+ const targetType = String(throughItem[targetDiscriminator]);
131
+ if (!getTargetRepoDict[targetType]) {
132
+ throw new InvalidPolymorphismError(
133
+ targetType,
134
+ String(targetDiscriminator),
135
+ );
136
+ }
137
+ if (!throughArrayByTargetType[targetType]) {
138
+ throughArrayByTargetType[targetType] = [];
139
+ }
140
+ throughArrayByTargetType[targetType].push(throughItem);
141
+ }
142
+ }
143
+ }
144
+ // get targets based on their polymorphic types
145
+ const targetOfTypes: {
146
+ [targetType: string]: (Target & TargetRelations)[];
147
+ } = {};
148
+ for (const targetType of Object.keys(throughArrayByTargetType)) {
149
+ const targetIds = throughArrayByTargetType[targetType].map(
150
+ throughItem => throughItem[throughKeyTo],
151
+ );
152
+ const targetRepo = await getTargetRepoDict[targetType]();
117
153
  const targetEntityList = await findByForeignKeys<
118
154
  Target,
119
155
  TargetRelations,
120
156
  StringKeyOf<Target>
121
- >(targetRepo, targetKey, targetIds as unknown as [], scope, {
122
- ...options,
123
- isThroughModelInclude: true,
124
- });
125
- result.push(targetEntityList);
126
- } else {
127
- // no entities found, add undefined to results
128
- result.push(entityList);
157
+ >(targetRepo, targetKey, targetIds as unknown as [], scope, options);
158
+ targetOfTypes[targetType] = targetEntityList;
159
+ }
160
+ // put targets into arrays reflecting their throughs
161
+ // Why the order is correct:
162
+ // e.g. through model = T(target instance), target model 1 = a, target model 2 = b
163
+ // all entities: [S1, S2, S2]
164
+ // through-result: [[T(b-11), T(a-12), T(b-13), T(b-14)], [T(a-21), T(a-22), T(b-23)], [T(b-31), T(b-32), T(a-33)]]
165
+ // through-array-by-target-type: {a:[T(a-12), T(a-21), T(a-22), T(a-33)] b: [T(b-11), T(b-13), T(b-14), T(b-23), T(b-31), T(b-32)]}
166
+ // target-array-by-target-type: {a:[a-12, a-21, a-22, a-33] b: [b-11, b-13, b-14, b-23, b-31, b-32]}
167
+ // merged:
168
+ // through-result[0][0]->b => targets: [[b-11 from b.shift()]]
169
+ // through-result[0][1]->a => targets: [[b-11, a-12 from a.shift()]]
170
+ // through-result[0][2]->b => targets: [[b-11, a-12, b-13 from b.shift()]]
171
+ // through-result[0][3]->b => targets: [[b-11, a-12, b-13, b-14 from b.shift()]]
172
+ // through-result[1][0]->a => targets: [[b-11, a-12, b-13, b-14], [a-21, from a.shift()]]
173
+ // through-result[1][1]->a => targets: [[b-11, a-12, b-13, b-14], [a-21, a-22 from a.shift()]]
174
+ // through-result[1][2]->b => targets: [[b-11, a-12, b-13, b-14], [a-21, a-22, b-23 from b.shift()]]
175
+ // through-result[2][0]->b => targets: [[b-11, a-12, b-13, b-14], [a-21, a-22, b-23], [b-31, from b.shift()]]
176
+ // through-result[2][1]->b => targets: [[b-11, a-12, b-13, b-14], [a-21, a-22, b-23], [b-31, b-32 from b.shift()]]
177
+ // through-result[2][1]->b => targets: [[b-11, a-12, b-13, b-14], [a-21, a-22, b-23], [b-31, b-32, a-33 from a.shift()]]
178
+ const allTargetsOfThrough: ((Target & TargetRelations)[] | undefined)[] =
179
+ [];
180
+ for (const throughArray of throughResult) {
181
+ if (throughArray && throughArray.length > 0) {
182
+ const currentTargetThroughArray: (Target & TargetRelations)[] = [];
183
+ for (const throughItem of throughArray) {
184
+ const itemToAdd =
185
+ targetOfTypes[String(throughItem[targetDiscriminator])].shift();
186
+ if (itemToAdd) {
187
+ currentTargetThroughArray.push(itemToAdd);
188
+ }
189
+ }
190
+ allTargetsOfThrough.push(currentTargetThroughArray);
191
+ } else {
192
+ allTargetsOfThrough.push(undefined);
193
+ }
194
+ }
195
+ return allTargetsOfThrough;
196
+ } else {
197
+ const targetRepo = await getTargetRepoDict[relationMeta.target().name]();
198
+ const result = [];
199
+
200
+ // convert from through entities to the target entities
201
+ for (const entityList of throughResult) {
202
+ if (entityList) {
203
+ // get target ids from the through entities by foreign key
204
+ const targetIds = entityList.map(entity => entity[throughKeyTo]);
205
+
206
+ // the explicit types and casts are needed
207
+ const targetEntityList = await findByForeignKeys<
208
+ Target,
209
+ TargetRelations,
210
+ StringKeyOf<Target>
211
+ >(targetRepo, targetKey, targetIds as unknown as [], scope, {
212
+ ...options,
213
+ isThroughModelInclude: true,
214
+ });
215
+ result.push(targetEntityList);
216
+ } else {
217
+ // no entities found, add undefined to results
218
+ result.push(entityList);
219
+ }
129
220
  }
130
- }
131
221
 
132
- debug('fetchHasManyThroughModels result', result);
133
- return result;
222
+ debug('fetchHasManyThroughModels result', result);
223
+ return result;
224
+ }
134
225
  };
135
226
  }
@@ -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
  }