@goatlab/fluent-firebase 0.6.16 → 0.7.2
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.
- package/README.md +22 -4
- package/dist/Firebase.d.ts +4 -2
- package/dist/Firebase.js +7 -5
- package/dist/FirebaseConnector.d.ts +29 -34
- package/dist/FirebaseConnector.js +349 -345
- package/dist/test/car.repository.d.ts +8 -0
- package/dist/test/car.repository.js +21 -0
- package/dist/test/goat.repository.d.ts +3 -4
- package/dist/test/goat.repository.js +9 -6
- package/dist/test/roles.repository.d.ts +8 -0
- package/dist/test/roles.repository.js +21 -0
- package/dist/test/roles_user.repository.d.ts +6 -0
- package/dist/test/roles_user.repository.js +15 -0
- package/dist/test/typeOrm.repository.d.ts +5 -0
- package/dist/test/typeOrm.repository.js +15 -0
- package/dist/test/user.repository.d.ts +10 -0
- package/dist/test/user.repository.js +29 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +5 -95
- package/dist/firebaseConnector.http_spec.d.ts +0 -1
- package/dist/firebaseConnector.http_spec.js +0 -37
- package/dist/test/advanced/advancedTestSuite.d.ts +0 -1
- package/dist/test/advanced/advancedTestSuite.js +0 -114
- package/dist/test/advanced/firebase.repository.d.ts +0 -5
- package/dist/test/advanced/firebase.repository.js +0 -12
- package/dist/test/advanced/typeOrm.entity.d.ts +0 -16
- package/dist/test/advanced/typeOrm.entity.js +0 -57
- package/dist/test/basic/basicTestSuite.d.ts +0 -1
- package/dist/test/basic/basicTestSuite.js +0 -45
- package/dist/test/basic/goat.dto.d.ts +0 -8
- package/dist/test/basic/goat.dto.js +0 -18
- package/dist/test/basic/goat.entity.d.ts +0 -10
- package/dist/test/basic/goat.entity.js +0 -41
- package/dist/test/flock.d.ts +0 -4
- package/dist/test/flock.js +0 -25
- package/dist/test/relations/car/car.dto.d.ts +0 -5
- package/dist/test/relations/car/car.dto.js +0 -12
- package/dist/test/relations/car/car.entity.d.ts +0 -7
- package/dist/test/relations/car/car.entity.js +0 -32
- package/dist/test/relations/car/car.repositoryFirebase.d.ts +0 -8
- package/dist/test/relations/car/car.repositoryFirebase.js +0 -13
- package/dist/test/relations/relationsTestsSuite.d.ts +0 -1
- package/dist/test/relations/relationsTestsSuite.js +0 -93
- package/dist/test/relations/roles/role.dto.d.ts +0 -5
- package/dist/test/relations/roles/role.dto.js +0 -12
- package/dist/test/relations/roles/roles.entity.d.ts +0 -6
- package/dist/test/relations/roles/roles.entity.js +0 -29
- package/dist/test/relations/roles/roles.repositoryFirebase.d.ts +0 -8
- package/dist/test/relations/roles/roles.repositoryFirebase.js +0 -14
- package/dist/test/relations/roles/roles_user.dto.d.ts +0 -5
- package/dist/test/relations/roles/roles_user.dto.js +0 -12
- package/dist/test/relations/roles/roles_user.entity.d.ts +0 -5
- package/dist/test/relations/roles/roles_user.entity.js +0 -23
- package/dist/test/relations/roles/roles_users.repositoryFirebase.d.ts +0 -6
- package/dist/test/relations/roles/roles_users.repositoryFirebase.js +0 -11
- package/dist/test/relations/user/user.dto.d.ts +0 -5
- package/dist/test/relations/user/user.dto.js +0 -12
- package/dist/test/relations/user/user.entity.d.ts +0 -14
- package/dist/test/relations/user/user.entity.js +0 -56
- package/dist/test/relations/user/user.repositoryFirebase.d.ts +0 -10
- 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 =
|
|
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
|
-
|
|
11
|
-
|
|
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
|
-
|
|
51
|
-
this.
|
|
52
|
-
|
|
53
|
-
this.
|
|
54
|
-
|
|
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
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
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
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
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
|
-
|
|
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
|
|
124
|
-
const
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
this.
|
|
136
|
-
|
|
137
|
-
|
|
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
|
-
|
|
162
|
-
|
|
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
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
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
|
|
191
|
-
const
|
|
192
|
-
const
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
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
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
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
|
-
|
|
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
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
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
|
-
|
|
254
|
-
|
|
255
|
-
|
|
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
|
-
|
|
258
|
-
this.reset();
|
|
259
|
-
return results;
|
|
131
|
+
return detachedClass;
|
|
260
132
|
}
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
133
|
+
getGeneratedQueries(query) {
|
|
134
|
+
let { andWhere, orWhere } = this.getFirebaseWhereQuery(query?.where);
|
|
135
|
+
let mergedQueries = [];
|
|
136
|
+
if (andWhere) {
|
|
137
|
+
mergedQueries = [andWhere, ...orWhere];
|
|
265
138
|
}
|
|
266
|
-
|
|
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
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
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
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
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
|
-
|
|
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
|
|
303
|
-
if (
|
|
304
|
-
|
|
158
|
+
const cloned = [...mergedQueries];
|
|
159
|
+
if (andWhere) {
|
|
160
|
+
cloned.shift();
|
|
305
161
|
}
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
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
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
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
|
-
|
|
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
|
-
|
|
325
|
-
|
|
326
|
-
const element = condition
|
|
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
|
-
|
|
183
|
+
case fluent_1.LogicOperator.equals:
|
|
184
|
+
andWhereQuery = andWhereQuery.where(element, '==', value);
|
|
335
185
|
break;
|
|
336
|
-
case
|
|
337
|
-
|
|
186
|
+
case fluent_1.LogicOperator.isNot:
|
|
187
|
+
andWhereQuery = andWhereQuery.where(element, '!=', value);
|
|
338
188
|
break;
|
|
339
|
-
case
|
|
340
|
-
|
|
189
|
+
case fluent_1.LogicOperator.greaterThan:
|
|
190
|
+
andWhereQuery = andWhereQuery.where(element, '>', value);
|
|
341
191
|
break;
|
|
342
|
-
case
|
|
343
|
-
|
|
192
|
+
case fluent_1.LogicOperator.greaterOrEqualThan:
|
|
193
|
+
andWhereQuery = andWhereQuery.where(element, '>=', value);
|
|
344
194
|
break;
|
|
345
|
-
case
|
|
346
|
-
|
|
195
|
+
case fluent_1.LogicOperator.lessThan:
|
|
196
|
+
andWhereQuery = andWhereQuery.where(element, '<', value);
|
|
347
197
|
break;
|
|
348
|
-
case
|
|
349
|
-
|
|
198
|
+
case fluent_1.LogicOperator.lessOrEqualThan:
|
|
199
|
+
andWhereQuery = andWhereQuery.where(element, '<=', value);
|
|
350
200
|
break;
|
|
351
|
-
case
|
|
352
|
-
|
|
201
|
+
case fluent_1.LogicOperator.in:
|
|
202
|
+
andWhereQuery = andWhereQuery.where(element, 'in', value);
|
|
353
203
|
break;
|
|
354
|
-
case
|
|
355
|
-
|
|
204
|
+
case fluent_1.LogicOperator.arrayContains:
|
|
205
|
+
andWhereQuery = andWhereQuery.where(element, 'array-contains', value);
|
|
356
206
|
break;
|
|
357
|
-
case
|
|
358
|
-
|
|
207
|
+
case fluent_1.LogicOperator.notIn:
|
|
208
|
+
andWhereQuery = andWhereQuery.where(element, 'not-in', value);
|
|
359
209
|
break;
|
|
360
|
-
case
|
|
210
|
+
case fluent_1.LogicOperator.exists:
|
|
361
211
|
throw new Error('The nin Operator cannot be used in Firabase');
|
|
362
|
-
|
|
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
|
|
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
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
302
|
+
let andWhereCondition = undefined;
|
|
303
|
+
if (!andConditions?.length &&
|
|
304
|
+
!rootLevelConditions?.length &&
|
|
305
|
+
!orConditions?.length) {
|
|
306
|
+
andWhereCondition = this.collection;
|
|
382
307
|
}
|
|
383
|
-
|
|
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
|
|
311
|
+
return {
|
|
312
|
+
andWhere: andWhereCondition,
|
|
313
|
+
orWhere: orWhereQueries
|
|
314
|
+
};
|
|
390
315
|
}
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
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
|
-
|
|
399
|
-
|
|
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
|
|
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;
|