@goatlab/fluent 0.6.18 → 0.6.19

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.
@@ -1,10 +1,11 @@
1
1
  import { TypedPathWrapper } from 'typed-path';
2
- import { Filter, DaoOutput, BaseDaoExtendedAttributes, LogicOperator, Primitives, PrimitivesArray } from './types';
3
2
  import { Collection } from '@goatlab/js-utils';
3
+ import { Filter, DaoOutput, BaseDaoExtendedAttributes, LogicOperator, Primitives, PrimitivesArray } from './types';
4
4
  export interface FluentConnectorInterface<InputDTO, OutputDTO> {
5
5
  get(): Promise<DaoOutput<InputDTO, OutputDTO>[]>;
6
6
  all(filter: Filter): Promise<DaoOutput<InputDTO, OutputDTO>[]>;
7
7
  findById(id: string): Promise<DaoOutput<InputDTO, OutputDTO>>;
8
+ findByIds(id: string[]): Promise<DaoOutput<InputDTO, OutputDTO>[]>;
8
9
  find(filter: Filter): Promise<DaoOutput<InputDTO, OutputDTO>[]>;
9
10
  deleteById(id: string): Promise<string>;
10
11
  updateById(id: string, data: InputDTO): Promise<DaoOutput<InputDTO, OutputDTO>>;
@@ -12,7 +13,7 @@ export interface FluentConnectorInterface<InputDTO, OutputDTO> {
12
13
  insertMany(data: InputDTO[]): Promise<DaoOutput<InputDTO, OutputDTO>[]>;
13
14
  }
14
15
  export declare abstract class BaseConnector<ModelDTO, InputDTO, OutputDTO> {
15
- _keys: TypedPathWrapper<ModelDTO & InputDTO & OutputDTO, Record<never, never> & {
16
+ generatedKeyPath: TypedPathWrapper<ModelDTO & InputDTO & OutputDTO, Record<never, never> & {
16
17
  $path: (path: import("typed-path").TypedPathKey[]) => string;
17
18
  $raw: (path: import("typed-path").TypedPathKey[]) => string[];
18
19
  $rawPath: (path: import("typed-path").TypedPathKey[]) => import("typed-path").TypedPathKey[];
@@ -43,24 +44,26 @@ export declare abstract class BaseConnector<ModelDTO, InputDTO, OutputDTO> {
43
44
  isMongoDB: boolean;
44
45
  protected getExtendedCreateAttributes: () => BaseDaoExtendedAttributes;
45
46
  constructor();
47
+ findByIds(ids: string[]): Promise<DaoOutput<InputDTO, OutputDTO>[]>;
46
48
  get(): Promise<DaoOutput<InputDTO, OutputDTO>[]>;
47
49
  insertMany(data: InputDTO[]): Promise<DaoOutput<InputDTO, OutputDTO>[]>;
50
+ updateById(id: string, data: InputDTO): Promise<DaoOutput<InputDTO, OutputDTO>>;
48
51
  owner(user: string): this;
49
52
  own(user: string): this;
50
53
  first(): Promise<DaoOutput<InputDTO, OutputDTO> | null>;
51
54
  collect(): Promise<Collection<DaoOutput<InputDTO, OutputDTO>>>;
52
- select(...columns: TypedPathWrapper<Primitives, Primitives>[]): this;
53
- forceSelect(...columns: TypedPathWrapper<Primitives, Primitives>[]): this;
55
+ select(paths: (p: TypedPathWrapper<ModelDTO & InputDTO & OutputDTO, Record<never, never>>) => TypedPathWrapper<string, Record<never, never>>[] | TypedPathWrapper<string[], Record<never, never>[]>): this;
56
+ forceSelect(paths: (p: TypedPathWrapper<ModelDTO & InputDTO & OutputDTO, Record<never, never>>) => TypedPathWrapper<string, Record<never, never>>[] | TypedPathWrapper<string[], Record<never, never>[]>): this;
54
57
  offset(offset: number): this;
55
58
  populate(...relations: any[]): this;
56
59
  skip(offset: number): this;
57
- where(path: TypedPathWrapper<Primitives, Primitives>, operator: LogicOperator, value: Primitives | PrimitivesArray): this;
58
- andWhere(path: TypedPathWrapper<Primitives, Primitives>, operator: LogicOperator, value: Primitives | Primitives[]): this;
59
- orWhere(path: TypedPathWrapper<Primitives, Primitives>, operator: LogicOperator, value: Primitives): this;
60
+ where(path: (p: TypedPathWrapper<ModelDTO & InputDTO & OutputDTO, Record<never, never>>) => TypedPathWrapper<string, Record<never, never>> | TypedPathWrapper<string[], Record<never, never>>, operator: LogicOperator, value: Primitives | PrimitivesArray): this;
61
+ andWhere(path: (p: TypedPathWrapper<ModelDTO & InputDTO & OutputDTO, Record<never, never>>) => TypedPathWrapper<string, Record<never, never>> | TypedPathWrapper<string[], Record<never, never>>, operator: LogicOperator, value: Primitives | Primitives[]): this;
62
+ orWhere(path: (p: TypedPathWrapper<ModelDTO & InputDTO & OutputDTO, Record<never, never>>) => TypedPathWrapper<string, Record<never, never>> | TypedPathWrapper<string[], Record<never, never>>, operator: LogicOperator, value: Primitives): this;
60
63
  limit(limit: number): this;
61
64
  take(limit: number): this;
62
- pluck(path: TypedPathWrapper<Primitives, Primitives>): Promise<string[]>;
63
- orderBy(path: TypedPathWrapper<Primitives, Primitives>, order?: 'asc' | 'desc', orderType?: 'string' | 'number' | 'date'): this;
65
+ pluck(path: (p: TypedPathWrapper<ModelDTO & InputDTO & OutputDTO, Record<never, never>>) => TypedPathWrapper<string, Record<never, never>> | TypedPathWrapper<string[], Record<never, never>>): Promise<string[]>;
66
+ orderBy(path: (p: TypedPathWrapper<ModelDTO & InputDTO & OutputDTO, Record<never, never>>) => TypedPathWrapper<string, Record<never, never>> | TypedPathWrapper<string[], Record<never, never>>, order?: 'asc' | 'desc', orderType?: 'string' | 'number' | 'date'): this;
64
67
  protected jsApplySelect(data: any): any[];
65
68
  protected jsApplyOrderBy(data: any): any[];
66
69
  protected reset(): void;
@@ -68,12 +71,13 @@ export declare abstract class BaseConnector<ModelDTO, InputDTO, OutputDTO> {
68
71
  loadFirst(): Promise<this>;
69
72
  getLoadedData(): DaoOutput<InputDTO, OutputDTO>[] | DaoOutput<InputDTO, OutputDTO>;
70
73
  with(entities: any): this;
71
- attach(data: InputDTO): Promise<DaoOutput<InputDTO, OutputDTO>[]>;
74
+ attach(data: InputDTO | DaoOutput<InputDTO, OutputDTO>): Promise<DaoOutput<InputDTO, OutputDTO>[]>;
72
75
  associate(id: string): any;
73
76
  protected hasMany<T>(Repository: any, relationName: string): T;
74
77
  protected hasOne(): void;
75
78
  protected belongsTo<T>(Repository: any, relationName: string): T;
76
79
  protected belongsToMany<T, R>(Repository: any, Pivot: any, relationName: string): T;
80
+ withPivot(): this;
77
81
  protected hasManyThrough(): void;
78
82
  private prepareInput;
79
83
  }
@@ -6,7 +6,7 @@ const dates_1 = require("@goatlab/dates");
6
6
  const js_utils_1 = require("@goatlab/js-utils");
7
7
  class BaseConnector {
8
8
  constructor() {
9
- this._keys = (0, typed_path_1.typedPath)();
9
+ this.generatedKeyPath = (0, typed_path_1.typedPath)();
10
10
  this.chainReference = [];
11
11
  this.whereArray = [];
12
12
  this.orWhereArray = [];
@@ -50,12 +50,18 @@ class BaseConnector {
50
50
  this.outputKeys = [];
51
51
  this.getFirst = false;
52
52
  }
53
+ async findByIds(ids) {
54
+ throw new Error('findByIds() method not implemented');
55
+ }
53
56
  async get() {
54
57
  throw new Error('get() method not implemented');
55
58
  }
56
59
  async insertMany(data) {
57
60
  throw new Error('get() method not implemented');
58
61
  }
62
+ async updateById(id, data) {
63
+ throw new Error('get() method not implemented');
64
+ }
59
65
  owner(user) {
60
66
  this.chainReference.push({ method: 'owner', args: user });
61
67
  this.ownerId = user;
@@ -79,19 +85,23 @@ class BaseConnector {
79
85
  }
80
86
  return new js_utils_1.Collection(data);
81
87
  }
82
- select(...columns) {
83
- columns = this.prepareInput(columns);
88
+ select(paths) {
89
+ const arrCols = paths(this.generatedKeyPath);
90
+ const cols = arrCols.map(c => c.toString());
91
+ const columns = this.prepareInput(cols);
84
92
  this.chainReference.push({ method: 'select', args: columns });
85
93
  this.selectArray = this.selectArray
86
94
  .concat(columns)
87
95
  .filter((elem, pos, arr) => arr.indexOf(elem) === pos);
88
96
  return this;
89
97
  }
90
- forceSelect(...columns) {
98
+ forceSelect(paths) {
91
99
  if (typeof module === 'undefined' || !module.exports) {
92
100
  throw new Error('forceSelect cant be used in frontend');
93
101
  }
94
- columns = this.prepareInput(columns);
102
+ const arrCols = paths(this.generatedKeyPath);
103
+ const cols = arrCols.map(c => c.toString());
104
+ const columns = this.prepareInput(cols);
95
105
  this.chainReference.push({ method: 'forceSelect', args: columns });
96
106
  this.forceSelectArray = this.forceSelectArray
97
107
  .concat(columns)
@@ -112,7 +122,8 @@ class BaseConnector {
112
122
  return this.offset(offset);
113
123
  }
114
124
  where(path, operator, value) {
115
- const stringPath = path.toString();
125
+ const stringP = path(this.generatedKeyPath);
126
+ const stringPath = stringP.toString();
116
127
  const chainedWhere = [stringPath, operator, value];
117
128
  this.chainReference.push({ method: 'where', chainedWhere });
118
129
  this.whereArray = [];
@@ -120,14 +131,16 @@ class BaseConnector {
120
131
  return this;
121
132
  }
122
133
  andWhere(path, operator, value) {
123
- const stringPath = path.toString();
134
+ const stringP = path(this.generatedKeyPath);
135
+ const stringPath = stringP.toString();
124
136
  const chainedWhere = [stringPath, operator, value];
125
137
  this.chainReference.push({ method: 'andWhere', chainedWhere });
126
138
  this.whereArray.push(chainedWhere);
127
139
  return this;
128
140
  }
129
141
  orWhere(path, operator, value) {
130
- const stringPath = path.toString();
142
+ const stringP = path(this.generatedKeyPath);
143
+ const stringPath = stringP.toString();
131
144
  const chainedWhere = [stringPath, operator, value];
132
145
  this.chainReference.push({ method: 'orWhere', chainedWhere });
133
146
  this.orWhereArray.push(chainedWhere);
@@ -142,7 +155,8 @@ class BaseConnector {
142
155
  return this.limit(limit);
143
156
  }
144
157
  async pluck(path) {
145
- const stringPath = path.toString();
158
+ const stringP = path(this.generatedKeyPath);
159
+ const stringPath = stringP.toString();
146
160
  this.chainReference.push({ method: 'pluck', args: stringPath });
147
161
  const data = await this.get();
148
162
  const result = data.map(e => {
@@ -154,7 +168,8 @@ class BaseConnector {
154
168
  return result;
155
169
  }
156
170
  orderBy(path, order = 'desc', orderType = 'string') {
157
- const stringPath = path.toString();
171
+ const stringP = path(this.generatedKeyPath);
172
+ const stringPath = stringP.toString();
158
173
  const orderB = [stringPath, order, orderType];
159
174
  this.chainReference.push({ method: 'orderBy', orderB });
160
175
  this.orderByArray = orderB;
@@ -279,39 +294,53 @@ class BaseConnector {
279
294
  if (!this.relationQuery.relation || !this.relationQuery.data) {
280
295
  throw new Error('Attached can only be called as a related model');
281
296
  }
282
- if (this.relationQuery && this.relationQuery.data) {
283
- const D = Array.isArray(this.relationQuery.data)
284
- ? this.relationQuery.data
285
- : [this.relationQuery.data];
286
- const relatedData = D.map(d => ({
287
- [this.relationQuery.relation.inverseSidePropertyPath]: this.isMongoDB
288
- ? js_utils_1.Ids.objectID(d.id)
289
- : d.id,
290
- ...data
291
- }));
292
- return await this.insertMany(relatedData);
297
+ const foreignKeyName = this.relationQuery.relation.inverseSidePropertyPath;
298
+ const D = Array.isArray(this.relationQuery.data)
299
+ ? this.relationQuery.data
300
+ : [this.relationQuery.data];
301
+ const relatedData = D.map(d => ({
302
+ [foreignKeyName]: this.isMongoDB
303
+ ? js_utils_1.Ids.objectID(d.id)
304
+ : d.id,
305
+ ...data
306
+ }));
307
+ const existingData = await this.findByIds(relatedData.map(r => r.id));
308
+ const updateQueries = [];
309
+ const insertQueries = [];
310
+ for (const related of relatedData) {
311
+ const exists = existingData.find(d => d.id === related.id);
312
+ if (exists) {
313
+ updateQueries.push(this.updateById(exists.id, {
314
+ ...exists,
315
+ [foreignKeyName]: related[foreignKeyName]
316
+ }));
317
+ }
318
+ else {
319
+ insertQueries.push(related);
320
+ }
293
321
  }
322
+ const updateResult = await Promise.all(updateQueries);
323
+ const insertedResult = await this.insertMany(insertQueries);
324
+ return [...updateResult, ...insertedResult];
294
325
  }
295
326
  associate(id) {
296
- if (!this.relationQuery.relation || !this.relationQuery.data) {
297
- throw new Error('Attached can only be called as a related model');
298
- }
299
- if (this.relationQuery && this.relationQuery.data) {
300
- const D = Array.isArray(this.relationQuery.data)
301
- ? this.relationQuery.data
302
- : [this.relationQuery.data];
303
- const relatedData = D.map(d => ({
304
- [this.relationQuery.relation.joinColumns[0].propertyName]: this
305
- .isMongoDB
306
- ? js_utils_1.Ids.objectID(d.id)
307
- : d.id,
308
- [this.relationQuery.relation.inverseJoinColumns[0].propertyName]: this
309
- .isMongoDB
310
- ? js_utils_1.Ids.objectID(id)
311
- : id
312
- }));
313
- return this.relationQuery.pivot.insertMany(relatedData);
327
+ if (!this.relationQuery?.relation || !this.relationQuery.data) {
328
+ throw new Error('Associate can only be called as a related model');
314
329
  }
330
+ const D = Array.isArray(this.relationQuery.data)
331
+ ? this.relationQuery.data
332
+ : [this.relationQuery.data];
333
+ const relatedData = D.map(d => ({
334
+ [this.relationQuery.relation.joinColumns[0].propertyName]: this
335
+ .isMongoDB
336
+ ? js_utils_1.Ids.objectID(d.id)
337
+ : d.id,
338
+ [this.relationQuery.relation.inverseJoinColumns[0].propertyName]: this
339
+ .isMongoDB
340
+ ? js_utils_1.Ids.objectID(id)
341
+ : id
342
+ }));
343
+ return this.relationQuery.pivot.insertMany(relatedData);
315
344
  }
316
345
  hasMany(Repository, relationName) {
317
346
  if (this.relationQuery) {
@@ -346,6 +375,12 @@ class BaseConnector {
346
375
  this.reset();
347
376
  return newClass;
348
377
  }
378
+ withPivot() {
379
+ if (this.relationQuery?.pivot) {
380
+ this.relationQuery.returnPivot = true;
381
+ }
382
+ return this;
383
+ }
349
384
  hasManyThrough() {
350
385
  throw new Error('Method not implemented');
351
386
  }
@@ -6,8 +6,8 @@ export declare const getRelations: (typeOrmRepo: any) => {
6
6
  relations: {};
7
7
  };
8
8
  export declare class TypeOrmConnector<ModelDTO = BaseDataElement, InputDTO = ModelDTO, OutputDTO = InputDTO> extends BaseConnector<ModelDTO, InputDTO, OutputDTO> implements FluentConnectorInterface<InputDTO, DaoOutput<InputDTO, OutputDTO>> {
9
- private repository;
10
- private dataSource;
9
+ private readonly repository;
10
+ private readonly dataSource;
11
11
  constructor(entity: any, dataSource: DataSource, relationQuery?: any);
12
12
  get(): Promise<DaoOutput<InputDTO, OutputDTO>[]>;
13
13
  getPaginated(): Promise<PaginatedData<DaoOutput<InputDTO, OutputDTO>>>;
@@ -22,6 +22,7 @@ export declare class TypeOrmConnector<ModelDTO = BaseDataElement, InputDTO = Mod
22
22
  clear({ sure }: Sure): Promise<boolean>;
23
23
  deleteById(id: string): Promise<string>;
24
24
  findById(id: string): Promise<DaoOutput<InputDTO, OutputDTO>>;
25
+ findByIds(ids: string[]): Promise<DaoOutput<InputDTO, OutputDTO>[]>;
25
26
  private getPage;
26
27
  private getPaginatorLimit;
27
28
  private getPopulate;
@@ -11,7 +11,7 @@ const generatorDatasource_1 = require("../generatorDatasource");
11
11
  const getRelations = typeOrmRepo => {
12
12
  const relations = {};
13
13
  for (const relation of typeOrmRepo.metadata.relations) {
14
- relations[relation.inverseEntityMetadata.givenTableName.toLowerCase()] = {
14
+ relations[relation.propertyName] = {
15
15
  isOneToMany: relation.isOneToMany,
16
16
  isManyToOne: relation.isManyToOne,
17
17
  isManyToMany: relation.isManyToMany,
@@ -140,7 +140,7 @@ class TypeOrmConnector extends BaseConnector_1.BaseConnector {
140
140
  ...{ updated: new Date() }
141
141
  }
142
142
  : data;
143
- const updated = await this.repository.update(id, dataToInsert);
143
+ await this.repository.update(id, dataToInsert);
144
144
  const dbResult = await this.repository.findBy({
145
145
  id: (0, typeorm_1.In)([parsedId])
146
146
  });
@@ -185,8 +185,7 @@ class TypeOrmConnector extends BaseConnector_1.BaseConnector {
185
185
  if (!sure || sure !== true) {
186
186
  throw new Error('Clear() method will delete everything!, you must set the "sure" parameter "clear({sure:true})" to continue');
187
187
  }
188
- return;
189
- const data = await this.repository.clear();
188
+ await this.repository.clear();
190
189
  this.reset();
191
190
  return true;
192
191
  }
@@ -194,7 +193,7 @@ class TypeOrmConnector extends BaseConnector_1.BaseConnector {
194
193
  const parsedId = this.isMongoDB
195
194
  ? new mongodb_1.ObjectId(id)
196
195
  : id;
197
- const removed = this.repository.delete(parsedId);
196
+ await this.repository.delete(parsedId);
198
197
  this.reset();
199
198
  return id;
200
199
  }
@@ -209,6 +208,17 @@ class TypeOrmConnector extends BaseConnector_1.BaseConnector {
209
208
  this.reset();
210
209
  return result[0];
211
210
  }
211
+ async findByIds(ids) {
212
+ const parsedIds = [...ids];
213
+ if (this.isMongoDB) {
214
+ parsedIds.map(id => new mongodb_1.ObjectId(id));
215
+ }
216
+ const data = await this.repository.findBy({
217
+ id: (0, typeorm_1.In)(parsedIds)
218
+ });
219
+ const result = this.jsApplySelect(data);
220
+ return result;
221
+ }
212
222
  getPage() {
213
223
  const page = 'page=';
214
224
  if (this.paginator && this.paginator.page) {
@@ -48,48 +48,49 @@ const advancedTestSuite = Model => {
48
48
  });
49
49
  it('pluck() should return a single array', async () => {
50
50
  await insertTestData(Model);
51
- const data = await Model.pluck(Model._keys.test);
51
+ const data = await Model.pluck(keys => keys.test);
52
52
  expect(typeof data[0]).toBe('boolean');
53
53
  });
54
54
  it('orderBy() should order results desc', async () => {
55
55
  await insertTestData(Model);
56
- const forms = await Model.select(Model._keys.test, Model._keys.nestedTest.b.c, Model._keys.order)
57
- .orderBy(Model._keys.order, 'desc')
56
+ const forms = await Model.select(keys => [keys.test, keys.nestedTest.b.c, keys.order])
57
+ .orderBy(keys => keys.order, 'desc')
58
58
  .get();
59
59
  expect(forms[0].order).toBe(3);
60
60
  expect(forms[0].nestedTest.b.c).toBe(true);
61
61
  });
62
62
  it('orderBy() should order results asc', async () => {
63
63
  await insertTestData(Model);
64
- const forms = await Model.select(Model._keys.test, Model._keys.nestedTest.b.c, Model._keys.order)
65
- .orderBy(Model._keys.order, 'asc')
64
+ const forms = await Model.select(keys => [keys.test, keys.nestedTest.b.c, keys.order])
65
+ .orderBy(keys => keys.order, 'asc')
66
66
  .get();
67
67
  expect(forms[0].order).toBe(1);
68
68
  });
69
69
  it('orderBy() should order by Dates with Select()', async () => {
70
70
  await insertTestData(Model);
71
- const forms = await Model.select(Model._keys.created, Model._keys.order)
72
- .orderBy(Model._keys.created, 'asc', 'date')
71
+ const forms = await Model.select(keys => [keys.created, keys.order])
72
+ .orderBy(keys => keys.created, 'asc', 'date')
73
73
  .get();
74
74
  expect(forms[0].order).toBe(3);
75
75
  });
76
76
  it('orderBy() should order by Dates without Select()', async () => {
77
77
  await insertTestData(Model);
78
- const forms = await Model.orderBy(Model._keys.created, 'asc', 'date').get();
78
+ const forms = await Model.orderBy(keys => keys.created, 'asc', 'date').get();
79
79
  expect(forms[0].order).toBe(3);
80
80
  });
81
81
  it('limit() should limit the amount of results', async () => {
82
82
  await insertTestData(Model);
83
- const forms = await Model.select(Model._keys.created, Model._keys.order)
84
- .orderBy(Model._keys.created, 'asc', 'date')
83
+ const forms = await Model.select(keys => [keys.created, keys.order])
84
+ .orderBy(keys => keys.created, 'asc', 'date')
85
85
  .limit(2)
86
86
  .get();
87
+ console.log('FOOORMS LENGTH', forms[0]);
87
88
  expect(forms.length > 0).toBe(true);
88
89
  expect(forms.length <= 2).toBe(true);
89
90
  });
90
91
  it('offset() should start at the given position', async () => {
91
92
  await insertTestData(Model);
92
- const forms = await Model.select(Model._keys.created, Model._keys.order)
93
+ const forms = await Model.select(keys => [keys.created, keys.order])
93
94
  .offset(1)
94
95
  .limit(1)
95
96
  .get();
@@ -97,7 +98,7 @@ const advancedTestSuite = Model => {
97
98
  });
98
99
  it('where() should filter the data', async () => {
99
100
  await insertTestData(Model);
100
- const forms = await Model.where(Model._keys.nestedTest.c, '>=', 3).get();
101
+ const forms = await Model.where(keys => keys.nestedTest.c, '>=', 3).get();
101
102
  expect(forms.length > 0).toBe(true);
102
103
  forms.forEach(form => {
103
104
  expect(form.nestedTest.c >= 3).toBe(true);
@@ -105,8 +106,8 @@ const advancedTestSuite = Model => {
105
106
  });
106
107
  it('first() should take the first result from data', async () => {
107
108
  await insertTestData(Model);
108
- const form = await Model.select(Model._keys.nestedTest.c, Model._keys.id)
109
- .where(Model._keys.nestedTest.c, '>=', 3)
109
+ const form = await Model.select(keys => [keys.nestedTest.c, keys.id])
110
+ .where(keys => keys.nestedTest.c, '>=', 3)
110
111
  .first();
111
112
  expect(typeof form.nestedTest.c).toBe('number');
112
113
  });
@@ -1 +1 @@
1
- export declare const relationsTestSuite: (Model: any, BelongsToModel: any, ManyToManyModel: any) => void;
1
+ export declare const relationsTestSuite: (ModelF: any, BelongsToModelF: any, ManyToManyModelF: any) => void;
@@ -1,11 +1,14 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.relationsTestSuite = void 0;
4
- const relationsTestSuite = (Model, BelongsToModel, ManyToManyModel) => {
4
+ let Model;
5
+ let BelongsToModel;
6
+ let ManyToManyModel;
7
+ const relationsTestSuite = (ModelF, BelongsToModelF, ManyToManyModelF) => {
5
8
  beforeAll(() => {
6
- Model = new Model();
7
- BelongsToModel = new BelongsToModel();
8
- ManyToManyModel = new ManyToManyModel();
9
+ Model = new ModelF();
10
+ BelongsToModel = new BelongsToModelF();
11
+ ManyToManyModel = new ManyToManyModelF();
9
12
  });
10
13
  test('Attach - OneToMany - Should insert data', async () => {
11
14
  const insertedUser = await Model.insert({
@@ -13,7 +16,7 @@ const relationsTestSuite = (Model, BelongsToModel, ManyToManyModel) => {
13
16
  age: 20
14
17
  });
15
18
  expect(typeof insertedUser.id).toBe('string');
16
- const user = await Model.where(Model.cars()._keys.id, '=', insertedUser.id).load();
19
+ const user = await Model.where(keys => keys.id, '=', insertedUser.id).load();
17
20
  const cars = await user.cars().attach({ name: 'Another new car' });
18
21
  expect(Array.isArray(cars)).toBe(true);
19
22
  expect(cars[0].name).toBe('Another new car');
@@ -24,36 +27,36 @@ const relationsTestSuite = (Model, BelongsToModel, ManyToManyModel) => {
24
27
  age: 20
25
28
  });
26
29
  expect(typeof insertedUser.id).toBe('string');
27
- const user1 = await Model.where(Model._keys.id, '=', insertedUser.id).load();
30
+ const user1 = await Model.where(keys => keys.id, '=', insertedUser.id).load();
28
31
  const cars = await user1.cars().attach({ name: 'My new car' });
29
32
  expect(Array.isArray(cars)).toBe(true);
30
- const searchUserWithRelation = await Model.where(Model._keys.id, '=', insertedUser.id)
31
- .with({ cars: true })
33
+ const searchUserWithRelation = await Model.where(keys => keys.id, '=', insertedUser.id)
34
+ .with({ cars: BelongsToModelF })
32
35
  .get();
33
36
  expect(Array.isArray(searchUserWithRelation[0].cars)).toBe(true);
34
37
  expect(searchUserWithRelation[0].cars.length > 0).toBe(true);
35
38
  const searchCar = await user1
36
39
  .cars()
37
- .where(Model.cars()._keys.name, '=', 'My new car')
40
+ .where(keys => keys.name, '=', 'My new car')
38
41
  .get();
39
42
  expect(Array.isArray(searchCar)).toBe(true);
40
43
  expect(searchCar.length > 0).toBe(true);
41
44
  const searchCar2 = await user1
42
45
  .cars()
43
- .where(Model.cars()._keys.name, '=', 'My.......')
46
+ .where(keys => keys.name, '=', 'My.......')
44
47
  .get();
45
48
  expect(Array.isArray(searchCar2)).toBe(true);
46
49
  expect(searchCar2.length === 0).toBe(true);
47
50
  });
48
- test('Query related model - BelongsTo', async () => {
51
+ test('Query related model - BelongTo', async () => {
49
52
  const insertedUser = await Model.insert({
50
53
  name: 'testUser',
51
54
  age: 20
52
55
  });
53
56
  expect(typeof insertedUser.id).toBe('string');
54
- const user1 = await Model.where(Model.cars()._keys.id, '=', insertedUser.id).load();
57
+ const user1 = await Model.where(keys => keys.id, '=', insertedUser.id).load();
55
58
  await user1.cars().attach({ name: 'My new car' });
56
- const results = await BelongsToModel.with({ users: true }).get();
59
+ const results = await BelongsToModel.with({ user: ModelF }).get();
57
60
  expect(Array.isArray(results)).toBe(true);
58
61
  expect(results.length > 0).toBe(true);
59
62
  expect(typeof results[0].user.name).toBe('string');
@@ -67,21 +70,21 @@ const relationsTestSuite = (Model, BelongsToModel, ManyToManyModel) => {
67
70
  const adminRole = await ManyToManyModel.insert({
68
71
  name: 'Administrator'
69
72
  });
70
- const user = await Model.where(Model._keys.id, '=', insertedUser.id).load();
73
+ const user = await Model.where(keys => keys.id, '=', insertedUser.id).load();
71
74
  const associated = await user.roles().associate(adminRole.id);
72
75
  expect(associated[0].userId).toBe(insertedUser.id);
73
76
  expect(associated[0].roleId).toBe(adminRole.id);
74
- const searchUserWithRelation = await Model.where(Model._keys.id, '=', insertedUser.id)
77
+ const searchUserWithRelation = await Model.where(keys => keys.id, '=', insertedUser.id)
75
78
  .with({
76
- roles: true
79
+ roles: ManyToManyModelF
77
80
  })
78
81
  .get();
79
82
  expect(Array.isArray(searchUserWithRelation[0].roles)).toBe(true);
80
83
  expect(searchUserWithRelation[0].roles.length > 0).toBe(true);
81
84
  expect(typeof searchUserWithRelation[0].roles[0].name).toBe('string');
82
- const roles = await ManyToManyModel.where(ManyToManyModel._keys.name, '=', 'Administrator')
85
+ const roles = await ManyToManyModel.where(keys => keys.name, '=', 'Administrator')
83
86
  .with({
84
- users: true
87
+ users: ModelF
85
88
  })
86
89
  .get();
87
90
  expect(Array.isArray(roles)).toBe(true);
@@ -6,6 +6,7 @@ interface RelationshipLoader {
6
6
  dataSource?: DataSource;
7
7
  provider?: 'typeorm' | 'firebase';
8
8
  self: any;
9
+ returnPivot?: boolean;
9
10
  }
10
- export declare const loadRelations: ({ data, relations, modelRelations, dataSource, provider, self }: RelationshipLoader) => Promise<any[]>;
11
+ export declare const loadRelations: ({ data, relations, modelRelations, provider, self, returnPivot }: RelationshipLoader) => Promise<any[]>;
11
12
  export {};
@@ -2,7 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.loadRelations = void 0;
4
4
  const js_utils_1 = require("@goatlab/js-utils");
5
- const loadRelations = async ({ data, relations, modelRelations, dataSource, provider, self }) => {
5
+ const loadRelations = async ({ data, relations, modelRelations, provider, self, returnPivot }) => {
6
6
  if (!relations) {
7
7
  return data;
8
8
  }
@@ -12,11 +12,11 @@ const loadRelations = async ({ data, relations, modelRelations, dataSource, prov
12
12
  const relationModel = modelRelations[relation];
13
13
  const Model = new relations[relation]();
14
14
  if (relationModel.isOneToMany) {
15
- const ids = js_utils_1.Arrays.deDuplicate(data.map(d => Model.isMongoDB ? js_utils_1.Ids.objectID(d.id) : d.id));
16
- const chunks = js_utils_1.Arrays.chunk(ids, chunkSize);
15
+ const ids = new Set(data.map(d => Model.isMongoDB ? js_utils_1.Ids.objectID(d.id) : d.id));
16
+ const chunks = js_utils_1.Arrays.chunk(Array.from(ids), chunkSize);
17
17
  const promises = [];
18
18
  for (const relatedIds of chunks) {
19
- const results = await Model.andWhere(Model._keys[relationModel.inverseSidePropertyPath], 'in', relatedIds).get();
19
+ const results = await Model.andWhere(keys => keys[relationModel.inverseSidePropertyPath], 'in', relatedIds).get();
20
20
  promises.push(results);
21
21
  }
22
22
  const relatedResults = js_utils_1.Arrays.collapse(await Promise.all(promises));
@@ -32,7 +32,7 @@ const loadRelations = async ({ data, relations, modelRelations, dataSource, prov
32
32
  const chunks = js_utils_1.Arrays.chunk(ids, chunkSize);
33
33
  const promises = [];
34
34
  for (const relatedIds of chunks) {
35
- const results = await Model.andWhere(Model._keys.id, 'in', relatedIds).get();
35
+ const results = await Model.andWhere(keys => keys.id, 'in', relatedIds).get();
36
36
  promises.push(results);
37
37
  }
38
38
  const relatedResults = js_utils_1.Arrays.collapse(promises);
@@ -54,7 +54,7 @@ const loadRelations = async ({ data, relations, modelRelations, dataSource, prov
54
54
  const promises = [];
55
55
  for (const pivotIds of chunks) {
56
56
  const results = await pivotRepository
57
- .where(relationModel.joinColumns[0].propertyName, 'in', pivotIds)
57
+ .where(k => k[relationModel.joinColumns[0].propertyName], 'in', pivotIds)
58
58
  .get();
59
59
  promises.push(results);
60
60
  }
@@ -63,10 +63,14 @@ const loadRelations = async ({ data, relations, modelRelations, dataSource, prov
63
63
  const relationChunks = js_utils_1.Arrays.chunk(uniquePivotIds, chunkSize);
64
64
  const relationPromises = [];
65
65
  for (const relatedIds of relationChunks) {
66
- const results = await Model.andWhere(Model._keys.id, 'in', relatedIds).get();
66
+ const results = await Model.andWhere(keys => keys.id, 'in', relatedIds).get();
67
67
  relationPromises.push(results);
68
68
  }
69
- const relatedResults = js_utils_1.Arrays.collapse(await Promise.all(relationPromises));
69
+ let relatedResults = js_utils_1.Arrays.collapse(await Promise.all(relationPromises));
70
+ const pivotInverseKey = relationModel.inverseJoinColumns[0].propertyName;
71
+ relatedResults = relatedResults.map(r => {
72
+ return { ...r, pivot: pivotResults.find(p => p[pivotInverseKey] === r.id) };
73
+ });
70
74
  const groupedPivot = js_utils_1.Arrays.groupBy(pivotResults, r => r[relationModel.joinColumns[0].propertyName]);
71
75
  const groupedRelated = js_utils_1.Arrays.groupBy(relatedResults, r => r.id);
72
76
  data.forEach(d => {