@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/.github/workflows/docs.yml +1 -1
- package/.github/workflows/release.yml +1 -1
- package/CHANGELOG.md +1 -5
- package/dist/bin/gqm.cjs +24 -12
- package/dist/cjs/index.cjs +48 -24
- package/dist/esm/client/mutations.js +18 -2
- package/dist/esm/client/mutations.js.map +1 -1
- package/dist/esm/migrations/generate.js +2 -7
- package/dist/esm/migrations/generate.js.map +1 -1
- package/dist/esm/models/model-definitions.d.ts +2 -0
- package/dist/esm/models/models.d.ts +2 -0
- package/dist/esm/models/models.js.map +1 -1
- package/dist/esm/models/mutation-hook.d.ts +1 -0
- package/dist/esm/resolvers/mutations.d.ts +17 -5
- package/dist/esm/resolvers/mutations.js +22 -10
- package/dist/esm/resolvers/mutations.js.map +1 -1
- package/dist/esm/schema/generate.js +2 -0
- package/dist/esm/schema/generate.js.map +1 -1
- package/docker-compose.yml +1 -1
- package/docs/package-lock.json +3423 -2391
- package/package.json +1 -1
- package/src/client/mutations.ts +23 -2
- package/src/migrations/generate.ts +8 -15
- package/src/models/model-definitions.ts +14 -2
- package/src/models/models.ts +14 -2
- package/src/models/mutation-hook.ts +1 -0
- package/src/resolvers/mutations.ts +38 -9
- package/src/schema/generate.ts +2 -0
package/package.json
CHANGED
package/src/client/mutations.ts
CHANGED
|
@@ -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($
|
|
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($
|
|
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
|
-
|
|
1031
|
-
|
|
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(
|
|
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?:
|
|
149
|
-
|
|
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
|
| {
|
package/src/models/models.ts
CHANGED
|
@@ -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?:
|
|
348
|
-
|
|
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
|
|
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
|
|
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 (
|
|
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 (
|
|
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 (
|
|
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
|
});
|
package/src/schema/generate.ts
CHANGED
|
@@ -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
|
}
|