@smartive/graphql-magic 23.10.0 → 24.0.0-next.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@smartive/graphql-magic",
3
- "version": "23.10.0",
3
+ "version": "24.0.0-next.1",
4
4
  "description": "",
5
5
  "repository": {
6
6
  "type": "git",
@@ -1,25 +1,46 @@
1
1
  import upperCase from 'lodash/upperCase';
2
+ import { Field } from '../schema/utils';
2
3
  import { isRootModel, not } from '..';
3
4
  import { Models } from '../models/models';
4
5
 
5
6
  const constantCase = (str: string) => upperCase(str).replace(/ /g, '_');
6
7
 
8
+ const argTypeStr = (field: Field) => {
9
+ const base = field.list ? `[${field.type}!]` : field.type;
10
+
11
+ return field.nonNull ? `${base}!` : base;
12
+ };
13
+
14
+ const argsToVariables = (args: readonly Field[]) => args.map((a) => `$${a.name}: ${argTypeStr(a)}`).join(', ');
15
+
16
+ const argsToMutationArgs = (args: readonly Field[]) => args.map((a) => `${a.name}: $${a.name}`).join(', ');
17
+
7
18
  export const generateMutations = (models: Models) => {
8
19
  const parts: string[] = [];
9
20
  for (const { name, creatable, updatable, deletable } of models.entities.filter(not(isRootModel))) {
10
21
  if (creatable) {
22
+ const extraArgs = creatable !== true && creatable.args ? creatable.args : [];
23
+ const variables = extraArgs.length ? `$data: Create${name}!, ${argsToVariables(extraArgs)}` : `$data: Create${name}!`;
24
+ const mutationArgs = extraArgs.length ? `data: $data, ${argsToMutationArgs(extraArgs)}` : `data: $data`;
11
25
  parts.push(
12
26
  `export const CREATE_${constantCase(
13
27
  name,
14
- )} = gql\`\n mutation Create${name}Mutation($data: Create${name}!) {\n create${name}(data: $data) { id }\n }\n\`;`,
28
+ )} = gql\`\n mutation Create${name}Mutation(${variables}) {\n create${name}(${mutationArgs}) { id }\n }\n\`;`,
15
29
  );
16
30
  }
17
31
 
18
32
  if (updatable) {
33
+ const extraArgs = updatable !== true && updatable.args ? updatable.args : [];
34
+ const variables = extraArgs.length
35
+ ? `$id: ID!, $data: Update${name}!, ${argsToVariables(extraArgs)}`
36
+ : `$id: ID!, $data: Update${name}!`;
37
+ const mutationArgs = extraArgs.length
38
+ ? `where: { id: $id }, data: $data, ${argsToMutationArgs(extraArgs)}`
39
+ : `where: { id: $id }, data: $data`;
19
40
  parts.push(
20
41
  `export const UPDATE_${constantCase(
21
42
  name,
22
- )} = gql\`\n mutation Update${name}Mutation($id: ID!, $data: Update${name}!) {\n update${name}(where: { id: $id }, data: $data) { id }\n }\n\`;`,
43
+ )} = gql\`\n mutation Update${name}Mutation(${variables}) {\n update${name}(${mutationArgs}) { id }\n }\n\`;`,
23
44
  );
24
45
  }
25
46
 
@@ -1026,19 +1026,11 @@ export class MigrationGenerator {
1026
1026
  return -1;
1027
1027
  }
1028
1028
 
1029
- private static readonly TRIGGER_EVENT_ORDER: readonly ('INSERT' | 'UPDATE' | 'DELETE')[] = [
1030
- 'INSERT',
1031
- 'UPDATE',
1032
- 'DELETE',
1033
- ];
1034
-
1035
- private static sortTriggerEvents(
1036
- events: readonly ('INSERT' | 'UPDATE' | 'DELETE')[],
1037
- ): ('INSERT' | 'UPDATE' | 'DELETE')[] {
1029
+ private static readonly TRIGGER_EVENT_ORDER: readonly ('INSERT' | 'UPDATE' | 'DELETE')[] = ['INSERT', 'UPDATE', 'DELETE'];
1030
+
1031
+ private static sortTriggerEvents(events: readonly ('INSERT' | 'UPDATE' | 'DELETE')[]): ('INSERT' | 'UPDATE' | 'DELETE')[] {
1038
1032
  return [...events].sort(
1039
- (a, b) =>
1040
- MigrationGenerator.TRIGGER_EVENT_ORDER.indexOf(a) -
1041
- MigrationGenerator.TRIGGER_EVENT_ORDER.indexOf(b),
1033
+ (a, b) => MigrationGenerator.TRIGGER_EVENT_ORDER.indexOf(a) - MigrationGenerator.TRIGGER_EVENT_ORDER.indexOf(b),
1042
1034
  );
1043
1035
  }
1044
1036
 
@@ -1050,7 +1042,9 @@ export class MigrationGenerator {
1050
1042
  .replace(/\bON\s+[a-zA-Z_][a-zA-Z0-9_]*\./gi, 'ON ')
1051
1043
  .trim();
1052
1044
 
1053
- const eventsMatch = s.match(/\b(AFTER|BEFORE)\s+((?:INSERT|UPDATE|DELETE)(?:\s+OR\s+(?:INSERT|UPDATE|DELETE))+)\s+ON\b/i);
1045
+ const eventsMatch = s.match(
1046
+ /\b(AFTER|BEFORE)\s+((?:INSERT|UPDATE|DELETE)(?:\s+OR\s+(?:INSERT|UPDATE|DELETE))+)\s+ON\b/i,
1047
+ );
1054
1048
  if (eventsMatch) {
1055
1049
  const events = eventsMatch[2].split(/\s+OR\s+/).map((e) => e.toUpperCase());
1056
1050
  const sorted = [...events].sort(
@@ -1311,8 +1305,7 @@ export class MigrationGenerator {
1311
1305
 
1312
1306
  private sortTriggerEvents(events: readonly ('INSERT' | 'UPDATE' | 'DELETE')[]): ('INSERT' | 'UPDATE' | 'DELETE')[] {
1313
1307
  return [...events].sort(
1314
- (a, b) =>
1315
- MigrationGenerator.TRIGGER_EVENT_ORDER.indexOf(a) - MigrationGenerator.TRIGGER_EVENT_ORDER.indexOf(b),
1308
+ (a, b) => MigrationGenerator.TRIGGER_EVENT_ORDER.indexOf(a) - MigrationGenerator.TRIGGER_EVENT_ORDER.indexOf(b),
1316
1309
  );
1317
1310
  }
1318
1311
 
@@ -145,8 +145,20 @@ export type ModelDefinition = {
145
145
  interfaces?: readonly string[];
146
146
  queriable?: boolean;
147
147
  listQueriable?: boolean | { args?: readonly Field[] };
148
- creatable?: boolean | { createdBy?: Partial<RelationFieldDefinition>; createdAt?: Partial<DateTimeFieldDefinition> };
149
- updatable?: boolean | { updatedBy?: Partial<RelationFieldDefinition>; updatedAt?: Partial<DateTimeFieldDefinition> };
148
+ creatable?:
149
+ | boolean
150
+ | {
151
+ createdBy?: Partial<RelationFieldDefinition>;
152
+ createdAt?: Partial<DateTimeFieldDefinition>;
153
+ args?: readonly Field[];
154
+ };
155
+ updatable?:
156
+ | boolean
157
+ | {
158
+ updatedBy?: Partial<RelationFieldDefinition>;
159
+ updatedAt?: Partial<DateTimeFieldDefinition>;
160
+ args?: readonly Field[];
161
+ };
150
162
  deletable?:
151
163
  | boolean
152
164
  | {
@@ -344,8 +344,20 @@ export class EntityModel extends Model {
344
344
  interfaces?: string[];
345
345
  queriable?: boolean;
346
346
  listQueriable?: boolean | { args?: readonly Field[] };
347
- creatable?: boolean | { createdBy?: Partial<RelationFieldDefinition>; createdAt?: Partial<DateTimeFieldDefinition> };
348
- updatable?: boolean | { updatedBy?: Partial<RelationFieldDefinition>; updatedAt?: Partial<DateTimeFieldDefinition> };
347
+ creatable?:
348
+ | boolean
349
+ | {
350
+ createdBy?: Partial<RelationFieldDefinition>;
351
+ createdAt?: Partial<DateTimeFieldDefinition>;
352
+ args?: readonly Field[];
353
+ };
354
+ updatable?:
355
+ | boolean
356
+ | {
357
+ updatedBy?: Partial<RelationFieldDefinition>;
358
+ updatedAt?: Partial<DateTimeFieldDefinition>;
359
+ args?: readonly Field[];
360
+ };
349
361
  deletable?:
350
362
  | boolean
351
363
  | {
@@ -19,6 +19,7 @@ export type MutationHook<DateType extends AnyDateType = AnyDateType> = (args: {
19
19
  trigger: Trigger;
20
20
  when: 'before' | 'after';
21
21
  data: { prev: Entity; input: Entity; normalizedInput: Entity; next: Entity };
22
+ args?: Record<string, unknown>;
22
23
  ctx: MutationContext<DateType>;
23
24
  }) => Promise<void> | void;
24
25
 
@@ -18,14 +18,14 @@ export const mutationResolver = async (_parent: any, args: any, partialCtx: Cont
18
18
  const [, mutation, modelName] = it(info.fieldName.match(/^(create|update|delete|restore)(.+)$/));
19
19
  switch (mutation) {
20
20
  case 'create': {
21
- const id = await createEntity(modelName, args.data, ctx, 'mutation');
21
+ const id = await createEntity(modelName, args.data, ctx, { trigger: 'mutation', args });
22
22
 
23
23
  return await resolve(ctx, id);
24
24
  }
25
25
  case 'update': {
26
26
  const id = args.where.id;
27
27
 
28
- await updateEntity(modelName, id, args.data, ctx, 'mutation');
28
+ await updateEntity(modelName, id, args.data, ctx, { trigger: 'mutation', args });
29
29
 
30
30
  return await resolve(ctx, id);
31
31
  }
@@ -35,6 +35,7 @@ export const mutationResolver = async (_parent: any, args: any, partialCtx: Cont
35
35
  await deleteEntity(modelName, id, ctx, {
36
36
  dryRun: args.dryRun,
37
37
  trigger: 'mutation',
38
+ args,
38
39
  });
39
40
 
40
41
  return id;
@@ -42,7 +43,7 @@ export const mutationResolver = async (_parent: any, args: any, partialCtx: Cont
42
43
  case 'restore': {
43
44
  const id = args.where.id;
44
45
 
45
- await restoreEntity(modelName, id, ctx, 'mutation');
46
+ await restoreEntity(modelName, id, ctx, { trigger: 'mutation', args });
46
47
 
47
48
  return id;
48
49
  }
@@ -53,7 +54,7 @@ export const createEntity = async (
53
54
  modelName: string,
54
55
  input: Entity,
55
56
  ctx: MutationContext,
56
- trigger: Trigger = 'direct-call',
57
+ { args, trigger = 'direct-call' }: { args?: Record<string, unknown>; trigger?: Trigger } = {},
57
58
  ) =>
58
59
  withTransaction(ctx, async (ctx) => {
59
60
  const model = ctx.models.getModel(modelName, 'entity');
@@ -81,6 +82,7 @@ export const createEntity = async (
81
82
  trigger,
82
83
  when: 'before',
83
84
  data: { prev: {}, input, normalizedInput, next: normalizedInput },
85
+ args,
84
86
  ctx,
85
87
  });
86
88
 
@@ -114,6 +116,7 @@ export const createEntity = async (
114
116
  trigger,
115
117
  when: 'after',
116
118
  data: { prev: {}, input, normalizedInput, next: normalizedInput },
119
+ args,
117
120
  ctx,
118
121
  });
119
122
 
@@ -125,11 +128,12 @@ export const updateEntities = async (
125
128
  where: Record<string, unknown>,
126
129
  updateFields: Entity,
127
130
  ctx: MutationContext,
131
+ { args }: { args?: Record<string, unknown> } = {},
128
132
  ) =>
129
133
  withTransaction(ctx, async (ctx) => {
130
134
  const entities = await ctx.knex(modelName).where(where).select('id');
131
135
  for (const entity of entities) {
132
- await updateEntity(modelName, entity.id, updateFields, ctx);
136
+ await updateEntity(modelName, entity.id, updateFields, ctx, args);
133
137
  }
134
138
  });
135
139
 
@@ -138,7 +142,7 @@ export const updateEntity = async (
138
142
  id: string,
139
143
  input: Entity,
140
144
  ctx: MutationContext,
141
- trigger: Trigger = 'direct-call',
145
+ { args, trigger = 'direct-call' }: { args?: Record<string, unknown>; trigger?: Trigger } = {},
142
146
  ) =>
143
147
  withTransaction(ctx, async (ctx) => {
144
148
  const model = ctx.models.getModel(modelName, 'entity');
@@ -164,6 +168,7 @@ export const updateEntity = async (
164
168
  trigger,
165
169
  when: 'before',
166
170
  data: { prev: currentEntity, input, normalizedInput, next: { ...currentEntity, ...normalizedInput } },
171
+ args,
167
172
  ctx,
168
173
  });
169
174
  await doUpdate(model, currentEntity, normalizedInput, ctx);
@@ -173,6 +178,7 @@ export const updateEntity = async (
173
178
  trigger,
174
179
  when: 'after',
175
180
  data: { prev: currentEntity, input, normalizedInput, next: { ...currentEntity, ...normalizedInput } },
181
+ args,
176
182
  ctx,
177
183
  });
178
184
  }
@@ -180,12 +186,18 @@ export const updateEntity = async (
180
186
 
181
187
  type Callbacks = (() => Promise<void>)[];
182
188
 
183
- export const deleteEntities = async (modelName: string, where: Record<string, unknown>, ctx: MutationContext) =>
189
+ export const deleteEntities = async (
190
+ modelName: string,
191
+ where: Record<string, unknown>,
192
+ ctx: MutationContext,
193
+ args?: Record<string, unknown>,
194
+ ) =>
184
195
  withTransaction(ctx, async (ctx) => {
185
196
  const entities = await ctx.knex(modelName).where(where).select('id');
186
197
  for (const entity of entities) {
187
198
  await deleteEntity(modelName, entity.id, ctx, {
188
199
  trigger: 'direct-call',
200
+ args,
189
201
  });
190
202
  }
191
203
  });
@@ -200,6 +212,7 @@ export const deleteEntity = async (
200
212
  }: {
201
213
  dryRun?: boolean;
202
214
  trigger?: Trigger;
215
+ args?: Record<string, unknown>;
203
216
  } = {},
204
217
  ) =>
205
218
  withTransaction(ctx, async (ctx) => {
@@ -238,7 +251,12 @@ export const deleteEntity = async (
238
251
  const afterHooks: Callbacks = [];
239
252
 
240
253
  const mutationHook = ctx.mutationHook;
241
- const deleteCascade = async (currentModel: EntityModel, currentEntity: Entity, currentTrigger: Trigger) => {
254
+ const deleteCascade = async (
255
+ currentModel: EntityModel,
256
+ currentEntity: Entity,
257
+ currentTrigger: Trigger,
258
+ args?: Record<string, unknown>,
259
+ ) => {
242
260
  if (!(currentModel.name in toDelete)) {
243
261
  toDelete[currentModel.name] = {};
244
262
  }
@@ -263,6 +281,7 @@ export const deleteEntity = async (
263
281
  trigger: currentTrigger,
264
282
  when: 'before',
265
283
  data: { prev: currentEntity, input: {}, normalizedInput, next: { ...currentEntity, ...normalizedInput } },
284
+ args,
266
285
  ctx,
267
286
  });
268
287
  });
@@ -278,6 +297,7 @@ export const deleteEntity = async (
278
297
  trigger: currentTrigger,
279
298
  when: 'after',
280
299
  data: { prev: currentEntity, input: {}, normalizedInput, next: { ...currentEntity, ...normalizedInput } },
300
+ args,
281
301
  ctx,
282
302
  });
283
303
  });
@@ -322,6 +342,7 @@ export const deleteEntity = async (
322
342
  trigger: 'set-null',
323
343
  when: 'before',
324
344
  data: { prev: descendant, input: {}, normalizedInput, next: { ...descendant, ...normalizedInput } },
345
+ args,
325
346
  ctx,
326
347
  });
327
348
  });
@@ -337,6 +358,7 @@ export const deleteEntity = async (
337
358
  trigger: 'set-null',
338
359
  when: 'after',
339
360
  data: { prev: descendant, input: {}, normalizedInput, next: { ...descendant, ...normalizedInput } },
361
+ args,
340
362
  ctx,
341
363
  });
342
364
  });
@@ -407,7 +429,12 @@ export const deleteEntity = async (
407
429
  }
408
430
  });
409
431
 
410
- export const restoreEntity = async (modelName: string, id: string, ctx: MutationContext, trigger: Trigger = 'direct-call') =>
432
+ export const restoreEntity = async (
433
+ modelName: string,
434
+ id: string,
435
+ ctx: MutationContext,
436
+ { args, trigger = 'direct-call' }: { args?: Record<string, unknown>; trigger?: Trigger } = {},
437
+ ) =>
411
438
  withTransaction(ctx, async (ctx) => {
412
439
  const model = ctx.models.getModel(modelName, 'entity');
413
440
  const rootModel = model.rootModel;
@@ -465,6 +492,7 @@ export const restoreEntity = async (modelName: string, id: string, ctx: Mutation
465
492
  trigger: currentTrigger,
466
493
  when: 'before',
467
494
  data: { prev: currentEntity, input: {}, normalizedInput, next: { ...currentEntity, ...normalizedInput } },
495
+ args,
468
496
  ctx,
469
497
  });
470
498
  });
@@ -496,6 +524,7 @@ export const restoreEntity = async (modelName: string, id: string, ctx: Mutation
496
524
  trigger: currentTrigger,
497
525
  when: 'after',
498
526
  data: { prev: currentEntity, input: {}, normalizedInput, next: { ...currentEntity, ...normalizedInput } },
527
+ args,
499
528
  ctx,
500
529
  });
501
530
  });
@@ -249,6 +249,7 @@ export const generateDefinitions = ({
249
249
  type: `Create${model.name}`,
250
250
  nonNull: true,
251
251
  },
252
+ ...((model.creatable && model.creatable !== true && model.creatable.args) || []),
252
253
  ],
253
254
  });
254
255
  }
@@ -269,6 +270,7 @@ export const generateDefinitions = ({
269
270
  type: `Update${model.name}`,
270
271
  nonNull: true,
271
272
  },
273
+ ...((model.updatable && model.updatable !== true && model.updatable.args) || []),
272
274
  ],
273
275
  });
274
276
  }