@smartive/graphql-magic 5.1.2 → 7.0.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.
- package/CHANGELOG.md +1 -6
- package/dist/cjs/index.cjs +149 -140
- package/dist/esm/client/index.d.ts +1 -0
- package/dist/esm/client/index.js +1 -0
- package/dist/esm/client/index.js.map +1 -1
- package/dist/esm/client/models.d.ts +1 -0
- package/dist/esm/client/models.js +2 -0
- package/dist/esm/client/models.js.map +1 -0
- package/dist/esm/client/queries.d.ts +2 -2
- package/dist/esm/client/queries.js +3 -3
- package/dist/esm/client/queries.js.map +1 -1
- package/dist/esm/context.d.ts +5 -1
- package/dist/esm/db/generate.js +17 -19
- package/dist/esm/db/generate.js.map +1 -1
- package/dist/esm/migrations/generate.js +69 -57
- package/dist/esm/migrations/generate.js.map +1 -1
- package/dist/esm/models/index.d.ts +1 -0
- package/dist/esm/models/index.js +1 -0
- package/dist/esm/models/index.js.map +1 -1
- package/dist/esm/models/models.d.ts +65 -59
- package/dist/esm/models/mutation-hook.d.ts +17 -0
- package/dist/esm/models/mutation-hook.js +2 -0
- package/dist/esm/models/mutation-hook.js.map +1 -0
- package/dist/esm/models/utils.d.ts +398 -22
- package/dist/esm/models/utils.js +22 -20
- package/dist/esm/models/utils.js.map +1 -1
- package/dist/esm/permissions/check.js +2 -2
- package/dist/esm/permissions/check.js.map +1 -1
- package/dist/esm/resolvers/filters.js +1 -1
- package/dist/esm/resolvers/mutations.js +4 -4
- package/dist/esm/resolvers/mutations.js.map +1 -1
- package/dist/esm/resolvers/node.js +2 -2
- package/dist/esm/resolvers/node.js.map +1 -1
- package/dist/esm/resolvers/resolver.js +1 -1
- package/dist/esm/schema/generate.js +27 -37
- package/dist/esm/schema/generate.js.map +1 -1
- package/dist/esm/schema/utils.d.ts +1 -1
- package/dist/esm/schema/utils.js +2 -2
- package/dist/esm/schema/utils.js.map +1 -1
- package/package.json +5 -5
- package/src/client/index.ts +1 -0
- package/src/client/models.ts +1 -0
- package/src/client/queries.ts +5 -5
- package/src/context.ts +4 -1
- package/src/db/generate.ts +25 -27
- package/src/migrations/generate.ts +69 -57
- package/src/models/index.ts +1 -0
- package/src/models/models.ts +88 -97
- package/src/models/mutation-hook.ts +17 -0
- package/src/models/utils.ts +27 -21
- package/src/permissions/check.ts +2 -2
- package/src/resolvers/filters.ts +1 -1
- package/src/resolvers/mutations.ts +9 -8
- package/src/resolvers/node.ts +2 -2
- package/src/resolvers/resolver.ts +1 -1
- package/src/schema/generate.ts +31 -48
- package/src/schema/utils.ts +3 -3
- package/tests/unit/__snapshots__/generate.spec.ts.snap +2 -2
- package/tests/unit/resolve.spec.ts +1 -0
- package/tests/utils/models.ts +12 -12
- package/tests/utils/server.ts +1 -0
|
@@ -3,8 +3,9 @@ import { DateTime } from 'luxon';
|
|
|
3
3
|
import { v4 as uuid } from 'uuid';
|
|
4
4
|
import { Context, FullContext } from '../context';
|
|
5
5
|
import { ForbiddenError, GraphQLError } from '../errors';
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
6
|
+
import { Model, ModelField } from '../models/models';
|
|
7
|
+
import { Entity, FullEntity } from '../models/mutation-hook';
|
|
8
|
+
import { get, isEnumList, isPrimitive, it, summonByName, typeToField } from '../models/utils';
|
|
8
9
|
import { applyPermissions, checkCanWrite, getEntityToMutate } from '../permissions/check';
|
|
9
10
|
import { resolve } from './resolver';
|
|
10
11
|
import { AliasGenerator } from './utils';
|
|
@@ -106,7 +107,7 @@ const del = async (model: Model, { where, dryRun }: { where: any; dryRun: boolea
|
|
|
106
107
|
const mutations: Callbacks = [];
|
|
107
108
|
const afterHooks: Callbacks = [];
|
|
108
109
|
|
|
109
|
-
const deleteCascade = async (currentModel: Model, entity:
|
|
110
|
+
const deleteCascade = async (currentModel: Model, entity: FullEntity) => {
|
|
110
111
|
if (entity.deleted) {
|
|
111
112
|
return;
|
|
112
113
|
}
|
|
@@ -220,7 +221,7 @@ const restore = async (model: Model, { where }: { where: any }, ctx: FullContext
|
|
|
220
221
|
const mutations: Callbacks = [];
|
|
221
222
|
const afterHooks: Callbacks = [];
|
|
222
223
|
|
|
223
|
-
const restoreCascade = async (currentModel: Model, relatedEntity:
|
|
224
|
+
const restoreCascade = async (currentModel: Model, relatedEntity: FullEntity) => {
|
|
224
225
|
if (!relatedEntity.deleted || !relatedEntity.deletedAt || !relatedEntity.deletedAt.equals(entity.deletedAt)) {
|
|
225
226
|
return;
|
|
226
227
|
}
|
|
@@ -265,7 +266,7 @@ const restore = async (model: Model, { where }: { where: any }, ctx: FullContext
|
|
|
265
266
|
|
|
266
267
|
const createRevision = async (model: Model, data: Entity, ctx: Context) => {
|
|
267
268
|
if (model.updatable) {
|
|
268
|
-
const revisionData = {
|
|
269
|
+
const revisionData: Entity = {
|
|
269
270
|
id: uuid(),
|
|
270
271
|
[`${typeToField(model.name)}Id`]: data.id,
|
|
271
272
|
createdAt: ctx.now,
|
|
@@ -276,10 +277,10 @@ const createRevision = async (model: Model, data: Entity, ctx: Context) => {
|
|
|
276
277
|
revisionData.deleted = data.deleted || false;
|
|
277
278
|
}
|
|
278
279
|
|
|
279
|
-
for (const { type, name, nonNull, ...field } of model.fields.filter(({ updatable }) => updatable)) {
|
|
280
|
+
for (const { kind: type, name, nonNull, ...field } of model.fields.filter(({ updatable }) => updatable)) {
|
|
280
281
|
const col = type === 'relation' ? `${name}Id` : name;
|
|
281
282
|
if (nonNull && (!(col in data) || col === undefined || col === null)) {
|
|
282
|
-
revisionData[col] = get(field, '
|
|
283
|
+
revisionData[col] = get(field, 'defaultValue');
|
|
283
284
|
} else {
|
|
284
285
|
revisionData[col] = data[col];
|
|
285
286
|
}
|
|
@@ -314,4 +315,4 @@ const sanitize = (ctx: FullContext, model: Model, data: Entity) => {
|
|
|
314
315
|
};
|
|
315
316
|
|
|
316
317
|
const isEndOfDay = (field?: ModelField) =>
|
|
317
|
-
field.type === 'DateTime' && field?.endOfDay === true && field?.dateTimeType === 'date'
|
|
318
|
+
isPrimitive(field) && field.type === 'DateTime' && field?.endOfDay === true && field?.dateTimeType === 'date';
|
package/src/resolvers/node.ts
CHANGED
|
@@ -113,7 +113,7 @@ export const getSimpleFields = (node: ResolverNode) => {
|
|
|
113
113
|
return true;
|
|
114
114
|
}
|
|
115
115
|
|
|
116
|
-
return node.model.fields.some(({ type, name }) => type === 'json' && name === selection.name.value);
|
|
116
|
+
return node.model.fields.some(({ kind: type, name }) => type === 'json' && name === selection.name.value);
|
|
117
117
|
});
|
|
118
118
|
};
|
|
119
119
|
|
|
@@ -165,7 +165,7 @@ export const getJoins = (node: ResolverNode, toMany: boolean) => {
|
|
|
165
165
|
foreignKey = reverseRelation.foreignKey;
|
|
166
166
|
} else {
|
|
167
167
|
const modelField = baseModel.fieldsByName[fieldName];
|
|
168
|
-
if (modelField?.
|
|
168
|
+
if (modelField?.kind !== 'relation') {
|
|
169
169
|
continue;
|
|
170
170
|
}
|
|
171
171
|
foreignKey = modelField.foreignKey;
|
|
@@ -115,7 +115,7 @@ const applySelects = (node: ResolverNode, query: Knex.QueryBuilder, joins: Joins
|
|
|
115
115
|
.filter((n) => {
|
|
116
116
|
const field = node.model.fields.find(({ name }) => name === n.name.value);
|
|
117
117
|
|
|
118
|
-
if (!field || field.
|
|
118
|
+
if (!field || field.kind === 'relation' || field.kind === 'raw') {
|
|
119
119
|
return false;
|
|
120
120
|
}
|
|
121
121
|
|
package/src/schema/generate.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { DefinitionNode, DocumentNode, GraphQLSchema, buildASTSchema, print } from 'graphql';
|
|
2
2
|
import flatMap from 'lodash/flatMap';
|
|
3
3
|
import { RawModels } from '../models/models';
|
|
4
4
|
import {
|
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
isScalarModel,
|
|
13
13
|
typeToField,
|
|
14
14
|
} from '../models/utils';
|
|
15
|
-
import { document, enm,
|
|
15
|
+
import { Field, document, enm, input, object, scalar } from './utils';
|
|
16
16
|
|
|
17
17
|
export const generateDefinitions = (rawModels: RawModels): DefinitionNode[] => {
|
|
18
18
|
const models = getModels(rawModels);
|
|
@@ -30,17 +30,13 @@ export const generateDefinitions = (rawModels: RawModels): DefinitionNode[] => {
|
|
|
30
30
|
...rawModels
|
|
31
31
|
.filter(isRawObjectModel)
|
|
32
32
|
.filter((model) =>
|
|
33
|
-
models.some(
|
|
34
|
-
(m) => m.creatable && m.fields.some((f) => f.creatable && f.type === 'json' && f.typeName === model.name)
|
|
35
|
-
)
|
|
33
|
+
models.some((m) => m.creatable && m.fields.some((f) => f.creatable && f.kind === 'json' && f.type === model.name))
|
|
36
34
|
)
|
|
37
35
|
.map((model) => input(`Create${model.name}`, model.fields)),
|
|
38
36
|
...rawModels
|
|
39
37
|
.filter(isRawObjectModel)
|
|
40
38
|
.filter((model) =>
|
|
41
|
-
models.some(
|
|
42
|
-
(m) => m.creatable && m.fields.some((f) => f.creatable && f.type === 'json' && f.typeName === model.name)
|
|
43
|
-
)
|
|
39
|
+
models.some((m) => m.creatable && m.fields.some((f) => f.creatable && f.kind === 'json' && f.type === model.name))
|
|
44
40
|
)
|
|
45
41
|
.map((model) => input(`Update${model.name}`, model.fields)),
|
|
46
42
|
|
|
@@ -52,10 +48,7 @@ export const generateDefinitions = (rawModels: RawModels): DefinitionNode[] => {
|
|
|
52
48
|
[
|
|
53
49
|
...model.fields.filter(isQueriableField).map((field) => ({
|
|
54
50
|
...field,
|
|
55
|
-
type:
|
|
56
|
-
field.type === 'relation' || field.type === 'enum' || field.type === 'raw' || field.type === 'json'
|
|
57
|
-
? field.typeName
|
|
58
|
-
: field.type,
|
|
51
|
+
type: field.type,
|
|
59
52
|
args: [...(field.args || [])],
|
|
60
53
|
directives: field.directives,
|
|
61
54
|
})),
|
|
@@ -79,33 +72,33 @@ export const generateDefinitions = (rawModels: RawModels): DefinitionNode[] => {
|
|
|
79
72
|
),
|
|
80
73
|
input(`${model.name}Where`, [
|
|
81
74
|
...model.fields
|
|
82
|
-
.filter(({
|
|
83
|
-
.map((
|
|
84
|
-
name,
|
|
85
|
-
type,
|
|
75
|
+
.filter(({ kind, unique, filterable }) => (unique || filterable) && kind !== 'relation')
|
|
76
|
+
.map((field) => ({
|
|
77
|
+
name: field.name,
|
|
78
|
+
type: field.type,
|
|
86
79
|
list: true,
|
|
87
|
-
default: typeof filterable === 'object' ? filterable.default : undefined,
|
|
80
|
+
default: typeof field.filterable === 'object' ? field.filterable.default : undefined,
|
|
88
81
|
})),
|
|
89
82
|
...flatMap(
|
|
90
83
|
model.fields.filter(({ comparable }) => comparable),
|
|
91
|
-
(
|
|
92
|
-
{ name: `${name}_GT`, type },
|
|
93
|
-
{ name: `${name}_GTE`, type },
|
|
94
|
-
{ name: `${name}_LT`, type },
|
|
95
|
-
{ name: `${name}_LTE`, type },
|
|
84
|
+
(field) => [
|
|
85
|
+
{ name: `${field.name}_GT`, type: field.type },
|
|
86
|
+
{ name: `${field.name}_GTE`, type: field.type },
|
|
87
|
+
{ name: `${field.name}_LT`, type: field.type },
|
|
88
|
+
{ name: `${field.name}_LTE`, type: field.type },
|
|
96
89
|
]
|
|
97
90
|
),
|
|
98
91
|
...model.fields
|
|
99
92
|
.filter(isRelation)
|
|
100
93
|
.filter(({ filterable }) => filterable)
|
|
101
|
-
.map(({ name,
|
|
94
|
+
.map(({ name, type }) => ({
|
|
102
95
|
name,
|
|
103
|
-
type: `${
|
|
96
|
+
type: `${type}Where`,
|
|
104
97
|
})),
|
|
105
98
|
]),
|
|
106
99
|
input(
|
|
107
100
|
`${model.name}WhereUnique`,
|
|
108
|
-
model.fields.filter(({ unique }) => unique).map((
|
|
101
|
+
model.fields.filter(({ unique }) => unique).map((field) => ({ name: field.name, type: field.type }))
|
|
109
102
|
),
|
|
110
103
|
...(model.fields.some(({ orderable }) => orderable)
|
|
111
104
|
? [
|
|
@@ -123,19 +116,14 @@ export const generateDefinitions = (rawModels: RawModels): DefinitionNode[] => {
|
|
|
123
116
|
`Create${model.name}`,
|
|
124
117
|
model.fields
|
|
125
118
|
.filter(({ creatable }) => creatable)
|
|
126
|
-
.map((
|
|
127
|
-
field.
|
|
128
|
-
? { name: `${name}Id`, type: 'ID', nonNull }
|
|
119
|
+
.map((field) =>
|
|
120
|
+
field.kind === 'relation'
|
|
121
|
+
? { name: `${field.name}Id`, type: 'ID', nonNull: field.nonNull }
|
|
129
122
|
: {
|
|
130
|
-
name,
|
|
131
|
-
type:
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
: field.type === 'json'
|
|
135
|
-
? `Create${field.typeName}`
|
|
136
|
-
: field.type,
|
|
137
|
-
list,
|
|
138
|
-
nonNull: nonNull && defaultValue === undefined,
|
|
123
|
+
name: field.name,
|
|
124
|
+
type: field.kind === 'json' ? `Create${field.type}` : field.type,
|
|
125
|
+
list: field.list,
|
|
126
|
+
nonNull: field.nonNull && field.defaultValue === undefined,
|
|
139
127
|
}
|
|
140
128
|
)
|
|
141
129
|
)
|
|
@@ -148,18 +136,13 @@ export const generateDefinitions = (rawModels: RawModels): DefinitionNode[] => {
|
|
|
148
136
|
`Update${model.name}`,
|
|
149
137
|
model.fields
|
|
150
138
|
.filter(({ updatable }) => updatable)
|
|
151
|
-
.map((
|
|
152
|
-
field.
|
|
153
|
-
? { name: `${name}Id`, type: 'ID' }
|
|
139
|
+
.map((field) =>
|
|
140
|
+
field.kind === 'relation'
|
|
141
|
+
? { name: `${field.name}Id`, type: 'ID' }
|
|
154
142
|
: {
|
|
155
|
-
name,
|
|
156
|
-
type:
|
|
157
|
-
|
|
158
|
-
? field.typeName
|
|
159
|
-
: field.type === 'json'
|
|
160
|
-
? `Update${field.typeName}`
|
|
161
|
-
: field.type,
|
|
162
|
-
list,
|
|
143
|
+
name: field.name,
|
|
144
|
+
type: field.kind === 'json' ? `Update${field.type}` : field.type,
|
|
145
|
+
list: field.list,
|
|
163
146
|
}
|
|
164
147
|
)
|
|
165
148
|
)
|
package/src/schema/utils.ts
CHANGED
|
@@ -30,7 +30,7 @@ export type Field = {
|
|
|
30
30
|
description?: string;
|
|
31
31
|
list?: boolean;
|
|
32
32
|
nonNull?: boolean;
|
|
33
|
-
|
|
33
|
+
defaultValue?: Value;
|
|
34
34
|
args?: Field[];
|
|
35
35
|
directives?: Directive[];
|
|
36
36
|
};
|
|
@@ -90,7 +90,7 @@ export const inputValues = (fields: Field[]): InputValueDefinitionNode[] =>
|
|
|
90
90
|
kind: 'InputValueDefinition',
|
|
91
91
|
name: name(field.name),
|
|
92
92
|
type: fieldType(field),
|
|
93
|
-
defaultValue: field.
|
|
93
|
+
defaultValue: field.defaultValue === undefined ? undefined : value(field.defaultValue),
|
|
94
94
|
directives: directives(field.directives),
|
|
95
95
|
})
|
|
96
96
|
);
|
|
@@ -105,7 +105,7 @@ export const fields = (fields: Field[]): FieldDefinitionNode[] =>
|
|
|
105
105
|
kind: 'InputValueDefinition',
|
|
106
106
|
name: name(arg.name),
|
|
107
107
|
type: fieldType(arg),
|
|
108
|
-
defaultValue: arg.
|
|
108
|
+
defaultValue: arg.defaultValue === undefined ? undefined : value(arg.defaultValue),
|
|
109
109
|
})),
|
|
110
110
|
directives: directives(field.directives),
|
|
111
111
|
})
|
|
@@ -19,7 +19,7 @@ input AnotherObjectOrderBy {
|
|
|
19
19
|
|
|
20
20
|
input AnotherObjectWhere {
|
|
21
21
|
id: [ID!]
|
|
22
|
-
deleted: [Boolean!]
|
|
22
|
+
deleted: [Boolean!]
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
input AnotherObjectWhereUnique {
|
|
@@ -88,7 +88,7 @@ input SomeObjectOrderBy {
|
|
|
88
88
|
|
|
89
89
|
input SomeObjectWhere {
|
|
90
90
|
id: [ID!]
|
|
91
|
-
deleted: [Boolean!]
|
|
91
|
+
deleted: [Boolean!]
|
|
92
92
|
another: AnotherObjectWhere
|
|
93
93
|
}
|
|
94
94
|
|
|
@@ -23,6 +23,7 @@ const test = async (operationName: string, query: string, variables: object, res
|
|
|
23
23
|
|
|
24
24
|
const user = await knexInstance('User').where({ id: 1 }).first();
|
|
25
25
|
const result = await execute({
|
|
26
|
+
req: null as any,
|
|
26
27
|
knex: knexInstance,
|
|
27
28
|
locale: 'en',
|
|
28
29
|
locales: ['en'],
|
package/tests/utils/models.ts
CHANGED
|
@@ -5,23 +5,23 @@ import { generatePermissions, PermissionsConfig } from '../../src/permissions/ge
|
|
|
5
5
|
export const rawModels: RawModels = [
|
|
6
6
|
{
|
|
7
7
|
name: 'SomeEnum',
|
|
8
|
-
|
|
8
|
+
kind: 'enum',
|
|
9
9
|
values: ['A', 'B', 'C'],
|
|
10
10
|
},
|
|
11
11
|
{
|
|
12
12
|
name: 'Role',
|
|
13
|
-
|
|
13
|
+
kind: 'enum',
|
|
14
14
|
values: ['ADMIN', 'USER'],
|
|
15
15
|
},
|
|
16
16
|
|
|
17
17
|
{
|
|
18
18
|
name: 'SomeRawObject',
|
|
19
|
-
|
|
19
|
+
kind: 'raw',
|
|
20
20
|
fields: [{ name: 'field', type: 'String' }],
|
|
21
21
|
},
|
|
22
22
|
|
|
23
23
|
{
|
|
24
|
-
|
|
24
|
+
kind: 'object',
|
|
25
25
|
name: 'User',
|
|
26
26
|
fields: [
|
|
27
27
|
{
|
|
@@ -30,13 +30,13 @@ export const rawModels: RawModels = [
|
|
|
30
30
|
},
|
|
31
31
|
{
|
|
32
32
|
name: 'role',
|
|
33
|
-
|
|
34
|
-
|
|
33
|
+
kind: 'enum',
|
|
34
|
+
type: 'Role',
|
|
35
35
|
},
|
|
36
36
|
],
|
|
37
37
|
},
|
|
38
38
|
{
|
|
39
|
-
|
|
39
|
+
kind: 'object',
|
|
40
40
|
name: 'AnotherObject',
|
|
41
41
|
listQueriable: true,
|
|
42
42
|
deletable: true,
|
|
@@ -48,8 +48,8 @@ export const rawModels: RawModels = [
|
|
|
48
48
|
orderable: true,
|
|
49
49
|
},
|
|
50
50
|
{
|
|
51
|
-
|
|
52
|
-
|
|
51
|
+
kind: 'relation',
|
|
52
|
+
type: 'AnotherObject',
|
|
53
53
|
name: 'myself',
|
|
54
54
|
toOne: true,
|
|
55
55
|
reverse: 'self',
|
|
@@ -57,7 +57,7 @@ export const rawModels: RawModels = [
|
|
|
57
57
|
],
|
|
58
58
|
},
|
|
59
59
|
{
|
|
60
|
-
|
|
60
|
+
kind: 'object',
|
|
61
61
|
name: 'SomeObject',
|
|
62
62
|
plural: 'ManyObjects',
|
|
63
63
|
description: 'An object',
|
|
@@ -74,8 +74,8 @@ export const rawModels: RawModels = [
|
|
|
74
74
|
},
|
|
75
75
|
{
|
|
76
76
|
name: 'another',
|
|
77
|
-
|
|
78
|
-
|
|
77
|
+
kind: 'relation',
|
|
78
|
+
type: 'AnotherObject',
|
|
79
79
|
filterable: true,
|
|
80
80
|
updatable: true,
|
|
81
81
|
nonNull: true,
|