@goatlab/fluent-firebase 0.6.15 → 0.7.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 (65) hide show
  1. package/README.md +22 -4
  2. package/dist/Firebase.d.ts +4 -2
  3. package/dist/Firebase.js +7 -5
  4. package/dist/FirebaseConnector.d.ts +29 -34
  5. package/dist/FirebaseConnector.js +349 -345
  6. package/dist/FirebaseInit.d.ts +0 -0
  7. package/dist/FirebaseInit.js +0 -0
  8. package/dist/index.d.ts +0 -0
  9. package/dist/index.js +0 -0
  10. package/dist/test/car.repository.d.ts +8 -0
  11. package/dist/test/car.repository.js +21 -0
  12. package/dist/test/goat.repository.d.ts +3 -4
  13. package/dist/test/goat.repository.js +9 -6
  14. package/dist/test/roles.repository.d.ts +8 -0
  15. package/dist/test/roles.repository.js +21 -0
  16. package/dist/test/roles_user.repository.d.ts +6 -0
  17. package/dist/test/roles_user.repository.js +15 -0
  18. package/dist/test/typeOrm.repository.d.ts +5 -0
  19. package/dist/test/typeOrm.repository.js +15 -0
  20. package/dist/test/user.repository.d.ts +10 -0
  21. package/dist/test/user.repository.js +29 -0
  22. package/dist/tsconfig.tsbuildinfo +1 -1
  23. package/package.json +4 -94
  24. package/dist/firebaseConnector.http_spec.d.ts +0 -1
  25. package/dist/firebaseConnector.http_spec.js +0 -37
  26. package/dist/test/advanced/advancedTestSuite.d.ts +0 -1
  27. package/dist/test/advanced/advancedTestSuite.js +0 -114
  28. package/dist/test/advanced/firebase.repository.d.ts +0 -5
  29. package/dist/test/advanced/firebase.repository.js +0 -12
  30. package/dist/test/advanced/typeOrm.entity.d.ts +0 -16
  31. package/dist/test/advanced/typeOrm.entity.js +0 -57
  32. package/dist/test/basic/basicTestSuite.d.ts +0 -1
  33. package/dist/test/basic/basicTestSuite.js +0 -45
  34. package/dist/test/basic/goat.dto.d.ts +0 -8
  35. package/dist/test/basic/goat.dto.js +0 -18
  36. package/dist/test/basic/goat.entity.d.ts +0 -10
  37. package/dist/test/basic/goat.entity.js +0 -41
  38. package/dist/test/flock.d.ts +0 -4
  39. package/dist/test/flock.js +0 -25
  40. package/dist/test/relations/car/car.dto.d.ts +0 -5
  41. package/dist/test/relations/car/car.dto.js +0 -12
  42. package/dist/test/relations/car/car.entity.d.ts +0 -7
  43. package/dist/test/relations/car/car.entity.js +0 -32
  44. package/dist/test/relations/car/car.repositoryFirebase.d.ts +0 -8
  45. package/dist/test/relations/car/car.repositoryFirebase.js +0 -13
  46. package/dist/test/relations/relationsTestsSuite.d.ts +0 -1
  47. package/dist/test/relations/relationsTestsSuite.js +0 -93
  48. package/dist/test/relations/roles/role.dto.d.ts +0 -5
  49. package/dist/test/relations/roles/role.dto.js +0 -12
  50. package/dist/test/relations/roles/roles.entity.d.ts +0 -6
  51. package/dist/test/relations/roles/roles.entity.js +0 -29
  52. package/dist/test/relations/roles/roles.repositoryFirebase.d.ts +0 -8
  53. package/dist/test/relations/roles/roles.repositoryFirebase.js +0 -14
  54. package/dist/test/relations/roles/roles_user.dto.d.ts +0 -5
  55. package/dist/test/relations/roles/roles_user.dto.js +0 -12
  56. package/dist/test/relations/roles/roles_user.entity.d.ts +0 -5
  57. package/dist/test/relations/roles/roles_user.entity.js +0 -23
  58. package/dist/test/relations/roles/roles_users.repositoryFirebase.d.ts +0 -6
  59. package/dist/test/relations/roles/roles_users.repositoryFirebase.js +0 -11
  60. package/dist/test/relations/user/user.dto.d.ts +0 -5
  61. package/dist/test/relations/user/user.dto.js +0 -12
  62. package/dist/test/relations/user/user.entity.d.ts +0 -14
  63. package/dist/test/relations/user/user.entity.js +0 -56
  64. package/dist/test/relations/user/user.repositoryFirebase.d.ts +0 -10
  65. package/dist/test/relations/user/user.repositoryFirebase.js +0 -16
@@ -1,407 +1,366 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.FirebaseConnector = exports.createFirebaseRepository = void 0;
3
+ exports.FirebaseConnector = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  const admin = tslib_1.__importStar(require("firebase-admin"));
6
- const fireorm_1 = require("fireorm");
7
- const firestore_1 = require("@google-cloud/firestore");
8
6
  const fluent_1 = require("@goatlab/fluent");
7
+ const fluent_2 = require("@goatlab/fluent");
9
8
  const js_utils_1 = require("@goatlab/js-utils");
10
- const createFirebaseRepository = (Entity, dataSource) => {
11
- const typeOrmRepo = dataSource.getRepository(Entity);
12
- const repository = (0, fireorm_1.getRepository)(Entity);
13
- let name = '';
14
- let path = '';
15
- const relations = {};
16
- for (const relation of typeOrmRepo.metadata.relations) {
17
- relations[relation.propertyName] = {
18
- isOneToMany: relation.isOneToMany,
19
- isManyToOne: relation.isManyToOne,
20
- isManyToMany: relation.isManyToMany,
21
- inverseSidePropertyPath: relation.inverseSidePropertyPath,
22
- propertyPath: relation.propertyName,
23
- entityName: relation.inverseEntityMetadata.name,
24
- tableName: relation.inverseEntityMetadata.tableName,
25
- targetClass: relation.inverseEntityMetadata.target,
26
- joinColumns: relation.joinColumns,
27
- inverseJoinColumns: relation.inverseJoinColumns
28
- };
29
- }
30
- try {
31
- const parsed = JSON.parse(JSON.stringify(repository));
32
- name = parsed.colMetadata.name;
33
- path = parsed.path;
34
- }
35
- catch (error) {
36
- name = '';
37
- }
38
- return {
39
- repository,
40
- name,
41
- path,
42
- keys: [...['id', '_id'], ...(0, fluent_1.getOutputKeys)(typeOrmRepo)],
43
- relations
44
- };
45
- };
46
- exports.createFirebaseRepository = createFirebaseRepository;
47
- class FirebaseConnector extends fluent_1.BaseConnector {
48
- constructor(Entity, dataSource, relationQuery) {
9
+ class FirebaseConnector extends fluent_2.BaseConnector {
10
+ constructor({ entity, inputSchema, outputSchema }) {
49
11
  super();
50
- const { repository, keys, name, relations } = (0, exports.createFirebaseRepository)(Entity, dataSource);
51
- this.relationQuery = relationQuery;
52
- this.repository = repository;
53
- this.collection = admin.firestore().collection(name);
54
- this.outputKeys = keys || [];
12
+ this.inputSchema = inputSchema;
13
+ this.outputSchema =
14
+ outputSchema || inputSchema;
15
+ this.entity = entity;
16
+ const relationShipBuilder = fluent_1.modelGeneratorDataSource.getRepository(entity);
17
+ const name = relationShipBuilder.metadata.givenTableName;
18
+ if (!name) {
19
+ throw new Error(`Could not find table by name. Did you include @f.entity in your model?`);
20
+ }
21
+ this.collection = admin
22
+ .firestore()
23
+ .collection(name);
24
+ const { relations } = (0, fluent_1.getRelationsFromModelGenerator)(relationShipBuilder);
55
25
  this.modelRelations = relations;
26
+ this.outputKeys = (0, fluent_2.getOutputKeys)(relationShipBuilder) || [];
56
27
  }
57
- async get() {
58
- let query = this.getGeneratedQuery();
59
- let pivotData = [];
60
- if (this.relationQuery && this.relationQuery.data && this.relationQuery.relation) {
61
- const ids = this.relationQuery.data.map(d => d.id);
62
- if (this.relationQuery?.relation?.isManyToMany) {
63
- const pivotForeignKey = this.relationQuery.relation.joinColumns[0].propertyName;
64
- const pivotInverseKey = this.relationQuery.relation.inverseJoinColumns[0].propertyName;
65
- const { pivot } = this.relationQuery;
66
- pivotData = await pivot.where(key => key[pivotForeignKey], "in", ids).get();
67
- if (!pivotData.length) {
68
- return [];
69
- }
70
- const inverseIds = [...new Set(pivotData.map(d => d[pivotInverseKey]))];
71
- if (!inverseIds.length) {
72
- return [];
73
- }
74
- if (inverseIds.length) {
75
- query = query.where("id", 'in', inverseIds);
76
- }
28
+ async insert(data) {
29
+ const validatedData = this.inputSchema.parse(data);
30
+ if (data['id']) {
31
+ const found = await this.findById(data['id']);
32
+ if (found) {
33
+ throw new Error(`A document with id ${found[0]['id']} already exists.`);
77
34
  }
78
- else {
79
- query = query.where(this.relationQuery.relation.inverseSidePropertyPath, 'in', ids);
80
- }
81
- }
82
- const snapshot = await query.get();
83
- const result = [];
84
- snapshot.forEach(doc => {
85
- result.push(doc.data());
86
- });
87
- let data = this.jsApplySelect(result);
88
- data = await (0, fluent_1.loadRelations)({
89
- data,
90
- relations: this.relations,
91
- modelRelations: this.modelRelations,
92
- provider: 'firebase',
93
- self: this,
94
- returnPivot: Boolean(this.relationQuery?.returnPivot)
95
- });
96
- if (pivotData.length && this.relationQuery?.returnPivot) {
97
- const pivotInverseKey = this.relationQuery.relation.inverseJoinColumns[0].propertyName;
98
- data = data.map(d => {
99
- return { ...d, pivot: pivotData.find(p => p[pivotInverseKey] === d.id) };
100
- });
101
35
  }
102
- this.reset();
103
- return data;
104
- }
105
- async getPaginated() {
106
- const response = await this.get();
107
- const result = this.jsApplySelect(response);
108
- const results = {
109
- current_page: 1,
110
- data: result,
111
- first_page_url: 'response[0].meta.firstPageUrl,',
112
- next_page_url: 'response[0].meta.nextPageUrl',
113
- path: 'response[0].meta.path',
114
- per_page: 1,
115
- prev_page_url: ' response[0].meta.previousPageUrl',
116
- total: 10
36
+ const id = data['id'] || js_utils_1.Ids.objectIdString();
37
+ const item = {
38
+ id,
39
+ ...validatedData
117
40
  };
118
- return results;
119
- }
120
- async all() {
121
- return this.get();
41
+ await this.collection.doc(id).set(item);
42
+ return this.outputSchema.parse(this.clearEmpties(js_utils_1.Objects.deleteNulls(item)));
122
43
  }
123
- async find(filter = {}) {
124
- const stringFilter = filter;
125
- let parsedFilter = {};
126
- try {
127
- parsedFilter = JSON.parse(stringFilter);
128
- }
129
- catch (error) {
130
- parsedFilter = {};
131
- }
132
- this.selectArray = (parsedFilter && parsedFilter.fields) || [];
133
- this.whereArray =
134
- (parsedFilter && parsedFilter.where && parsedFilter.where.and) || [];
135
- this.orWhereArray =
136
- (parsedFilter && parsedFilter.where && parsedFilter.where.or) || [];
137
- this.limit((parsedFilter && (parsedFilter.limit || parsedFilter.take)) || 20);
138
- this.offset((parsedFilter && (parsedFilter.offset || parsedFilter.skip)) || 0);
139
- if (parsedFilter && parsedFilter.order) {
140
- const orderB = [
141
- parsedFilter.order.field,
142
- parsedFilter.order.asc ? 'asc' : 'desc',
143
- parsedFilter.order.type || 'string'
144
- ];
145
- this.chainReference.push({ method: 'orderBy', orderB });
146
- this.orderByArray = orderB;
147
- }
148
- return this.get();
149
- }
150
- async paginate(paginator) {
151
- if (!paginator) {
152
- throw new Error('Paginator cannot be empty');
153
- }
154
- this.paginator = paginator;
155
- const response = await this.getPaginated();
156
- return response;
44
+ async insertMany(data) {
45
+ const validatedData = this.inputSchema.array().parse(data);
46
+ const batch = admin.firestore().batch();
47
+ const batchInserted = [];
48
+ validatedData.forEach(d => {
49
+ const id = d['id'] || js_utils_1.Ids.objectIdString();
50
+ const item = { id, ...d };
51
+ const insert = this.collection.doc(id);
52
+ batch.set(insert, item);
53
+ batchInserted.push(item);
54
+ });
55
+ await batch.commit();
56
+ return this.outputSchema.array().parse(batchInserted.map(d => {
57
+ return this.clearEmpties(js_utils_1.Objects.deleteNulls(d));
58
+ }));
157
59
  }
158
60
  raw() {
159
61
  return this.collection;
160
62
  }
161
- async insert(data, forcedId) {
162
- const id = forcedId || js_utils_1.Ids.objectIdString();
163
- const datum = await this.repository.create({ id, ...data });
164
- const result = this.jsApplySelect([datum]);
165
- this.reset();
166
- return result[0];
63
+ rawFirebase() {
64
+ return admin.firestore();
167
65
  }
168
- async insertMany(data, forcedId) {
169
- const batch = [];
170
- data.forEach(d => {
171
- const id = js_utils_1.Ids.objectIdString();
172
- batch.push(this.repository.create({ id, ...d }));
173
- });
174
- const inserted = await Promise.all(batch);
175
- const result = this.jsApplySelect(inserted);
176
- this.reset();
177
- return result;
178
- }
179
- async batchInsert(data) {
180
- const batch = this.repository.createBatch();
181
- data.forEach(d => {
182
- const id = js_utils_1.Ids.objectIdString();
183
- batch.create({ id, ...d });
66
+ async loadRelatedData(data, loadedKeys) {
67
+ let pivotData = [];
68
+ const result = await (0, fluent_2.loadRelations)({
69
+ data,
70
+ relations: loadedKeys,
71
+ modelRelations: this.modelRelations,
72
+ provider: 'firebase',
73
+ self: this,
74
+ returnPivot: false
184
75
  });
185
- const inserted = await batch.commit();
186
- const result = this.jsApplySelect(inserted);
187
- this.reset();
188
76
  return result;
189
77
  }
190
- async updateById(id, data) {
191
- const parsedId = id;
192
- const dbResult = await this.repository.findById(parsedId);
193
- const updateData = {
194
- ...dbResult,
195
- ...data
196
- };
197
- const updated = await this.repository.update(updateData);
198
- const result = this.jsApplySelect([updated]);
199
- this.reset();
200
- return result[0];
201
- }
202
- async replaceById(id, data) {
203
- const parsedId = id;
204
- const value = await this.repository.findById(parsedId);
205
- const flatValue = js_utils_1.Objects.flatten(JSON.parse(JSON.stringify(value)));
206
- Object.keys(flatValue).forEach(key => {
207
- if (key !== 'id') {
208
- flatValue[key] = null;
209
- }
210
- });
211
- const nullObject = js_utils_1.Objects.nest(flatValue);
212
- const newValue = { ...nullObject, ...data };
213
- delete newValue.created;
214
- delete newValue.updated;
215
- const entity = { ...newValue };
216
- await this.repository.update(entity);
217
- const val = await this.repository.findById(parsedId);
218
- const returnValue = this.jsApplySelect([val]);
219
- this.reset();
220
- return returnValue[0];
221
- }
222
- async clear({ sure }) {
223
- if (!sure || sure !== true) {
224
- throw new Error('Clear() method will delete everything!, you must set the "sure" parameter "clear({sure:true})" to continue');
78
+ async findMany(query) {
79
+ const [andQuery, orQueries] = this.getGeneratedQueries(query);
80
+ const results = [];
81
+ if (andQuery) {
82
+ const snapshot = await andQuery.get();
83
+ snapshot.forEach(doc => {
84
+ results.push(doc.data());
85
+ });
225
86
  }
226
- const query = this.collection.orderBy('__name__').limit(300);
227
- this.reset();
228
- return new Promise((resolve, reject) => {
229
- this.deleteQueryBatch(admin.firestore(), query, 300, resolve, reject);
87
+ const promises = [];
88
+ for (const orQuery of orQueries) {
89
+ promises.push(orQuery.get());
90
+ }
91
+ const orSnapshots = await Promise.all(promises);
92
+ for (const orSnapshot of orSnapshots) {
93
+ orSnapshot.forEach(doc => {
94
+ results.push(doc.data());
95
+ });
96
+ }
97
+ let found = [...new Map(results.map(v => [v.id, v])).values()];
98
+ found.map(d => {
99
+ this.clearEmpties(js_utils_1.Objects.deleteNulls(d));
230
100
  });
231
- }
232
- async deleteById(id) {
233
- const parsedId = id;
234
- await this.repository.delete(parsedId);
235
- this.reset();
236
- return id;
237
- }
238
- async findById(id) {
239
- const parsedId = id;
240
- const data = await this.repository.findById(parsedId);
241
- const result = this.jsApplySelect(data);
242
- this.reset();
243
- if (result.length === 0) {
244
- return null;
101
+ if (query?.include) {
102
+ found = await this.loadRelatedData(found, js_utils_1.Objects.flatten(query?.include || {}));
245
103
  }
246
- return result[0];
247
- }
248
- async findByIds(ids) {
249
- const data = await this.raw().where('id', 'in', ids).get();
250
- if (data.empty) {
251
- return null;
104
+ if (query?.paginated) {
105
+ const paginationInfo = {
106
+ total: 0,
107
+ perPage: query.paginated.perPage,
108
+ currentPage: query.paginated.page,
109
+ nextPage: query.paginated.page + 1,
110
+ firstPage: 1,
111
+ lastPage: Math.ceil(0 / query.paginated.perPage),
112
+ prevPage: query.paginated.page === 1 ? null : query.paginated.page - 1,
113
+ from: (query.paginated.page - 1) * query.paginated.perPage + 1,
114
+ to: query.paginated.perPage * query.paginated.page,
115
+ data: found
116
+ };
117
+ return paginationInfo;
252
118
  }
253
- const res = [];
254
- data.forEach(doc => {
255
- res.push(doc.data());
119
+ if (query?.select) {
120
+ return found;
121
+ }
122
+ return this.outputSchema?.array().parse(found);
123
+ }
124
+ loadFirst(query) {
125
+ const detachedClass = Object.assign(Object.create(Object.getPrototypeOf(this)), this);
126
+ detachedClass.setRelatedQuery({
127
+ entity: this.entity,
128
+ repository: this,
129
+ query
256
130
  });
257
- const results = this.jsApplySelect(res);
258
- this.reset();
259
- return results;
131
+ return detachedClass;
260
132
  }
261
- getPage() {
262
- const page = 'page=';
263
- if (this.paginator && this.paginator.page) {
264
- return `${page + this.paginator.page}&`;
133
+ getGeneratedQueries(query) {
134
+ let { andWhere, orWhere } = this.getFirebaseWhereQuery(query?.where);
135
+ let mergedQueries = [];
136
+ if (andWhere) {
137
+ mergedQueries = [andWhere, ...orWhere];
265
138
  }
266
- return '';
267
- }
268
- getPaginatorLimit(filter) {
269
- if (this.paginator && this.paginator.perPage) {
270
- return { ...filter, limit: this.paginator.perPage };
139
+ else {
140
+ mergedQueries = orWhere;
271
141
  }
272
- return filter;
273
- }
274
- getPopulate() {
275
- const populate = [];
276
- this.populateArray.forEach(relation => {
277
- if (typeof relation === 'string') {
278
- populate.push({ relation });
142
+ const select = Object.keys(js_utils_1.Objects.flatten(query?.select || {}));
143
+ for (const [index] of mergedQueries.entries()) {
144
+ if (select?.length > 0) {
145
+ mergedQueries[index] = mergedQueries[index].select(...['id', ...select]);
279
146
  }
280
- else if (Array.isArray(relation)) {
281
- relation.forEach(nestedRelation => {
282
- if (typeof nestedRelation === 'string') {
283
- populate.push({ relation: nestedRelation });
147
+ mergedQueries[index] = mergedQueries[index].limit(query?.limit || 10);
148
+ mergedQueries[index] = mergedQueries[index].offset(query?.offset || 0);
149
+ if (query?.orderBy) {
150
+ for (const order of query?.orderBy) {
151
+ const flattenObject = js_utils_1.Objects.flatten(order);
152
+ for (const attribute of Object.keys(flattenObject)) {
153
+ mergedQueries[index] = mergedQueries[index].orderBy(attribute, flattenObject[attribute]);
284
154
  }
285
- else if (typeof nestedRelation === 'object') {
286
- populate.push(nestedRelation);
287
- }
288
- });
289
- }
290
- else if (typeof relation === 'object') {
291
- populate.push(relation);
155
+ }
292
156
  }
293
- });
294
- return populate;
295
- }
296
- getGeneratedQuery() {
297
- let queryBuilder = this.getFilters();
298
- const select = this.getSelect();
299
- if (select.length > 0) {
300
- queryBuilder = queryBuilder.select(...this.getSelect());
301
157
  }
302
- const limit = this.getLimit();
303
- if (limit > 0) {
304
- queryBuilder = queryBuilder.limit(limit);
158
+ const cloned = [...mergedQueries];
159
+ if (andWhere) {
160
+ cloned.shift();
305
161
  }
306
- const skip = this.getSkip();
307
- if (skip) {
308
- queryBuilder = queryBuilder.offset(skip);
162
+ return [andWhere ? mergedQueries[0] : undefined, cloned];
163
+ }
164
+ getFirebaseWhereQuery(where) {
165
+ if (!where || Object.keys(where).length === 0) {
166
+ return { andWhere: this.collection, orWhere: [] };
309
167
  }
310
- const order = this.getOrderBy();
311
- if (order[0] && order[0] !== '') {
312
- const fieldPath = new firestore_1.FieldPath(order[0] || '');
313
- const orderByOrder = order[1] || 'desc';
314
- queryBuilder = queryBuilder.orderBy(fieldPath, orderByOrder);
168
+ let andWhereQuery = this.collection;
169
+ let orWhereQueries = [];
170
+ const orConditions = this.extractConditions(where['OR']);
171
+ const andConditions = this.extractConditions(where['AND']);
172
+ const copy = js_utils_1.Objects.clone(where);
173
+ if (!!copy['AND']) {
174
+ delete copy['AND'];
315
175
  }
316
- return queryBuilder;
317
- }
318
- getFilters() {
319
- const andFilters = this.whereArray;
320
- const orFilters = this.orWhereArray;
321
- if (!andFilters || andFilters.length === 0) {
322
- return this.collection;
176
+ if (!!copy['OR']) {
177
+ delete copy['OR'];
323
178
  }
324
- let filterQuery;
325
- andFilters.forEach((condition, index) => {
326
- const element = condition[0];
327
- const operator = condition[1];
328
- const value = condition[2];
329
- if (index === 0) {
330
- filterQuery = this.collection;
331
- }
179
+ const rootLevelConditions = this.extractConditions([copy]);
180
+ for (const condition of andConditions) {
181
+ const { element, operator, value } = condition;
332
182
  switch (operator) {
333
- case '=':
334
- filterQuery = filterQuery.where(element, '==', value);
183
+ case fluent_1.LogicOperator.equals:
184
+ andWhereQuery = andWhereQuery.where(element, '==', value);
335
185
  break;
336
- case '!=':
337
- filterQuery = filterQuery.where(element, '!=', value);
186
+ case fluent_1.LogicOperator.isNot:
187
+ andWhereQuery = andWhereQuery.where(element, '!=', value);
338
188
  break;
339
- case '>':
340
- filterQuery = filterQuery.where(element, operator, value);
189
+ case fluent_1.LogicOperator.greaterThan:
190
+ andWhereQuery = andWhereQuery.where(element, '>', value);
341
191
  break;
342
- case '>=':
343
- filterQuery = filterQuery.where(element, operator, value);
192
+ case fluent_1.LogicOperator.greaterOrEqualThan:
193
+ andWhereQuery = andWhereQuery.where(element, '>=', value);
344
194
  break;
345
- case '<':
346
- filterQuery = filterQuery.where(element, operator, value);
195
+ case fluent_1.LogicOperator.lessThan:
196
+ andWhereQuery = andWhereQuery.where(element, '<', value);
347
197
  break;
348
- case '<=':
349
- filterQuery = filterQuery.where(element, operator, value);
198
+ case fluent_1.LogicOperator.lessOrEqualThan:
199
+ andWhereQuery = andWhereQuery.where(element, '<=', value);
350
200
  break;
351
- case 'in':
352
- filterQuery = filterQuery.where(element, 'in', value);
201
+ case fluent_1.LogicOperator.in:
202
+ andWhereQuery = andWhereQuery.where(element, 'in', value);
353
203
  break;
354
- case 'array-contains':
355
- filterQuery = filterQuery.where(element, 'array-contains', value);
204
+ case fluent_1.LogicOperator.arrayContains:
205
+ andWhereQuery = andWhereQuery.where(element, 'array-contains', value);
356
206
  break;
357
- case 'nin':
358
- throw new Error('The nin Operator cannot be used in Firabase');
207
+ case fluent_1.LogicOperator.notIn:
208
+ andWhereQuery = andWhereQuery.where(element, 'not-in', value);
359
209
  break;
360
- case 'exists':
210
+ case fluent_1.LogicOperator.exists:
361
211
  throw new Error('The nin Operator cannot be used in Firabase');
362
- break;
363
- case '!exists':
212
+ case fluent_1.LogicOperator.notExists:
364
213
  throw new Error('The !exists Operator cannot be used in Firabase');
214
+ case fluent_1.LogicOperator.regexp:
215
+ throw new Error('The regexp Operator cannot be used in Firabase');
216
+ default:
217
+ throw new Error('The regexp Operator cannot be used in Firabase');
218
+ }
219
+ }
220
+ for (const condition of rootLevelConditions) {
221
+ const { element, operator, value } = condition;
222
+ switch (operator) {
223
+ case fluent_1.LogicOperator.equals:
224
+ andWhereQuery = andWhereQuery.where(element, '==', value);
225
+ break;
226
+ case fluent_1.LogicOperator.isNot:
227
+ andWhereQuery = andWhereQuery.where(element, '!=', value);
228
+ break;
229
+ case fluent_1.LogicOperator.greaterThan:
230
+ andWhereQuery = andWhereQuery.where(element, '>', value);
365
231
  break;
366
- case 'regexp':
232
+ case fluent_1.LogicOperator.greaterOrEqualThan:
233
+ andWhereQuery = andWhereQuery.where(element, '>=', value);
234
+ break;
235
+ case fluent_1.LogicOperator.lessThan:
236
+ andWhereQuery = andWhereQuery.where(element, '<', value);
237
+ break;
238
+ case fluent_1.LogicOperator.lessOrEqualThan:
239
+ andWhereQuery = andWhereQuery.where(element, '<=', value);
240
+ break;
241
+ case fluent_1.LogicOperator.in:
242
+ andWhereQuery = andWhereQuery.where(element, 'in', value);
243
+ break;
244
+ case fluent_1.LogicOperator.arrayContains:
245
+ andWhereQuery = andWhereQuery.where(element, 'array-contains', value);
246
+ break;
247
+ case fluent_1.LogicOperator.notIn:
248
+ andWhereQuery = andWhereQuery.where(element, 'not-in', value);
249
+ break;
250
+ case fluent_1.LogicOperator.exists:
251
+ throw new Error('The nin Operator cannot be used in Firabase');
252
+ case fluent_1.LogicOperator.notExists:
253
+ throw new Error('The !exists Operator cannot be used in Firabase');
254
+ case fluent_1.LogicOperator.regexp:
367
255
  throw new Error('The regexp Operator cannot be used in Firabase');
256
+ default:
257
+ throw new Error('The regexp Operator cannot be used in Firabase');
258
+ }
259
+ }
260
+ for (const condition of orConditions) {
261
+ const { element, operator, value } = condition;
262
+ let orQuery = this.collection;
263
+ switch (operator) {
264
+ case fluent_1.LogicOperator.equals:
265
+ orQuery = orQuery.where(element, '==', value);
266
+ break;
267
+ case fluent_1.LogicOperator.isNot:
268
+ orQuery = orQuery.where(element, '!=', value);
269
+ break;
270
+ case fluent_1.LogicOperator.greaterThan:
271
+ orQuery = orQuery.where(element, '>', value);
272
+ break;
273
+ case fluent_1.LogicOperator.greaterOrEqualThan:
274
+ orQuery = orQuery.where(element, '>=', value);
275
+ break;
276
+ case fluent_1.LogicOperator.lessThan:
277
+ orQuery = orQuery.where(element, '<', value);
278
+ break;
279
+ case fluent_1.LogicOperator.lessOrEqualThan:
280
+ orQuery = orQuery.where(element, '<=', value);
368
281
  break;
282
+ case fluent_1.LogicOperator.in:
283
+ orQuery = orQuery.where(element, 'in', value);
284
+ break;
285
+ case fluent_1.LogicOperator.arrayContains:
286
+ orQuery = orQuery.where(element, 'array-contains', value);
287
+ break;
288
+ case fluent_1.LogicOperator.notIn:
289
+ orQuery = orQuery.where(element, 'not-in', value);
290
+ break;
291
+ case fluent_1.LogicOperator.exists:
292
+ throw new Error('The nin Operator cannot be used in Firabase');
293
+ case fluent_1.LogicOperator.notExists:
294
+ throw new Error('The !exists Operator cannot be used in Firabase');
295
+ case fluent_1.LogicOperator.regexp:
296
+ throw new Error('The regexp Operator cannot be used in Firabase');
297
+ default:
298
+ throw new Error('The regexp Operator cannot be used in Firabase');
369
299
  }
370
- });
371
- return filterQuery;
372
- }
373
- getOrderBy() {
374
- if (!this.orderByArray || this.orderByArray.length === 0) {
375
- return [];
300
+ orWhereQueries.push(orQuery);
376
301
  }
377
- return [this.orderByArray[0], this.orderByArray[1].toLowerCase()];
378
- }
379
- getLimit() {
380
- if (!this.limitNumber || this.limitNumber === 0) {
381
- this.limitNumber = (this.rawQuery && this.rawQuery.limit) || 20;
302
+ let andWhereCondition = undefined;
303
+ if (!andConditions?.length &&
304
+ !rootLevelConditions?.length &&
305
+ !orConditions?.length) {
306
+ andWhereCondition = this.collection;
382
307
  }
383
- return this.limitNumber;
384
- }
385
- getSkip() {
386
- if (!this.offsetNumber) {
387
- this.offsetNumber = (this.rawQuery && this.rawQuery.skip) || 0;
308
+ if (andConditions?.length || rootLevelConditions?.length) {
309
+ andWhereCondition = andWhereQuery;
388
310
  }
389
- return this.offsetNumber;
311
+ return {
312
+ andWhere: andWhereCondition,
313
+ orWhere: orWhereQueries
314
+ };
390
315
  }
391
- getSelect() {
392
- let select = this.selectArray;
393
- select = select.map(s => {
394
- s = s.split(' as ')[0];
395
- s = s.includes('id') ? 'id' : s;
396
- return s;
316
+ async updateById(id, data) {
317
+ const dataToInsert = this.outputKeys.includes('updated')
318
+ ? {
319
+ ...data,
320
+ ...{ updated: new Date() }
321
+ }
322
+ : data;
323
+ const validatedData = this.inputSchema.parse(dataToInsert);
324
+ await this.collection.doc(id).update({
325
+ ...validatedData,
326
+ id
397
327
  });
398
- if (select.find(e => e.startsWith('data.'))) {
399
- select.unshift('data');
400
- }
401
- if (!select) {
402
- return [];
328
+ const dbResult = await this.findById(id);
329
+ if (!dbResult) {
330
+ throw new Error(`Object not found: ${id}`);
403
331
  }
404
- return select;
332
+ return this.outputSchema?.parse(this.clearEmpties(js_utils_1.Objects.deleteNulls(dbResult)));
333
+ }
334
+ async replaceById(id, data) {
335
+ const value = await this.findById(id);
336
+ const flatValue = js_utils_1.Objects.flatten(JSON.parse(JSON.stringify(value)));
337
+ Object.keys(flatValue).forEach(key => {
338
+ flatValue[key] = null;
339
+ });
340
+ const nullObject = js_utils_1.Objects.nest(flatValue);
341
+ const newValue = { ...nullObject, ...data };
342
+ delete newValue._id;
343
+ delete newValue.id;
344
+ delete newValue.created;
345
+ delete newValue.updated;
346
+ const dataToInsert = this.outputKeys.includes('updated')
347
+ ? {
348
+ ...data,
349
+ ...{ updated: new Date() }
350
+ }
351
+ : data;
352
+ const validatedData = this.inputSchema.parse(dataToInsert);
353
+ await this.collection
354
+ .doc(id)
355
+ .update(validatedData);
356
+ const val = await this.findById(id);
357
+ return this.outputSchema.parse(this.clearEmpties(js_utils_1.Objects.deleteNulls(val)));
358
+ }
359
+ async clear() {
360
+ const query = this.collection.orderBy('__name__').limit(300);
361
+ return new Promise((resolve, reject) => {
362
+ this.deleteQueryBatch(admin.firestore(), query, 300, resolve, reject);
363
+ });
405
364
  }
406
365
  deleteQueryBatch(db, query, batchSize, resolve, reject) {
407
366
  query
@@ -427,5 +386,50 @@ class FirebaseConnector extends fluent_1.BaseConnector {
427
386
  })
428
387
  .catch(reject);
429
388
  }
389
+ loadById(id) {
390
+ const newInstance = this.clone();
391
+ newInstance.setRelatedQuery({
392
+ entity: this.entity,
393
+ repository: this,
394
+ query: {
395
+ where: {
396
+ id
397
+ }
398
+ }
399
+ });
400
+ return newInstance;
401
+ }
402
+ clone() {
403
+ return new this.constructor();
404
+ }
405
+ async findByIds(ids, q) {
406
+ let data = await this.findMany({
407
+ where: {
408
+ id: {
409
+ in: ids
410
+ }
411
+ },
412
+ limit: q?.limit,
413
+ select: q?.select,
414
+ include: q?.include
415
+ });
416
+ return this.outputSchema?.array().parse(data);
417
+ }
418
+ async findById(id, q) {
419
+ const found = await this.findByIds([id], q);
420
+ return found[0];
421
+ }
422
+ async requireById(id, q) {
423
+ let found = await this.findById(id, {
424
+ select: q?.select,
425
+ include: q?.include,
426
+ limit: 1
427
+ });
428
+ if (!found) {
429
+ throw new Error(`Object ${id} not found`);
430
+ }
431
+ found = this.clearEmpties(js_utils_1.Objects.deleteNulls(found));
432
+ return this.outputSchema?.parse(found);
433
+ }
430
434
  }
431
435
  exports.FirebaseConnector = FirebaseConnector;