@drax/crud-back 2.11.0 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. package/dist/controllers/AbstractFastifyController.js +47 -24
  2. package/dist/repository/AbstractMongoRepository.js +12 -8
  3. package/dist/repository/AbstractSqliteRepository.js +40 -9
  4. package/dist/services/AbstractService.js +9 -6
  5. package/package.json +8 -7
  6. package/src/controllers/AbstractFastifyController.ts +56 -28
  7. package/src/repository/AbstractMongoRepository.ts +17 -8
  8. package/src/repository/AbstractSqliteRepository.ts +61 -10
  9. package/src/services/AbstractService.ts +12 -6
  10. package/test/_mocks/MockRepository.ts +1 -1
  11. package/test/controllers/PersonController.test.ts +547 -0
  12. package/test/people/controllers/CountryController.ts +40 -0
  13. package/test/people/controllers/LanguageController.ts +29 -0
  14. package/test/people/controllers/PersonController.ts +29 -0
  15. package/test/people/factory/services/CountryServiceFactory.ts +41 -0
  16. package/test/people/factory/services/LanguageServiceFactory.ts +41 -0
  17. package/test/people/factory/services/PersonServiceFactory.ts +41 -0
  18. package/test/people/interfaces/ICountry.ts +28 -0
  19. package/test/people/interfaces/ICountryRepository.ts +11 -0
  20. package/test/people/interfaces/ILanguage.ts +32 -0
  21. package/test/people/interfaces/ILanguageRepository.ts +11 -0
  22. package/test/people/interfaces/IPerson.ts +58 -0
  23. package/test/people/interfaces/IPersonRepository.ts +11 -0
  24. package/test/people/models/CountryModel.ts +38 -0
  25. package/test/people/models/LanguageModel.ts +40 -0
  26. package/test/people/models/PersonModel.ts +61 -0
  27. package/test/people/permissions/CountryPermissions.ts +14 -0
  28. package/test/people/permissions/LanguagePermissions.ts +14 -0
  29. package/test/people/permissions/PersonPermissions.ts +18 -0
  30. package/test/people/repository/mongo/CountryMongoRepository.ts +22 -0
  31. package/test/people/repository/mongo/LanguageMongoRepository.ts +22 -0
  32. package/test/people/repository/mongo/PersonMongoRepository.ts +22 -0
  33. package/test/people/repository/sqlite/CountrySqliteRepository.ts +33 -0
  34. package/test/people/repository/sqlite/LanguageSqliteRepository.ts +37 -0
  35. package/test/people/repository/sqlite/PersonSqliteRepository.ts +42 -0
  36. package/test/people/routes/CountryRoutes.ts +34 -0
  37. package/test/people/routes/LanguageRoutes.ts +34 -0
  38. package/test/people/routes/PersonRoutes.ts +40 -0
  39. package/test/people/schemas/CountrySchema.ts +22 -0
  40. package/test/people/schemas/LanguageSchema.ts +22 -0
  41. package/test/people/schemas/PersonSchema.ts +42 -0
  42. package/test/people/services/CountryService.ts +20 -0
  43. package/test/people/services/LanguageService.ts +20 -0
  44. package/test/people/services/PersonService.ts +20 -0
  45. package/test/services/AbstractService.test.ts +11 -7
  46. package/test/setup/MongoInMemory.ts +56 -0
  47. package/test/setup/TestSetup.ts +344 -0
  48. package/test/setup/data/admin-role.ts +13 -0
  49. package/test/setup/data/basic-user.ts +14 -0
  50. package/test/setup/data/one-tenant.ts +6 -0
  51. package/test/setup/data/restricted-role.ts +16 -0
  52. package/test/setup/data/root-user.ts +14 -0
  53. package/test/setup/data/tenant-one-user.ts +13 -0
  54. package/test/setup/data/tenant-two-user.ts +14 -0
  55. package/test/setup/data/two-tenant.ts +6 -0
  56. package/test/workers/ExportCsvWorker.test.ts +1 -1
  57. package/tsconfig.json +2 -1
  58. package/tsconfig.tsbuildinfo +1 -1
  59. package/types/controllers/AbstractFastifyController.d.ts.map +1 -1
  60. package/types/repository/AbstractMongoRepository.d.ts +3 -3
  61. package/types/repository/AbstractMongoRepository.d.ts.map +1 -1
  62. package/types/repository/AbstractSqliteRepository.d.ts +5 -4
  63. package/types/repository/AbstractSqliteRepository.d.ts.map +1 -1
  64. package/types/services/AbstractService.d.ts +4 -2
  65. package/types/services/AbstractService.d.ts.map +1 -1
@@ -1,4 +1,4 @@
1
- import { CommonConfig, DraxConfig, LimitError, NotFoundError, BadRequestError, CommonController } from "@drax/common-back";
1
+ import { CommonConfig, DraxConfig, LimitError, NotFoundError, BadRequestError, CommonController, setNestedValue } from "@drax/common-back";
2
2
  import { join } from "path";
3
3
  import QueryFilterRegex from "../regexs/QueryFilterRegex.js";
4
4
  import CrudEventEmitter from "../events/CrudEventEmitter.js";
@@ -72,15 +72,26 @@ class AbstractFastifyController extends CommonController {
72
72
  }
73
73
  }
74
74
  assertTenant(item, rbac) {
75
- if (this.tenantAssert) {
76
- const itemTenantId = item[this.tenantField]?._id ? item[this.tenantField]._id.toString() : null;
77
- rbac.assertTenantId(itemTenantId);
75
+ //Si tenantAssert esta habilitado y si ademas el usuario pertenece a un tenant
76
+ if (this.tenantAssert && rbac.hasTenant) {
77
+ //Si esta populado
78
+ if (item[this.tenantField]?._id) {
79
+ rbac.assertTenantId(item[this.tenantField]._id.toString()); //
80
+ //Si esta crudo
81
+ }
82
+ else if (item[this.tenantField]) {
83
+ rbac.assertTenantId(item[this.tenantField].toString());
84
+ }
78
85
  }
79
86
  }
80
87
  assertUser(item, rbac) {
81
88
  if (this.userAssert) {
82
- const itemUserId = item[this.userField]?._id ? item[this.userField]._id.toString() : null;
83
- rbac.assertUserId(itemUserId);
89
+ if (item[this.userField]?._id) {
90
+ rbac.assertUserId(item[this.userField]._id.toString());
91
+ }
92
+ else if (item[this.userField]) {
93
+ rbac.assertUserId(item[this.userField].toString());
94
+ }
84
95
  }
85
96
  }
86
97
  assertUserAndTenant(item, rbac) {
@@ -89,10 +100,10 @@ class AbstractFastifyController extends CommonController {
89
100
  }
90
101
  applyUserAndTenantSetters(payload, rbac) {
91
102
  if (this.tenantSetter && rbac.tenantId) {
92
- payload[this.tenantField] = rbac.tenantId;
103
+ setNestedValue(payload, this.tenantField, rbac.tenantId);
93
104
  }
94
105
  if (this.userSetter && rbac.userId) {
95
- payload[this.userField] = rbac.userId;
106
+ setNestedValue(payload, this.userField, rbac.userId);
96
107
  }
97
108
  }
98
109
  extractRequestData(request) {
@@ -212,17 +223,21 @@ class AbstractFastifyController extends CommonController {
212
223
  const id = request.params.id;
213
224
  const payload = request.body;
214
225
  let preItem = await this.service.findById(id);
226
+ if (!preItem) {
227
+ reply.statusCode = 404;
228
+ reply.send({ error: 'NOT_FOUND' });
229
+ }
215
230
  if (!request.rbac.hasSomePermission([this.permission.All, this.permission.UpdateAll])) {
216
- if (!preItem) {
217
- reply.statusCode = 404;
218
- reply.send({ error: 'NOT_FOUND' });
219
- }
231
+ //Si assertUser habilitado y si el usuario no tiene UpdateAll/All, solo puede modificar sus propios registros
220
232
  this.assertUser(preItem, request.rbac);
221
233
  }
222
- //Definido el tenant/user en el create no debe modificarse en un update
234
+ //Si assertTenant habilitado y si usuario tiene tenant, solo puede modificar registros de su tenant
235
+ this.assertTenant(preItem, request.rbac);
236
+ //Definido el tenant en create no debe modificarse en un update
223
237
  if (this.tenantSetter) {
224
238
  delete payload[this.tenantField];
225
239
  }
240
+ //Definido el user en create no debe modificarse en un update
226
241
  if (this.userSetter) {
227
242
  delete payload[this.userField];
228
243
  }
@@ -255,17 +270,21 @@ class AbstractFastifyController extends CommonController {
255
270
  const id = request.params.id;
256
271
  const payload = request.body;
257
272
  let preItem = await this.service.findById(id);
273
+ if (!preItem) {
274
+ reply.statusCode = 404;
275
+ reply.send({ error: 'NOT_FOUND' });
276
+ }
258
277
  if (!request.rbac.hasSomePermission([this.permission.All, this.permission.UpdateAll])) {
259
- if (!preItem) {
260
- reply.statusCode = 404;
261
- reply.send({ error: 'NOT_FOUND' });
262
- }
278
+ //Si assertUser habilitado y si el usuario no tiene UpdateAll/All, solo puede modificar sus propios registros
263
279
  this.assertUser(preItem, request.rbac);
264
280
  }
265
- //Definido el tenant/user en el create no debe modificarse en un update
281
+ //Si assertTenant habilitado y si usuario tiene tenant, solo puede modificar registros de su tenant
282
+ this.assertTenant(preItem, request.rbac);
283
+ //Definido el tenant en el create no debe modificarse en un update
266
284
  if (this.tenantSetter) {
267
285
  delete payload[this.tenantField];
268
286
  }
287
+ //Definido el user en el create no debe modificarse en un update
269
288
  if (this.userSetter) {
270
289
  delete payload[this.userField];
271
290
  }
@@ -404,10 +423,12 @@ class AbstractFastifyController extends CommonController {
404
423
  const limit = this.defaultLimit;
405
424
  const field = request.params.field;
406
425
  const value = request.params.value;
407
- let items = await this.service.findBy(field, value, limit);
408
- for (let item of items) {
409
- this.assertUserAndTenant(item, request.rbac);
410
- }
426
+ let filters = [];
427
+ this.applyUserAndTenantFilters(filters, request.rbac);
428
+ let items = await this.service.findBy(field, value, limit, filters);
429
+ // for (let item of items) {
430
+ // this.assertUserAndTenant(item, request.rbac)
431
+ // }
411
432
  return items;
412
433
  }
413
434
  catch (e) {
@@ -423,8 +444,10 @@ class AbstractFastifyController extends CommonController {
423
444
  }
424
445
  const field = request.params.field;
425
446
  const value = request.params.value;
426
- let item = await this.service.findOneBy(field, value);
427
- this.assertUserAndTenant(item, request.rbac);
447
+ let filters = [];
448
+ this.applyUserAndTenantFilters(filters, request.rbac);
449
+ let item = await this.service.findOneBy(field, value, filters);
450
+ // this.assertUserAndTenant(item, request.rbac);
428
451
  return item;
429
452
  }
430
453
  catch (e) {
@@ -89,28 +89,32 @@ class AbstractMongoRepository {
89
89
  .exec();
90
90
  return item;
91
91
  }
92
- async findByIds(ids) {
92
+ async findByIds(ids, filters = []) {
93
93
  ids.map(id => this.assertId(id));
94
+ const query = { _id: { $in: ids } };
95
+ MongooseQueryFilter.applyFilters(query, filters, this._model);
94
96
  const items = await this._model
95
- .find({ _id: { $in: ids } })
97
+ .find(query)
96
98
  .populate(this._populateFields)
97
99
  .lean(this._lean)
98
100
  .exec();
99
101
  return items;
100
102
  }
101
- async findOneBy(field, value) {
102
- const filter = { [field]: value };
103
+ async findOneBy(field, value, filters = []) {
104
+ const query = { [field]: value };
105
+ MongooseQueryFilter.applyFilters(query, filters, this._model);
103
106
  const item = await this._model
104
- .findOne(filter)
107
+ .findOne(query)
105
108
  .populate(this._populateFields)
106
109
  .lean(this._lean)
107
110
  .exec();
108
111
  return item;
109
112
  }
110
- async findBy(field, value, limit = 0) {
111
- const filter = { [field]: value };
113
+ async findBy(field, value, limit = 0, filters = []) {
114
+ const query = { [field]: value };
115
+ MongooseQueryFilter.applyFilters(query, filters, this._model);
112
116
  const items = await this._model
113
- .find(filter)
117
+ .find(query)
114
118
  .limit(limit)
115
119
  .populate(this._populateFields)
116
120
  .lean(this._lean)
@@ -200,7 +200,7 @@ class AbstractSqliteRepository {
200
200
  }
201
201
  return items;
202
202
  }
203
- async search(value, limit = 1000) {
203
+ async search(value, limit = 1000, filters = []) {
204
204
  let where = "";
205
205
  let params = [];
206
206
  if (value && this.searchFields.length > 0) {
@@ -225,19 +225,50 @@ class AbstractSqliteRepository {
225
225
  await this.decorate(item);
226
226
  return item;
227
227
  }
228
- async findBy(field, value, limit = 0) {
229
- const items = this.db.prepare(`SELECT *
230
- FROM ${this.tableName}
231
- WHERE ${field} = ? LIMIT ${limit}`).all(value);
228
+ async findByIds(ids, filters = []) {
229
+ const inPlaceholders = ids.map(() => '?').join(',');
230
+ let where = `WHERE ID IN(${inPlaceholders})`;
231
+ let params = [ids];
232
+ if (filters.length > 0) {
233
+ const result = SqlQueryFilter.applyFilters(where, filters);
234
+ where = result.where;
235
+ params.push(...result.params);
236
+ }
237
+ const items = this.db
238
+ .prepare(`SELECT * FROM ${this.tableName} ${where}`)
239
+ .all(params);
232
240
  for (const item of items) {
233
241
  await this.decorate(item);
234
242
  }
235
243
  return items;
236
244
  }
237
- async findOneBy(field, value) {
238
- const item = this.db.prepare(`SELECT *
239
- FROM ${this.tableName}
240
- WHERE ${field} = ?`).get(value);
245
+ async findBy(field, value, limit = 0, filters = []) {
246
+ let where = `WHERE ${field} = ?`;
247
+ let params = [value];
248
+ if (filters.length > 0) {
249
+ const result = SqlQueryFilter.applyFilters(where, filters);
250
+ where = result.where;
251
+ params.push(...result.params);
252
+ }
253
+ const items = this.db
254
+ .prepare(`SELECT * FROM ${this.tableName} ${where} LIMIT ?`)
255
+ .all([...params, limit]);
256
+ for (const item of items) {
257
+ await this.decorate(item);
258
+ }
259
+ return items;
260
+ }
261
+ async findOneBy(field, value, filters = []) {
262
+ let where = `WHERE ${field} = ?`;
263
+ let params = [value];
264
+ if (filters.length > 0) {
265
+ const result = SqlQueryFilter.applyFilters(where, filters);
266
+ where = result.where;
267
+ params.push(...result.params);
268
+ }
269
+ const item = this.db
270
+ .prepare(`SELECT * FROM ${this.tableName} ${where} LIMIT 1`)
271
+ .get(params);
241
272
  await this.decorate(item);
242
273
  return item;
243
274
  }
@@ -110,9 +110,12 @@ class AbstractService {
110
110
  }
111
111
  async updatePartial(id, data) {
112
112
  data = await this.validateInputUpdatePartial(data);
113
+ if (this.transformUpdatePartial) {
114
+ data = await this.transformUpdatePartial(data);
115
+ }
113
116
  let item = await this._repository.updatePartial(id, data);
114
- if (this.onUpdated) {
115
- await this.onUpdated(item);
117
+ if (this.onUpdatedPartial) {
118
+ await this.onUpdatedPartial(item);
116
119
  }
117
120
  item = await this.validateOutput(item);
118
121
  return item;
@@ -155,9 +158,9 @@ class AbstractService {
155
158
  throw e;
156
159
  }
157
160
  }
158
- async findOneBy(field, value) {
161
+ async findOneBy(field, value, filters = []) {
159
162
  try {
160
- let item = await this._repository.findOneBy(field, value);
163
+ let item = await this._repository.findOneBy(field, value, filters);
161
164
  if (item && this.transformRead) {
162
165
  item = await this.transformRead(item);
163
166
  }
@@ -211,9 +214,9 @@ class AbstractService {
211
214
  throw e;
212
215
  }
213
216
  }
214
- async findBy(field, value, limit = 1000) {
217
+ async findBy(field, value, limit = 1000, filters = []) {
215
218
  try {
216
- let items = await this._repository.findBy(field, value, limit);
219
+ let items = await this._repository.findBy(field, value, limit, filters);
217
220
  if (this.transformRead) {
218
221
  items = await Promise.all(items.map(item => this.transformRead(item)));
219
222
  }
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "2.11.0",
6
+ "version": "3.1.0",
7
7
  "description": "Crud utils across modules",
8
8
  "main": "dist/index.js",
9
9
  "types": "types/index.d.ts",
@@ -22,10 +22,10 @@
22
22
  "author": "Cristian Incarnato & Drax Team",
23
23
  "license": "ISC",
24
24
  "dependencies": {
25
- "@drax/common-back": "^2.11.0",
26
- "@drax/common-share": "^2.0.0",
27
- "@drax/identity-share": "^2.0.0",
28
- "@drax/media-back": "^2.11.0",
25
+ "@drax/common-back": "^3.0.0",
26
+ "@drax/common-share": "^3.0.0",
27
+ "@drax/identity-share": "^3.0.0",
28
+ "@drax/media-back": "^3.1.0",
29
29
  "@graphql-tools/load-files": "^7.0.0",
30
30
  "@graphql-tools/merge": "^9.0.4",
31
31
  "mongoose": "^8.23.0",
@@ -44,7 +44,8 @@
44
44
  "nodemon": "^3.1.0",
45
45
  "ts-node": "^10.9.2",
46
46
  "tsc-alias": "^1.8.10",
47
- "typescript": "^5.9.3"
47
+ "typescript": "^5.9.3",
48
+ "vitest": "^3.2.4"
48
49
  },
49
- "gitHead": "8919d31d4d9512e48ac461b0876dc85a5849daea"
50
+ "gitHead": "262ea8f861c84ca1ad4d555545c5a94b95dbf25e"
50
51
  }
@@ -5,7 +5,7 @@ import {
5
5
  LimitError,
6
6
  NotFoundError,
7
7
  BadRequestError,
8
- CommonController
8
+ CommonController, setNestedValue
9
9
  } from "@drax/common-back";
10
10
  import {IRbac} from "@drax/identity-share";
11
11
  import type {FastifyReply, FastifyRequest} from "fastify";
@@ -150,17 +150,28 @@ class AbstractFastifyController<T, C, U> extends CommonController {
150
150
  }
151
151
 
152
152
  protected assertTenant(item: T, rbac: IRbac) {
153
- if (this.tenantAssert) {
154
- const itemTenantId = item[this.tenantField]?._id ? item[this.tenantField]._id.toString() : null
155
- rbac.assertTenantId(itemTenantId)
153
+
154
+ //Si tenantAssert esta habilitado y si ademas el usuario pertenece a un tenant
155
+ if (this.tenantAssert && rbac.hasTenant) {
156
+
157
+ //Si esta populado
158
+ if(item[this.tenantField]?._id){
159
+ rbac.assertTenantId(item[this.tenantField]._id.toString())//
160
+ //Si esta crudo
161
+ }else if(item[this.tenantField]){
162
+ rbac.assertTenantId(item[this.tenantField].toString())
163
+ }
156
164
  }
157
165
  }
158
166
 
159
167
  protected assertUser(item: T, rbac: IRbac) {
160
168
 
161
169
  if (this.userAssert) {
162
- const itemUserId = item[this.userField]?._id ? item[this.userField]._id.toString() : null
163
- rbac.assertUserId(itemUserId)
170
+ if(item[this.userField]?._id){
171
+ rbac.assertUserId(item[this.userField]._id.toString())
172
+ }else if(item[this.userField]){
173
+ rbac.assertUserId(item[this.userField].toString())
174
+ }
164
175
  }
165
176
  }
166
177
 
@@ -170,12 +181,13 @@ class AbstractFastifyController<T, C, U> extends CommonController {
170
181
  }
171
182
 
172
183
  protected applyUserAndTenantSetters(payload: any, rbac: any) {
184
+
173
185
  if (this.tenantSetter && rbac.tenantId) {
174
- payload[this.tenantField] = rbac.tenantId
186
+ setNestedValue(payload, this.tenantField, rbac.tenantId)
175
187
  }
176
188
 
177
189
  if (this.userSetter && rbac.userId) {
178
- payload[this.userField] = rbac.userId
190
+ setNestedValue(payload, this.userField, rbac.userId)
179
191
  }
180
192
  }
181
193
 
@@ -309,21 +321,24 @@ class AbstractFastifyController<T, C, U> extends CommonController {
309
321
 
310
322
  let preItem = await this.service.findById(id)
311
323
 
312
- if (!request.rbac.hasSomePermission([this.permission.All, this.permission.UpdateAll])) {
313
-
314
- if (!preItem) {
315
- reply.statusCode = 404
316
- reply.send({error: 'NOT_FOUND'})
317
- }
324
+ if (!preItem) {
325
+ reply.statusCode = 404
326
+ reply.send({error: 'NOT_FOUND'})
327
+ }
318
328
 
329
+ if (!request.rbac.hasSomePermission([this.permission.All, this.permission.UpdateAll])) {
330
+ //Si assertUser habilitado y si el usuario no tiene UpdateAll/All, solo puede modificar sus propios registros
319
331
  this.assertUser(preItem, request.rbac)
320
332
  }
333
+ //Si assertTenant habilitado y si usuario tiene tenant, solo puede modificar registros de su tenant
334
+ this.assertTenant(preItem, request.rbac)
321
335
 
322
- //Definido el tenant/user en el create no debe modificarse en un update
336
+ //Definido el tenant en create no debe modificarse en un update
323
337
  if(this.tenantSetter) {
324
338
  delete payload[this.tenantField]
325
339
  }
326
340
 
341
+ //Definido el user en create no debe modificarse en un update
327
342
  if(this.userSetter){
328
343
  delete payload[this.userField]
329
344
  }
@@ -365,21 +380,25 @@ class AbstractFastifyController<T, C, U> extends CommonController {
365
380
 
366
381
  let preItem = await this.service.findById(id)
367
382
 
368
- if (!request.rbac.hasSomePermission([this.permission.All, this.permission.UpdateAll])) {
369
-
370
- if (!preItem) {
371
- reply.statusCode = 404
372
- reply.send({error: 'NOT_FOUND'})
373
- }
383
+ if (!preItem) {
384
+ reply.statusCode = 404
385
+ reply.send({error: 'NOT_FOUND'})
386
+ }
374
387
 
388
+ if (!request.rbac.hasSomePermission([this.permission.All, this.permission.UpdateAll])) {
389
+ //Si assertUser habilitado y si el usuario no tiene UpdateAll/All, solo puede modificar sus propios registros
375
390
  this.assertUser(preItem, request.rbac)
376
391
  }
377
392
 
378
- //Definido el tenant/user en el create no debe modificarse en un update
393
+ //Si assertTenant habilitado y si usuario tiene tenant, solo puede modificar registros de su tenant
394
+ this.assertTenant(preItem, request.rbac)
395
+
396
+ //Definido el tenant en el create no debe modificarse en un update
379
397
  if(this.tenantSetter) {
380
398
  delete payload[this.tenantField]
381
399
  }
382
400
 
401
+ //Definido el user en el create no debe modificarse en un update
383
402
  if(this.userSetter){
384
403
  delete payload[this.userField]
385
404
  }
@@ -552,11 +571,15 @@ class AbstractFastifyController<T, C, U> extends CommonController {
552
571
  const limit = this.defaultLimit
553
572
  const field = request.params.field
554
573
  const value = request.params.value
555
- let items = await this.service.findBy(field, value, limit)
556
574
 
557
- for (let item of items) {
558
- this.assertUserAndTenant(item, request.rbac)
559
- }
575
+ let filters = []
576
+ this.applyUserAndTenantFilters(filters, request.rbac);
577
+
578
+ let items = await this.service.findBy(field, value, limit, filters)
579
+
580
+ // for (let item of items) {
581
+ // this.assertUserAndTenant(item, request.rbac)
582
+ // }
560
583
 
561
584
  return items
562
585
  } catch (e) {
@@ -574,8 +597,13 @@ class AbstractFastifyController<T, C, U> extends CommonController {
574
597
 
575
598
  const field = request.params.field
576
599
  const value = request.params.value
577
- let item = await this.service.findOneBy(field, value)
578
- this.assertUserAndTenant(item, request.rbac);
600
+
601
+ let filters = []
602
+ this.applyUserAndTenantFilters(filters, request.rbac);
603
+
604
+ let item = await this.service.findOneBy(field, value, filters)
605
+
606
+ // this.assertUserAndTenant(item, request.rbac);
579
607
 
580
608
  return item
581
609
  } catch (e) {
@@ -122,12 +122,16 @@ class AbstractMongoRepository<T, C, U> implements IDraxCrud<T, C, U> {
122
122
  return item as T;
123
123
  }
124
124
 
125
- async findByIds(ids: Array<string>): Promise<T[]> {
125
+ async findByIds(ids: Array<string>, filters: IDraxFieldFilter[] = []): Promise<T[]> {
126
126
 
127
127
  ids.map(id => this.assertId(id))
128
128
 
129
+ const query: any = {_id: {$in: ids}}
130
+
131
+ MongooseQueryFilter.applyFilters(query, filters, this._model)
132
+
129
133
  const items = await this._model
130
- .find({_id: {$in: ids}})
134
+ .find(query)
131
135
  .populate(this._populateFields)
132
136
  .lean(this._lean)
133
137
  .exec()
@@ -136,11 +140,13 @@ class AbstractMongoRepository<T, C, U> implements IDraxCrud<T, C, U> {
136
140
  return items as T[]
137
141
  }
138
142
 
139
- async findOneBy(field: string, value: any): Promise<T | null> {
140
- const filter: any = {[field]: value}
143
+ async findOneBy(field: string, value: any, filters: IDraxFieldFilter[] = []): Promise<T | null> {
144
+ const query: any = {[field]: value}
145
+
146
+ MongooseQueryFilter.applyFilters(query, filters, this._model)
141
147
 
142
148
  const item = await this._model
143
- .findOne(filter)
149
+ .findOne(query)
144
150
  .populate(this._populateFields)
145
151
  .lean(this._lean)
146
152
  .exec()
@@ -149,10 +155,13 @@ class AbstractMongoRepository<T, C, U> implements IDraxCrud<T, C, U> {
149
155
  return item as T
150
156
  }
151
157
 
152
- async findBy(field: string, value: any, limit: number = 0): Promise<T[]> {
153
- const filter: any = {[field]: value}
158
+ async findBy(field: string, value: any, limit: number = 0, filters: IDraxFieldFilter[] = []): Promise<T[]> {
159
+ const query: any = {[field]: value}
160
+
161
+ MongooseQueryFilter.applyFilters(query, filters, this._model)
162
+
154
163
  const items = await this._model
155
- .find(filter)
164
+ .find(query)
156
165
  .limit(limit)
157
166
  .populate(this._populateFields)
158
167
  .lean(this._lean)
@@ -1,6 +1,6 @@
1
1
  import sqlite from "better-sqlite3";
2
2
  import type {
3
- IDraxCrud,
3
+ IDraxCrud, IDraxFieldFilter,
4
4
  IDraxFindOptions,
5
5
  IDraxGroupByOptions,
6
6
  IDraxPaginateOptions,
@@ -299,7 +299,7 @@ class AbstractSqliteRepository<T, C, U> implements IDraxCrud<T, C, U> {
299
299
  return items
300
300
  }
301
301
 
302
- async search(value: any, limit: number = 1000): Promise<T[]> {
302
+ async search(value: any, limit: number = 1000, filters: IDraxFieldFilter[] = []): Promise<T[]> {
303
303
 
304
304
  let where = ""
305
305
  let params: any[] = []
@@ -334,22 +334,73 @@ class AbstractSqliteRepository<T, C, U> implements IDraxCrud<T, C, U> {
334
334
  return item
335
335
  }
336
336
 
337
- async findBy(field: string, value: any, limit: number = 0): Promise<T[] | null> {
338
- const items = this.db.prepare(`SELECT *
339
- FROM ${this.tableName}
340
- WHERE ${field} = ? LIMIT ${limit}`).all(value);
337
+ async findByIds(ids: string[], filters: IDraxFieldFilter[] = []): Promise<T[] | null> {
338
+
339
+ const inPlaceholders = ids.map(() => '?').join(',')
340
+
341
+ let where = `WHERE ID IN(${inPlaceholders})`
342
+ let params: any[] = [ids]
343
+
344
+ if (filters.length > 0) {
345
+ const result = SqlQueryFilter.applyFilters(where, filters)
346
+ where = result.where
347
+ params.push(...result.params)
348
+ }
349
+
350
+ const items = this.db
351
+ .prepare(`SELECT * FROM ${this.tableName} ${where}`)
352
+ .all(params) as T[]
353
+
341
354
  for (const item of items) {
342
355
  await this.decorate(item)
343
356
  }
357
+
344
358
  return items
359
+
345
360
  }
346
361
 
347
- async findOneBy(field: string, value: any): Promise<T | null> {
348
- const item = this.db.prepare(`SELECT *
349
- FROM ${this.tableName}
350
- WHERE ${field} = ?`).get(value);
362
+ async findBy(field: string, value: any, limit: number = 0, filters: IDraxFieldFilter[] = []): Promise<T[] | null> {
363
+
364
+ let where = `WHERE ${field} = ?`
365
+ let params: any[] = [value]
366
+
367
+ if (filters.length > 0) {
368
+ const result = SqlQueryFilter.applyFilters(where, filters)
369
+ where = result.where
370
+ params.push(...result.params)
371
+ }
372
+
373
+ const items = this.db
374
+ .prepare(`SELECT * FROM ${this.tableName} ${where} LIMIT ?`)
375
+ .all([...params, limit]) as T[]
376
+
377
+ for (const item of items) {
378
+ await this.decorate(item)
379
+ }
380
+
381
+ return items
382
+
383
+ }
384
+
385
+ async findOneBy(field: string, value: any, filters: IDraxFieldFilter[] = []): Promise<T | null> {
386
+
387
+ let where = `WHERE ${field} = ?`
388
+ let params: any[] = [value]
389
+
390
+ if (filters.length > 0) {
391
+ const result = SqlQueryFilter.applyFilters(where, filters)
392
+ where = result.where
393
+ params.push(...result.params)
394
+ }
395
+
396
+ const item = this.db
397
+ .prepare(`SELECT * FROM ${this.tableName} ${where} LIMIT 1`)
398
+ .get(params) as T
399
+
351
400
  await this.decorate(item)
401
+
352
402
  return item
403
+
353
404
  }
354
405
 
355
406
  async findOne({