@smartive/graphql-magic 16.3.6 → 16.3.8

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 (79) hide show
  1. package/.github/workflows/testing.yml +1 -1
  2. package/CHANGELOG.md +2 -2
  3. package/dist/bin/gqm.cjs +37 -35
  4. package/dist/cjs/index.cjs +51 -48
  5. package/dist/esm/api/execute.d.ts +1 -5
  6. package/dist/esm/api/execute.js.map +1 -1
  7. package/dist/esm/client/queries.d.ts +4 -4
  8. package/dist/esm/client/queries.js.map +1 -1
  9. package/dist/esm/db/generate.js +2 -0
  10. package/dist/esm/db/generate.js.map +1 -1
  11. package/dist/esm/migrations/generate.js +1 -1
  12. package/dist/esm/migrations/generate.js.map +1 -1
  13. package/dist/esm/models/models.d.ts +1 -1
  14. package/dist/esm/models/models.js.map +1 -1
  15. package/dist/esm/models/utils.d.ts +8 -12
  16. package/dist/esm/models/utils.js +3 -5
  17. package/dist/esm/models/utils.js.map +1 -1
  18. package/dist/esm/permissions/check.js +0 -15
  19. package/dist/esm/permissions/check.js.map +1 -1
  20. package/dist/esm/permissions/generate.d.ts +5 -19
  21. package/dist/esm/permissions/generate.js.map +1 -1
  22. package/dist/esm/resolvers/arguments.js.map +1 -1
  23. package/dist/esm/resolvers/filters.js +0 -2
  24. package/dist/esm/resolvers/filters.js.map +1 -1
  25. package/dist/esm/resolvers/mutations.js +5 -4
  26. package/dist/esm/resolvers/mutations.js.map +1 -1
  27. package/dist/esm/resolvers/node.js.map +1 -1
  28. package/dist/esm/resolvers/resolver.d.ts +2 -2
  29. package/dist/esm/resolvers/resolver.js +1 -1
  30. package/dist/esm/resolvers/resolver.js.map +1 -1
  31. package/dist/esm/resolvers/selects.js.map +1 -1
  32. package/dist/esm/resolvers/utils.d.ts +2 -6
  33. package/dist/esm/resolvers/utils.js +4 -2
  34. package/dist/esm/resolvers/utils.js.map +1 -1
  35. package/dist/esm/schema/utils.d.ts +4 -4
  36. package/dist/esm/schema/utils.js +31 -30
  37. package/dist/esm/schema/utils.js.map +1 -1
  38. package/dist/esm/utils/dates.d.ts +2 -4
  39. package/dist/esm/utils/dates.js +1 -3
  40. package/dist/esm/utils/dates.js.map +1 -1
  41. package/docs/docs/1-tutorial.md +1 -1
  42. package/docs/package-lock.json +1675 -893
  43. package/docs/package.json +4 -4
  44. package/eslint.config.mjs +42 -0
  45. package/migrations/20230912185644_setup.ts +3 -3
  46. package/package.json +8 -13
  47. package/src/api/execute.ts +1 -0
  48. package/src/bin/gqm/codegen.ts +1 -1
  49. package/src/client/gql.ts +1 -1
  50. package/src/client/mutations.ts +8 -8
  51. package/src/client/queries.ts +15 -14
  52. package/src/db/generate.ts +8 -5
  53. package/src/migrations/generate.ts +26 -22
  54. package/src/models/models.ts +24 -9
  55. package/src/models/mutation-hook.ts +1 -1
  56. package/src/models/utils.ts +8 -7
  57. package/src/permissions/check.ts +22 -30
  58. package/src/permissions/generate.ts +8 -25
  59. package/src/resolvers/arguments.ts +7 -2
  60. package/src/resolvers/filters.ts +8 -10
  61. package/src/resolvers/mutations.ts +19 -16
  62. package/src/resolvers/node.ts +3 -2
  63. package/src/resolvers/resolver.ts +11 -10
  64. package/src/resolvers/selects.ts +4 -3
  65. package/src/resolvers/utils.ts +15 -10
  66. package/src/schema/generate.ts +11 -11
  67. package/src/schema/utils.ts +84 -82
  68. package/src/utils/dates.ts +3 -3
  69. package/tests/generated/api/index.ts +2 -2
  70. package/tests/generated/client/index.ts +1 -193
  71. package/tests/generated/db/index.ts +4 -4
  72. package/tests/generated/models.json +2 -1
  73. package/tests/generated/schema.graphql +1 -1
  74. package/tests/utils/graphql-client.ts +49 -0
  75. package/tests/utils/models.ts +1 -0
  76. package/tests/utils/server.ts +4 -5
  77. package/tsconfig.eslint.json +18 -3
  78. package/tsconfig.json +11 -2
  79. package/.eslintrc +0 -13
@@ -71,7 +71,7 @@ export class Models {
71
71
  kind: 'raw-enum',
72
72
  name: 'Order',
73
73
  values: ['ASC', 'DESC'],
74
- }
74
+ },
75
75
  );
76
76
  const entities = this.definitions.filter(isEntityModelDefinition);
77
77
 
@@ -204,7 +204,7 @@ export class Models {
204
204
  }
205
205
 
206
206
  this.models = this.definitions.map(
207
- (definition) => new (MODEL_KIND_TO_CLASS_MAPPING[definition.kind] as any)(this, definition)
207
+ (definition) => new (MODEL_KIND_TO_CLASS_MAPPING[definition.kind] as any)(this, definition),
208
208
  );
209
209
  for (const model of this.models) {
210
210
  this.modelsByName[model.name] = model;
@@ -228,6 +228,7 @@ export class Models {
228
228
  if (!(model instanceof expectedType)) {
229
229
  throw new Error(`Model ${name} is not of kind ${kind}.`);
230
230
  }
231
+
231
232
  return model as ModelKindToClassMapping[K];
232
233
  }
233
234
  }
@@ -237,7 +238,10 @@ export abstract class Model {
237
238
  plural: string;
238
239
  description: string;
239
240
 
240
- constructor(public models: Models, definition: ModelDefinition) {
241
+ constructor(
242
+ public models: Models,
243
+ definition: ModelDefinition,
244
+ ) {
241
245
  Object.assign(this, definition);
242
246
  this.plural = definition.plural || pluralize(definition.name);
243
247
  }
@@ -358,6 +362,7 @@ export class EntityModel extends Model {
358
362
  .filter(isRelation)
359
363
  .map((relationField) => new NormalRelation(this, relationField, this.models.getModel(relationField.type, 'entity')));
360
364
  }
365
+
361
366
  return this._relations;
362
367
  }
363
368
 
@@ -368,6 +373,7 @@ export class EntityModel extends Model {
368
373
  this._relationsByName[relation.name] = relation;
369
374
  }
370
375
  }
376
+
371
377
  return this._relationsByName;
372
378
  }
373
379
 
@@ -380,9 +386,10 @@ export class EntityModel extends Model {
380
386
  this._reverseRelations = this.models.entities.flatMap((model) =>
381
387
  model.relations
382
388
  .filter((relation) => relation.targetModel.name === this.name || relation.targetModel.name === this.rootModel.name)
383
- .map((relation) => relation.reverse)
389
+ .map((relation) => relation.reverse),
384
390
  );
385
391
  }
392
+
386
393
  return this._reverseRelations;
387
394
  }
388
395
 
@@ -393,6 +400,7 @@ export class EntityModel extends Model {
393
400
  this._reverseRelationsByName[reverseRelation.name] = reverseRelation;
394
401
  }
395
402
  }
403
+
396
404
  return this._reverseRelationsByName;
397
405
  }
398
406
 
@@ -405,7 +413,7 @@ export class EntityModel extends Model {
405
413
  this._manyToManyRelations = [];
406
414
  for (const relationFromSource of this.reverseRelations) {
407
415
  const relationToTarget = relationFromSource.targetModel.relations.find(
408
- (relation) => !relation.field.generated && relation.field.name !== relationFromSource.field.name
416
+ (relation) => !relation.field.generated && relation.field.name !== relationFromSource.field.name,
409
417
  );
410
418
  if (!relationToTarget) {
411
419
  continue;
@@ -413,7 +421,7 @@ export class EntityModel extends Model {
413
421
 
414
422
  const inapplicableFields = relationFromSource.targetModel.fields.filter(
415
423
  (otherField) =>
416
- !otherField.generated && ![relationFromSource.field.name, relationToTarget.field.name].includes(otherField.name)
424
+ !otherField.generated && ![relationFromSource.field.name, relationToTarget.field.name].includes(otherField.name),
417
425
  );
418
426
  if (inapplicableFields.length) {
419
427
  continue;
@@ -422,6 +430,7 @@ export class EntityModel extends Model {
422
430
  this._manyToManyRelations.push(new ManyToManyRelation(relationFromSource, relationToTarget));
423
431
  }
424
432
  }
433
+
425
434
  return this._manyToManyRelations;
426
435
  }
427
436
 
@@ -432,6 +441,7 @@ export class EntityModel extends Model {
432
441
  this._manyToManyRelationsByName[manyToManyRelation.name] = manyToManyRelation;
433
442
  }
434
443
  }
444
+
435
445
  return this._manyToManyRelationsByName;
436
446
  }
437
447
 
@@ -444,6 +454,7 @@ export class EntityModel extends Model {
444
454
  if (!this._parentModel) {
445
455
  this._parentModel = this.models.getModel(this.parent, 'entity');
446
456
  }
457
+
447
458
  return this._parentModel;
448
459
  }
449
460
  }
@@ -472,14 +483,18 @@ export abstract class Relation {
472
483
  public name: string,
473
484
  public sourceModel: EntityModel,
474
485
  public field: RelationField,
475
- public targetModel: EntityModel
486
+ public targetModel: EntityModel,
476
487
  ) {}
477
488
  }
478
489
 
479
490
  export class NormalRelation extends Relation {
480
491
  public reverse: ReverseRelation;
481
492
 
482
- constructor(sourceModel: EntityModel, public field: RelationField, targetModel: EntityModel) {
493
+ constructor(
494
+ sourceModel: EntityModel,
495
+ public field: RelationField,
496
+ targetModel: EntityModel,
497
+ ) {
483
498
  super(field.name, sourceModel, field, targetModel);
484
499
  this.reverse = new ReverseRelation(this);
485
500
  }
@@ -492,7 +507,7 @@ export class ReverseRelation extends Relation {
492
507
  (reverse.field.toOne ? typeToField(reverse.sourceModel.name) : reverse.sourceModel.pluralField),
493
508
  reverse.targetModel,
494
509
  reverse.field,
495
- reverse.sourceModel
510
+ reverse.sourceModel,
496
511
  );
497
512
  }
498
513
  }
@@ -10,5 +10,5 @@ export type MutationHook<DateType extends AnyDateType = AnyDateType> = (
10
10
  action: Action,
11
11
  when: 'before' | 'after',
12
12
  data: { prev: Entity; input: Entity; normalizedInput: Entity; next: Entity },
13
- ctx: Context<DateType>
13
+ ctx: Context<DateType>,
14
14
  ) => Promise<void>;
@@ -19,7 +19,7 @@ import {
19
19
 
20
20
  const isNotFalsy = <T>(v: T | null | undefined | false): v is T => typeof v !== 'undefined' && v !== null && v !== false;
21
21
 
22
- export const merge = <T>(objects: ({ [name: string]: T } | undefined | false)[] | undefined): { [name: string]: T } =>
22
+ export const merge = <T>(objects: (Record<string, T> | undefined | false)[] | undefined): Record<string, T> =>
23
23
  (objects || []).filter(isNotFalsy).reduce((i, acc) => ({ ...acc, ...i }), {});
24
24
 
25
25
  // Target -> target
@@ -42,7 +42,7 @@ export const not =
42
42
  (field: T) =>
43
43
  !predicate(field);
44
44
 
45
- export const isRootModel = (model: EntityModel) => model.root;
45
+ export const isRootModel = (model: EntityModel) => !!model.root;
46
46
 
47
47
  export const isEntityModel = (model: Model): model is EntityModel => model instanceof EntityModel;
48
48
 
@@ -77,7 +77,7 @@ export const isEnum = (field: EntityField): field is EnumField => field.kind ===
77
77
 
78
78
  export const isRelation = (field: EntityField): field is RelationField => field.kind === 'relation';
79
79
 
80
- export const isInherited = (field: EntityField) => field.inherited;
80
+ export const isInherited = (field: EntityField) => !!field.inherited;
81
81
 
82
82
  export const isInTable = (field: EntityField) => field.name === 'id' || !field.inherited;
83
83
 
@@ -114,7 +114,7 @@ export const getActionableRelations = (model: EntityModel, action: 'create' | 'u
114
114
  (relation) =>
115
115
  relation.field[
116
116
  `${action === 'filter' ? action : action.slice(0, -1)}able` as 'filterable' | 'creatable' | 'updatable'
117
- ]
117
+ ],
118
118
  )
119
119
  .map(({ name }) => name);
120
120
 
@@ -133,6 +133,7 @@ export const summon = <T>(array: readonly T[] | undefined, cb: Parameters<T[]['f
133
133
  console.trace();
134
134
  throw new Error(errorMessage || 'Element not found.');
135
135
  }
136
+
136
137
  return result;
137
138
  };
138
139
 
@@ -154,11 +155,13 @@ export const get = <T, U extends keyof ForSure<T>>(object: T | null | undefined,
154
155
  console.warn(error);
155
156
  throw error;
156
157
  }
158
+
157
159
  return value as ForSure<ForSure<T>[U]>;
158
160
  };
159
161
 
160
162
  export const getString = (v: unknown) => {
161
163
  assert(typeof v === 'string');
164
+
162
165
  return v;
163
166
  };
164
167
 
@@ -168,9 +171,8 @@ export const retry = async <T>(cb: () => Promise<T>, condition: (e: any) => bool
168
171
  } catch (e) {
169
172
  if (condition(e)) {
170
173
  return await cb();
171
- } else {
172
- throw e;
173
174
  }
175
+ throw e;
174
176
  }
175
177
  };
176
178
 
@@ -182,7 +184,6 @@ type Typeof = {
182
184
  symbol: symbol;
183
185
  undefined: undefined;
184
186
  object: object;
185
- // eslint-disable-next-line @typescript-eslint/ban-types
186
187
  function: Function;
187
188
  };
188
189
 
@@ -11,7 +11,7 @@ export const getRole = (ctx: Pick<FullContext, 'user'>) => ctx.user?.role ?? 'UN
11
11
  export const getPermissionStack = (
12
12
  ctx: Pick<FullContext, 'permissions' | 'user'>,
13
13
  type: string,
14
- action: PermissionAction
14
+ action: PermissionAction,
15
15
  ): boolean | PermissionStack => {
16
16
  const rolePermissions = ctx.permissions[getRole(ctx)];
17
17
  if (typeof rolePermissions === 'boolean' || rolePermissions === undefined) {
@@ -37,7 +37,7 @@ export const applyPermissions = (
37
37
  tableAlias: string,
38
38
  query: Knex.QueryBuilder,
39
39
  action: PermissionAction,
40
- verifiedPermissionStack?: PermissionStack
40
+ verifiedPermissionStack?: PermissionStack,
41
41
  ): boolean | PermissionStack => {
42
42
  const permissionStack = getPermissionStack(ctx, type, action);
43
43
 
@@ -47,8 +47,9 @@ export const applyPermissions = (
47
47
 
48
48
  if (permissionStack === false) {
49
49
  console.error(`No applicable permissions exist for ${getRole(ctx)} ${type} ${action}.`);
50
- // eslint-disable-next-line @typescript-eslint/no-floating-promises -- we do not need to await knex here
50
+
51
51
  query.where(false);
52
+
52
53
  return permissionStack;
53
54
  }
54
55
 
@@ -59,8 +60,8 @@ export const applyPermissions = (
59
60
  hash(prefixChain) === hash(chain.slice(0, -1)) &&
60
61
  // TODO: this is stricter than it could be if we add these checks to the query
61
62
  !('where' in get(chain, chain.length - 1)) &&
62
- !('me' in get(chain, chain.length - 1))
63
- )
63
+ !('me' in get(chain, chain.length - 1)),
64
+ ),
64
65
  )
65
66
  ) {
66
67
  // The user has access to a parent entity with one or more from a set of rules, all of which are inherited by this entity
@@ -68,15 +69,14 @@ export const applyPermissions = (
68
69
  return permissionStack;
69
70
  }
70
71
 
71
- // eslint-disable-next-line @typescript-eslint/no-floating-promises -- we do not need to await knex here
72
72
  ors(
73
73
  query,
74
74
  permissionStack.map(
75
75
  (links) => (query) =>
76
76
  query
77
77
  .whereNull(`${tableAlias}.id`)
78
- .orWhereExists((subQuery) => permissionLinkQuery(ctx, subQuery, links, ctx.knex.raw(`"${tableAlias}".id`)))
79
- )
78
+ .orWhereExists((subQuery) => permissionLinkQuery(ctx, subQuery, links, ctx.knex.raw(`"${tableAlias}".id`))),
79
+ ),
80
80
  );
81
81
 
82
82
  return permissionStack;
@@ -89,7 +89,7 @@ export const getEntityToMutate = async (
89
89
  ctx: Pick<FullContext, 'models' | 'permissions' | 'user' | 'knex'>,
90
90
  model: EntityModel,
91
91
  where: Record<string, unknown>,
92
- action: 'UPDATE' | 'DELETE' | 'RESTORE'
92
+ action: 'UPDATE' | 'DELETE' | 'RESTORE',
93
93
  ) => {
94
94
  const query = ctx
95
95
  .knex(model.parent || model.name)
@@ -101,7 +101,7 @@ export const getEntityToMutate = async (
101
101
  console.error(
102
102
  `Not found: ${Object.entries(where)
103
103
  .map(([key, value]) => `${key}: ${value}`)
104
- .join(', ')}`
104
+ .join(', ')}`,
105
105
  );
106
106
  throw new NotFoundError(`Entity to ${action.toLowerCase()}`);
107
107
  }
@@ -112,7 +112,7 @@ export const getEntityToMutate = async (
112
112
  console.error(
113
113
  `Permission error: ${Object.entries(where)
114
114
  .map(([key, value]) => `${key}: ${value}`)
115
- .join(', ')}`
115
+ .join(', ')}`,
116
116
  );
117
117
  throw new PermissionError(getRole(ctx), action, `this ${model.name}`, 'no available permissions applied');
118
118
  }
@@ -132,7 +132,7 @@ export const checkCanWrite = async (
132
132
  ctx: Pick<FullContext, 'models' | 'permissions' | 'user' | 'knex'>,
133
133
  model: EntityModel,
134
134
  data: Record<string, unknown>,
135
- action: 'CREATE' | 'UPDATE'
135
+ action: 'CREATE' | 'UPDATE',
136
136
  ) => {
137
137
  const permissionStack = getPermissionStack(ctx, model.name, action);
138
138
 
@@ -143,7 +143,6 @@ export const checkCanWrite = async (
143
143
  throw new PermissionError(getRole(ctx), action, model.plural, 'no applicable permissions');
144
144
  }
145
145
 
146
- // eslint-disable-next-line @typescript-eslint/no-explicit-any -- using `select(1 as any)` to instantiate an "empty" query builder
147
146
  const query = ctx.knex.select(1 as any).first();
148
147
  let linked = false;
149
148
 
@@ -168,7 +167,7 @@ export const checkCanWrite = async (
168
167
 
169
168
  if (fieldPermissionStack === true) {
170
169
  // User can link any entity from this type, just check whether it exists
171
- // eslint-disable-next-line @typescript-eslint/no-floating-promises -- we do not need to await knex here
170
+
172
171
  query.whereExists((subQuery) => subQuery.from(`${field.type} as a`).whereRaw(`a.id = ?`, foreignId));
173
172
  continue;
174
173
  }
@@ -178,16 +177,15 @@ export const checkCanWrite = async (
178
177
  role,
179
178
  action,
180
179
  `this ${model.name}'s ${field.name}`,
181
- 'no applicable permissions on data to link'
180
+ 'no applicable permissions on data to link',
182
181
  );
183
182
  }
184
183
 
185
- // eslint-disable-next-line @typescript-eslint/no-floating-promises -- we do not need to await knex here
186
184
  ors(
187
185
  query,
188
186
  fieldPermissionStack.map(
189
- (links) => (query) => query.whereExists((subQuery) => permissionLinkQuery(ctx, subQuery, links, foreignId))
190
- )
187
+ (links) => (query) => query.whereExists((subQuery) => permissionLinkQuery(ctx, subQuery, links, foreignId)),
188
+ ),
191
189
  );
192
190
  }
193
191
 
@@ -206,7 +204,7 @@ const permissionLinkQuery = (
206
204
  ctx: Pick<FullContext, 'models' | 'user'>,
207
205
  subQuery: Knex.QueryBuilder,
208
206
  links: PermissionLink[],
209
- id: Knex.RawBinding | Knex.ValueDict
207
+ id: Knex.RawBinding | Knex.ValueDict,
210
208
  ) => {
211
209
  const aliases = new AliasGenerator();
212
210
  let alias = aliases.getShort();
@@ -214,16 +212,14 @@ const permissionLinkQuery = (
214
212
 
215
213
  if (me) {
216
214
  if (!ctx.user) {
217
- // eslint-disable-next-line @typescript-eslint/no-floating-promises -- we do not need to await knex here
218
215
  subQuery.where(false);
216
+
219
217
  return;
220
218
  }
221
219
 
222
- // eslint-disable-next-line @typescript-eslint/no-floating-promises -- we do not need to await knex here
223
220
  subQuery.where({ [`${alias}.id`]: ctx.user.id });
224
221
  }
225
222
 
226
- // eslint-disable-next-line @typescript-eslint/no-floating-promises -- we do not need to await knex here
227
223
  subQuery.from(`${type} as ${alias}`);
228
224
 
229
225
  if (where) {
@@ -234,20 +230,18 @@ const permissionLinkQuery = (
234
230
  const model = ctx.models.getModel(type, 'entity');
235
231
  const subAlias = aliases.getShort();
236
232
  if (reverse) {
237
- // eslint-disable-next-line @typescript-eslint/no-floating-promises -- we do not need to await knex here
238
233
  subQuery.leftJoin(`${type} as ${subAlias}`, `${alias}.${foreignKey || 'id'}`, `${subAlias}.id`);
239
234
  } else {
240
- // eslint-disable-next-line @typescript-eslint/no-floating-promises -- we do not need to await knex here
241
235
  subQuery.rightJoin(`${type} as ${subAlias}`, `${alias}.id`, `${subAlias}.${foreignKey || 'id'}`);
242
236
  }
243
- // eslint-disable-next-line @typescript-eslint/no-floating-promises -- we do not need to await knex here
237
+
244
238
  subQuery.where({ [`${subAlias}.deleted`]: false });
245
239
  if (where) {
246
240
  applyWhere(model, subQuery, subAlias, where, aliases);
247
241
  }
248
242
  alias = subAlias;
249
243
  }
250
- // eslint-disable-next-line @typescript-eslint/no-floating-promises -- we do not need to await knex here
244
+
251
245
  subQuery.whereRaw(`"${alias}".id = ?`, id);
252
246
  };
253
247
 
@@ -257,18 +251,16 @@ const applyWhere = (model: EntityModel, query: Knex.QueryBuilder, alias: string,
257
251
 
258
252
  if (relation) {
259
253
  const subAlias = aliases.getShort();
260
- // eslint-disable-next-line @typescript-eslint/no-floating-promises -- we do not need to await knex here
254
+
261
255
  query.leftJoin(
262
256
  `${relation.targetModel.name} as ${subAlias}`,
263
257
  `${alias}.${relation.field.foreignKey || `${relation.field.name}Id`}`,
264
- `${subAlias}.id`
258
+ `${subAlias}.id`,
265
259
  );
266
260
  applyWhere(relation.targetModel, query, subAlias, value, aliases);
267
261
  } else if (Array.isArray(value)) {
268
- // eslint-disable-next-line @typescript-eslint/no-floating-promises -- we do not need to await knex here
269
262
  query.whereIn(`${alias}.${key}`, value);
270
263
  } else {
271
- // eslint-disable-next-line @typescript-eslint/no-floating-promises -- we do not need to await knex here
272
264
  query.where({ [`${alias}.${key}`]: value });
273
265
  }
274
266
  }
@@ -8,36 +8,19 @@ const ACTIONS: PermissionAction[] = ['READ', 'CREATE', 'UPDATE', 'DELETE', 'REST
8
8
  /**
9
9
  * Initial representation (tree structure, as defined by user).
10
10
  */
11
- export type PermissionsConfig = {
12
- [role: string]:
13
- | true
14
- | {
15
- [type: string]: PermissionsBlock;
16
- };
17
- };
11
+ export type PermissionsConfig = Record<string, true | Record<string, PermissionsBlock>>;
18
12
 
19
- export type PermissionsBlock = {
20
- [action in PermissionAction]?: true;
21
- } & {
22
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
13
+ export type PermissionsBlock = Partial<Record<PermissionAction, true>> & {
23
14
  WHERE?: Record<string, any>;
24
- RELATIONS?: {
25
- [relation: string]: PermissionsBlock;
26
- };
15
+ RELATIONS?: Record<string, PermissionsBlock>;
27
16
  };
28
17
 
29
18
  /**
30
19
  * Final representation (lookup table (role, model, action) -> permission stack).
31
20
  */
32
- export type Permissions = {
33
- [role: string]: true | RolePermissions;
34
- };
21
+ export type Permissions = Record<string, true | RolePermissions>;
35
22
 
36
- type RolePermissions = {
37
- [type: string]: {
38
- [action in PermissionAction]?: true | PermissionStack;
39
- };
40
- };
23
+ type RolePermissions = Record<string, Partial<Record<PermissionAction, true | PermissionStack>>>;
41
24
 
42
25
  /**
43
26
  * For a given role, model and action,
@@ -53,7 +36,7 @@ export type PermissionLink = {
53
36
  foreignKey?: string;
54
37
  reverse?: boolean;
55
38
  me?: boolean;
56
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
39
+
57
40
  where?: any;
58
41
  };
59
42
 
@@ -85,7 +68,7 @@ export const generatePermissions = (models: Models, config: PermissionsConfig) =
85
68
  ...('WHERE' in block && { where: block.WHERE }),
86
69
  },
87
70
  ],
88
- block
71
+ block,
89
72
  );
90
73
  }
91
74
  permissions[role] = rolePermissions;
@@ -107,7 +90,7 @@ const addPermissions = (models: Models, permissions: RolePermissions, links: Per
107
90
  permissions[type][action] = [];
108
91
  }
109
92
  if (permissions[type][action] !== true) {
110
- (permissions[type][action] as PermissionStack).push(links);
93
+ permissions[type][action].push(links);
111
94
  }
112
95
  }
113
96
  }
@@ -35,6 +35,7 @@ function getRawValue(value: ValueNode, values?: VariableValues): Value {
35
35
  if (!values) {
36
36
  return;
37
37
  }
38
+
38
39
  return value.values.map((value) => getRawValue(value, values));
39
40
  case Kind.VARIABLE:
40
41
  return values?.[value.name.value];
@@ -56,6 +57,7 @@ function getRawValue(value: ValueNode, values?: VariableValues): Value {
56
57
  for (const field of value.fields) {
57
58
  res[field.name.value] = getRawValue(field.value, values);
58
59
  }
60
+
59
61
  return res;
60
62
  }
61
63
  }
@@ -69,7 +71,7 @@ export const normalizeArguments = (node: FieldResolverNode) => {
69
71
  const normalizedValue = normalizeValue(
70
72
  rawValue,
71
73
  summonByKey(node.fieldDefinition.arguments || [], 'name.value', argument.name.value).type,
72
- node.ctx.info.schema
74
+ node.ctx.info.schema,
73
75
  );
74
76
  if (normalizedValue === undefined) {
75
77
  continue;
@@ -77,6 +79,7 @@ export const normalizeArguments = (node: FieldResolverNode) => {
77
79
  normalizedArguments[argument.name.value] = normalizedValue as any;
78
80
  }
79
81
  }
82
+
80
83
  return normalizedArguments;
81
84
  };
82
85
 
@@ -88,6 +91,7 @@ export function normalizeValue(value: Value, type: TypeNode, schema: GraphQLSche
88
91
  for (const v of value) {
89
92
  res.push(normalizeValue(v, type.type, schema));
90
93
  }
94
+
91
95
  return res;
92
96
  }
93
97
 
@@ -104,7 +108,7 @@ export function normalizeValue(value: Value, type: TypeNode, schema: GraphQLSche
104
108
  return normalizeValueByTypeDefinition(
105
109
  value,
106
110
  (schema.getType(type.name.value) as Maybe<GraphQLObjectType>)?.astNode,
107
- schema
111
+ schema,
108
112
  );
109
113
  }
110
114
  }
@@ -125,5 +129,6 @@ export const normalizeValueByTypeDefinition = (value: Value, type: Maybe<TypeDef
125
129
  }
126
130
  res[key] = normalizedValue;
127
131
  }
132
+
128
133
  return res;
129
134
  };
@@ -33,12 +33,10 @@ export const applyFilters = (node: FieldResolverNode, query: Knex.QueryBuilder,
33
33
  const { limit, offset, orderBy, where, search } = normalizedArguments;
34
34
 
35
35
  if (limit) {
36
- // eslint-disable-next-line @typescript-eslint/no-floating-promises -- we do not need to await knex here
37
36
  query.limit(limit);
38
37
  }
39
38
 
40
39
  if (offset) {
41
- // eslint-disable-next-line @typescript-eslint/no-floating-promises -- we do not need to await knex here
42
40
  query.offset(offset);
43
41
  }
44
42
 
@@ -108,8 +106,8 @@ const applyWhere = (node: WhereNode, where: Where | undefined, ops: QueryBuilder
108
106
  ops.push((query) =>
109
107
  ors(
110
108
  query,
111
- allSubOps.map((subOps) => (subQuery) => apply(subQuery, subOps))
112
- )
109
+ allSubOps.map((subOps) => (subQuery) => apply(subQuery, subOps)),
110
+ ),
113
111
  );
114
112
  continue;
115
113
  }
@@ -145,7 +143,7 @@ const applyWhere = (node: WhereNode, where: Where | undefined, ops: QueryBuilder
145
143
  ]);
146
144
  void apply(subQuery, subOps);
147
145
  applyJoins(aliases, subQuery, subJoins);
148
- })
146
+ }),
149
147
  );
150
148
  continue;
151
149
  }
@@ -183,8 +181,8 @@ const applyWhere = (node: WhereNode, where: Where | undefined, ops: QueryBuilder
183
181
  ops.push((query) =>
184
182
  ors(
185
183
  query,
186
- value.map((v) => (subQuery) => subQuery.whereRaw('? = ANY(??)', [v, column] as string[]))
187
- )
184
+ value.map((v) => (subQuery) => subQuery.whereRaw('? = ANY(??)', [v, column] as string[])),
185
+ ),
188
186
  );
189
187
  continue;
190
188
  }
@@ -195,7 +193,7 @@ const applyWhere = (node: WhereNode, where: Where | undefined, ops: QueryBuilder
195
193
  ors(query, [
196
194
  (subQuery) => subQuery.whereIn(column, value.filter((v) => v !== null) as string[]),
197
195
  (subQuery) => subQuery.whereNull(column),
198
- ])
196
+ ]),
199
197
  );
200
198
  continue;
201
199
  }
@@ -220,8 +218,8 @@ const applySearch = (node: FieldResolverNode, search: string, query: Knex.QueryB
220
218
  .map(
221
219
  ({ name }) =>
222
220
  (query) =>
223
- query.whereILike(getColumn(node, name), `%${search}%`)
224
- )
221
+ query.whereILike(getColumn(node, name), `%${search}%`),
222
+ ),
225
223
  );
226
224
 
227
225
  const applyOrderBy = (node: FieldResolverNode, orderBy: OrderBy, query: Knex.QueryBuilder) => {