@appxdigital/appx-core 0.1.97 → 0.1.99

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.
@@ -14,6 +14,7 @@ export declare class PrismaService {
14
14
  prismaClient: PrismaClient;
15
15
  constructor(prismaClient: PrismaClient, permissionsConfig: PermissionsConfigType);
16
16
  debugQueries(enable: boolean): void;
17
+ withExposedModels(models: string[], callback: () => Promise<void>): Promise<void>;
17
18
  private debug;
18
19
  $transaction<T>(fn: (prisma: Prisma.TransactionClient) => Promise<T>): any;
19
20
  proxyModels(): void;
@@ -90,6 +91,7 @@ export declare class PrismaService {
90
91
  * @param modelName - The name of the model being queried.
91
92
  * @param omitFields - A list of fields to omit based on the user's role.
92
93
  * @param includeRelations - The relations to include in the query.
94
+ * @param defaultSelect - The select object provided in the query arguments.
93
95
  * @param userRole - The role of the user making the request.
94
96
  * @returns A `select` object for Prisma queries.
95
97
  */
@@ -1 +1 @@
1
- {"version":3,"file":"prisma.service.d.ts","sourceRoot":"","sources":["../../src/prisma/prisma.service.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,MAAM,EAAE,YAAY,EAAC,MAAM,gBAAgB,CAAC;AACpD,OAAO,EAAC,qBAAqB,EAAC,MAAM,yCAAyC,CAAC;AAE9E,OAAO,KAAK,EAAC,YAAY,IAAI,aAAa,EAAC,MAAM,gBAAgB,CAAC;AAGlE,KAAK,QAAQ,GAAG,MAAM,aAAa,CAAC;AAEpC,oDAAoD;AACpD,MAAM,MAAM,iBAAiB,GAAG;IAC5B,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC9B,CAAC;AAGF,MAAM,MAAM,eAAe,CAAC,CAAC,SAAS,QAAQ,IAAI,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,YAAY,GAAG,mBAAmB,GAAG,QAAQ,GAAG,QAAQ,CAAC,CAAC;AAEtI,qBACa,aAAa;IAMY,OAAO,CAAC,QAAQ,CAAC,iBAAiB;IALpE,OAAO,CAAC,YAAY,CAA2B;IAC/C,YAAY,EAAE,YAAY,CAAC;gBAGvB,YAAY,EAAE,YAAY,EACqB,iBAAiB,EAAE,qBAAqB;IAO3F,YAAY,CAAC,MAAM,EAAE,OAAO;IAI5B,OAAO,CAAC,KAAK;IAQb,YAAY,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,iBAAiB,KAAK,OAAO,CAAC,CAAC,CAAC;IAIpE,WAAW;IAuDX;;;;OAIG;IACH,gBAAgB,CAAC,CAAC,SAAS,QAAQ,EAAE,KAAK,EAAE,CAAC,GAAG,eAAe,CAAC,CAAC,CAAC;IAYlE,IAAI,KAAK,IAAI,aAAa,CAUzB;IAED,IAAI,IAAI,IAAI,eAAe,CAAC,MAAM,CAAC,CAElC;IAED,IAAI,OAAO,IAAI,eAAe,CAAC,SAAS,CAAC,CAExC;IAED,IAAI,gBAAgB,QAEnB;IAED;;;OAGG;IACH,WAAW;IAoDX;;;;;;;;OAQG;IACH,OAAO,CAAC,kBAAkB;IAmC1B,IAAI,2BAA2B,QAM9B;IAED;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,oBAAoB;IAwI5B;;;;;;;OAOG;IACH,OAAO,CAAC,eAAe;IAgBvB;;;;;;;OAOG;IACH,OAAO,CAAC,mBAAmB;IA2B3B;;;;;;;OAOG;IACH,OAAO,CAAC,eAAe;IAUvB;;;;;;;;;OASG;IACH,OAAO,CAAC,iBAAiB;IAkDzB,WAAW,CAAC,WAAW,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,eAAe,CAAC,EAAE,IAAI,GAAG;QAC5E,KAAK,EAAE,MAAM,CAAC;QACd,QAAQ,EAAE,MAAM,CAAC;QACjB,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,iBAAiB,CAAC,EAAE,MAAM,CAAC;KAC9B;IAkBD,gBAAgB,CAAC,WAAW,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM;CAgBzF"}
1
+ {"version":3,"file":"prisma.service.d.ts","sourceRoot":"","sources":["../../src/prisma/prisma.service.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,MAAM,EAAE,YAAY,EAAC,MAAM,gBAAgB,CAAC;AACpD,OAAO,EAAC,qBAAqB,EAAC,MAAM,yCAAyC,CAAC;AAE9E,OAAO,KAAK,EAAC,YAAY,IAAI,aAAa,EAAC,MAAM,gBAAgB,CAAC;AAGlE,KAAK,QAAQ,GAAG,MAAM,aAAa,CAAC;AAEpC,oDAAoD;AACpD,MAAM,MAAM,iBAAiB,GAAG;IAC5B,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC9B,CAAC;AAGF,MAAM,MAAM,eAAe,CAAC,CAAC,SAAS,QAAQ,IAAI,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,YAAY,GAAG,mBAAmB,GAAG,QAAQ,GAAG,QAAQ,CAAC,CAAC;AAEtI,qBACa,aAAa;IAMY,OAAO,CAAC,QAAQ,CAAC,iBAAiB;IALpE,OAAO,CAAC,YAAY,CAA2B;IAC/C,YAAY,EAAE,YAAY,CAAC;gBAGvB,YAAY,EAAE,YAAY,EACqB,iBAAiB,EAAE,qBAAqB;IAO3F,YAAY,CAAC,MAAM,EAAE,OAAO;IAO5B,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC;IAQjE,OAAO,CAAC,KAAK;IAQb,YAAY,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,iBAAiB,KAAK,OAAO,CAAC,CAAC,CAAC;IAIpE,WAAW;IAuDX;;;;OAIG;IACH,gBAAgB,CAAC,CAAC,SAAS,QAAQ,EAAE,KAAK,EAAE,CAAC,GAAG,eAAe,CAAC,CAAC,CAAC;IAYlE,IAAI,KAAK,IAAI,aAAa,CAUzB;IAED,IAAI,IAAI,IAAI,eAAe,CAAC,MAAM,CAAC,CAElC;IAED,IAAI,OAAO,IAAI,eAAe,CAAC,SAAS,CAAC,CAExC;IAED,IAAI,gBAAgB,QAEnB;IAED;;;OAGG;IACH,WAAW;IAoDX;;;;;;;;OAQG;IACH,OAAO,CAAC,kBAAkB;IAqC1B,IAAI,2BAA2B,QAM9B;IAED;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,oBAAoB;IAmJ5B;;;;;;;OAOG;IACH,OAAO,CAAC,eAAe;IAgBvB;;;;;;;OAOG;IACH,OAAO,CAAC,mBAAmB;IA2B3B;;;;;;;OAOG;IACH,OAAO,CAAC,eAAe;IAUvB;;;;;;;;;;OAUG;IACH,OAAO,CAAC,iBAAiB;IA8EzB,WAAW,CAAC,WAAW,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,eAAe,CAAC,EAAE,IAAI,GAAG;QAC5E,KAAK,EAAE,MAAM,CAAC;QACd,QAAQ,EAAE,MAAM,CAAC;QACjB,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,iBAAiB,CAAC,EAAE,MAAM,CAAC;KAC9B;IAkBD,gBAAgB,CAAC,WAAW,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM;CAgBzF"}
@@ -27,6 +27,16 @@ let PrismaService = class PrismaService {
27
27
  debugQueries(enable) {
28
28
  nestjs_request_context_1.RequestContext.currentContext.req.corePrismaDebug = enable;
29
29
  }
30
+ /*
31
+ * Exposes the specified models for the duration of the callback execution.
32
+ */
33
+ withExposedModels(models, callback) {
34
+ const previous = nestjs_request_context_1.RequestContext.currentContext?.req.prismaExposedModels || [];
35
+ nestjs_request_context_1.RequestContext.currentContext.req.prismaExposedModels = [...new Set([...previous, ...models.map(m => m.toLowerCase())])];
36
+ return callback().finally(() => {
37
+ nestjs_request_context_1.RequestContext.currentContext.req.prismaExposedModels = previous;
38
+ });
39
+ }
30
40
  debug(msg, type = 'log') {
31
41
  if (nestjs_request_context_1.RequestContext.currentContext?.req.corePrismaDebug) {
32
42
  // Default for log, yellow for warn, red for error, blue for info
@@ -194,11 +204,11 @@ let PrismaService = class PrismaService {
194
204
  }
195
205
  else if (args.include) {
196
206
  this.debug(`Found included model '${modelName}', generating select fields`);
197
- args.select = this.buildSelectFields(modelName, omitFields, args.include, userRole);
207
+ args.select = this.buildSelectFields(modelName, omitFields, args.include, null, userRole);
198
208
  delete args.include;
199
209
  }
200
210
  else {
201
- args.select = this.buildSelectFields(modelName, omitFields, null, userRole);
211
+ args.select = this.buildSelectFields(modelName, omitFields, null, null, userRole);
202
212
  }
203
213
  return args;
204
214
  }
@@ -249,11 +259,16 @@ let PrismaService = class PrismaService {
249
259
  // If field is relation
250
260
  let relation = this.getRelation(modelName, field);
251
261
  if (!relation) {
262
+ if (field === '_count') {
263
+ // TODO implement filtering on _count
264
+ // args.select[field] = this.applyWhereConditions(modelName, userRole, args.select[field], user, action);
265
+ }
252
266
  continue;
253
267
  }
254
268
  if (relation.relation === 'belongsTo') {
255
269
  this.debug(`Found 1:1 / *:1 (belongsTo) relation to model '${relation.model}' from model '${modelName}' via field '${field}'. Filter will be applied to main conditions...`);
256
- const relatedPermissions = this.selectPermission(permissionsConfig[relation.model.toLowerCase()]?.[userRole] || {}, action.toString(), relation.model, userRole);
270
+ // findFirst permissions for related model
271
+ const relatedPermissions = this.selectPermission(permissionsConfig[relation.model.toLowerCase()]?.[userRole] || {}, 'findFirst', relation.model, userRole);
257
272
  // If model is exposed, do not apply conditions
258
273
  if (nestjs_request_context_1.RequestContext.currentContext?.req.prismaExposedModels?.map((m) => m.toLowerCase()).includes(relation.model.toLowerCase())) {
259
274
  this.debug(`Related model '${relation.model}' is exposed via @Permission() decorator. Skipping conditions for action '${String(action)}' on role ${userRole}.`);
@@ -289,7 +304,11 @@ let PrismaService = class PrismaService {
289
304
  },
290
305
  })
291
306
  */
292
- args.select[field].where = this.applyWhereConditions(relation.model, userRole, args.select[field], user, action).where;
307
+ if (args.select[field] === true) {
308
+ args.select[field] = {};
309
+ }
310
+ // findMany permissions for related model
311
+ args.select[field].where = this.applyWhereConditions(relation.model, userRole, args.select[field], user, 'findMany').where;
293
312
  delete args.select[field].select.where;
294
313
  }
295
314
  }
@@ -400,16 +419,30 @@ let PrismaService = class PrismaService {
400
419
  * @param modelName - The name of the model being queried.
401
420
  * @param omitFields - A list of fields to omit based on the user's role.
402
421
  * @param includeRelations - The relations to include in the query.
422
+ * @param defaultSelect - The select object provided in the query arguments.
403
423
  * @param userRole - The role of the user making the request.
404
424
  * @returns A `select` object for Prisma queries.
405
425
  */
406
- buildSelectFields(modelName, omitFields, includeRelations, userRole) {
426
+ buildSelectFields(modelName, omitFields, includeRelations, defaultSelect, userRole) {
407
427
  const modelInfo = this.fieldConfigs[modelName.toLowerCase()];
408
428
  if (!modelInfo) {
409
429
  return {};
410
430
  }
411
- const { scalarFields, relationFields } = modelInfo;
431
+ let { scalarFields, relationFields } = modelInfo;
412
432
  const selectFields = {};
433
+ // If defaultSelect is provided, only include those fields
434
+ if (defaultSelect) {
435
+ // Use default select but separate scalar and relation fields. If not in any, consider relation
436
+ scalarFields = Object.keys(defaultSelect).filter((field) => modelInfo.scalarFields.includes(field));
437
+ relationFields = Object.keys(defaultSelect).filter((field) => !modelInfo.scalarFields.includes(field) || field === '_count').reduce((acc, field) => {
438
+ acc[field] = defaultSelect[field];
439
+ return acc;
440
+ }, {});
441
+ // Merge with includeRelations if any
442
+ if (Object.keys(relationFields).length > 0) {
443
+ includeRelations = { ...(includeRelations || {}), ...relationFields };
444
+ }
445
+ }
413
446
  for (const field of scalarFields) {
414
447
  if (!omitFields.includes(field)) {
415
448
  selectFields[field] = true;
@@ -417,16 +450,27 @@ let PrismaService = class PrismaService {
417
450
  }
418
451
  if (includeRelations) {
419
452
  for (const relationKey in includeRelations) {
420
- if (!relationFields[relationKey])
453
+ if (!relationFields[relationKey] && relationKey !== '_count')
421
454
  continue;
422
455
  let includedArgs = includeRelations[relationKey];
423
456
  if (includedArgs === true) {
424
457
  includedArgs = {};
425
458
  }
426
- const relatedModelName = this.getRelation(modelName, relationKey, true).model;
427
- this.debug(`Found relation to model '${relatedModelName}' from model '${modelName}' via field '${relationKey}'. Generating select fields...`);
428
- const relatedModelOmitFields = this.getFieldsToOmit(relatedModelName, userRole);
429
- const relatedSelectFields = this.buildSelectFields(relatedModelName, relatedModelOmitFields, includedArgs.include || null, userRole);
459
+ let relatedSelectFields = {};
460
+ if (relationKey === '_count') {
461
+ if (includedArgs.select) {
462
+ relatedSelectFields = includedArgs.select;
463
+ omitFields.forEach((field) => {
464
+ delete relatedSelectFields[field];
465
+ });
466
+ }
467
+ }
468
+ else {
469
+ const relatedModelName = this.getRelation(modelName, relationKey, true).model;
470
+ this.debug(`Found relation to model '${relatedModelName}' from model '${modelName}' via field '${relationKey}'. Generating select fields...`);
471
+ const relatedModelOmitFields = this.getFieldsToOmit(relatedModelName, userRole);
472
+ relatedSelectFields = this.buildSelectFields(relatedModelName, relatedModelOmitFields, includedArgs.include || null, includedArgs.select || null, userRole);
473
+ }
430
474
  if (Object.keys(relatedSelectFields).length > 0) {
431
475
  selectFields[relationKey] = { select: relatedSelectFields };
432
476
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@appxdigital/appx-core",
3
- "version": "0.1.97",
3
+ "version": "0.1.99",
4
4
  "description": "Appx Core is a library that provides a set of tools to help you build your application faster.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",