@goatlab/fluent 0.7.6 → 0.7.11

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 (86) hide show
  1. package/dist/BaseConnector.d.ts +8 -31
  2. package/dist/BaseConnector.js +11 -104
  3. package/dist/FluentConnectorInterface.d.ts +17 -0
  4. package/dist/FluentConnectorInterface.js +2 -0
  5. package/dist/TypeOrmConnector/TypeOrmConnector.d.ts +8 -12
  6. package/dist/TypeOrmConnector/TypeOrmConnector.js +183 -546
  7. package/dist/TypeOrmConnector/queryBuilder/mongodb/getMongoBaseAggregations.d.ts +7 -0
  8. package/dist/TypeOrmConnector/queryBuilder/mongodb/getMongoBaseAggregations.js +148 -0
  9. package/dist/TypeOrmConnector/queryBuilder/mongodb/getMongoFindAggregatedQuery.d.ts +6 -0
  10. package/dist/TypeOrmConnector/queryBuilder/mongodb/getMongoFindAggregatedQuery.js +34 -0
  11. package/dist/TypeOrmConnector/queryBuilder/mongodb/getMongoSelect.d.ts +4 -0
  12. package/dist/TypeOrmConnector/queryBuilder/mongodb/getMongoSelect.js +12 -0
  13. package/dist/TypeOrmConnector/queryBuilder/mongodb/getMongoWhere.d.ts +6 -0
  14. package/dist/TypeOrmConnector/queryBuilder/mongodb/getMongoWhere.js +166 -0
  15. package/dist/TypeOrmConnector/queryBuilder/sql/getQueryBuilderWhere.d.ts +8 -0
  16. package/dist/TypeOrmConnector/queryBuilder/sql/getQueryBuilderWhere.js +200 -0
  17. package/dist/TypeOrmConnector/queryBuilder/sql/getTypeOrmWhere.d.ts +6 -0
  18. package/dist/TypeOrmConnector/queryBuilder/sql/getTypeOrmWhere.js +207 -0
  19. package/dist/TypeOrmConnector/test/basic/basicTestSuite.js +164 -0
  20. package/dist/TypeOrmConnector/test/basic/goat.entity.d.ts +3 -3
  21. package/dist/TypeOrmConnector/test/basic/goat.entity.js +1 -1
  22. package/dist/TypeOrmConnector/test/docker/docker.d.ts +1 -1
  23. package/dist/TypeOrmConnector/test/docker/docker.js +3 -4
  24. package/dist/TypeOrmConnector/test/docker/mongo.d.ts +16 -0
  25. package/dist/TypeOrmConnector/test/docker/mongo.js +93 -0
  26. package/dist/TypeOrmConnector/test/docker/mysql.js +1 -1
  27. package/dist/TypeOrmConnector/test/mongo/car.mongo.repository.d.ts +4 -2
  28. package/dist/TypeOrmConnector/test/mongo/car.mongo.repository.js +6 -1
  29. package/dist/TypeOrmConnector/test/mongo/roles.mongo.repository.d.ts +3 -2
  30. package/dist/TypeOrmConnector/test/mongo/roles.mongo.repository.js +3 -1
  31. package/dist/TypeOrmConnector/test/mongo/user.mongo.repository.d.ts +2 -2
  32. package/dist/TypeOrmConnector/test/mongo/user.mongo.repository.js +2 -1
  33. package/dist/TypeOrmConnector/test/mysql/car.mysql.repository.d.ts +6 -2
  34. package/dist/TypeOrmConnector/test/mysql/car.mysql.repository.js +10 -1
  35. package/dist/TypeOrmConnector/test/mysql/mysqlDataSource.js +1 -1
  36. package/dist/TypeOrmConnector/test/mysql/roles.mysql.repository.d.ts +3 -2
  37. package/dist/TypeOrmConnector/test/mysql/roles.mysql.repository.js +3 -1
  38. package/dist/TypeOrmConnector/test/mysql/user.mysql.repository.d.ts +2 -2
  39. package/dist/TypeOrmConnector/test/mysql/user.mysql.repository.js +2 -1
  40. package/dist/TypeOrmConnector/test/relations/car/car.entity.d.ts +0 -1
  41. package/dist/TypeOrmConnector/test/relations/car/car.entity.js +0 -8
  42. package/dist/TypeOrmConnector/test/relations/car/car.output.schema.d.ts +511 -0
  43. package/dist/TypeOrmConnector/test/relations/car/car.output.schema.js +8 -0
  44. package/dist/TypeOrmConnector/test/relations/car/car.repositoryTypeOrm.d.ts +4 -2
  45. package/dist/TypeOrmConnector/test/relations/car/car.repositoryTypeOrm.js +6 -1
  46. package/dist/TypeOrmConnector/test/relations/car/car.schema.d.ts +2 -25
  47. package/dist/TypeOrmConnector/test/relations/car/car.schema.js +3 -8
  48. package/dist/TypeOrmConnector/test/relations/relationsTestsSuite.d.ts +1 -1
  49. package/dist/TypeOrmConnector/test/relations/relationsTestsSuite.js +435 -35
  50. package/dist/TypeOrmConnector/test/relations/roles/role.output.schema.d.ts +152 -0
  51. package/dist/TypeOrmConnector/test/relations/roles/role.output.schema.js +14 -0
  52. package/dist/TypeOrmConnector/test/relations/roles/role.schema.d.ts +2 -25
  53. package/dist/TypeOrmConnector/test/relations/roles/role.schema.js +2 -10
  54. package/dist/TypeOrmConnector/test/relations/roles/roles.repositoryTypeOrm.d.ts +3 -2
  55. package/dist/TypeOrmConnector/test/relations/roles/roles.repositoryTypeOrm.js +3 -1
  56. package/dist/TypeOrmConnector/test/relations/user/user.repositoryTypeOrm.d.ts +2 -2
  57. package/dist/TypeOrmConnector/test/relations/user/user.repositoryTypeOrm.js +2 -1
  58. package/dist/TypeOrmConnector/test/relations/user/user.schema.d.ts +465 -69
  59. package/dist/TypeOrmConnector/test/relations/user/user.schema.js +54 -5
  60. package/dist/TypeOrmConnector/util/clearEmpties.d.ts +1 -0
  61. package/dist/TypeOrmConnector/util/clearEmpties.js +25 -0
  62. package/dist/TypeOrmConnector/util/extractConditions.d.ts +6 -0
  63. package/dist/TypeOrmConnector/util/extractConditions.js +80 -0
  64. package/dist/TypeOrmConnector/util/extractInclude.d.ts +2 -0
  65. package/dist/TypeOrmConnector/util/extractInclude.js +25 -0
  66. package/dist/TypeOrmConnector/util/extractMetadataFromKeys.d.ts +12 -0
  67. package/dist/TypeOrmConnector/util/extractMetadataFromKeys.js +42 -0
  68. package/dist/TypeOrmConnector/util/extractOrderBy.d.ts +4 -0
  69. package/dist/TypeOrmConnector/util/extractOrderBy.js +18 -0
  70. package/dist/TypeOrmConnector/util/getRelationsFromModelGenerator.d.ts +19 -0
  71. package/dist/TypeOrmConnector/util/getRelationsFromModelGenerator.js +26 -0
  72. package/dist/TypeOrmConnector/util/getSelectedKeysFromRawSql.d.ts +1 -0
  73. package/dist/TypeOrmConnector/util/getSelectedKeysFromRawSql.js +20 -0
  74. package/dist/TypeOrmConnector/util/isAnyObject.d.ts +1 -0
  75. package/dist/TypeOrmConnector/util/isAnyObject.js +7 -0
  76. package/dist/TypeOrmConnector/util/nestQueryResults.d.ts +2 -0
  77. package/dist/TypeOrmConnector/util/nestQueryResults.js +31 -0
  78. package/dist/index.d.ts +12 -5
  79. package/dist/index.js +15 -2
  80. package/dist/loadRelations.js +8 -10
  81. package/dist/tsconfig.tsbuildinfo +1 -1
  82. package/dist/types.d.ts +37 -20
  83. package/package.json +4 -3
  84. package/CHANGELOG.md +0 -1072
  85. package/dist/TypeOrmConnector/test/mongo/mongo.memory.d.ts +0 -4
  86. package/dist/TypeOrmConnector/test/mongo/mongo.memory.js +0 -43
@@ -6,16 +6,21 @@ const car_schema_1 = require("./car.schema");
6
6
  const TypeOrmConnector_1 = require("../../../TypeOrmConnector");
7
7
  const user_repositoryTypeOrm_1 = require("../user/user.repositoryTypeOrm");
8
8
  const memoryDataSource_1 = require("../../sqlite/memoryDataSource");
9
+ const car_output_schema_1 = require("./car.output.schema");
9
10
  class CarsRepository extends TypeOrmConnector_1.TypeOrmConnector {
10
11
  constructor() {
11
12
  super({
12
13
  entity: car_entity_1.CarsEntity,
13
14
  dataSource: memoryDataSource_1.MemoryDataSource,
14
- inputSchema: car_schema_1.CarsEntitySchema
15
+ inputSchema: car_schema_1.carInputSchema,
16
+ outputSchema: car_output_schema_1.carOutputSchema
15
17
  });
16
18
  this.user = () => this.belongsTo({
17
19
  repository: user_repositoryTypeOrm_1.UserRepository
18
20
  });
21
+ this.anotherRelation = () => this.belongsTo({
22
+ repository: user_repositoryTypeOrm_1.UserRepository
23
+ });
19
24
  }
20
25
  }
21
26
  exports.CarsRepository = CarsRepository;
@@ -1,38 +1,15 @@
1
1
  import { z } from 'zod';
2
- export declare const CarsEntitySchema: z.ZodObject<{
2
+ export declare const carInputSchema: z.ZodObject<{
3
3
  id: z.ZodOptional<z.ZodString>;
4
4
  name: z.ZodString;
5
5
  userId: z.ZodOptional<z.ZodString>;
6
- user: z.ZodOptional<z.ZodObject<{
7
- id: z.ZodOptional<z.ZodString>;
8
- name: z.ZodString;
9
- age: z.ZodOptional<z.ZodNumber>;
10
- }, "strip", z.ZodTypeAny, {
11
- id?: string | undefined;
12
- age?: number | undefined;
13
- name: string;
14
- }, {
15
- id?: string | undefined;
16
- age?: number | undefined;
17
- name: string;
18
- }>>;
19
6
  }, "strip", z.ZodTypeAny, {
20
7
  id?: string | undefined;
21
8
  userId?: string | undefined;
22
- user?: {
23
- id?: string | undefined;
24
- age?: number | undefined;
25
- name: string;
26
- } | undefined;
27
9
  name: string;
28
10
  }, {
29
11
  id?: string | undefined;
30
12
  userId?: string | undefined;
31
- user?: {
32
- id?: string | undefined;
33
- age?: number | undefined;
34
- name: string;
35
- } | undefined;
36
13
  name: string;
37
14
  }>;
38
- export declare type CarsEntityInputSchema = z.infer<typeof CarsEntitySchema>;
15
+ export declare type CarDtoInput = z.infer<typeof carInputSchema>;
@@ -1,14 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.CarsEntitySchema = void 0;
3
+ exports.carInputSchema = void 0;
4
4
  const zod_1 = require("zod");
5
- exports.CarsEntitySchema = zod_1.z.object({
5
+ exports.carInputSchema = zod_1.z.object({
6
6
  id: zod_1.z.string().optional(),
7
7
  name: zod_1.z.string(),
8
- userId: zod_1.z.string().optional(),
9
- user: zod_1.z.object({
10
- id: zod_1.z.string().optional(),
11
- name: zod_1.z.string(),
12
- age: zod_1.z.number().optional(),
13
- }).optional()
8
+ userId: zod_1.z.string().optional()
14
9
  });
@@ -1 +1 @@
1
- export declare const relationsTestSuite: (ModelF: any, BelongsToModelF: any, ManyToManyModelF: any) => void;
1
+ export declare const relationsTestSuite: (UserRepo: any, BelongsToModelF: any, ManyToManyModelF: any) => void;
@@ -2,69 +2,89 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.relationsTestSuite = void 0;
4
4
  const js_utils_1 = require("@goatlab/js-utils");
5
- let Model;
6
- let BelongsToModel;
7
- let ManyToManyModel;
8
- const relationsTestSuite = (ModelF, BelongsToModelF, ManyToManyModelF) => {
5
+ let User;
6
+ let Car;
7
+ let Role;
8
+ const relationsTestSuite = (UserRepo, BelongsToModelF, ManyToManyModelF) => {
9
9
  beforeAll(() => {
10
- Model = new ModelF();
11
- BelongsToModel = new BelongsToModelF();
12
- ManyToManyModel = new ManyToManyModelF();
10
+ User = new UserRepo();
11
+ Car = new BelongsToModelF();
12
+ Role = new ManyToManyModelF();
13
13
  });
14
+ const insertRelatedData = async () => {
15
+ const insertedUser = await User.insert({
16
+ name: 'testUser1',
17
+ age: 20
18
+ });
19
+ await User.insert({
20
+ name: 'anotherUser 2',
21
+ age: 24
22
+ });
23
+ const adminRole = await Role.insert({
24
+ name: 'Administrator'
25
+ });
26
+ const user = await User.loadById(insertedUser.id);
27
+ const attachedRole = await user.roles().attach(adminRole.id);
28
+ const associatedCar1 = await user.cars().associate({ name: 'My' });
29
+ const associatedCar2 = await user.cars().associate({ name: 'My new car 2' });
30
+ const associatedCar3 = await user.cars().associate({ name: 'My new car 4' });
31
+ const associatedCar4 = await user.cars().associate({ name: 'My new car 4' });
32
+ return { insertedUser, adminRole };
33
+ };
14
34
  test('requireById - Should return valid Object', async () => {
15
- const insertedUser = await Model.insert({
35
+ const insertedUser = await User.insert({
16
36
  name: 'testUser',
17
37
  age: 20
18
38
  });
19
39
  expect(typeof insertedUser.id).toBe('string');
20
- const findById = await Model.requireById(insertedUser.id);
40
+ const findById = await User.requireById(insertedUser.id);
21
41
  expect(findById.id).toBe(insertedUser.id);
22
42
  });
23
43
  test('requireById - Should fail if not found', async () => {
24
- const insertedUser = await Model.insert({
44
+ const insertedUser = await User.insert({
25
45
  name: 'testUser',
26
46
  age: 20
27
47
  });
28
- const [error, found] = await js_utils_1.Promises.try(Model.requireById('62ed01e4219a6ab760ae5c50'));
48
+ const [error, found] = await js_utils_1.Promises.try(User.requireById('62ed01e4219a6ab760ae5c50'));
29
49
  expect(error?.message).toBe('Object 62ed01e4219a6ab760ae5c50 not found');
30
50
  });
31
51
  test('loadFirst - Should return a cloned class', async () => {
32
- const insertedUser = await Model.insert({
52
+ const insertedUser = await User.insert({
33
53
  name: 'testUser',
34
54
  age: 20
35
55
  });
36
56
  expect(typeof insertedUser.id).toBe('string');
37
- const user = Model.loadFirst({
57
+ const user = User.loadFirst({
38
58
  where: {
39
59
  id: insertedUser.id
40
60
  }
41
61
  });
42
62
  expect(Array.isArray(user)).toBe(false);
43
63
  expect(typeof user).toBe('object');
44
- expect(typeof user.associate).toBe('function');
64
+ expect(user).toHaveProperty('associate');
45
65
  });
46
66
  test('Associate - OneToMany - Should insert data', async () => {
47
- const insertedUser = await Model.insert({
67
+ const insertedUser = await User.insert({
48
68
  name: 'testUser',
49
69
  age: 20
50
70
  });
51
71
  expect(typeof insertedUser.id).toBe('string');
52
- const user = await Model.loadById(insertedUser.id);
72
+ const user = await User.loadById(insertedUser.id);
53
73
  const cars = await user.cars().associate({ name: 'Another new car' });
54
74
  expect(Array.isArray(cars)).toBe(true);
55
75
  expect(cars[0].name).toBe('Another new car');
56
76
  expect(cars[0].userId).toBe(insertedUser.id);
57
77
  });
58
78
  test('Query related model - OneToMany (belongsToMany)', async () => {
59
- const insertedUser = await Model.insert({
79
+ const insertedUser = await User.insert({
60
80
  name: 'testUser',
61
81
  age: 20
62
82
  });
63
83
  expect(typeof insertedUser.id).toBe('string');
64
- const user1 = await Model.loadById(insertedUser.id);
84
+ const user1 = await User.loadById(insertedUser.id);
65
85
  const cars = await user1.cars().associate({ name: 'My new car' });
66
86
  expect(Array.isArray(cars)).toBe(true);
67
- const searchUserWithRelation = await Model.findMany({
87
+ const searchUserWithRelation = await User.findMany({
68
88
  where: { id: insertedUser.id },
69
89
  include: {
70
90
  cars: true
@@ -75,11 +95,13 @@ const relationsTestSuite = (ModelF, BelongsToModelF, ManyToManyModelF) => {
75
95
  expect(Array.isArray(firstResult.cars)).toBe(true);
76
96
  expect(firstResult.cars.length > 0).toBe(true);
77
97
  expect(firstResult.cars[0].userId).toBe(insertedUser.id);
78
- const searchCar = await user1
79
- .cars()
80
- .findMany({ where: { name: 'My new car' } });
98
+ const searchCar = await user1.cars().findMany({
99
+ where: { name: 'My new car' },
100
+ include: { user: true }
101
+ });
81
102
  expect(Array.isArray(searchCar)).toBe(true);
82
103
  expect(searchCar.length > 0).toBe(true);
104
+ expect(searchCar[0].user?.id).toBe(insertedUser.id);
83
105
  const searchCar2 = await user1
84
106
  .cars()
85
107
  .findMany({ where: { name: 'My.......' } });
@@ -87,14 +109,14 @@ const relationsTestSuite = (ModelF, BelongsToModelF, ManyToManyModelF) => {
87
109
  expect(searchCar2.length === 0).toBe(true);
88
110
  });
89
111
  test('Query related model - ManyToOne (BelongsTo)', async () => {
90
- const insertedUser = await Model.insert({
112
+ const insertedUser = await User.insert({
91
113
  name: 'testUser',
92
114
  age: 20
93
115
  });
94
116
  expect(typeof insertedUser.id).toBe('string');
95
- const user1 = await Model.loadById(insertedUser.id);
117
+ const user1 = await User.loadById(insertedUser.id);
96
118
  await user1.cars().associate({ name: 'My new car' });
97
- const results = await BelongsToModel.findMany({
119
+ const results = await Car.findMany({
98
120
  where: {
99
121
  userId: insertedUser.id
100
122
  },
@@ -107,43 +129,421 @@ const relationsTestSuite = (ModelF, BelongsToModelF, ManyToManyModelF) => {
107
129
  expect(typeof results[0].user?.name).toBe('string');
108
130
  expect(results[0].user['id']).toBe(insertedUser.id);
109
131
  });
132
+ test('Include - can load cyclical relations', async () => {
133
+ const { insertedUser } = await insertRelatedData();
134
+ const searchUserWithRelations = await User.findMany({
135
+ where: {
136
+ id: insertedUser.id
137
+ },
138
+ include: {
139
+ cars: {
140
+ include: {
141
+ user: {
142
+ include: {
143
+ cars: {
144
+ include: {
145
+ user: true
146
+ }
147
+ }
148
+ }
149
+ }
150
+ }
151
+ }
152
+ }
153
+ });
154
+ expect(searchUserWithRelations.length).toBe(1);
155
+ expect(searchUserWithRelations[0].cars?.length).toBe(4);
156
+ expect(searchUserWithRelations[0].cars[0].user?.id).toBe(insertedUser.id);
157
+ expect(searchUserWithRelations[0].cars[0].user?.name).toBe(insertedUser.name);
158
+ expect(searchUserWithRelations[0].cars[0].user?.id).toBe(searchUserWithRelations[0].id);
159
+ expect(searchUserWithRelations[0].cars[0].user?.name).toBe(searchUserWithRelations[0].name);
160
+ expect(searchUserWithRelations[0].cars[0].user?.cars?.length).toBe(4);
161
+ expect(searchUserWithRelations[0].cars[0].user?.cars[0].user?.id).toBe(searchUserWithRelations[0].id);
162
+ });
163
+ test('Include - can filter related models', async () => {
164
+ const { insertedUser } = await insertRelatedData();
165
+ const searchUserWithRelations = await User.findMany({
166
+ where: {
167
+ id: insertedUser.id
168
+ },
169
+ include: {
170
+ cars: {
171
+ select: {
172
+ name: true,
173
+ id: true
174
+ },
175
+ where: {
176
+ name: 'My new car 4'
177
+ },
178
+ include: {
179
+ user: {
180
+ include: {
181
+ cars: {
182
+ where: {
183
+ name: 'My new car XXXxX'
184
+ },
185
+ include: {
186
+ user: true
187
+ }
188
+ }
189
+ }
190
+ }
191
+ }
192
+ }
193
+ }
194
+ });
195
+ expect(searchUserWithRelations[0].cars?.length).toBe(2);
196
+ expect(searchUserWithRelations[0].cars[0].name).toBe('My new car 4');
197
+ expect(searchUserWithRelations[0].cars[0].user?.cars?.length).toBe(0);
198
+ });
199
+ test('Include - (One to Many) Should display [] if not found', async () => {
200
+ const { insertedUser } = await insertRelatedData();
201
+ const searchUserWithRelations = await User.findMany({
202
+ where: {
203
+ id: insertedUser.id
204
+ },
205
+ include: {
206
+ cars: {
207
+ where: {
208
+ name: 'My new car XX'
209
+ }
210
+ }
211
+ }
212
+ });
213
+ expect(Array.isArray(searchUserWithRelations[0].cars)).toBe(true);
214
+ expect(searchUserWithRelations[0].cars?.length).toBe(0);
215
+ });
216
+ test('Include - (Many to One) Should display null if not found', async () => {
217
+ const { insertedUser } = await insertRelatedData();
218
+ const insertedCars = await Car.findMany({
219
+ where: {
220
+ userId: insertedUser.id
221
+ },
222
+ select: {
223
+ id: true,
224
+ name: true,
225
+ userId: true,
226
+ user: true
227
+ },
228
+ include: {
229
+ user: {
230
+ where: {
231
+ name: 'JOHN'
232
+ }
233
+ }
234
+ }
235
+ });
236
+ expect(insertedCars[0].user === null || insertedCars[0].user === undefined).toBe(true);
237
+ expect(insertedCars.length).toBe(4);
238
+ });
239
+ test('Include - Should pull info from the main search object if no related data', async () => {
240
+ const { insertedUser } = await insertRelatedData();
241
+ const searchUserWithRelations = await User.findMany({
242
+ select: {
243
+ id: true,
244
+ name: true,
245
+ cars: {
246
+ name: true,
247
+ user: {
248
+ id: true,
249
+ name: true,
250
+ cars: {
251
+ id: true,
252
+ user: true,
253
+ name: true
254
+ }
255
+ }
256
+ }
257
+ },
258
+ where: {
259
+ id: insertedUser.id
260
+ },
261
+ include: {
262
+ cars: {
263
+ select: {
264
+ name: true,
265
+ id: true
266
+ },
267
+ where: {
268
+ name: 'My new car XXX'
269
+ },
270
+ include: {
271
+ user: {
272
+ include: {
273
+ cars: {
274
+ where: {
275
+ name: 'My new car XXXxX'
276
+ },
277
+ include: {
278
+ user: true
279
+ }
280
+ }
281
+ }
282
+ }
283
+ }
284
+ }
285
+ }
286
+ });
287
+ expect(searchUserWithRelations[0].id).toBe(insertedUser.id);
288
+ expect(searchUserWithRelations[0].name).toBe(insertedUser.name);
289
+ expect(searchUserWithRelations[0].cars?.length).toBe(0);
290
+ });
291
+ test('Include - Can filter and select specific keys', async () => {
292
+ const { insertedUser } = await insertRelatedData();
293
+ const searchUserWithRelations = await User.findMany({
294
+ select: {
295
+ id: true,
296
+ name: true,
297
+ age: true,
298
+ cars: {
299
+ name: true,
300
+ user: {
301
+ id: true,
302
+ name: true,
303
+ cars: {
304
+ id: true,
305
+ user: true,
306
+ name: true
307
+ }
308
+ }
309
+ }
310
+ },
311
+ where: {
312
+ id: insertedUser.id
313
+ },
314
+ include: {
315
+ cars: {
316
+ select: {
317
+ name: true,
318
+ id: true
319
+ },
320
+ where: {
321
+ name: 'My new car 4'
322
+ },
323
+ include: {
324
+ user: {
325
+ include: {
326
+ cars: {
327
+ where: {
328
+ name: 'My new car XXXxX'
329
+ },
330
+ include: {
331
+ user: true
332
+ }
333
+ }
334
+ }
335
+ }
336
+ }
337
+ }
338
+ }
339
+ });
340
+ expect(searchUserWithRelations[0]).toHaveProperty('age');
341
+ expect(searchUserWithRelations[0].age).toBe(insertedUser.age);
342
+ expect(searchUserWithRelations[0]).not.toHaveProperty('breed');
343
+ });
344
+ test('Include - Should filter keys from nested objects', async () => {
345
+ const { insertedUser } = await insertRelatedData();
346
+ const searchUserWithRelations = await User.findMany({
347
+ select: {
348
+ id: true,
349
+ name: true,
350
+ cars: {
351
+ name: true,
352
+ user: {
353
+ id: true,
354
+ name: true,
355
+ cars: {
356
+ id: true,
357
+ user: true,
358
+ name: true
359
+ }
360
+ }
361
+ }
362
+ },
363
+ where: {
364
+ id: insertedUser.id
365
+ },
366
+ include: {
367
+ cars: {
368
+ select: {
369
+ name: true
370
+ },
371
+ where: {
372
+ name: 'My new car 4'
373
+ },
374
+ include: {
375
+ user: {
376
+ select: {
377
+ id: true,
378
+ name: true
379
+ },
380
+ include: {
381
+ cars: {
382
+ where: {
383
+ name: 'My new car XXXxX'
384
+ },
385
+ include: {
386
+ user: true
387
+ }
388
+ }
389
+ }
390
+ }
391
+ }
392
+ }
393
+ }
394
+ });
395
+ expect(searchUserWithRelations[0].cars[0]).not.toHaveProperty('id');
396
+ expect(searchUserWithRelations[0].cars[0]).not.toHaveProperty('userId');
397
+ expect(searchUserWithRelations[0].cars[0]).toHaveProperty('user');
398
+ expect(searchUserWithRelations[0].cars[0].name).toBe('My new car 4');
399
+ expect(searchUserWithRelations[0].cars[0].user).not.toHaveProperty('age');
400
+ expect(searchUserWithRelations[0].cars[0].user).not.toHaveProperty('breed');
401
+ expect(searchUserWithRelations[0].cars[0].user?.id).toBe(insertedUser.id);
402
+ });
403
+ test('Include - Can select keys using main select or nested selects', async () => {
404
+ const { insertedUser } = await insertRelatedData();
405
+ await User.findMany({
406
+ select: {
407
+ id: true,
408
+ name: true,
409
+ cars: {
410
+ name: true,
411
+ user: {
412
+ id: true,
413
+ name: true,
414
+ cars: {
415
+ id: true,
416
+ user: true,
417
+ name: true
418
+ }
419
+ }
420
+ }
421
+ },
422
+ where: {
423
+ id: insertedUser.id
424
+ },
425
+ include: {
426
+ cars: {
427
+ select: {
428
+ name: true,
429
+ id: true
430
+ },
431
+ where: {
432
+ name: 'My new car 4'
433
+ },
434
+ include: {
435
+ user: {
436
+ include: {
437
+ cars: {
438
+ where: {
439
+ name: 'My new car XXXxX'
440
+ },
441
+ include: {
442
+ user: true
443
+ }
444
+ }
445
+ }
446
+ }
447
+ }
448
+ }
449
+ }
450
+ });
451
+ });
452
+ test('Include - (Many to Many) should display [] if not found', async () => {
453
+ const { insertedUser } = await insertRelatedData();
454
+ await User.findMany({
455
+ select: {
456
+ id: true,
457
+ name: true,
458
+ cars: {
459
+ name: true,
460
+ user: {
461
+ id: true,
462
+ name: true,
463
+ cars: {
464
+ id: true,
465
+ user: true,
466
+ name: true
467
+ }
468
+ }
469
+ }
470
+ },
471
+ where: {
472
+ id: insertedUser.id
473
+ },
474
+ include: {
475
+ cars: {
476
+ select: {
477
+ name: true,
478
+ id: true
479
+ },
480
+ where: {
481
+ name: 'My new car 4'
482
+ },
483
+ include: {
484
+ user: {
485
+ include: {
486
+ cars: {
487
+ where: {
488
+ name: 'My new car XXXxX'
489
+ },
490
+ include: {
491
+ user: true
492
+ }
493
+ }
494
+ }
495
+ }
496
+ }
497
+ }
498
+ }
499
+ });
500
+ });
110
501
  test('Query related model - ManyToMany', async () => {
111
- const insertedUser = await Model.insert({
502
+ const insertedUser = await User.insert({
112
503
  name: 'testUser',
113
504
  age: 20
114
505
  });
115
506
  expect(typeof insertedUser.id).toBe('string');
116
- const adminRole = await ManyToManyModel.insert({
507
+ const adminRole = await Role.insert({
117
508
  name: 'Administrator'
118
509
  });
119
- const user = await Model.loadById(insertedUser.id);
120
- const associated = await user.roles().attach(adminRole.id);
121
- expect(associated[0].userId).toBe(insertedUser.id);
122
- expect(associated[0].roleId).toBe(adminRole.id);
123
- const searchUserWithRelation = await Model.findMany({
510
+ const user = await User.loadById(insertedUser.id);
511
+ const attached = await user.roles().attach(adminRole.id);
512
+ expect(attached[0].userId).toBe(insertedUser.id);
513
+ expect(attached[0].roleId).toBe(adminRole.id);
514
+ const searchUserWithRelation = await User.findMany({
124
515
  where: {
125
516
  id: insertedUser.id
126
517
  },
127
518
  include: {
128
- roles: true
519
+ roles: {
520
+ withPivot: true
521
+ }
129
522
  }
130
523
  });
524
+ console.log(searchUserWithRelation[0]);
131
525
  expect(Array.isArray(searchUserWithRelation[0].roles)).toBe(true);
132
526
  expect(searchUserWithRelation[0].roles.length > 0).toBe(true);
133
527
  expect(typeof searchUserWithRelation[0].roles[0].name).toBe('string');
134
528
  expect(searchUserWithRelation[0].roles[0].id).toBe(adminRole.id);
135
- const roles = await ManyToManyModel.findMany({
529
+ expect(searchUserWithRelation[0].roles[0].pivot.id).toBe(attached[0].id);
530
+ const roles = await Role.findMany({
136
531
  where: {
137
532
  name: 'Administrator'
138
533
  },
139
534
  include: {
140
- users: true
535
+ users: { withPivot: true }
141
536
  }
142
537
  });
143
538
  expect(Array.isArray(roles)).toBe(true);
144
539
  expect(roles.length > 0).toBe(true);
145
540
  expect(typeof roles[0].users[0].name).toBe('string');
146
541
  expect(typeof roles[0].users[0].age).toBe('number');
542
+ expect(roles[0].users[0].pivot).toBeDefined();
543
+ expect(roles[0].users[0].id).toBe(roles[0].users[0].pivot.userId);
544
+ expect(roles.some(r => {
545
+ return r.users.some(u => u.id === insertedUser.id);
546
+ })).toBe(true);
147
547
  });
148
548
  };
149
549
  exports.relationsTestSuite = relationsTestSuite;