@smartive/graphql-magic 9.1.2 → 10.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/.eslintrc +2 -10
- package/.github/workflows/release.yml +1 -1
- package/.gqmrc.json +6 -0
- package/CHANGELOG.md +2 -2
- package/README.md +1 -1
- package/dist/bin/gqm.cjs +684 -330
- package/dist/cjs/index.cjs +998 -554
- package/dist/esm/api/execute.js +1 -1
- package/dist/esm/api/execute.js.map +1 -1
- package/dist/esm/client/mutations.d.ts +2 -2
- package/dist/esm/client/mutations.js +5 -4
- package/dist/esm/client/mutations.js.map +1 -1
- package/dist/esm/client/queries.d.ts +12 -17
- package/dist/esm/client/queries.js +30 -50
- package/dist/esm/client/queries.js.map +1 -1
- package/dist/esm/context.d.ts +1 -2
- package/dist/esm/db/generate.d.ts +3 -3
- package/dist/esm/db/generate.js +31 -29
- package/dist/esm/db/generate.js.map +1 -1
- package/dist/esm/migrations/generate.d.ts +3 -4
- package/dist/esm/migrations/generate.js +114 -107
- 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/model-definitions.d.ts +189 -0
- package/dist/esm/models/model-definitions.js +2 -0
- package/dist/esm/models/model-definitions.js.map +1 -0
- package/dist/esm/models/models.d.ts +128 -174
- package/dist/esm/models/models.js +411 -1
- package/dist/esm/models/models.js.map +1 -1
- package/dist/esm/models/mutation-hook.d.ts +2 -2
- package/dist/esm/models/utils.d.ts +35 -497
- package/dist/esm/models/utils.js +21 -144
- package/dist/esm/models/utils.js.map +1 -1
- package/dist/esm/permissions/check.d.ts +3 -3
- package/dist/esm/permissions/check.js +14 -7
- package/dist/esm/permissions/check.js.map +1 -1
- package/dist/esm/permissions/generate.js +6 -6
- package/dist/esm/permissions/generate.js.map +1 -1
- package/dist/esm/resolvers/filters.d.ts +8 -0
- package/dist/esm/resolvers/filters.js +28 -25
- package/dist/esm/resolvers/filters.js.map +1 -1
- package/dist/esm/resolvers/index.d.ts +1 -0
- package/dist/esm/resolvers/index.js +1 -0
- package/dist/esm/resolvers/index.js.map +1 -1
- package/dist/esm/resolvers/mutations.js +85 -21
- package/dist/esm/resolvers/mutations.js.map +1 -1
- package/dist/esm/resolvers/node.d.ts +13 -15
- package/dist/esm/resolvers/node.js +41 -36
- package/dist/esm/resolvers/node.js.map +1 -1
- package/dist/esm/resolvers/resolver.js +19 -49
- package/dist/esm/resolvers/resolver.js.map +1 -1
- package/dist/esm/resolvers/resolvers.d.ts +1 -8
- package/dist/esm/resolvers/resolvers.js +15 -7
- package/dist/esm/resolvers/resolvers.js.map +1 -1
- package/dist/esm/resolvers/selects.d.ts +3 -0
- package/dist/esm/resolvers/selects.js +50 -0
- package/dist/esm/resolvers/selects.js.map +1 -0
- package/dist/esm/resolvers/utils.d.ts +12 -4
- package/dist/esm/resolvers/utils.js +30 -22
- package/dist/esm/resolvers/utils.js.map +1 -1
- package/dist/esm/schema/generate.d.ts +4 -4
- package/dist/esm/schema/generate.js +122 -131
- 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 -1
- package/dist/esm/schema/utils.js.map +1 -1
- package/knexfile.ts +31 -0
- package/migrations/20230912185644_setup.ts +127 -0
- package/package.json +16 -14
- package/src/api/execute.ts +1 -1
- package/src/bin/gqm/gqm.ts +25 -23
- package/src/bin/gqm/parse-models.ts +5 -5
- package/src/bin/gqm/settings.ts +13 -4
- package/src/bin/gqm/static-eval.ts +5 -0
- package/src/bin/gqm/templates.ts +23 -3
- package/src/client/mutations.ts +11 -5
- package/src/client/queries.ts +43 -80
- package/src/context.ts +1 -2
- package/src/db/generate.ts +41 -41
- package/src/migrations/generate.ts +165 -146
- package/src/models/index.ts +1 -0
- package/src/models/model-definitions.ts +168 -0
- package/src/models/models.ts +510 -166
- package/src/models/mutation-hook.ts +2 -2
- package/src/models/utils.ts +53 -187
- package/src/permissions/check.ts +19 -11
- package/src/permissions/generate.ts +6 -6
- package/src/resolvers/filters.ts +44 -28
- package/src/resolvers/index.ts +1 -0
- package/src/resolvers/mutations.ts +98 -36
- package/src/resolvers/node.ts +79 -51
- package/src/resolvers/resolver.ts +20 -74
- package/src/resolvers/resolvers.ts +18 -7
- package/src/resolvers/selects.ts +77 -0
- package/src/resolvers/utils.ts +41 -25
- package/src/schema/generate.ts +106 -127
- package/src/schema/utils.ts +2 -1
- package/tests/api/__snapshots__/inheritance.spec.ts.snap +83 -0
- package/tests/api/inheritance.spec.ts +130 -0
- package/tests/generated/api/index.ts +1174 -0
- package/tests/generated/client/index.ts +1163 -0
- package/tests/generated/client/mutations.ts +109 -0
- package/tests/generated/db/index.ts +291 -0
- package/tests/generated/db/knex.ts +14 -0
- package/tests/generated/models.json +675 -0
- package/tests/generated/schema.graphql +325 -0
- package/tests/unit/__snapshots__/resolve.spec.ts.snap +23 -0
- package/tests/unit/queries.spec.ts +5 -5
- package/tests/unit/resolve.spec.ts +8 -8
- package/tests/utils/database/knex.ts +5 -13
- package/tests/utils/database/seed.ts +57 -18
- package/tests/utils/models.ts +62 -7
- package/tests/utils/server.ts +5 -5
- package/tsconfig.eslint.json +1 -0
- package/tests/unit/__snapshots__/generate.spec.ts.snap +0 -128
- package/tests/unit/generate.spec.ts +0 -8
- package/tests/utils/database/schema.ts +0 -64
- package/tests/utils/generate-migration.ts +0 -24
package/dist/bin/gqm.cjs
CHANGED
|
@@ -36,9 +36,9 @@ var import_lodash = require("lodash");
|
|
|
36
36
|
// src/client/mutations.ts
|
|
37
37
|
var import_upperCase = __toESM(require("lodash/upperCase"), 1);
|
|
38
38
|
var constantCase = (str) => (0, import_upperCase.default)(str).replace(/ /g, "_");
|
|
39
|
-
var generateMutations = (models) => {
|
|
39
|
+
var generateMutations = (models, gqmModule = "@smartive/graphql-magic") => {
|
|
40
40
|
const parts = [];
|
|
41
|
-
for (const { name: name2, creatable, updatable, deletable } of models.filter(
|
|
41
|
+
for (const { name: name2, creatable, updatable, deletable } of models.entities.filter(not(isRootModel))) {
|
|
42
42
|
if (creatable) {
|
|
43
43
|
parts.push(
|
|
44
44
|
`export const CREATE_${constantCase(
|
|
@@ -69,11 +69,20 @@ var generateMutations = (models) => {
|
|
|
69
69
|
mutation Delete${name2}Mutation($id: ID!) {
|
|
70
70
|
delete${name2}(where: { id: $id })
|
|
71
71
|
}
|
|
72
|
+
\`;`
|
|
73
|
+
);
|
|
74
|
+
parts.push(
|
|
75
|
+
`export const RESTORE_${constantCase(
|
|
76
|
+
name2
|
|
77
|
+
)} = gql\`
|
|
78
|
+
mutation Restore${name2}Mutation($id: ID!) {
|
|
79
|
+
restore${name2}(where: { id: $id })
|
|
80
|
+
}
|
|
72
81
|
\`;`
|
|
73
82
|
);
|
|
74
83
|
}
|
|
75
84
|
}
|
|
76
|
-
return `import { gql } from "
|
|
85
|
+
return `import { gql } from "${gqmModule}";
|
|
77
86
|
|
|
78
87
|
${parts.join("\n\n")}`;
|
|
79
88
|
};
|
|
@@ -82,77 +91,104 @@ ${parts.join("\n\n")}`;
|
|
|
82
91
|
var import_upperFirst = __toESM(require("lodash/upperFirst"), 1);
|
|
83
92
|
|
|
84
93
|
// src/models/utils.ts
|
|
85
|
-
var
|
|
86
|
-
var import_camelCase = __toESM(require("lodash/camelCase"), 1);
|
|
94
|
+
var import_lodash3 = require("lodash");
|
|
87
95
|
var import_get = __toESM(require("lodash/get"), 1);
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
var
|
|
91
|
-
var
|
|
92
|
-
var
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
96
|
+
|
|
97
|
+
// src/models/models.ts
|
|
98
|
+
var import_inflection = require("inflection");
|
|
99
|
+
var import_lodash2 = require("lodash");
|
|
100
|
+
var Models = class {
|
|
101
|
+
models;
|
|
102
|
+
modelsByName = {};
|
|
103
|
+
scalars;
|
|
104
|
+
rawEnums;
|
|
105
|
+
enums;
|
|
106
|
+
inputs;
|
|
107
|
+
interfaces;
|
|
108
|
+
objects;
|
|
109
|
+
entities;
|
|
110
|
+
definitions;
|
|
111
|
+
constructor(definitions) {
|
|
112
|
+
this.definitions = (0, import_lodash2.cloneDeep)(definitions);
|
|
113
|
+
this.definitions.push(
|
|
114
|
+
{
|
|
115
|
+
kind: "scalar",
|
|
116
|
+
name: "DateTime"
|
|
117
|
+
},
|
|
118
|
+
{ kind: "scalar", name: "Upload" },
|
|
119
|
+
{
|
|
120
|
+
kind: "raw-enum",
|
|
121
|
+
name: "Order",
|
|
122
|
+
values: ["ASC", "DESC"]
|
|
123
|
+
}
|
|
124
|
+
);
|
|
125
|
+
const entities = this.definitions.filter(isEntityModelDefinition);
|
|
126
|
+
for (const entity of entities) {
|
|
127
|
+
if (entity.root) {
|
|
128
|
+
this.definitions.push({
|
|
129
|
+
kind: "enum",
|
|
130
|
+
name: `${entity.name}Type`,
|
|
131
|
+
values: entities.filter((subModel) => subModel.parent === entity.name).map((subModel) => subModel.name)
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
entity.fields = [
|
|
135
|
+
{
|
|
136
|
+
name: "id",
|
|
137
|
+
type: "ID",
|
|
138
|
+
nonNull: true,
|
|
139
|
+
unique: true,
|
|
140
|
+
primary: true,
|
|
141
|
+
generated: true
|
|
142
|
+
},
|
|
143
|
+
...entity.root ? [
|
|
144
|
+
{
|
|
145
|
+
name: "type",
|
|
146
|
+
kind: "enum",
|
|
147
|
+
type: `${entity.name}Type`,
|
|
148
|
+
nonNull: true,
|
|
149
|
+
generated: true
|
|
150
|
+
}
|
|
151
|
+
] : [],
|
|
152
|
+
...entity.fields,
|
|
153
|
+
...entity.creatable ? [
|
|
118
154
|
{
|
|
119
155
|
name: "createdAt",
|
|
120
156
|
type: "DateTime",
|
|
121
157
|
nonNull: true,
|
|
122
158
|
orderable: true,
|
|
123
159
|
generated: true,
|
|
124
|
-
...typeof
|
|
160
|
+
...typeof entity.creatable === "object" && entity.creatable.createdAt
|
|
125
161
|
},
|
|
126
162
|
{
|
|
127
163
|
name: "createdBy",
|
|
128
164
|
kind: "relation",
|
|
129
165
|
type: "User",
|
|
130
166
|
nonNull: true,
|
|
131
|
-
reverse: `created${getModelPlural(
|
|
167
|
+
reverse: `created${getModelPlural(entity)}`,
|
|
132
168
|
generated: true,
|
|
133
|
-
...typeof
|
|
169
|
+
...typeof entity.creatable === "object" && entity.creatable.createdBy
|
|
134
170
|
}
|
|
135
171
|
] : [],
|
|
136
|
-
...
|
|
172
|
+
...entity.updatable ? [
|
|
137
173
|
{
|
|
138
174
|
name: "updatedAt",
|
|
139
175
|
type: "DateTime",
|
|
140
176
|
nonNull: true,
|
|
141
177
|
orderable: true,
|
|
142
178
|
generated: true,
|
|
143
|
-
...typeof
|
|
179
|
+
...typeof entity.updatable === "object" && entity.updatable.updatedAt
|
|
144
180
|
},
|
|
145
181
|
{
|
|
146
182
|
name: "updatedBy",
|
|
147
183
|
kind: "relation",
|
|
148
184
|
type: "User",
|
|
149
185
|
nonNull: true,
|
|
150
|
-
reverse: `updated${getModelPlural(
|
|
186
|
+
reverse: `updated${getModelPlural(entity)}`,
|
|
151
187
|
generated: true,
|
|
152
|
-
...typeof
|
|
188
|
+
...typeof entity.updatable === "object" && entity.updatable.updatedBy
|
|
153
189
|
}
|
|
154
190
|
] : [],
|
|
155
|
-
...
|
|
191
|
+
...entity.deletable ? [
|
|
156
192
|
{
|
|
157
193
|
name: "deleted",
|
|
158
194
|
type: "Boolean",
|
|
@@ -160,65 +196,326 @@ var getModels = (rawModels) => {
|
|
|
160
196
|
defaultValue: false,
|
|
161
197
|
filterable: { default: false },
|
|
162
198
|
generated: true,
|
|
163
|
-
...typeof
|
|
199
|
+
...typeof entity.deletable === "object" && entity.deletable.deleted
|
|
164
200
|
},
|
|
165
201
|
{
|
|
166
202
|
name: "deletedAt",
|
|
167
203
|
type: "DateTime",
|
|
168
204
|
orderable: true,
|
|
169
205
|
generated: true,
|
|
170
|
-
...typeof
|
|
206
|
+
...typeof entity.deletable === "object" && entity.deletable.deletedAt
|
|
171
207
|
},
|
|
172
208
|
{
|
|
173
209
|
name: "deletedBy",
|
|
174
210
|
kind: "relation",
|
|
175
211
|
type: "User",
|
|
176
|
-
reverse: `deleted${getModelPlural(
|
|
212
|
+
reverse: `deleted${getModelPlural(entity)}`,
|
|
177
213
|
generated: true,
|
|
178
|
-
...typeof
|
|
214
|
+
...typeof entity.deletable === "object" && entity.deletable.deletedBy
|
|
179
215
|
}
|
|
180
216
|
] : []
|
|
181
|
-
]
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
foreignKey
|
|
217
|
+
];
|
|
218
|
+
for (const field of entity.fields) {
|
|
219
|
+
if (field.kind === "relation") {
|
|
220
|
+
field.foreignKey = field.foreignKey || `${field.name}Id`;
|
|
185
221
|
}
|
|
186
|
-
}
|
|
187
|
-
};
|
|
188
|
-
for (const field of objectModel.fields) {
|
|
189
|
-
objectModel.fieldsByName[field.name] = field;
|
|
222
|
+
}
|
|
190
223
|
}
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
224
|
+
for (const model of entities) {
|
|
225
|
+
if (model.parent) {
|
|
226
|
+
const parent = summonByName(entities, model.parent);
|
|
227
|
+
const INHERITED_FIELDS = ["queriable", "listQueriable", "creatable", "updatable", "deletable"];
|
|
228
|
+
Object.assign(model, (0, import_lodash2.pick)(parent, INHERITED_FIELDS), (0, import_lodash2.pick)(model, INHERITED_FIELDS));
|
|
229
|
+
model.fields = [
|
|
230
|
+
...parent.fields.map((field) => ({
|
|
231
|
+
...field,
|
|
232
|
+
...field.kind === "relation" && field.reverse && { reverse: field.reverse.replace(getModelPlural(parent), getModelPlural(model)) },
|
|
233
|
+
...model.fields.find((childField) => childField.name === field.name),
|
|
234
|
+
inherited: true
|
|
235
|
+
})),
|
|
236
|
+
...model.fields.filter((field) => !parent.fields.some((parentField) => parentField.name === field.name))
|
|
237
|
+
];
|
|
197
238
|
}
|
|
198
|
-
const fieldModel = summonByName(models, field.type);
|
|
199
|
-
const reverseRelation = {
|
|
200
|
-
kind: "relation",
|
|
201
|
-
name: field.reverse || (field.toOne ? typeToField(model.name) : getModelPluralField(model)),
|
|
202
|
-
foreignKey: get(field, "foreignKey"),
|
|
203
|
-
type: model.name,
|
|
204
|
-
toOne: !!field.toOne,
|
|
205
|
-
fieldModel,
|
|
206
|
-
field,
|
|
207
|
-
model
|
|
208
|
-
};
|
|
209
|
-
const relation = {
|
|
210
|
-
field,
|
|
211
|
-
model: fieldModel,
|
|
212
|
-
reverseRelation
|
|
213
|
-
};
|
|
214
|
-
model.relations.push(relation);
|
|
215
|
-
model.relationsByName[relation.field.name] = relation;
|
|
216
|
-
fieldModel.reverseRelations.push(reverseRelation);
|
|
217
|
-
fieldModel.reverseRelationsByName[reverseRelation.name] = reverseRelation;
|
|
218
239
|
}
|
|
240
|
+
this.models = this.definitions.map(
|
|
241
|
+
(definition) => new MODEL_KIND_TO_CLASS_MAPPING[definition.kind](this, definition)
|
|
242
|
+
);
|
|
243
|
+
for (const model of this.models) {
|
|
244
|
+
this.modelsByName[model.name] = model;
|
|
245
|
+
}
|
|
246
|
+
this.entities = this.models.filter((model) => model instanceof EntityModel);
|
|
247
|
+
this.enums = this.models.filter((model) => model instanceof EnumModel);
|
|
248
|
+
this.inputs = this.models.filter((model) => model instanceof InputModel);
|
|
249
|
+
this.interfaces = this.models.filter((model) => model instanceof InterfaceModel);
|
|
250
|
+
this.objects = this.models.filter((model) => model instanceof ObjectModel);
|
|
251
|
+
this.rawEnums = this.models.filter((model) => model instanceof RawEnumModel);
|
|
252
|
+
this.scalars = this.models.filter((model) => model instanceof ScalarModel);
|
|
253
|
+
}
|
|
254
|
+
getModel(name2, kind) {
|
|
255
|
+
const model = get(this.modelsByName, name2);
|
|
256
|
+
if (!kind) {
|
|
257
|
+
return model;
|
|
258
|
+
}
|
|
259
|
+
const expectedType = MODEL_KIND_TO_CLASS_MAPPING[kind];
|
|
260
|
+
if (!(model instanceof expectedType)) {
|
|
261
|
+
throw new Error(`Model ${name2} is not of kind ${kind}.`);
|
|
262
|
+
}
|
|
263
|
+
return model;
|
|
264
|
+
}
|
|
265
|
+
};
|
|
266
|
+
var Model = class {
|
|
267
|
+
constructor(models, definition) {
|
|
268
|
+
this.models = models;
|
|
269
|
+
Object.assign(this, definition);
|
|
270
|
+
this.plural = definition.plural || (0, import_inflection.pluralize)(definition.name);
|
|
271
|
+
}
|
|
272
|
+
name;
|
|
273
|
+
plural;
|
|
274
|
+
description;
|
|
275
|
+
};
|
|
276
|
+
var ScalarModel = class extends Model {
|
|
277
|
+
kind;
|
|
278
|
+
};
|
|
279
|
+
var EnumModel = class extends Model {
|
|
280
|
+
kind;
|
|
281
|
+
values;
|
|
282
|
+
deleted;
|
|
283
|
+
constructor(models, definition) {
|
|
284
|
+
super(models, definition);
|
|
285
|
+
Object.assign(this, (0, import_lodash2.omit)(definition, "name", "plural", "description"));
|
|
286
|
+
}
|
|
287
|
+
};
|
|
288
|
+
var RawEnumModel = class extends Model {
|
|
289
|
+
kind;
|
|
290
|
+
values;
|
|
291
|
+
constructor(models, definition) {
|
|
292
|
+
super(models, definition);
|
|
293
|
+
Object.assign(this, (0, import_lodash2.omit)(definition, "name", "plural", "description"));
|
|
294
|
+
}
|
|
295
|
+
};
|
|
296
|
+
var InterfaceModel = class extends Model {
|
|
297
|
+
kind;
|
|
298
|
+
fields;
|
|
299
|
+
constructor(models, definition) {
|
|
300
|
+
super(models, definition);
|
|
301
|
+
Object.assign(this, (0, import_lodash2.omit)(definition, "name", "plural", "description"));
|
|
219
302
|
}
|
|
220
|
-
return models;
|
|
221
303
|
};
|
|
304
|
+
var InputModel = class extends Model {
|
|
305
|
+
kind;
|
|
306
|
+
fields;
|
|
307
|
+
constructor(models, definition) {
|
|
308
|
+
super(models, definition);
|
|
309
|
+
Object.assign(this, (0, import_lodash2.omit)(definition, "name", "plural", "description"));
|
|
310
|
+
}
|
|
311
|
+
};
|
|
312
|
+
var ObjectModel = class extends Model {
|
|
313
|
+
kind;
|
|
314
|
+
fields;
|
|
315
|
+
constructor(models, definition) {
|
|
316
|
+
super(models, definition);
|
|
317
|
+
Object.assign(this, (0, import_lodash2.omit)(definition, "name", "plural", "description"));
|
|
318
|
+
}
|
|
319
|
+
};
|
|
320
|
+
var EntityModel = class extends Model {
|
|
321
|
+
kind;
|
|
322
|
+
root;
|
|
323
|
+
parent;
|
|
324
|
+
interfaces;
|
|
325
|
+
queriable;
|
|
326
|
+
listQueriable;
|
|
327
|
+
creatable;
|
|
328
|
+
updatable;
|
|
329
|
+
deletable;
|
|
330
|
+
displayField;
|
|
331
|
+
defaultOrderBy;
|
|
332
|
+
fields;
|
|
333
|
+
// temporary fields for the generation of migrations
|
|
334
|
+
deleted;
|
|
335
|
+
oldName;
|
|
336
|
+
fieldsByName = {};
|
|
337
|
+
fieldsByColumnName = {};
|
|
338
|
+
_relations;
|
|
339
|
+
_relationsByName;
|
|
340
|
+
_reverseRelations;
|
|
341
|
+
_reverseRelationsByName;
|
|
342
|
+
_manyToManyRelations;
|
|
343
|
+
_manyToManyRelationsByName;
|
|
344
|
+
pluralField;
|
|
345
|
+
slug;
|
|
346
|
+
labelPlural;
|
|
347
|
+
label;
|
|
348
|
+
_parentModel;
|
|
349
|
+
constructor(models, definition) {
|
|
350
|
+
super(models, definition);
|
|
351
|
+
Object.assign(this, (0, import_lodash2.omit)(definition, "name", "plural", "description"));
|
|
352
|
+
this.pluralField = typeToField(this.plural);
|
|
353
|
+
this.slug = (0, import_lodash2.kebabCase)(this.plural);
|
|
354
|
+
this.labelPlural = getLabel(this.plural);
|
|
355
|
+
this.label = getLabel(definition.name);
|
|
356
|
+
for (const field of definition.fields) {
|
|
357
|
+
this.fieldsByName[field.name] = field;
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
getField(name2) {
|
|
361
|
+
return get(this.fieldsByName, name2);
|
|
362
|
+
}
|
|
363
|
+
get relations() {
|
|
364
|
+
if (!this._relations) {
|
|
365
|
+
this._relations = this.fields.filter(isRelation).map((relationField) => new NormalRelation(this, relationField, this.models.getModel(relationField.type, "entity")));
|
|
366
|
+
}
|
|
367
|
+
return this._relations;
|
|
368
|
+
}
|
|
369
|
+
get relationsByName() {
|
|
370
|
+
if (!this._relationsByName) {
|
|
371
|
+
this._relationsByName = {};
|
|
372
|
+
for (const relation of this.relations) {
|
|
373
|
+
this._relationsByName[relation.name] = relation;
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
return this._relationsByName;
|
|
377
|
+
}
|
|
378
|
+
getRelation(name2) {
|
|
379
|
+
return get(this.relationsByName, name2);
|
|
380
|
+
}
|
|
381
|
+
get reverseRelations() {
|
|
382
|
+
if (!this._reverseRelations) {
|
|
383
|
+
this._reverseRelations = this.models.entities.flatMap(
|
|
384
|
+
(model) => model.relations.filter((relation) => relation.targetModel.name === this.name || relation.targetModel.name === this.rootModel.name).map((relation) => relation.reverse)
|
|
385
|
+
);
|
|
386
|
+
}
|
|
387
|
+
return this._reverseRelations;
|
|
388
|
+
}
|
|
389
|
+
get reverseRelationsByName() {
|
|
390
|
+
if (!this._reverseRelationsByName) {
|
|
391
|
+
this._reverseRelationsByName = {};
|
|
392
|
+
for (const reverseRelation of this.reverseRelations) {
|
|
393
|
+
this._reverseRelationsByName[reverseRelation.name] = reverseRelation;
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
return this._reverseRelationsByName;
|
|
397
|
+
}
|
|
398
|
+
getReverseRelation(name2) {
|
|
399
|
+
return get(this.reverseRelationsByName, name2);
|
|
400
|
+
}
|
|
401
|
+
get manyToManyRelations() {
|
|
402
|
+
if (!this._manyToManyRelations) {
|
|
403
|
+
this._manyToManyRelations = [];
|
|
404
|
+
for (const relationFromSource of this.reverseRelations) {
|
|
405
|
+
const relationToTarget = relationFromSource.targetModel.relations.find(
|
|
406
|
+
(relation) => !relation.field.generated && relation.field.name !== relationFromSource.field.name
|
|
407
|
+
);
|
|
408
|
+
if (!relationToTarget) {
|
|
409
|
+
continue;
|
|
410
|
+
}
|
|
411
|
+
const inapplicableFields = relationFromSource.targetModel.fields.filter(
|
|
412
|
+
(otherField) => !otherField.generated && ![relationFromSource.field.name, relationToTarget.field.name].includes(otherField.name)
|
|
413
|
+
);
|
|
414
|
+
if (inapplicableFields.length) {
|
|
415
|
+
continue;
|
|
416
|
+
}
|
|
417
|
+
this._manyToManyRelations.push(new ManyToManyRelation(relationFromSource, relationToTarget));
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
return this._manyToManyRelations;
|
|
421
|
+
}
|
|
422
|
+
get manyToManyRelationsByName() {
|
|
423
|
+
if (!this._manyToManyRelationsByName) {
|
|
424
|
+
this._manyToManyRelationsByName = {};
|
|
425
|
+
for (const manyToManyRelation of this.manyToManyRelations) {
|
|
426
|
+
this._manyToManyRelationsByName[manyToManyRelation.name] = manyToManyRelation;
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
return this._manyToManyRelationsByName;
|
|
430
|
+
}
|
|
431
|
+
getManyToManyRelation(name2) {
|
|
432
|
+
return get(this.manyToManyRelationsByName, name2);
|
|
433
|
+
}
|
|
434
|
+
get parentModel() {
|
|
435
|
+
if (this.parent) {
|
|
436
|
+
if (!this._parentModel) {
|
|
437
|
+
this._parentModel = this.models.getModel(this.parent, "entity");
|
|
438
|
+
}
|
|
439
|
+
return this._parentModel;
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
get rootModel() {
|
|
443
|
+
return this.parentModel || this;
|
|
444
|
+
}
|
|
445
|
+
};
|
|
446
|
+
var MODEL_KIND_TO_CLASS_MAPPING = {
|
|
447
|
+
entity: EntityModel,
|
|
448
|
+
enum: EnumModel,
|
|
449
|
+
input: InputModel,
|
|
450
|
+
interface: InterfaceModel,
|
|
451
|
+
object: ObjectModel,
|
|
452
|
+
"raw-enum": RawEnumModel,
|
|
453
|
+
scalar: ScalarModel
|
|
454
|
+
};
|
|
455
|
+
var Relation = class {
|
|
456
|
+
constructor(name2, sourceModel, field, targetModel) {
|
|
457
|
+
this.name = name2;
|
|
458
|
+
this.sourceModel = sourceModel;
|
|
459
|
+
this.field = field;
|
|
460
|
+
this.targetModel = targetModel;
|
|
461
|
+
}
|
|
462
|
+
};
|
|
463
|
+
var NormalRelation = class extends Relation {
|
|
464
|
+
constructor(sourceModel, field, targetModel) {
|
|
465
|
+
super(field.name, sourceModel, field, targetModel);
|
|
466
|
+
this.field = field;
|
|
467
|
+
this.reverse = new ReverseRelation(this);
|
|
468
|
+
}
|
|
469
|
+
reverse;
|
|
470
|
+
};
|
|
471
|
+
var ReverseRelation = class extends Relation {
|
|
472
|
+
constructor(reverse) {
|
|
473
|
+
super(
|
|
474
|
+
reverse.field.reverse || (reverse.field.toOne ? typeToField(reverse.sourceModel.name) : reverse.sourceModel.pluralField),
|
|
475
|
+
reverse.targetModel,
|
|
476
|
+
reverse.field,
|
|
477
|
+
reverse.sourceModel
|
|
478
|
+
);
|
|
479
|
+
this.reverse = reverse;
|
|
480
|
+
}
|
|
481
|
+
};
|
|
482
|
+
var ManyToManyRelation = class {
|
|
483
|
+
name;
|
|
484
|
+
sourceModel;
|
|
485
|
+
relationFromSource;
|
|
486
|
+
relationModel;
|
|
487
|
+
relationToTarget;
|
|
488
|
+
targetModel;
|
|
489
|
+
constructor(relationFromSource, relationToTarget) {
|
|
490
|
+
this.name = relationFromSource.name;
|
|
491
|
+
this.sourceModel = relationFromSource.sourceModel;
|
|
492
|
+
this.relationFromSource = relationFromSource;
|
|
493
|
+
this.relationModel = relationFromSource.targetModel;
|
|
494
|
+
if (this.relationModel !== relationToTarget.sourceModel) {
|
|
495
|
+
throw new Error(`Relation model is ambiguous.`);
|
|
496
|
+
}
|
|
497
|
+
this.relationToTarget = relationToTarget;
|
|
498
|
+
this.targetModel = relationToTarget.targetModel;
|
|
499
|
+
}
|
|
500
|
+
};
|
|
501
|
+
var isEntityModelDefinition = (definition) => definition.kind === "entity";
|
|
502
|
+
var getModelPlural = (model) => model.plural || (0, import_inflection.pluralize)(model.name);
|
|
503
|
+
|
|
504
|
+
// src/models/utils.ts
|
|
505
|
+
var typeToField = (type) => type.substr(0, 1).toLowerCase() + type.substr(1);
|
|
506
|
+
var getLabel = (s) => (0, import_lodash3.startCase)((0, import_lodash3.camelCase)(s));
|
|
507
|
+
var and = (...predicates) => (field) => predicates.every((predicate) => predicate(field));
|
|
508
|
+
var not = (predicate) => (field) => !predicate(field);
|
|
509
|
+
var isRootModel = (model) => model.root;
|
|
510
|
+
var isUpdatableModel = (model) => model.updatable && model.fields.some(isUpdatableField);
|
|
511
|
+
var isUpdatableField = (field) => !field.inherited && !!field.updatable;
|
|
512
|
+
var modelNeedsTable = (model) => model.fields.some((field) => !field.inherited);
|
|
513
|
+
var isRelation = (field) => field.kind === "relation";
|
|
514
|
+
var isInherited = (field) => field.inherited;
|
|
515
|
+
var isInTable = (field) => field.name === "id" || !field.inherited;
|
|
516
|
+
var isQueriableField = ({ queriable }) => queriable !== false;
|
|
517
|
+
var isCustomField = (field) => field.kind === "custom";
|
|
518
|
+
var isSimpleField = and(not(isRelation), not(isCustomField));
|
|
222
519
|
var summonByName = (array, value2) => summonByKey(array, "name", value2);
|
|
223
520
|
var summonByKey = (array, key, value2) => summon(array, (element) => (0, import_get.default)(element, key) === value2, `No element found with ${key} ${value2}`);
|
|
224
521
|
var summon = (array, cb, errorMessage) => {
|
|
@@ -243,8 +540,9 @@ var it = (object2) => {
|
|
|
243
540
|
var get = (object2, key) => {
|
|
244
541
|
const value2 = it(object2)[key];
|
|
245
542
|
if (value2 === void 0 || value2 === null) {
|
|
246
|
-
|
|
247
|
-
|
|
543
|
+
const error = new Error(`Object doesn't have ${String(key)}`);
|
|
544
|
+
console.warn(error);
|
|
545
|
+
throw error;
|
|
248
546
|
}
|
|
249
547
|
return value2;
|
|
250
548
|
};
|
|
@@ -261,56 +559,59 @@ var PRIMITIVE_TYPES = {
|
|
|
261
559
|
DateTime: "DateTime | string"
|
|
262
560
|
};
|
|
263
561
|
var OPTIONAL_SEED_FIELDS = ["createdAt", "createdById", "updatedAt", "updatedById", "deletedAt", "deletedById"];
|
|
264
|
-
var generateDBModels = (
|
|
562
|
+
var generateDBModels = (models) => {
|
|
265
563
|
const writer = new import_code_block_writer.default["default"]({
|
|
266
564
|
useSingleQuote: true,
|
|
267
565
|
indentNumberOfSpaces: 2
|
|
268
566
|
});
|
|
269
567
|
writer.write(`import { DateTime } from 'luxon';`).blankLine();
|
|
270
|
-
for (const enm2 of
|
|
568
|
+
for (const enm2 of models.enums) {
|
|
271
569
|
writer.write(`export type ${enm2.name} = ${enm2.values.map((v) => `'${v}'`).join(" | ")};`).blankLine();
|
|
272
570
|
}
|
|
273
|
-
const
|
|
274
|
-
|
|
275
|
-
const fields2 = model.fields.some((field) => field.kind === "relation" && field.foreignKey === "id") ? model.fields.filter((field) => field.name !== "id") : model.fields;
|
|
571
|
+
for (const model of models.entities) {
|
|
572
|
+
const fields2 = model.relations.some((relation) => relation.field.foreignKey === "id") ? model.fields.filter((field) => field.name !== "id") : model.fields;
|
|
276
573
|
writer.write(`export type ${model.name} = `).inlineBlock(() => {
|
|
277
574
|
for (const field of fields2.filter(not(isCustomField))) {
|
|
278
|
-
writer.write(`'${
|
|
575
|
+
writer.write(`'${getColumnName(field)}': ${getFieldType(field)}${field.nonNull ? "" : " | null"};`).newLine();
|
|
279
576
|
}
|
|
280
577
|
}).blankLine();
|
|
281
578
|
writer.write(`export type ${model.name}Initializer = `).inlineBlock(() => {
|
|
282
|
-
for (const field of fields2.filter(not(isCustomField))) {
|
|
579
|
+
for (const field of fields2.filter(not(isCustomField)).filter(isInTable)) {
|
|
283
580
|
writer.write(
|
|
284
|
-
`'${
|
|
581
|
+
`'${getColumnName(field)}'${field.nonNull && field.defaultValue === void 0 ? "" : "?"}: ${getFieldType(
|
|
285
582
|
field
|
|
286
|
-
)}${field.list ? " | string" : ""}${field.nonNull ? "" : " | null"}
|
|
583
|
+
)}${field.list ? " | string" : ""}${field.nonNull ? "" : " | null"};`
|
|
287
584
|
).newLine();
|
|
288
585
|
}
|
|
289
586
|
}).blankLine();
|
|
290
587
|
writer.write(`export type ${model.name}Mutator = `).inlineBlock(() => {
|
|
291
|
-
for (const field of fields2.filter(not(isCustomField))) {
|
|
588
|
+
for (const field of fields2.filter(not(isCustomField)).filter(isInTable)) {
|
|
292
589
|
writer.write(
|
|
293
|
-
`'${
|
|
294
|
-
).newLine();
|
|
295
|
-
}
|
|
296
|
-
}).blankLine();
|
|
297
|
-
writer.write(`export type ${model.name}Seed = `).inlineBlock(() => {
|
|
298
|
-
for (const field of fields2.filter(not(isCustomField))) {
|
|
299
|
-
const fieldName = getFieldName(field);
|
|
300
|
-
writer.write(
|
|
301
|
-
`'${getFieldName(field)}'${field.nonNull && field.defaultValue === void 0 && !OPTIONAL_SEED_FIELDS.includes(fieldName) ? "" : "?"}: ${field.kind === "enum" ? field.list ? "string[]" : "string" : getFieldType(field)}${field.list ? " | string" : ""}${field.nonNull ? "" : " | null"},`
|
|
590
|
+
`'${getColumnName(field)}'?: ${getFieldType(field)}${field.list ? " | string" : ""}${field.nonNull ? "" : " | null"};`
|
|
302
591
|
).newLine();
|
|
303
592
|
}
|
|
304
593
|
}).blankLine();
|
|
594
|
+
if (!isRootModel(model)) {
|
|
595
|
+
writer.write(`export type ${model.name}Seed = `).inlineBlock(() => {
|
|
596
|
+
for (const field of fields2.filter(not(isCustomField))) {
|
|
597
|
+
if (model.parent && field.name === "type") {
|
|
598
|
+
continue;
|
|
599
|
+
}
|
|
600
|
+
const fieldName = getColumnName(field);
|
|
601
|
+
writer.write(
|
|
602
|
+
`'${getColumnName(field)}'${field.nonNull && field.defaultValue === void 0 && !OPTIONAL_SEED_FIELDS.includes(fieldName) ? "" : "?"}: ${field.kind === "enum" ? field.list ? "string[]" : "string" : getFieldType(field)}${field.list ? " | string" : ""}${field.nonNull ? "" : " | null"};`
|
|
603
|
+
).newLine();
|
|
604
|
+
}
|
|
605
|
+
}).blankLine();
|
|
606
|
+
}
|
|
305
607
|
}
|
|
306
608
|
writer.write(`export type SeedData = `).inlineBlock(() => {
|
|
307
|
-
for (const model of models) {
|
|
308
|
-
writer.write(`${model.name}: ${model.name}Seed[]
|
|
609
|
+
for (const model of models.entities.filter(not(isRootModel))) {
|
|
610
|
+
writer.write(`${model.name}: ${model.name}Seed[];`).newLine();
|
|
309
611
|
}
|
|
310
612
|
});
|
|
311
613
|
return writer.toString();
|
|
312
614
|
};
|
|
313
|
-
var getFieldName = (field) => field.kind === "relation" ? field.foreignKey || `${field.name}Id` : field.name;
|
|
314
615
|
var getFieldType = (field) => {
|
|
315
616
|
const kind = field.kind;
|
|
316
617
|
switch (kind) {
|
|
@@ -331,19 +632,18 @@ var getFieldType = (field) => {
|
|
|
331
632
|
}
|
|
332
633
|
}
|
|
333
634
|
};
|
|
334
|
-
var generateKnexTables = (
|
|
635
|
+
var generateKnexTables = (models) => {
|
|
335
636
|
const writer = new import_code_block_writer.default["default"]({
|
|
336
637
|
useSingleQuote: true,
|
|
337
638
|
indentNumberOfSpaces: 2
|
|
338
639
|
});
|
|
339
|
-
const models = getModels(rawModels);
|
|
340
640
|
writer.write(`import { Knex } from 'knex';`).newLine();
|
|
341
641
|
writer.write(
|
|
342
|
-
`import { ${models.map((model) => `${model.name}, ${model.name}Initializer, ${model.name}Mutator`).join(", ")} } from '.';`
|
|
642
|
+
`import { ${models.entities.map((model) => `${model.name}, ${model.name}Initializer, ${model.name}Mutator`).join(", ")} } from '.';`
|
|
343
643
|
).blankLine();
|
|
344
644
|
writer.write(`declare module 'knex/types/tables' `).inlineBlock(() => {
|
|
345
645
|
writer.write(`interface Tables `).inlineBlock(() => {
|
|
346
|
-
for (const model of models) {
|
|
646
|
+
for (const model of models.entities) {
|
|
347
647
|
writer.write(`'${model.name}': Knex.CompositeTableType<${model.name}, ${model.name}Initializer, ${model.name}Mutator>,`).newLine();
|
|
348
648
|
}
|
|
349
649
|
});
|
|
@@ -356,10 +656,9 @@ var import_code_block_writer2 = __toESM(require("code-block-writer"), 1);
|
|
|
356
656
|
var import_knex_schema_inspector = require("knex-schema-inspector");
|
|
357
657
|
var import_lowerFirst = __toESM(require("lodash/lowerFirst"), 1);
|
|
358
658
|
var MigrationGenerator = class {
|
|
359
|
-
constructor(knex2,
|
|
360
|
-
this.
|
|
659
|
+
constructor(knex2, models) {
|
|
660
|
+
this.models = models;
|
|
361
661
|
this.schema = (0, import_knex_schema_inspector.SchemaInspector)(knex2);
|
|
362
|
-
this.models = getModels(rawModels);
|
|
363
662
|
}
|
|
364
663
|
writer = new import_code_block_writer2.default["default"]({
|
|
365
664
|
useSingleQuote: true,
|
|
@@ -369,9 +668,8 @@ var MigrationGenerator = class {
|
|
|
369
668
|
columns = {};
|
|
370
669
|
uuidUsed;
|
|
371
670
|
nowUsed;
|
|
372
|
-
models;
|
|
373
671
|
async generate() {
|
|
374
|
-
const { writer, schema,
|
|
672
|
+
const { writer, schema, models } = this;
|
|
375
673
|
const enums = (await schema.knex("pg_type").where({ typtype: "e" }).select("typname")).map(({ typname }) => typname);
|
|
376
674
|
const tables = await schema.tables();
|
|
377
675
|
for (const table of tables) {
|
|
@@ -380,11 +678,11 @@ var MigrationGenerator = class {
|
|
|
380
678
|
const up = [];
|
|
381
679
|
const down = [];
|
|
382
680
|
this.createEnums(
|
|
383
|
-
|
|
681
|
+
this.models.enums.filter((enm2) => !enums.includes((0, import_lowerFirst.default)(enm2.name))),
|
|
384
682
|
up,
|
|
385
683
|
down
|
|
386
684
|
);
|
|
387
|
-
for (const model of models) {
|
|
685
|
+
for (const model of models.entities) {
|
|
388
686
|
if (model.deleted) {
|
|
389
687
|
up.push(() => {
|
|
390
688
|
this.dropTable(model.name);
|
|
@@ -396,7 +694,7 @@ var MigrationGenerator = class {
|
|
|
396
694
|
}
|
|
397
695
|
});
|
|
398
696
|
});
|
|
399
|
-
if (model
|
|
697
|
+
if (isUpdatableModel(model)) {
|
|
400
698
|
up.push(() => {
|
|
401
699
|
this.dropTable(`${model.name}Revision`);
|
|
402
700
|
});
|
|
@@ -415,7 +713,7 @@ var MigrationGenerator = class {
|
|
|
415
713
|
tables[tables.indexOf(model.oldName)] = model.name;
|
|
416
714
|
this.columns[model.name] = this.columns[model.oldName];
|
|
417
715
|
delete this.columns[model.oldName];
|
|
418
|
-
if (model
|
|
716
|
+
if (isUpdatableModel(model)) {
|
|
419
717
|
up.push(() => {
|
|
420
718
|
this.renameTable(`${model.oldName}Revision`, `${model.name}Revision`);
|
|
421
719
|
this.alterTable(`${model.name}Revision`, () => {
|
|
@@ -433,92 +731,102 @@ var MigrationGenerator = class {
|
|
|
433
731
|
delete this.columns[`${model.oldName}Revision`];
|
|
434
732
|
}
|
|
435
733
|
}
|
|
436
|
-
if (
|
|
437
|
-
|
|
438
|
-
this.createTable(model.name, () => {
|
|
439
|
-
for (const field of model.fields) {
|
|
440
|
-
this.column(field);
|
|
441
|
-
}
|
|
442
|
-
});
|
|
443
|
-
});
|
|
444
|
-
down.push(() => {
|
|
445
|
-
this.dropTable(model.name);
|
|
446
|
-
});
|
|
447
|
-
} else {
|
|
448
|
-
this.renameFields(
|
|
449
|
-
model,
|
|
450
|
-
model.fields.filter(({ oldName }) => oldName),
|
|
451
|
-
up,
|
|
452
|
-
down
|
|
453
|
-
);
|
|
454
|
-
this.createFields(
|
|
455
|
-
model,
|
|
456
|
-
model.fields.filter(
|
|
457
|
-
({ name: name2, ...field }) => field.kind !== "custom" && !this.columns[model.name].some(
|
|
458
|
-
(col) => col.name === (field.kind === "relation" ? field.foreignKey || `${name2}Id` : name2)
|
|
459
|
-
)
|
|
460
|
-
),
|
|
461
|
-
up,
|
|
462
|
-
down
|
|
463
|
-
);
|
|
464
|
-
const existingFields = model.fields.filter(({ name: name2, kind, nonNull: nonNull2 }) => {
|
|
465
|
-
const col = this.columns[model.name].find((col2) => col2.name === (kind === "relation" ? `${name2}Id` : name2));
|
|
466
|
-
if (!col) {
|
|
467
|
-
return false;
|
|
468
|
-
}
|
|
469
|
-
return !nonNull2 && !col.is_nullable;
|
|
470
|
-
});
|
|
471
|
-
this.updateFields(model, existingFields, up, down);
|
|
472
|
-
}
|
|
473
|
-
if (model.updatable) {
|
|
474
|
-
if (!tables.includes(`${model.name}Revision`)) {
|
|
734
|
+
if (modelNeedsTable(model)) {
|
|
735
|
+
if (!tables.includes(model.name)) {
|
|
475
736
|
up.push(() => {
|
|
476
|
-
this.
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
writer.write(`await knex.batchInsert('${model.name}Revision', data.map((row) => (`).inlineBlock(() => {
|
|
484
|
-
writer.writeLine(`id: uuid(),`);
|
|
485
|
-
writer.writeLine(`${typeToField(model.name)}Id: row.id,`);
|
|
486
|
-
this.nowUsed = true;
|
|
487
|
-
writer.writeLine(`createdAt: row.updatedAt || row.createdAt || now,`);
|
|
488
|
-
writer.writeLine(`createdById: row.updatedById || row.createdById,`);
|
|
489
|
-
if (model.deletable) {
|
|
490
|
-
writer.writeLine(`deleted: row.deleted,`);
|
|
491
|
-
}
|
|
492
|
-
for (const { name: name2, kind } of model.fields.filter(({ updatable }) => updatable)) {
|
|
493
|
-
const col = kind === "relation" ? `${name2}Id` : name2;
|
|
494
|
-
writer.writeLine(`${col}: row.${col},`);
|
|
495
|
-
}
|
|
496
|
-
}).write(")));").newLine();
|
|
737
|
+
this.createTable(model.name, () => {
|
|
738
|
+
if (model.parent) {
|
|
739
|
+
this.column({
|
|
740
|
+
...model.fieldsByName.id,
|
|
741
|
+
kind: "relation",
|
|
742
|
+
type: model.parent,
|
|
743
|
+
foreignKey: "id"
|
|
497
744
|
});
|
|
498
|
-
}
|
|
745
|
+
}
|
|
746
|
+
for (const field of model.fields.filter(not(isInherited))) {
|
|
747
|
+
this.column(field);
|
|
748
|
+
}
|
|
499
749
|
});
|
|
500
|
-
}
|
|
750
|
+
});
|
|
501
751
|
down.push(() => {
|
|
502
|
-
this.dropTable(
|
|
752
|
+
this.dropTable(model.name);
|
|
503
753
|
});
|
|
504
754
|
} else {
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
({
|
|
508
|
-
|
|
509
|
-
|
|
755
|
+
this.renameFields(
|
|
756
|
+
model,
|
|
757
|
+
model.fields.filter(not(isInherited)).filter(({ oldName }) => oldName),
|
|
758
|
+
up,
|
|
759
|
+
down
|
|
510
760
|
);
|
|
511
|
-
this.
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
(
|
|
515
|
-
|
|
761
|
+
this.createFields(
|
|
762
|
+
model,
|
|
763
|
+
model.fields.filter(not(isInherited)).filter(
|
|
764
|
+
({ name: name2, ...field }) => field.kind !== "custom" && !this.columns[model.name].some(
|
|
765
|
+
(col) => col.name === (field.kind === "relation" ? field.foreignKey || `${name2}Id` : name2)
|
|
766
|
+
)
|
|
767
|
+
),
|
|
768
|
+
up,
|
|
769
|
+
down
|
|
516
770
|
);
|
|
517
|
-
|
|
771
|
+
const existingFields = model.fields.filter(({ name: name2, kind, nonNull: nonNull2 }) => {
|
|
772
|
+
const col = this.columns[model.name].find((col2) => col2.name === (kind === "relation" ? `${name2}Id` : name2));
|
|
773
|
+
if (!col) {
|
|
774
|
+
return false;
|
|
775
|
+
}
|
|
776
|
+
return !nonNull2 && !col.is_nullable;
|
|
777
|
+
});
|
|
778
|
+
this.updateFields(model, existingFields, up, down);
|
|
779
|
+
}
|
|
780
|
+
if (isUpdatableModel(model)) {
|
|
781
|
+
if (!tables.includes(`${model.name}Revision`)) {
|
|
782
|
+
up.push(() => {
|
|
783
|
+
this.createRevisionTable(model);
|
|
784
|
+
});
|
|
785
|
+
if (tables.includes(model.name)) {
|
|
786
|
+
up.push(() => {
|
|
787
|
+
writer.block(() => {
|
|
788
|
+
writer.writeLine(`const data = await knex('${model.name}');`);
|
|
789
|
+
writer.write(`if (data.length)`).block(() => {
|
|
790
|
+
writer.write(`await knex.batchInsert('${model.name}Revision', data.map((row) => (`).inlineBlock(() => {
|
|
791
|
+
writer.writeLine(`id: uuid(),`);
|
|
792
|
+
writer.writeLine(`${typeToField(model.name)}Id: row.id,`);
|
|
793
|
+
this.nowUsed = true;
|
|
794
|
+
writer.writeLine(`createdAt: row.updatedAt || row.createdAt || now,`);
|
|
795
|
+
writer.writeLine(`createdById: row.updatedById || row.createdById,`);
|
|
796
|
+
if (model.deletable) {
|
|
797
|
+
writer.writeLine(`deleted: row.deleted,`);
|
|
798
|
+
}
|
|
799
|
+
for (const { name: name2, kind } of model.fields.filter(isUpdatableField)) {
|
|
800
|
+
const col = kind === "relation" ? `${name2}Id` : name2;
|
|
801
|
+
writer.writeLine(`${col}: row.${col},`);
|
|
802
|
+
}
|
|
803
|
+
}).write(")));").newLine();
|
|
804
|
+
});
|
|
805
|
+
}).blankLine();
|
|
806
|
+
});
|
|
807
|
+
}
|
|
808
|
+
down.push(() => {
|
|
809
|
+
this.dropTable(`${model.name}Revision`);
|
|
810
|
+
});
|
|
811
|
+
} else {
|
|
812
|
+
const revisionTable = `${model.name}Revision`;
|
|
813
|
+
const missingRevisionFields = model.fields.filter(isUpdatableField).filter(
|
|
814
|
+
({ name: name2, ...field }) => field.kind !== "custom" && !this.columns[revisionTable].some(
|
|
815
|
+
(col) => col.name === (field.kind === "relation" ? field.foreignKey || `${name2}Id` : name2)
|
|
816
|
+
)
|
|
817
|
+
);
|
|
818
|
+
this.createRevisionFields(model, missingRevisionFields, up, down);
|
|
819
|
+
const revisionFieldsToRemove = model.fields.filter(
|
|
820
|
+
({ name: name2, updatable, generated, ...field }) => !generated && field.kind !== "custom" && !updatable && !(field.kind === "relation" && field.foreignKey === "id") && this.columns[revisionTable].some(
|
|
821
|
+
(col) => col.name === (field.kind === "relation" ? field.foreignKey || `${name2}Id` : name2)
|
|
822
|
+
)
|
|
823
|
+
);
|
|
824
|
+
this.createRevisionFields(model, revisionFieldsToRemove, down, up);
|
|
825
|
+
}
|
|
518
826
|
}
|
|
519
827
|
}
|
|
520
828
|
}
|
|
521
|
-
for (const model of
|
|
829
|
+
for (const model of models.entities) {
|
|
522
830
|
if (tables.includes(model.name)) {
|
|
523
831
|
this.createFields(
|
|
524
832
|
model,
|
|
@@ -526,10 +834,10 @@ var MigrationGenerator = class {
|
|
|
526
834
|
down,
|
|
527
835
|
up
|
|
528
836
|
);
|
|
529
|
-
if (model
|
|
837
|
+
if (isUpdatableModel(model)) {
|
|
530
838
|
this.createRevisionFields(
|
|
531
839
|
model,
|
|
532
|
-
model.fields.filter(({ deleted
|
|
840
|
+
model.fields.filter(isUpdatableField).filter(({ deleted }) => deleted),
|
|
533
841
|
down,
|
|
534
842
|
up
|
|
535
843
|
);
|
|
@@ -537,7 +845,7 @@ var MigrationGenerator = class {
|
|
|
537
845
|
}
|
|
538
846
|
}
|
|
539
847
|
this.createEnums(
|
|
540
|
-
|
|
848
|
+
this.models.enums.filter((enm2) => enm2.deleted),
|
|
541
849
|
down,
|
|
542
850
|
up
|
|
543
851
|
);
|
|
@@ -645,8 +953,8 @@ var MigrationGenerator = class {
|
|
|
645
953
|
}
|
|
646
954
|
});
|
|
647
955
|
});
|
|
648
|
-
if (model
|
|
649
|
-
const updatableFields = fields2.filter(
|
|
956
|
+
if (isUpdatableModel(model)) {
|
|
957
|
+
const updatableFields = fields2.filter(isUpdatableField);
|
|
650
958
|
if (!updatableFields.length) {
|
|
651
959
|
return;
|
|
652
960
|
}
|
|
@@ -674,15 +982,15 @@ var MigrationGenerator = class {
|
|
|
674
982
|
const writer = this.writer;
|
|
675
983
|
this.createTable(`${model.name}Revision`, () => {
|
|
676
984
|
writer.writeLine(`table.uuid('id').notNullable().primary();`);
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
985
|
+
if (!model.parent) {
|
|
986
|
+
writer.writeLine(`table.uuid('${typeToField(model.name)}Id').notNullable();`);
|
|
987
|
+
writer.writeLine(`table.uuid('createdById').notNullable();`);
|
|
988
|
+
writer.writeLine(`table.timestamp('createdAt').notNullable().defaultTo(knex.fn.now(0));`);
|
|
989
|
+
if (model.deletable) {
|
|
990
|
+
writer.writeLine(`table.boolean('deleted').notNullable();`);
|
|
991
|
+
}
|
|
684
992
|
}
|
|
685
|
-
for (const field of model.fields.filter((
|
|
993
|
+
for (const field of model.fields.filter(and(isUpdatableField, not(isInherited)))) {
|
|
686
994
|
this.column(field, { setUnique: false, setDefault: false });
|
|
687
995
|
}
|
|
688
996
|
});
|
|
@@ -730,7 +1038,7 @@ var MigrationGenerator = class {
|
|
|
730
1038
|
`await knex.raw(\`CREATE TYPE "${name2}" AS ENUM (${enm2.values.map((value2) => `'${value2}'`).join(",")})\`);`
|
|
731
1039
|
).newLine()
|
|
732
1040
|
);
|
|
733
|
-
down.push(() => this.writer.writeLine(`await knex.raw('DROP TYPE "${name2}"')
|
|
1041
|
+
down.push(() => this.writer.writeLine(`await knex.raw('DROP TYPE "${name2}"');`));
|
|
734
1042
|
}
|
|
735
1043
|
}
|
|
736
1044
|
migration(name2, cbs) {
|
|
@@ -810,7 +1118,7 @@ var MigrationGenerator = class {
|
|
|
810
1118
|
if (field.double) {
|
|
811
1119
|
col(`table.double('${name2}')`);
|
|
812
1120
|
} else {
|
|
813
|
-
col(`table.decimal('${name2}', ${
|
|
1121
|
+
col(`table.decimal('${name2}', ${field.precision ?? "undefined"}, ${field.scale ?? "undefined"})`);
|
|
814
1122
|
}
|
|
815
1123
|
break;
|
|
816
1124
|
case "String":
|
|
@@ -831,14 +1139,16 @@ var MigrationGenerator = class {
|
|
|
831
1139
|
}
|
|
832
1140
|
break;
|
|
833
1141
|
case "relation":
|
|
834
|
-
col(`table.uuid('${
|
|
1142
|
+
col(`table.uuid('${field.foreignKey}')`);
|
|
835
1143
|
if (foreign && !alter) {
|
|
836
|
-
this.writer.writeLine(
|
|
1144
|
+
this.writer.writeLine(
|
|
1145
|
+
`table.foreign('${field.foreignKey}').references('id').inTable('${field.type}').onDelete('CASCADE');`
|
|
1146
|
+
);
|
|
837
1147
|
}
|
|
838
1148
|
break;
|
|
839
1149
|
case "enum":
|
|
840
1150
|
if (list2) {
|
|
841
|
-
this.writer.write(`table.specificType('${name2}', '"${typeToField(field.type)}"[]')
|
|
1151
|
+
this.writer.write(`table.specificType('${name2}', '"${typeToField(field.type)}"[]')`);
|
|
842
1152
|
} else {
|
|
843
1153
|
this.writer.write(`table.enum('${name2}', null as any, `).inlineBlock(() => {
|
|
844
1154
|
this.writer.writeLine(`useNative: true,`);
|
|
@@ -876,6 +1186,8 @@ var import_graphql2 = require("graphql");
|
|
|
876
1186
|
|
|
877
1187
|
// src/resolvers/utils.ts
|
|
878
1188
|
var import_graphql3 = require("graphql");
|
|
1189
|
+
var import_lodash4 = require("lodash");
|
|
1190
|
+
var getColumnName = (field) => field.kind === "relation" ? field.foreignKey || `${field.name}Id` : field.name;
|
|
879
1191
|
|
|
880
1192
|
// src/resolvers/arguments.ts
|
|
881
1193
|
var import_graphql4 = require("graphql");
|
|
@@ -889,7 +1201,6 @@ var import_flatMap = __toESM(require("lodash/flatMap"), 1);
|
|
|
889
1201
|
|
|
890
1202
|
// src/schema/generate.ts
|
|
891
1203
|
var import_graphql5 = require("graphql");
|
|
892
|
-
var import_flatMap2 = __toESM(require("lodash/flatMap"), 1);
|
|
893
1204
|
|
|
894
1205
|
// src/schema/utils.ts
|
|
895
1206
|
var import_luxon = require("luxon");
|
|
@@ -914,6 +1225,13 @@ var object = (nme, fds, interfaces, dvs) => ({
|
|
|
914
1225
|
interfaces: interfaces && interfaces.map((i) => namedType(i)),
|
|
915
1226
|
directives: directives(dvs)
|
|
916
1227
|
});
|
|
1228
|
+
var iface = (nme, fds, interfaces, dvs) => ({
|
|
1229
|
+
name: name(nme),
|
|
1230
|
+
fields: fields(fds),
|
|
1231
|
+
kind: "InterfaceTypeDefinition",
|
|
1232
|
+
interfaces: interfaces && interfaces.map((i) => namedType(i)),
|
|
1233
|
+
directives: directives(dvs)
|
|
1234
|
+
});
|
|
917
1235
|
var inputValues = (fields2) => fields2.map(
|
|
918
1236
|
(field) => ({
|
|
919
1237
|
kind: "InputValueDefinition",
|
|
@@ -1019,84 +1337,86 @@ var value = (val = null) => val === null ? {
|
|
|
1019
1337
|
};
|
|
1020
1338
|
|
|
1021
1339
|
// src/schema/generate.ts
|
|
1022
|
-
var generateDefinitions = (
|
|
1023
|
-
|
|
1340
|
+
var generateDefinitions = ({
|
|
1341
|
+
scalars,
|
|
1342
|
+
rawEnums,
|
|
1343
|
+
enums,
|
|
1344
|
+
inputs,
|
|
1345
|
+
interfaces,
|
|
1346
|
+
entities,
|
|
1347
|
+
objects
|
|
1348
|
+
}) => {
|
|
1024
1349
|
return [
|
|
1025
1350
|
// Predefined types
|
|
1026
|
-
enm(
|
|
1027
|
-
|
|
1028
|
-
scalar(
|
|
1029
|
-
...
|
|
1030
|
-
...
|
|
1031
|
-
...
|
|
1032
|
-
...
|
|
1033
|
-
|
|
1034
|
-
...rawModels.filter(isObjectModel).filter(
|
|
1035
|
-
(model) => models.some((m) => m.creatable && m.fields.some((f) => f.creatable && f.kind === "json" && f.type === model.name))
|
|
1351
|
+
...rawEnums.map((model) => enm(model.name, model.values)),
|
|
1352
|
+
...enums.map((model) => enm(model.name, model.values)),
|
|
1353
|
+
...scalars.map((model) => scalar(model.name)),
|
|
1354
|
+
...objects.filter(({ name: name2 }) => !["Query", "Mutation"].includes(name2)).map((model) => object(model.name, model.fields)),
|
|
1355
|
+
...interfaces.map(({ name: name2, fields: fields2 }) => iface(name2, fields2)),
|
|
1356
|
+
...inputs.map((model) => input(model.name, model.fields)),
|
|
1357
|
+
...objects.filter(
|
|
1358
|
+
(model) => entities.some((m) => m.creatable && m.fields.some((f) => f.creatable && f.kind === "json" && f.type === model.name))
|
|
1036
1359
|
).map((model) => input(`Create${model.name}`, model.fields)),
|
|
1037
|
-
...
|
|
1038
|
-
(model) =>
|
|
1360
|
+
...objects.filter(
|
|
1361
|
+
(model) => entities.some((m) => m.updatable && m.fields.some((f) => f.updatable && f.kind === "json" && f.type === model.name))
|
|
1039
1362
|
).map((model) => input(`Update${model.name}`, model.fields)),
|
|
1040
|
-
...(
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
...
|
|
1047
|
-
...field,
|
|
1048
|
-
type: field.type,
|
|
1049
|
-
args: [...field.args || []],
|
|
1050
|
-
directives: field.directives
|
|
1051
|
-
})),
|
|
1052
|
-
...model.reverseRelations.map(({ name: name2, field, model: model2 }) => ({
|
|
1053
|
-
name: name2,
|
|
1054
|
-
type: model2.name,
|
|
1055
|
-
list: !field.toOne,
|
|
1056
|
-
nonNull: !field.toOne,
|
|
1057
|
-
args: [
|
|
1058
|
-
{ name: "where", type: `${model2.name}Where` },
|
|
1059
|
-
...model2.fields.some(({ searchable }) => searchable) ? [{ name: "search", type: "String" }] : [],
|
|
1060
|
-
...model2.fields.some(({ orderable }) => orderable) ? [{ name: "orderBy", type: `${model2.name}OrderBy`, list: true }] : [],
|
|
1061
|
-
{ name: "limit", type: "Int" },
|
|
1062
|
-
{ name: "offset", type: "Int" }
|
|
1063
|
-
]
|
|
1064
|
-
}))
|
|
1065
|
-
],
|
|
1066
|
-
model.interfaces
|
|
1067
|
-
),
|
|
1068
|
-
input(`${model.name}Where`, [
|
|
1069
|
-
...model.fields.filter(({ kind, unique, filterable }) => (unique || filterable) && kind !== "relation").map((field) => ({
|
|
1070
|
-
name: field.name,
|
|
1363
|
+
...entities.flatMap((model) => {
|
|
1364
|
+
const types = [
|
|
1365
|
+
(isRootModel(model) ? iface : object)(
|
|
1366
|
+
model.name,
|
|
1367
|
+
[
|
|
1368
|
+
...model.fields.filter(isQueriableField).map((field) => ({
|
|
1369
|
+
...field,
|
|
1071
1370
|
type: field.type,
|
|
1072
|
-
|
|
1073
|
-
|
|
1371
|
+
args: [...field.args || []],
|
|
1372
|
+
directives: field.directives
|
|
1074
1373
|
})),
|
|
1075
|
-
...(
|
|
1076
|
-
model.fields.filter(({ comparable }) => comparable),
|
|
1077
|
-
(field) => [
|
|
1078
|
-
{ name: `${field.name}_GT`, type: field.type },
|
|
1079
|
-
{ name: `${field.name}_GTE`, type: field.type },
|
|
1080
|
-
{ name: `${field.name}_LT`, type: field.type },
|
|
1081
|
-
{ name: `${field.name}_LTE`, type: field.type }
|
|
1082
|
-
]
|
|
1083
|
-
),
|
|
1084
|
-
...model.fields.filter(isRelation).filter(({ filterable }) => filterable).map(({ name: name2, type }) => ({
|
|
1374
|
+
...model.reverseRelations.map(({ name: name2, field, targetModel }) => ({
|
|
1085
1375
|
name: name2,
|
|
1086
|
-
type:
|
|
1376
|
+
type: targetModel.name,
|
|
1377
|
+
list: !field.toOne,
|
|
1378
|
+
nonNull: !field.toOne,
|
|
1379
|
+
args: [
|
|
1380
|
+
{ name: "where", type: `${targetModel.name}Where` },
|
|
1381
|
+
...targetModel.fields.some(({ searchable }) => searchable) ? [{ name: "search", type: "String" }] : [],
|
|
1382
|
+
...targetModel.fields.some(({ orderable }) => orderable) ? [{ name: "orderBy", type: `${targetModel.name}OrderBy`, list: true }] : [],
|
|
1383
|
+
{ name: "limit", type: "Int" },
|
|
1384
|
+
{ name: "offset", type: "Int" }
|
|
1385
|
+
]
|
|
1087
1386
|
}))
|
|
1387
|
+
],
|
|
1388
|
+
[...model.parent ? [model.parent] : [], ...model.interfaces || []]
|
|
1389
|
+
),
|
|
1390
|
+
input(`${model.name}Where`, [
|
|
1391
|
+
...model.fields.filter(({ kind, unique, filterable }) => (unique || filterable) && kind !== "relation").map((field) => ({
|
|
1392
|
+
name: field.name,
|
|
1393
|
+
type: field.type,
|
|
1394
|
+
list: true,
|
|
1395
|
+
default: typeof field.filterable === "object" ? field.filterable.default : void 0
|
|
1396
|
+
})),
|
|
1397
|
+
...model.fields.filter(({ comparable }) => comparable).flatMap((field) => [
|
|
1398
|
+
{ name: `${field.name}_GT`, type: field.type },
|
|
1399
|
+
{ name: `${field.name}_GTE`, type: field.type },
|
|
1400
|
+
{ name: `${field.name}_LT`, type: field.type },
|
|
1401
|
+
{ name: `${field.name}_LTE`, type: field.type }
|
|
1088
1402
|
]),
|
|
1403
|
+
...model.fields.filter(isRelation).filter(({ filterable }) => filterable).map(({ name: name2, type }) => ({
|
|
1404
|
+
name: name2,
|
|
1405
|
+
type: `${type}Where`
|
|
1406
|
+
}))
|
|
1407
|
+
]),
|
|
1408
|
+
input(
|
|
1409
|
+
`${model.name}WhereUnique`,
|
|
1410
|
+
model.fields.filter(({ unique }) => unique).map((field) => ({ name: field.name, type: field.type }))
|
|
1411
|
+
),
|
|
1412
|
+
...model.fields.some(({ orderable }) => orderable) ? [
|
|
1089
1413
|
input(
|
|
1090
|
-
`${model.name}
|
|
1091
|
-
model.fields.filter(({
|
|
1092
|
-
)
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
model.fields.filter(({ orderable }) => orderable).map(({ name: name2 }) => ({ name: name2, type: "Order" }))
|
|
1097
|
-
)
|
|
1098
|
-
] : []
|
|
1099
|
-
];
|
|
1414
|
+
`${model.name}OrderBy`,
|
|
1415
|
+
model.fields.filter(({ orderable }) => orderable).map(({ name: name2 }) => ({ name: name2, type: "Order" }))
|
|
1416
|
+
)
|
|
1417
|
+
] : []
|
|
1418
|
+
];
|
|
1419
|
+
if (!isRootModel(model)) {
|
|
1100
1420
|
if (model.creatable) {
|
|
1101
1421
|
types.push(
|
|
1102
1422
|
input(
|
|
@@ -1126,15 +1446,15 @@ var generateDefinitions = (rawModels) => {
|
|
|
1126
1446
|
)
|
|
1127
1447
|
);
|
|
1128
1448
|
}
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
),
|
|
1449
|
+
}
|
|
1450
|
+
return types;
|
|
1451
|
+
}),
|
|
1132
1452
|
object("Query", [
|
|
1133
1453
|
{
|
|
1134
1454
|
name: "me",
|
|
1135
1455
|
type: "User"
|
|
1136
1456
|
},
|
|
1137
|
-
...
|
|
1457
|
+
...entities.filter(({ queriable }) => queriable).map(({ name: name2 }) => ({
|
|
1138
1458
|
name: typeToField(name2),
|
|
1139
1459
|
type: name2,
|
|
1140
1460
|
nonNull: true,
|
|
@@ -1146,8 +1466,8 @@ var generateDefinitions = (rawModels) => {
|
|
|
1146
1466
|
}
|
|
1147
1467
|
]
|
|
1148
1468
|
})),
|
|
1149
|
-
...
|
|
1150
|
-
name:
|
|
1469
|
+
...entities.filter(({ listQueriable }) => listQueriable).map((model) => ({
|
|
1470
|
+
name: model.pluralField,
|
|
1151
1471
|
type: model.name,
|
|
1152
1472
|
list: true,
|
|
1153
1473
|
nonNull: true,
|
|
@@ -1159,12 +1479,12 @@ var generateDefinitions = (rawModels) => {
|
|
|
1159
1479
|
{ name: "offset", type: "Int" }
|
|
1160
1480
|
]
|
|
1161
1481
|
})),
|
|
1162
|
-
...
|
|
1482
|
+
...objects.filter((model) => model.name === "Query").flatMap((model) => model.fields)
|
|
1163
1483
|
]),
|
|
1164
1484
|
object("Mutation", [
|
|
1165
|
-
...(
|
|
1166
|
-
|
|
1167
|
-
|
|
1485
|
+
...entities.flatMap((model) => {
|
|
1486
|
+
const mutations = [];
|
|
1487
|
+
if (!isRootModel(model)) {
|
|
1168
1488
|
if (model.creatable) {
|
|
1169
1489
|
mutations.push({
|
|
1170
1490
|
name: `create${model.name}`,
|
|
@@ -1228,14 +1548,14 @@ var generateDefinitions = (rawModels) => {
|
|
|
1228
1548
|
]
|
|
1229
1549
|
});
|
|
1230
1550
|
}
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
),
|
|
1234
|
-
...
|
|
1551
|
+
}
|
|
1552
|
+
return mutations;
|
|
1553
|
+
}),
|
|
1554
|
+
...objects.filter((model) => model.name === "Mutation").flatMap((model) => model.fields)
|
|
1235
1555
|
])
|
|
1236
1556
|
];
|
|
1237
1557
|
};
|
|
1238
|
-
var generate = (
|
|
1558
|
+
var generate = (models) => document(generateDefinitions(models));
|
|
1239
1559
|
var printSchema = (schema) => [
|
|
1240
1560
|
...schema.getDirectives().map((d) => d.astNode && (0, import_graphql5.print)(d.astNode)),
|
|
1241
1561
|
...Object.values(schema.getTypeMap()).filter((t) => !t.name.match(/^__/)).sort((a, b) => a.name > b.name ? 1 : -1).map((t) => t.astNode && (0, import_graphql5.print)(t.astNode))
|
|
@@ -1267,9 +1587,9 @@ var readLine = (prompt) => {
|
|
|
1267
1587
|
|
|
1268
1588
|
// src/bin/gqm/templates.ts
|
|
1269
1589
|
var EMPTY_MODELS = `
|
|
1270
|
-
import { RawModels,
|
|
1590
|
+
import { RawModels, Models } from '@smartive/graphql-magic';
|
|
1271
1591
|
|
|
1272
|
-
|
|
1592
|
+
const rawModels: RawModels = [
|
|
1273
1593
|
{
|
|
1274
1594
|
kind: 'entity',
|
|
1275
1595
|
name: 'User',
|
|
@@ -1277,9 +1597,22 @@ export const rawModels: RawModels = [
|
|
|
1277
1597
|
},
|
|
1278
1598
|
]
|
|
1279
1599
|
|
|
1280
|
-
export const models =
|
|
1600
|
+
export const models = new Models(rawModels);
|
|
1281
1601
|
`;
|
|
1282
1602
|
var KNEXFILE = `
|
|
1603
|
+
import { DateTime } from 'luxon';
|
|
1604
|
+
import { types } from 'pg';
|
|
1605
|
+
|
|
1606
|
+
const dateOids = { date: 1082, timestamptz: 1184, timestamp: 1114 };
|
|
1607
|
+
for (const oid of Object.values(dateOids)) {
|
|
1608
|
+
types.setTypeParser(oid, (val) => DateTime.fromSQL(val));
|
|
1609
|
+
}
|
|
1610
|
+
|
|
1611
|
+
const numberOids = { int8: 20, float8: 701, numeric: 1700 };
|
|
1612
|
+
for (const oid of Object.values(numberOids)) {
|
|
1613
|
+
types.setTypeParser(oid, Number);
|
|
1614
|
+
}
|
|
1615
|
+
|
|
1283
1616
|
const config = {
|
|
1284
1617
|
client: 'postgresql',
|
|
1285
1618
|
connection: {
|
|
@@ -1288,6 +1621,13 @@ const config = {
|
|
|
1288
1621
|
user: process.env.DATABASE_USER,
|
|
1289
1622
|
password: process.env.DATABASE_PASSWORD,
|
|
1290
1623
|
},
|
|
1624
|
+
migrations: {
|
|
1625
|
+
tableName: 'knex_migrations',
|
|
1626
|
+
},
|
|
1627
|
+
pool: {
|
|
1628
|
+
min: 0,
|
|
1629
|
+
max: 30,
|
|
1630
|
+
},
|
|
1291
1631
|
} as const;
|
|
1292
1632
|
|
|
1293
1633
|
export default config;
|
|
@@ -1319,6 +1659,9 @@ var DEFAULTS = {
|
|
|
1319
1659
|
init: (path) => {
|
|
1320
1660
|
ensureDirectoryExists(path);
|
|
1321
1661
|
}
|
|
1662
|
+
},
|
|
1663
|
+
gqlModule: {
|
|
1664
|
+
defaultValue: "@smartive/graphql-magic"
|
|
1322
1665
|
}
|
|
1323
1666
|
};
|
|
1324
1667
|
var initSetting = async (name2) => {
|
|
@@ -1329,8 +1672,10 @@ var initSetting = async (name2) => {
|
|
|
1329
1672
|
};
|
|
1330
1673
|
var initSettings = async () => {
|
|
1331
1674
|
const settings = {};
|
|
1332
|
-
for (const name2 of Object.
|
|
1333
|
-
|
|
1675
|
+
for (const [name2, config2] of Object.entries(DEFAULTS)) {
|
|
1676
|
+
if ("queston" in config2) {
|
|
1677
|
+
settings[name2] = await initSetting(name2);
|
|
1678
|
+
}
|
|
1334
1679
|
}
|
|
1335
1680
|
saveSettings(settings);
|
|
1336
1681
|
};
|
|
@@ -1346,8 +1691,12 @@ var getSettings = async () => {
|
|
|
1346
1691
|
var getSetting = async (name2) => {
|
|
1347
1692
|
const settings = await getSettings();
|
|
1348
1693
|
if (!(name2 in settings)) {
|
|
1349
|
-
|
|
1350
|
-
|
|
1694
|
+
if ("question" in DEFAULTS[name2]) {
|
|
1695
|
+
settings[name2] = await initSetting(name2);
|
|
1696
|
+
saveSettings(settings);
|
|
1697
|
+
} else {
|
|
1698
|
+
return DEFAULTS[name2].defaultValue;
|
|
1699
|
+
}
|
|
1351
1700
|
}
|
|
1352
1701
|
return settings[name2];
|
|
1353
1702
|
};
|
|
@@ -1512,6 +1861,8 @@ var VISITOR = {
|
|
|
1512
1861
|
return process;
|
|
1513
1862
|
case "Symbol":
|
|
1514
1863
|
return Symbol;
|
|
1864
|
+
case "Models":
|
|
1865
|
+
return Models;
|
|
1515
1866
|
}
|
|
1516
1867
|
const definitionNodes = node.getDefinitionNodes();
|
|
1517
1868
|
if (!definitionNodes.length) {
|
|
@@ -1652,7 +2003,8 @@ var VISITOR = {
|
|
|
1652
2003
|
return target[argument];
|
|
1653
2004
|
},
|
|
1654
2005
|
[import_ts_morph2.SyntaxKind.NoSubstitutionTemplateLiteral]: (node) => node.getLiteralValue(),
|
|
1655
|
-
[import_ts_morph2.SyntaxKind.NullKeyword]: () => null
|
|
2006
|
+
[import_ts_morph2.SyntaxKind.NullKeyword]: () => null,
|
|
2007
|
+
[import_ts_morph2.SyntaxKind.NewExpression]: (node, context) => new (staticEval(node.getExpression(), context))(...node.getArguments().map((arg) => staticEval(arg, context)))
|
|
1656
2008
|
};
|
|
1657
2009
|
|
|
1658
2010
|
// src/bin/gqm/utils.ts
|
|
@@ -1703,11 +2055,11 @@ var parseModels = async () => {
|
|
|
1703
2055
|
});
|
|
1704
2056
|
const modelsPath = await getSetting("modelsPath");
|
|
1705
2057
|
const sourceFile = project.addSourceFileAtPath(modelsPath);
|
|
1706
|
-
const modelsDeclaration = findDeclarationInFile(sourceFile, "
|
|
1707
|
-
const
|
|
2058
|
+
const modelsDeclaration = findDeclarationInFile(sourceFile, "models");
|
|
2059
|
+
const models = staticEval(modelsDeclaration, {});
|
|
1708
2060
|
const generatedFolderPath = await getSetting("generatedFolderPath");
|
|
1709
|
-
writeToFile(`${generatedFolderPath}/models.json`, JSON.stringify(
|
|
1710
|
-
return
|
|
2061
|
+
writeToFile(`${generatedFolderPath}/models.json`, JSON.stringify(models.definitions, null, 2));
|
|
2062
|
+
return models;
|
|
1711
2063
|
};
|
|
1712
2064
|
|
|
1713
2065
|
// src/bin/gqm/gqm.ts
|
|
@@ -1723,39 +2075,39 @@ import_commander.program.command("setup").description("Set up the project").acti
|
|
|
1723
2075
|
ensureFileExists(KNEXFILE_PATH, KNEXFILE);
|
|
1724
2076
|
});
|
|
1725
2077
|
import_commander.program.command("generate").description("Generate all the things").action(async () => {
|
|
1726
|
-
const
|
|
2078
|
+
const models = await parseModels();
|
|
1727
2079
|
const generatedFolderPath = await getSetting("generatedFolderPath");
|
|
1728
|
-
|
|
1729
|
-
writeToFile(`${generatedFolderPath}/
|
|
1730
|
-
writeToFile(`${generatedFolderPath}/
|
|
1731
|
-
writeToFile(`${generatedFolderPath}/db/
|
|
2080
|
+
const gqlModule = await getSetting("gqlModule");
|
|
2081
|
+
writeToFile(`${generatedFolderPath}/schema.graphql`, printSchemaFromModels(models));
|
|
2082
|
+
writeToFile(`${generatedFolderPath}/client/mutations.ts`, generateMutations(models, gqlModule));
|
|
2083
|
+
writeToFile(`${generatedFolderPath}/db/index.ts`, generateDBModels(models));
|
|
2084
|
+
writeToFile(`${generatedFolderPath}/db/knex.ts`, generateKnexTables(models));
|
|
1732
2085
|
await generateGraphqlApiTypes();
|
|
1733
2086
|
await generateGraphqlClientTypes();
|
|
1734
2087
|
});
|
|
1735
2088
|
import_commander.program.command("generate-models").description("Generate models.json").action(async () => {
|
|
1736
|
-
|
|
1737
|
-
const generatedFolderPath = await getSetting("generatedFolderPath");
|
|
1738
|
-
writeToFile(`${generatedFolderPath}/models.json`, JSON.stringify(rawModels, null, 2));
|
|
2089
|
+
await parseModels();
|
|
1739
2090
|
});
|
|
1740
2091
|
import_commander.program.command("generate-schema").description("Generate schema").action(async () => {
|
|
1741
|
-
const
|
|
2092
|
+
const models = await parseModels();
|
|
1742
2093
|
const generatedFolderPath = await getSetting("generatedFolderPath");
|
|
1743
|
-
writeToFile(`${generatedFolderPath}/schema.graphql`, printSchemaFromModels(
|
|
2094
|
+
writeToFile(`${generatedFolderPath}/schema.graphql`, printSchemaFromModels(models));
|
|
1744
2095
|
});
|
|
1745
2096
|
import_commander.program.command("generate-mutation-queries").description("Generate mutation-queries").action(async () => {
|
|
1746
|
-
const
|
|
2097
|
+
const models = await parseModels();
|
|
1747
2098
|
const generatedFolderPath = await getSetting("generatedFolderPath");
|
|
1748
|
-
|
|
2099
|
+
const gqlModule = await getSetting("gqlModule");
|
|
2100
|
+
writeToFile(`${generatedFolderPath}/client/mutations.ts`, generateMutations(models, gqlModule));
|
|
1749
2101
|
});
|
|
1750
2102
|
import_commander.program.command("generate-db-types").description("Generate DB types").action(async () => {
|
|
1751
|
-
const
|
|
2103
|
+
const models = await parseModels();
|
|
1752
2104
|
const generatedFolderPath = await getSetting("generatedFolderPath");
|
|
1753
|
-
writeToFile(`${generatedFolderPath}/db/index.ts`,
|
|
2105
|
+
writeToFile(`${generatedFolderPath}/db/index.ts`, generateDBModels(models));
|
|
1754
2106
|
});
|
|
1755
2107
|
import_commander.program.command("generate-knex-types").description("Generate Knex types").action(async () => {
|
|
1756
|
-
const
|
|
2108
|
+
const models = await parseModels();
|
|
1757
2109
|
const generatedFolderPath = await getSetting("generatedFolderPath");
|
|
1758
|
-
writeToFile(`${generatedFolderPath}/db/knex.ts`, generateKnexTables(
|
|
2110
|
+
writeToFile(`${generatedFolderPath}/db/knex.ts`, generateKnexTables(models));
|
|
1759
2111
|
});
|
|
1760
2112
|
import_commander.program.command("generate-graphql-api-types").description("Generate Graphql API types").action(async () => {
|
|
1761
2113
|
await generateGraphqlApiTypes();
|
|
@@ -1763,18 +2115,20 @@ import_commander.program.command("generate-graphql-api-types").description("Gene
|
|
|
1763
2115
|
import_commander.program.command("generate-graphql-client-types").description("Generate Graphql client types").action(async () => {
|
|
1764
2116
|
await generateGraphqlClientTypes();
|
|
1765
2117
|
});
|
|
1766
|
-
import_commander.program.command("generate-migration").description("Generate Migration").action(async () => {
|
|
2118
|
+
import_commander.program.command("generate-migration [<name>] [<date>]").description("Generate Migration").action(async (name2, date) => {
|
|
1767
2119
|
const git = (0, import_simple_git.simpleGit)();
|
|
1768
|
-
|
|
1769
|
-
|
|
2120
|
+
if (!name2) {
|
|
2121
|
+
name2 = (await git.branch()).current.split("/").pop();
|
|
2122
|
+
}
|
|
2123
|
+
if (!name2 || ["main", "staging", "production"].includes(name2)) {
|
|
1770
2124
|
name2 = await readLine("Migration name:");
|
|
1771
2125
|
}
|
|
1772
2126
|
const knexfile = await parseKnexfile();
|
|
1773
2127
|
const db = (0, import_knex.default)(knexfile);
|
|
1774
2128
|
try {
|
|
1775
|
-
const
|
|
1776
|
-
const migrations = await new MigrationGenerator(db,
|
|
1777
|
-
writeToFile(`migrations/${getMigrationDate()}_${name2}.ts`, migrations);
|
|
2129
|
+
const models = await parseModels();
|
|
2130
|
+
const migrations = await new MigrationGenerator(db, models).generate();
|
|
2131
|
+
writeToFile(`migrations/${date || getMigrationDate()}_${name2}.ts`, migrations);
|
|
1778
2132
|
} finally {
|
|
1779
2133
|
await db.destroy();
|
|
1780
2134
|
}
|