@smartive/graphql-magic 7.0.1 → 8.1.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.
Files changed (81) hide show
  1. package/CHANGELOG.md +3 -3
  2. package/README.md +8 -15
  3. package/dist/bin/gqm.cjs +1812 -0
  4. package/dist/cjs/index.cjs +568 -30
  5. package/dist/esm/bin/gqm.d.ts +2 -0
  6. package/dist/esm/bin/gqm.js +121 -0
  7. package/dist/esm/bin/gqm.js.map +1 -0
  8. package/dist/esm/client/mutations.d.ts +2 -2
  9. package/dist/esm/client/mutations.js +2 -1
  10. package/dist/esm/client/mutations.js.map +1 -1
  11. package/dist/esm/db/generate.js +7 -7
  12. package/dist/esm/db/generate.js.map +1 -1
  13. package/dist/esm/gqm/codegen.d.ts +2 -0
  14. package/dist/esm/gqm/codegen.js +46 -0
  15. package/dist/esm/gqm/codegen.js.map +1 -0
  16. package/dist/esm/gqm/index.d.ts +9 -0
  17. package/dist/esm/gqm/index.js +11 -0
  18. package/dist/esm/gqm/index.js.map +1 -0
  19. package/dist/esm/gqm/parse-knexfile.d.ts +2 -0
  20. package/dist/esm/gqm/parse-knexfile.js +19 -0
  21. package/dist/esm/gqm/parse-knexfile.js.map +1 -0
  22. package/dist/esm/gqm/parse-models.d.ts +2 -0
  23. package/dist/esm/gqm/parse-models.js +19 -0
  24. package/dist/esm/gqm/parse-models.js.map +1 -0
  25. package/dist/esm/gqm/readline.d.ts +1 -0
  26. package/dist/esm/gqm/readline.js +14 -0
  27. package/dist/esm/gqm/readline.js.map +1 -0
  28. package/dist/esm/gqm/settings.d.ts +9 -0
  29. package/dist/esm/gqm/settings.js +98 -0
  30. package/dist/esm/gqm/settings.js.map +1 -0
  31. package/dist/esm/gqm/static-eval.d.ts +3 -0
  32. package/dist/esm/gqm/static-eval.js +188 -0
  33. package/dist/esm/gqm/static-eval.js.map +1 -0
  34. package/dist/esm/gqm/templates.d.ts +4 -0
  35. package/dist/esm/gqm/templates.js +62 -0
  36. package/dist/esm/gqm/templates.js.map +1 -0
  37. package/dist/esm/gqm/utils.d.ts +2 -0
  38. package/dist/esm/gqm/utils.js +22 -0
  39. package/dist/esm/gqm/utils.js.map +1 -0
  40. package/dist/esm/gqm/visitor.d.ts +8 -0
  41. package/dist/esm/gqm/visitor.js +15 -0
  42. package/dist/esm/gqm/visitor.js.map +1 -0
  43. package/dist/esm/index.d.ts +1 -0
  44. package/dist/esm/index.js +1 -0
  45. package/dist/esm/index.js.map +1 -1
  46. package/dist/esm/migrations/generate.d.ts +1 -0
  47. package/dist/esm/migrations/generate.js +16 -5
  48. package/dist/esm/migrations/generate.js.map +1 -1
  49. package/dist/esm/models/models.d.ts +16 -10
  50. package/dist/esm/models/utils.d.ts +17 -9
  51. package/dist/esm/models/utils.js +6 -5
  52. package/dist/esm/models/utils.js.map +1 -1
  53. package/dist/esm/resolvers/node.js +2 -2
  54. package/dist/esm/resolvers/node.js.map +1 -1
  55. package/dist/esm/resolvers/resolver.js +1 -1
  56. package/dist/esm/resolvers/resolver.js.map +1 -1
  57. package/dist/esm/schema/generate.js +16 -4
  58. package/dist/esm/schema/generate.js.map +1 -1
  59. package/package.json +18 -5
  60. package/src/bin/gqm.ts +146 -0
  61. package/src/client/mutations.ts +4 -3
  62. package/src/db/generate.ts +7 -7
  63. package/src/gqm/codegen.ts +47 -0
  64. package/src/gqm/index.ts +11 -0
  65. package/src/gqm/parse-knexfile.ts +21 -0
  66. package/src/gqm/parse-models.ts +24 -0
  67. package/src/gqm/readline.ts +15 -0
  68. package/src/gqm/settings.ts +112 -0
  69. package/src/gqm/static-eval.ts +203 -0
  70. package/src/gqm/templates.ts +64 -0
  71. package/src/gqm/utils.ts +23 -0
  72. package/src/gqm/visitor.ts +29 -0
  73. package/src/index.ts +1 -0
  74. package/src/migrations/generate.ts +18 -5
  75. package/src/models/models.ts +12 -7
  76. package/src/models/utils.ts +11 -8
  77. package/src/resolvers/node.ts +2 -2
  78. package/src/resolvers/resolver.ts +1 -1
  79. package/src/schema/generate.ts +17 -4
  80. package/tests/utils/generate-migration.ts +2 -13
  81. package/tests/utils/models.ts +4 -4
@@ -0,0 +1,1812 @@
1
+ #!/usr/bin/env node
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __copyProps = (to, from, except, desc) => {
9
+ if (from && typeof from === "object" || typeof from === "function") {
10
+ for (let key of __getOwnPropNames(from))
11
+ if (!__hasOwnProp.call(to, key) && key !== except)
12
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
13
+ }
14
+ return to;
15
+ };
16
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
17
+ // If the importer is in node compatibility mode or this is not an ESM
18
+ // file that has been converted to a CommonJS file using a Babel-
19
+ // compatible transform (i.e. "__esModule" has not been set), then set
20
+ // "default" to the CommonJS "module.exports" for node compatibility.
21
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
22
+ mod
23
+ ));
24
+
25
+ // src/bin/gqm.ts
26
+ var import_commander = require("commander");
27
+ var import_dotenv = require("dotenv");
28
+ var import_knex = __toESM(require("knex"), 1);
29
+ var import_simple_git = require("simple-git");
30
+
31
+ // src/api/execute.ts
32
+ var import_schema = require("@graphql-tools/schema");
33
+ var import_graphql = require("graphql");
34
+
35
+ // src/client/mutations.ts
36
+ var import_upperCase = __toESM(require("lodash/upperCase"), 1);
37
+ var constantCase = (str) => (0, import_upperCase.default)(str).replace(/ /g, "_");
38
+ var generateMutations = (models) => {
39
+ const parts = [];
40
+ for (const { name: name2, creatable, updatable, deletable } of models.filter(isEntityModel)) {
41
+ if (creatable) {
42
+ parts.push(
43
+ `export const CREATE_${constantCase(
44
+ name2
45
+ )} = gql\`
46
+ mutation Create${name2}Mutation($data: Create${name2}!) {
47
+ create${name2}(data: $data) { id }
48
+ }
49
+ \`;`
50
+ );
51
+ }
52
+ if (updatable) {
53
+ parts.push(
54
+ `export const UPDATE_${constantCase(
55
+ name2
56
+ )} = gql\`
57
+ mutation Update${name2}Mutation($id: ID!, $data: Update${name2}!) {
58
+ update${name2}(where: { id: $id }, data: $data) { id }
59
+ }
60
+ \`;`
61
+ );
62
+ }
63
+ if (deletable) {
64
+ parts.push(
65
+ `export const DELETE_${constantCase(
66
+ name2
67
+ )} = gql\`
68
+ mutation Delete${name2}Mutation($id: ID!) {
69
+ delete${name2}(where: { id: $id })
70
+ }
71
+ \`;`
72
+ );
73
+ }
74
+ }
75
+ return `import { gql } from "@smartive/graphql-magic";
76
+
77
+ ${parts.join("\n\n")}`;
78
+ };
79
+
80
+ // src/client/queries.ts
81
+ var import_upperFirst = __toESM(require("lodash/upperFirst"), 1);
82
+
83
+ // src/models/utils.ts
84
+ var import_inflection = require("inflection");
85
+ var import_camelCase = __toESM(require("lodash/camelCase"), 1);
86
+ var import_get = __toESM(require("lodash/get"), 1);
87
+ var import_kebabCase = __toESM(require("lodash/kebabCase"), 1);
88
+ var import_startCase = __toESM(require("lodash/startCase"), 1);
89
+ var typeToField = (type) => type.substr(0, 1).toLowerCase() + type.substr(1);
90
+ var getModelPlural = (model) => model.plural || (0, import_inflection.pluralize)(model.name);
91
+ var getModelPluralField = (model) => typeToField(getModelPlural(model));
92
+ var isEntityModel = (model) => model.kind === "entity";
93
+ var isEnumModel = (model) => model.kind === "enum";
94
+ var isRawEnumModel = (model) => model.kind === "raw-enum";
95
+ var isScalarModel = (model) => model.kind === "scalar";
96
+ var isObjectModel = (model) => model.kind === "object";
97
+ var isInputModel = (model) => model.kind === "input";
98
+ var and = (...predicates) => (field) => predicates.every((predicate) => predicate(field));
99
+ var not = (predicate) => (field) => !predicate(field);
100
+ var isRelation = (field) => field.kind === "relation";
101
+ var isQueriableField = ({ queriable }) => queriable !== false;
102
+ var isCustomField = (field) => field.kind === "custom";
103
+ var isSimpleField = and(not(isRelation), not(isCustomField));
104
+ var getModels = (rawModels) => {
105
+ const models = rawModels.filter(isEntityModel).map((model) => {
106
+ const objectModel = {
107
+ ...model,
108
+ fieldsByName: {},
109
+ relations: [],
110
+ relationsByName: {},
111
+ reverseRelations: [],
112
+ reverseRelationsByName: {},
113
+ fields: [
114
+ { name: "id", type: "ID", nonNull: true, unique: true, primary: true, generated: true },
115
+ ...model.fields,
116
+ ...model.creatable ? [
117
+ {
118
+ name: "createdAt",
119
+ type: "DateTime",
120
+ nonNull: true,
121
+ orderable: true,
122
+ generated: true,
123
+ ...typeof model.creatable === "object" && model.creatable.createdAt
124
+ },
125
+ {
126
+ name: "createdBy",
127
+ kind: "relation",
128
+ type: "User",
129
+ nonNull: true,
130
+ reverse: `created${getModelPlural(model)}`,
131
+ generated: true,
132
+ ...typeof model.creatable === "object" && model.creatable.createdBy
133
+ }
134
+ ] : [],
135
+ ...model.updatable ? [
136
+ {
137
+ name: "updatedAt",
138
+ type: "DateTime",
139
+ nonNull: true,
140
+ orderable: true,
141
+ generated: true,
142
+ ...typeof model.updatable === "object" && model.updatable.updatedAt
143
+ },
144
+ {
145
+ name: "updatedBy",
146
+ kind: "relation",
147
+ type: "User",
148
+ nonNull: true,
149
+ reverse: `updated${getModelPlural(model)}`,
150
+ generated: true,
151
+ ...typeof model.updatable === "object" && model.updatable.updatedBy
152
+ }
153
+ ] : [],
154
+ ...model.deletable ? [
155
+ {
156
+ name: "deleted",
157
+ type: "Boolean",
158
+ nonNull: true,
159
+ defaultValue: false,
160
+ filterable: { default: false },
161
+ generated: true,
162
+ ...typeof model.deletable === "object" && model.deletable.deleted
163
+ },
164
+ {
165
+ name: "deletedAt",
166
+ type: "DateTime",
167
+ orderable: true,
168
+ generated: true,
169
+ ...typeof model.deletable === "object" && model.deletable.deletedAt
170
+ },
171
+ {
172
+ name: "deletedBy",
173
+ kind: "relation",
174
+ type: "User",
175
+ reverse: `deleted${getModelPlural(model)}`,
176
+ generated: true,
177
+ ...typeof model.deletable === "object" && model.deletable.deletedBy
178
+ }
179
+ ] : []
180
+ ].map((field) => ({
181
+ ...field,
182
+ ...field.kind === "relation" && {
183
+ foreignKey: field.foreignKey || `${field.name}Id`
184
+ }
185
+ }))
186
+ };
187
+ for (const field of objectModel.fields) {
188
+ objectModel.fieldsByName[field.name] = field;
189
+ }
190
+ return objectModel;
191
+ });
192
+ for (const model of models) {
193
+ for (const field of model.fields) {
194
+ if (field.kind !== "relation") {
195
+ continue;
196
+ }
197
+ const fieldModel = summonByName(models, field.type);
198
+ const reverseRelation = {
199
+ kind: "relation",
200
+ name: field.reverse || (field.toOne ? typeToField(model.name) : getModelPluralField(model)),
201
+ foreignKey: get(field, "foreignKey"),
202
+ type: model.name,
203
+ toOne: !!field.toOne,
204
+ fieldModel,
205
+ field,
206
+ model
207
+ };
208
+ const relation = {
209
+ field,
210
+ model: fieldModel,
211
+ reverseRelation
212
+ };
213
+ model.relations.push(relation);
214
+ model.relationsByName[relation.field.name] = relation;
215
+ fieldModel.reverseRelations.push(reverseRelation);
216
+ fieldModel.reverseRelationsByName[reverseRelation.name] = reverseRelation;
217
+ }
218
+ }
219
+ return models;
220
+ };
221
+ var summonByName = (array, value2) => summonByKey(array, "name", value2);
222
+ var summonByKey = (array, key, value2) => summon(array, (element) => (0, import_get.default)(element, key) === value2, `No element found with ${key} ${value2}`);
223
+ var summon = (array, cb, errorMessage) => {
224
+ if (array === void 0) {
225
+ console.trace();
226
+ throw new Error("Base array is not defined.");
227
+ }
228
+ const result = array.find(cb);
229
+ if (result === void 0) {
230
+ console.trace();
231
+ throw new Error(errorMessage || "Element not found.");
232
+ }
233
+ return result;
234
+ };
235
+ var it = (object2) => {
236
+ if (object2 === void 0 || object2 === null) {
237
+ console.trace();
238
+ throw new Error("Base object is not defined.");
239
+ }
240
+ return object2;
241
+ };
242
+ var get = (object2, key) => {
243
+ const value2 = it(object2)[key];
244
+ if (value2 === void 0 || value2 === null) {
245
+ console.trace();
246
+ throw new Error(`Object doesn't have ${String(key)}`);
247
+ }
248
+ return value2;
249
+ };
250
+
251
+ // src/db/generate.ts
252
+ var import_code_block_writer = __toESM(require("code-block-writer"), 1);
253
+ var PRIMITIVE_TYPES = {
254
+ ID: "string",
255
+ Boolean: "boolean",
256
+ Upload: "string",
257
+ Int: "number",
258
+ Float: "number",
259
+ String: "string",
260
+ DateTime: "DateTime | string"
261
+ };
262
+ var OPTIONAL_SEED_FIELDS = ["createdAt", "createdById", "updatedAt", "updatedById", "deletedAt", "deletedById"];
263
+ var generateDBModels = (rawModels) => {
264
+ const writer = new import_code_block_writer.default["default"]({
265
+ useSingleQuote: true,
266
+ indentNumberOfSpaces: 2
267
+ });
268
+ writer.write(`import { DateTime } from 'luxon';`).blankLine();
269
+ for (const enm2 of rawModels.filter(isEnumModel)) {
270
+ writer.write(`export type ${enm2.name} = ${enm2.values.map((v) => `'${v}'`).join(" | ")};`).blankLine();
271
+ }
272
+ const models = getModels(rawModels);
273
+ for (const model of models) {
274
+ const fields2 = model.fields.some((field) => field.kind === "relation" && field.foreignKey === "id") ? model.fields.filter((field) => field.name !== "id") : model.fields;
275
+ writer.write(`export type ${model.name} = `).inlineBlock(() => {
276
+ for (const field of fields2.filter(not(isCustomField))) {
277
+ writer.write(`'${getFieldName(field)}': ${getFieldType(field)}${field.nonNull ? "" : " | null"},`).newLine();
278
+ }
279
+ }).blankLine();
280
+ writer.write(`export type ${model.name}Initializer = `).inlineBlock(() => {
281
+ for (const field of fields2.filter(not(isCustomField))) {
282
+ writer.write(
283
+ `'${getFieldName(field)}'${field.nonNull && field.defaultValue === void 0 ? "" : "?"}: ${getFieldType(
284
+ field
285
+ )}${field.list ? " | string" : ""}${field.nonNull ? "" : " | null"},`
286
+ ).newLine();
287
+ }
288
+ }).blankLine();
289
+ writer.write(`export type ${model.name}Mutator = `).inlineBlock(() => {
290
+ for (const field of fields2.filter(not(isCustomField))) {
291
+ writer.write(
292
+ `'${getFieldName(field)}'?: ${getFieldType(field)}${field.list ? " | string" : ""}${field.nonNull ? "" : " | null"},`
293
+ ).newLine();
294
+ }
295
+ }).blankLine();
296
+ writer.write(`export type ${model.name}Seed = `).inlineBlock(() => {
297
+ for (const field of fields2.filter(not(isCustomField))) {
298
+ const fieldName = getFieldName(field);
299
+ writer.write(
300
+ `'${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"},`
301
+ ).newLine();
302
+ }
303
+ }).blankLine();
304
+ }
305
+ writer.write(`export type SeedData = `).inlineBlock(() => {
306
+ for (const model of models) {
307
+ writer.write(`${model.name}: ${model.name}Seed[],`).newLine();
308
+ }
309
+ });
310
+ return writer.toString();
311
+ };
312
+ var getFieldName = (field) => field.kind === "relation" ? field.foreignKey || `${field.name}Id` : field.name;
313
+ var getFieldType = (field) => {
314
+ const kind = field.kind;
315
+ switch (kind) {
316
+ case "json":
317
+ return "string";
318
+ case "relation":
319
+ return "string";
320
+ case "enum":
321
+ return field.type + (field.list ? "[]" : "");
322
+ case "custom":
323
+ throw new Error(`Custom fields are not in the db.`);
324
+ case "primitive":
325
+ case void 0:
326
+ return get(PRIMITIVE_TYPES, field.type) + (field.list ? "[]" : "");
327
+ default: {
328
+ const exhaustiveCheck = kind;
329
+ throw new Error(exhaustiveCheck);
330
+ }
331
+ }
332
+ };
333
+ var generateKnexTables = (rawModels) => {
334
+ const writer = new import_code_block_writer.default["default"]({
335
+ useSingleQuote: true,
336
+ indentNumberOfSpaces: 2
337
+ });
338
+ const models = getModels(rawModels);
339
+ writer.write(`import { Knex } from 'knex';`).newLine();
340
+ writer.write(
341
+ `import { ${models.map((model) => `${model.name}, ${model.name}Initializer, ${model.name}Mutator`).join(", ")} } from '.';`
342
+ ).blankLine();
343
+ writer.write(`declare module 'knex/types/tables' `).inlineBlock(() => {
344
+ writer.write(`interface Tables `).inlineBlock(() => {
345
+ for (const model of models) {
346
+ writer.write(`'${model.name}': Knex.CompositeTableType<${model.name}, ${model.name}Initializer, ${model.name}Mutator>,`).newLine();
347
+ }
348
+ });
349
+ });
350
+ return writer.toString();
351
+ };
352
+
353
+ // src/gqm/codegen.ts
354
+ var import_cli = require("@graphql-codegen/cli");
355
+
356
+ // src/gqm/settings.ts
357
+ var import_fs = require("fs");
358
+ var import_path = require("path");
359
+
360
+ // src/gqm/readline.ts
361
+ var import_readline = __toESM(require("readline"), 1);
362
+ var readLine = (prompt) => {
363
+ const rl = import_readline.default.createInterface({
364
+ input: process.stdin,
365
+ output: process.stdout
366
+ });
367
+ return new Promise((resolve2) => {
368
+ rl.question(prompt, (answer) => {
369
+ rl.close();
370
+ resolve2(answer);
371
+ });
372
+ });
373
+ };
374
+
375
+ // src/gqm/templates.ts
376
+ var EMPTY_MODELS = `
377
+ import { RawModels, getModels } from '@smartive/graphql-magic';
378
+
379
+ export const rawModels: RawModels = [
380
+ {
381
+ kind: 'entity',
382
+ name: 'User',
383
+ fields: []
384
+ },
385
+ ]
386
+
387
+ export const models = getModels(rawModels);
388
+ `;
389
+ var GRAPHQL_CODEGEN = (path) => `
390
+ overwrite: true
391
+ schema: '${path}/schema.graphql'
392
+ documents: null
393
+ generates:
394
+ ${path}/api/index.ts:
395
+ plugins:
396
+ - 'typescript'
397
+ - 'typescript-resolvers'
398
+ - add:
399
+ content: "import { DateTime } from 'luxon'"
400
+ config:
401
+ scalars:
402
+ DateTime: DateTime
403
+ `;
404
+ var CLIENT_CODEGEN = (path) => `
405
+ schema: ${path}/schema.graphql
406
+ documents: [ './src/**/*.ts', './src/**/*.tsx' ]
407
+ generates:
408
+ ${path}/client/index.ts:
409
+ plugins:
410
+ - typescript
411
+ - typescript-operations
412
+ - typescript-compatibility
413
+
414
+ config:
415
+ preResolveTypes: true # Simplifies the generated types
416
+ namingConvention: keep # Keeps naming as-is
417
+ nonOptionalTypename: true # Forces \`__typename\` on all selection sets
418
+ skipTypeNameForRoot: true # Don't generate __typename for root types
419
+ avoidOptionals: # Avoids optionals on the level of the field
420
+ field: true
421
+ scalars:
422
+ DateTime: string
423
+ `;
424
+ var KNEXFILE = `
425
+ const config = {
426
+ client: 'postgresql',
427
+ connection: {
428
+ host: process.env.DATABASE_HOST,
429
+ database: process.env.DATABASE_NAME,
430
+ user: process.env.DATABASE_USER,
431
+ password: process.env.DATABASE_PASSWORD,
432
+ },
433
+ } as const;
434
+
435
+ export default config;
436
+ `;
437
+
438
+ // src/gqm/settings.ts
439
+ var SETTINGS_PATH = ".gqmrc.json";
440
+ var DEFAULTS = {
441
+ modelsPath: {
442
+ question: "What is the models path?",
443
+ defaultValue: "src/config/models.ts",
444
+ init: (path) => {
445
+ ensureFileExists(path, EMPTY_MODELS);
446
+ }
447
+ },
448
+ generatedFolderPath: {
449
+ question: "What is the path for generated stuff?",
450
+ defaultValue: "src/generated",
451
+ init: (path) => {
452
+ ensureFileExists(`${path}/.gitkeep`, "");
453
+ ensureFileExists(`${path}/db/.gitkeep`, "");
454
+ ensureFileExists(`${path}/api/.gitkeep`, "");
455
+ ensureFileExists(`${path}/client/.gitkeep`, "");
456
+ ensureFileExists(`graphql-codegen.yml`, GRAPHQL_CODEGEN(path));
457
+ ensureFileExists(`client-codegen.yml`, CLIENT_CODEGEN(path));
458
+ }
459
+ }
460
+ };
461
+ var initSetting = async (name2) => {
462
+ const { question, defaultValue, init } = DEFAULTS[name2];
463
+ const value2 = await readLine(`${question} (${defaultValue})`) || defaultValue;
464
+ init(value2);
465
+ return value2;
466
+ };
467
+ var initSettings = async () => {
468
+ const settings = {};
469
+ for (const name2 of Object.keys(DEFAULTS)) {
470
+ settings[name2] = await initSetting(name2);
471
+ }
472
+ saveSettings(settings);
473
+ };
474
+ var saveSettings = (settings) => {
475
+ writeToFile(SETTINGS_PATH, JSON.stringify(settings, null, 2));
476
+ };
477
+ var getSettings = async () => {
478
+ if (!(0, import_fs.existsSync)(SETTINGS_PATH)) {
479
+ await initSettings();
480
+ }
481
+ return JSON.parse((0, import_fs.readFileSync)(SETTINGS_PATH, "utf8"));
482
+ };
483
+ var getSetting = async (name2) => {
484
+ const settings = await getSettings();
485
+ if (!(name2 in settings)) {
486
+ settings[name2] = await initSetting(name2);
487
+ saveSettings(settings);
488
+ }
489
+ return settings[name2];
490
+ };
491
+ var ensureDirectoryExists = (filePath) => {
492
+ const dir = (0, import_path.dirname)(filePath);
493
+ if ((0, import_fs.existsSync)(dir)) {
494
+ return true;
495
+ }
496
+ ensureDirectoryExists(dir);
497
+ try {
498
+ (0, import_fs.mkdirSync)(dir);
499
+ return true;
500
+ } catch (err) {
501
+ if (err.code === "EEXIST") {
502
+ return true;
503
+ }
504
+ throw err;
505
+ }
506
+ };
507
+ var ensureFileExists = (filePath, content) => {
508
+ if (!(0, import_fs.existsSync)(filePath)) {
509
+ console.info(`Creating ${filePath}`);
510
+ ensureDirectoryExists(filePath);
511
+ (0, import_fs.writeFileSync)(filePath, content);
512
+ }
513
+ };
514
+ var writeToFile = (filePath, content) => {
515
+ ensureDirectoryExists(filePath);
516
+ if ((0, import_fs.existsSync)(filePath)) {
517
+ const currentContent = (0, import_fs.readFileSync)(filePath, "utf-8");
518
+ if (content === currentContent) {
519
+ } else {
520
+ (0, import_fs.writeFileSync)(filePath, content);
521
+ console.info(`${filePath} updated`);
522
+ }
523
+ } else {
524
+ (0, import_fs.writeFileSync)(filePath, content);
525
+ console.info(`Created ${filePath}`);
526
+ }
527
+ };
528
+
529
+ // src/gqm/codegen.ts
530
+ var generateGraphqlApiTypes = async () => {
531
+ const generatedFolderPath = await getSetting("generatedFolderPath");
532
+ await (0, import_cli.generate)({
533
+ overwrite: true,
534
+ schema: `${generatedFolderPath}/schema.graphql`,
535
+ documents: null,
536
+ generates: {
537
+ [`${generatedFolderPath}/api/index.ts`]: {
538
+ plugins: ["typescript", "typescript-resolvers", { add: { content: `import { DateTime } from 'luxon';` } }]
539
+ }
540
+ },
541
+ config: {
542
+ scalars: {
543
+ DateTime: "DateTime"
544
+ }
545
+ }
546
+ });
547
+ };
548
+ var generateGraphqlClientTypes = async () => {
549
+ const generatedFolderPath = await getSetting("generatedFolderPath");
550
+ await (0, import_cli.generate)({
551
+ schema: `${generatedFolderPath}/schema.graphql`,
552
+ documents: ["./src/**/*.ts", "./src/**/*.tsx"],
553
+ generates: {
554
+ [`${generatedFolderPath}/client/index.ts`]: {
555
+ plugins: ["typescript", "typescript-operations", "typescript-compatibility"]
556
+ }
557
+ },
558
+ config: {
559
+ preResolveTypes: true,
560
+ // Simplifies the generated types
561
+ namingConvention: "keep",
562
+ // Keeps naming as-is
563
+ nonOptionalTypename: true,
564
+ // Forces `__typename` on all selection sets
565
+ skipTypeNameForRoot: true,
566
+ // Don't generate __typename for root types
567
+ avoidOptionals: {
568
+ // Avoids optionals on the level of the field
569
+ field: true
570
+ },
571
+ scalars: {
572
+ DateTime: "string"
573
+ }
574
+ }
575
+ });
576
+ };
577
+
578
+ // src/gqm/parse-knexfile.ts
579
+ var import_ts_morph4 = require("ts-morph");
580
+
581
+ // src/gqm/static-eval.ts
582
+ var import_ts_morph2 = require("ts-morph");
583
+
584
+ // src/gqm/visitor.ts
585
+ var import_ts_morph = require("ts-morph");
586
+ var visit = (node, context, visitor2) => {
587
+ const kind = node?.getKind();
588
+ if (kind in visitor2) {
589
+ return visitor2[kind](node.asKindOrThrow(kind), context);
590
+ }
591
+ if ("unknown" in visitor2) {
592
+ return visitor2.unknown(node);
593
+ }
594
+ console.error(node.getText());
595
+ console.error(node.getParent().getText());
596
+ throw new Error(
597
+ `Cannot handle kind ${get(
598
+ Object.entries(import_ts_morph.SyntaxKind).find(([, val]) => val === kind),
599
+ 0
600
+ )}`
601
+ );
602
+ };
603
+
604
+ // src/gqm/static-eval.ts
605
+ var staticEval = (node, context) => visit(node, context, visitor);
606
+ var visitor = {
607
+ undefined: () => void 0,
608
+ [import_ts_morph2.SyntaxKind.VariableDeclaration]: (node, context) => staticEval(node.getInitializer(), context),
609
+ [import_ts_morph2.SyntaxKind.ArrayLiteralExpression]: (node, context) => {
610
+ const values = [];
611
+ for (const value2 of node.getElements()) {
612
+ if (value2.isKind(import_ts_morph2.SyntaxKind.SpreadElement)) {
613
+ values.push(...staticEval(value2, context));
614
+ } else {
615
+ values.push(staticEval(value2, context));
616
+ }
617
+ }
618
+ return values;
619
+ },
620
+ [import_ts_morph2.SyntaxKind.ObjectLiteralExpression]: (node, context) => {
621
+ const result = {};
622
+ for (const property of node.getProperties()) {
623
+ Object.assign(result, staticEval(property, context));
624
+ }
625
+ return result;
626
+ },
627
+ [import_ts_morph2.SyntaxKind.StringLiteral]: (node) => node.getLiteralValue(),
628
+ [import_ts_morph2.SyntaxKind.PropertyAssignment]: (node, context) => ({
629
+ [node.getName()]: staticEval(node.getInitializer(), context)
630
+ }),
631
+ [import_ts_morph2.SyntaxKind.ShorthandPropertyAssignment]: (node, context) => ({
632
+ [node.getName()]: staticEval(node.getNameNode(), context)
633
+ }),
634
+ [import_ts_morph2.SyntaxKind.SpreadElement]: (node, context) => staticEval(node.getExpression(), context),
635
+ [import_ts_morph2.SyntaxKind.SpreadAssignment]: (node, context) => staticEval(node.getExpression(), context),
636
+ [import_ts_morph2.SyntaxKind.Identifier]: (node, context) => {
637
+ switch (node.getText()) {
638
+ case "undefined":
639
+ return void 0;
640
+ case "process":
641
+ return process;
642
+ }
643
+ const definitionNodes = node.getDefinitionNodes();
644
+ if (!definitionNodes.length) {
645
+ throw new Error(`No definition node found for identifier ${node.getText()}.`);
646
+ }
647
+ return staticEval(definitionNodes[0], context);
648
+ },
649
+ [import_ts_morph2.SyntaxKind.ParenthesizedExpression]: (node, context) => staticEval(node.getExpression(), context),
650
+ [import_ts_morph2.SyntaxKind.AsExpression]: (node, context) => staticEval(node.getExpression(), context),
651
+ [import_ts_morph2.SyntaxKind.ConditionalExpression]: (node, context) => staticEval(node.getCondition(), context) ? staticEval(node.getWhenTrue(), context) : staticEval(node.getWhenFalse(), context),
652
+ [import_ts_morph2.SyntaxKind.TrueKeyword]: () => true,
653
+ [import_ts_morph2.SyntaxKind.FalseKeyword]: () => false,
654
+ [import_ts_morph2.SyntaxKind.NumericLiteral]: (node) => node.getLiteralValue(),
655
+ [import_ts_morph2.SyntaxKind.CallExpression]: (node, context) => {
656
+ const method = staticEval(node.getExpression(), context);
657
+ const args2 = node.getArguments().map((arg) => staticEval(arg, context));
658
+ return method(...args2);
659
+ },
660
+ [import_ts_morph2.SyntaxKind.PropertyAccessExpression]: (node, context) => {
661
+ const target = staticEval(node.getExpression(), context);
662
+ const property = target[node.getName()];
663
+ if (typeof property === "function") {
664
+ if (Array.isArray(target)) {
665
+ switch (node.getName()) {
666
+ case "map":
667
+ case "flatMap":
668
+ case "includes":
669
+ case "some":
670
+ case "find":
671
+ case "filter":
672
+ return target[node.getName()].bind(target);
673
+ }
674
+ } else if (typeof target === "string") {
675
+ const name2 = node.getName();
676
+ switch (name2) {
677
+ case "slice":
678
+ case "toUpperCase":
679
+ case "toLowerCase":
680
+ return target[name2].bind(target);
681
+ }
682
+ }
683
+ throw new Error(`Cannot handle method ${node.getName()} on type ${typeof target}`);
684
+ }
685
+ return property;
686
+ },
687
+ [import_ts_morph2.SyntaxKind.ArrowFunction]: (node, context) => {
688
+ return (...args2) => {
689
+ const parameters = {};
690
+ let i = 0;
691
+ for (const parameter of node.getParameters()) {
692
+ parameters[parameter.getName()] = args2[i];
693
+ i++;
694
+ }
695
+ return staticEval(node.getBody(), { ...context, ...parameters });
696
+ };
697
+ },
698
+ [import_ts_morph2.SyntaxKind.Block]: (node, context) => {
699
+ for (const statement of node.getStatements()) {
700
+ return staticEval(statement, context);
701
+ }
702
+ },
703
+ [import_ts_morph2.SyntaxKind.CaseClause]: (node, context) => {
704
+ const statements = node.getStatements();
705
+ if (statements.length !== 1) {
706
+ console.error(node.getText());
707
+ throw new Error(`Can only handle code blocks with 1 statement.`);
708
+ }
709
+ return staticEval(statements[0], context);
710
+ },
711
+ [import_ts_morph2.SyntaxKind.DefaultClause]: (node, context) => {
712
+ const statements = node.getStatements();
713
+ if (statements.length !== 1) {
714
+ console.error(node.getText());
715
+ throw new Error(`Can only handle code blocks with exactly 1 statement.`);
716
+ }
717
+ return staticEval(statements[0], context);
718
+ },
719
+ [import_ts_morph2.SyntaxKind.ReturnStatement]: (node, context) => {
720
+ return staticEval(node.getExpression(), context);
721
+ },
722
+ [import_ts_morph2.SyntaxKind.SwitchStatement]: (node, context) => {
723
+ const value2 = staticEval(node.getExpression(), context);
724
+ let active = false;
725
+ for (const clause of node.getCaseBlock().getClauses()) {
726
+ switch (clause.getKind()) {
727
+ case import_ts_morph2.SyntaxKind.DefaultClause:
728
+ return staticEval(clause, context);
729
+ case import_ts_morph2.SyntaxKind.CaseClause: {
730
+ const caseClause = clause.asKindOrThrow(import_ts_morph2.SyntaxKind.CaseClause);
731
+ if (caseClause.getStatements().length && active) {
732
+ return staticEval(clause, context);
733
+ }
734
+ const caseValue = staticEval(caseClause.getExpression(), context);
735
+ if (value2 === caseValue) {
736
+ active = true;
737
+ if (caseClause.getStatements().length) {
738
+ return staticEval(clause, context);
739
+ }
740
+ }
741
+ }
742
+ }
743
+ }
744
+ },
745
+ [import_ts_morph2.SyntaxKind.Parameter]: (node, context) => context[node.getName()],
746
+ [import_ts_morph2.SyntaxKind.BinaryExpression]: (node, context) => {
747
+ switch (node.getOperatorToken().getKind()) {
748
+ case import_ts_morph2.SyntaxKind.EqualsEqualsEqualsToken:
749
+ return staticEval(node.getLeft(), context) === staticEval(node.getRight(), context);
750
+ case import_ts_morph2.SyntaxKind.BarBarToken:
751
+ return staticEval(node.getLeft(), context) || staticEval(node.getRight(), context);
752
+ default:
753
+ throw new Error(`Cannot handle operator of kind ${node.getOperatorToken().getKindName()}`);
754
+ }
755
+ },
756
+ [import_ts_morph2.SyntaxKind.SatisfiesExpression]: (node, context) => staticEval(node.getExpression(), context),
757
+ [import_ts_morph2.SyntaxKind.TemplateExpression]: (node, context) => node.getHead().getLiteralText() + node.getTemplateSpans().map((span) => staticEval(span.getExpression(), context) + staticEval(span.getLiteral(), context)).join(""),
758
+ [import_ts_morph2.SyntaxKind.TemplateTail]: (node) => node.getLiteralText(),
759
+ [import_ts_morph2.SyntaxKind.TemplateMiddle]: (node) => node.getLiteralText(),
760
+ [import_ts_morph2.SyntaxKind.PrefixUnaryExpression]: (node, context) => {
761
+ switch (node.getOperatorToken()) {
762
+ case import_ts_morph2.SyntaxKind.PlusToken:
763
+ return +staticEval(node.getOperand(), context);
764
+ case import_ts_morph2.SyntaxKind.MinusToken:
765
+ return -staticEval(node.getOperand(), context);
766
+ case import_ts_morph2.SyntaxKind.TildeToken:
767
+ return ~staticEval(node.getOperand(), context);
768
+ case import_ts_morph2.SyntaxKind.ExclamationToken:
769
+ return !staticEval(node.getOperand(), context);
770
+ case import_ts_morph2.SyntaxKind.PlusPlusToken:
771
+ case import_ts_morph2.SyntaxKind.MinusMinusToken:
772
+ throw new Error(`Cannot handle assignments.`);
773
+ }
774
+ },
775
+ [import_ts_morph2.SyntaxKind.ElementAccessExpression]: (node, context) => {
776
+ const target = staticEval(node.getExpression(), context);
777
+ const argument = staticEval(node.getArgumentExpression(), context);
778
+ return target[argument];
779
+ },
780
+ [import_ts_morph2.SyntaxKind.NoSubstitutionTemplateLiteral]: (node) => node.getLiteralValue()
781
+ };
782
+
783
+ // src/gqm/utils.ts
784
+ var import_ts_morph3 = require("ts-morph");
785
+ var findDeclarationInFile = (sourceFile, name2) => {
786
+ const syntaxList = sourceFile.getChildrenOfKind(import_ts_morph3.SyntaxKind.SyntaxList)[0];
787
+ if (!syntaxList) {
788
+ throw new Error("No SyntaxList");
789
+ }
790
+ const declaration = findDeclaration(syntaxList, name2);
791
+ if (!declaration) {
792
+ throw new Error(`No ${name2} declaration`);
793
+ }
794
+ return declaration;
795
+ };
796
+ var findDeclaration = (syntaxList, name2) => {
797
+ for (const variableStatement of syntaxList.getChildrenOfKind(import_ts_morph3.SyntaxKind.VariableStatement)) {
798
+ for (const declaration of variableStatement.getDeclarationList().getDeclarations()) {
799
+ if (declaration.getName() === name2) {
800
+ return declaration;
801
+ }
802
+ }
803
+ }
804
+ };
805
+
806
+ // src/gqm/parse-knexfile.ts
807
+ var KNEXFILE_PATH = `knexfile.ts`;
808
+ var parseKnexfile = async () => {
809
+ const project = new import_ts_morph4.Project({
810
+ manipulationSettings: {
811
+ indentationText: import_ts_morph4.IndentationText.TwoSpaces
812
+ }
813
+ });
814
+ ensureFileExists(KNEXFILE_PATH, KNEXFILE);
815
+ const sourceFile = project.addSourceFileAtPath(KNEXFILE_PATH);
816
+ const configDeclaration = findDeclarationInFile(sourceFile, "config");
817
+ const config2 = staticEval(configDeclaration, {});
818
+ return config2;
819
+ };
820
+
821
+ // src/gqm/parse-models.ts
822
+ var import_ts_morph5 = require("ts-morph");
823
+ var parseModels = async () => {
824
+ const project = new import_ts_morph5.Project({
825
+ manipulationSettings: {
826
+ indentationText: import_ts_morph5.IndentationText.TwoSpaces
827
+ }
828
+ });
829
+ const modelsPath = await getSetting("modelsPath");
830
+ const sourceFile = project.addSourceFileAtPath(modelsPath);
831
+ const modelsDeclaration = findDeclarationInFile(sourceFile, "rawModels");
832
+ const rawModels = staticEval(modelsDeclaration, {});
833
+ const generatedFolderPath = await getSetting("generatedFolderPath");
834
+ writeToFile(`${generatedFolderPath}/models.json`, JSON.stringify(rawModels, null, 2));
835
+ return rawModels;
836
+ };
837
+
838
+ // src/migrations/generate.ts
839
+ var import_code_block_writer2 = __toESM(require("code-block-writer"), 1);
840
+ var import_knex_schema_inspector = require("knex-schema-inspector");
841
+ var import_lowerFirst = __toESM(require("lodash/lowerFirst"), 1);
842
+ var MigrationGenerator = class {
843
+ constructor(knex2, rawModels) {
844
+ this.rawModels = rawModels;
845
+ this.schema = (0, import_knex_schema_inspector.SchemaInspector)(knex2);
846
+ this.models = getModels(rawModels);
847
+ }
848
+ writer = new import_code_block_writer2.default["default"]({
849
+ useSingleQuote: true,
850
+ indentNumberOfSpaces: 2
851
+ });
852
+ schema;
853
+ columns = {};
854
+ uuidUsed;
855
+ nowUsed;
856
+ models;
857
+ async generate() {
858
+ const { writer, schema, rawModels, models } = this;
859
+ const enums = (await schema.knex("pg_type").where({ typtype: "e" }).select("typname")).map(({ typname }) => typname);
860
+ const tables = await schema.tables();
861
+ for (const table of tables) {
862
+ this.columns[table] = await schema.columnInfo(table);
863
+ }
864
+ const up = [];
865
+ const down = [];
866
+ this.createEnums(
867
+ rawModels.filter(isEnumModel).filter((enm2) => !enums.includes((0, import_lowerFirst.default)(enm2.name))),
868
+ up,
869
+ down
870
+ );
871
+ for (const model of models) {
872
+ if (model.deleted) {
873
+ up.push(() => {
874
+ this.dropTable(model.name);
875
+ });
876
+ down.push(() => {
877
+ this.createTable(model.name, () => {
878
+ for (const field of model.fields) {
879
+ this.column(field);
880
+ }
881
+ });
882
+ });
883
+ if (model.updatable) {
884
+ up.push(() => {
885
+ this.dropTable(`${model.name}Revision`);
886
+ });
887
+ down.push(() => {
888
+ this.createRevisionTable(model);
889
+ });
890
+ }
891
+ }
892
+ if (model.oldName) {
893
+ up.push(() => {
894
+ this.renameTable(model.oldName, model.name);
895
+ });
896
+ down.push(() => {
897
+ this.renameTable(model.name, model.oldName);
898
+ });
899
+ tables[tables.indexOf(model.oldName)] = model.name;
900
+ this.columns[model.name] = this.columns[model.oldName];
901
+ delete this.columns[model.oldName];
902
+ if (model.updatable) {
903
+ up.push(() => {
904
+ this.renameTable(`${model.oldName}Revision`, `${model.name}Revision`);
905
+ this.alterTable(`${model.name}Revision`, () => {
906
+ this.renameColumn(`${typeToField(get(model, "oldName"))}Id`, `${typeToField(model.name)}Id`);
907
+ });
908
+ });
909
+ down.push(() => {
910
+ this.renameTable(`${model.name}Revision`, `${model.oldName}Revision`);
911
+ this.alterTable(`${model.oldName}Revision`, () => {
912
+ this.renameColumn(`${typeToField(model.name)}Id`, `${typeToField(get(model, "oldName"))}Id`);
913
+ });
914
+ });
915
+ tables[tables.indexOf(`${model.oldName}Revision`)] = `${model.name}Revision`;
916
+ this.columns[`${model.name}Revision`] = this.columns[`${model.oldName}Revision`];
917
+ delete this.columns[`${model.oldName}Revision`];
918
+ }
919
+ }
920
+ if (!tables.includes(model.name)) {
921
+ up.push(() => {
922
+ this.createTable(model.name, () => {
923
+ for (const field of model.fields) {
924
+ this.column(field);
925
+ }
926
+ });
927
+ });
928
+ down.push(() => {
929
+ this.dropTable(model.name);
930
+ });
931
+ } else {
932
+ this.renameFields(
933
+ model,
934
+ model.fields.filter(({ oldName }) => oldName),
935
+ up,
936
+ down
937
+ );
938
+ this.createFields(
939
+ model,
940
+ model.fields.filter(
941
+ ({ name: name2, ...field }) => field.kind !== "custom" && !this.columns[model.name].some(
942
+ (col) => col.name === (field.kind === "relation" ? field.foreignKey || `${name2}Id` : name2)
943
+ )
944
+ ),
945
+ up,
946
+ down
947
+ );
948
+ const existingFields = model.fields.filter(({ name: name2, kind, nonNull: nonNull2 }) => {
949
+ const col = this.columns[model.name].find((col2) => col2.name === (kind === "relation" ? `${name2}Id` : name2));
950
+ if (!col) {
951
+ return false;
952
+ }
953
+ return !nonNull2 && !col.is_nullable;
954
+ });
955
+ this.updateFields(model, existingFields, up, down);
956
+ }
957
+ if (model.updatable) {
958
+ if (!tables.includes(`${model.name}Revision`)) {
959
+ up.push(() => {
960
+ this.createRevisionTable(model);
961
+ });
962
+ if (tables.includes(model.name)) {
963
+ up.push(() => {
964
+ writer.block(() => {
965
+ writer.writeLine(`const data = await knex('${model.name}');`);
966
+ writer.write(`if (data.length)`).block(() => {
967
+ writer.write(`await knex.batchInsert('${model.name}Revision', data.map((row) => (`).inlineBlock(() => {
968
+ writer.writeLine(`id: uuid(),`);
969
+ writer.writeLine(`${typeToField(model.name)}Id: row.id,`);
970
+ this.nowUsed = true;
971
+ writer.writeLine(`createdAt: row.updatedAt || row.createdAt || now,`);
972
+ writer.writeLine(`createdById: row.updatedById || row.createdById,`);
973
+ if (model.deletable) {
974
+ writer.writeLine(`deleted: row.deleted,`);
975
+ }
976
+ for (const { name: name2, kind } of model.fields.filter(({ updatable }) => updatable)) {
977
+ const col = kind === "relation" ? `${name2}Id` : name2;
978
+ writer.writeLine(`${col}: row.${col},`);
979
+ }
980
+ }).write(")));").newLine();
981
+ });
982
+ }).blankLine();
983
+ });
984
+ }
985
+ down.push(() => {
986
+ this.dropTable(`${model.name}Revision`);
987
+ });
988
+ } else {
989
+ const revisionTable = `${model.name}Revision`;
990
+ const missingRevisionFields = model.fields.filter(
991
+ ({ name: name2, updatable, ...field }) => field.kind !== "custom" && updatable && !this.columns[revisionTable].some(
992
+ (col) => col.name === (field.kind === "relation" ? field.foreignKey || `${name2}Id` : name2)
993
+ )
994
+ );
995
+ this.createRevisionFields(model, missingRevisionFields, up, down);
996
+ const revisionFieldsToRemove = model.fields.filter(
997
+ ({ name: name2, updatable, generated, ...field }) => !generated && field.kind !== "custom" && !updatable && !(field.kind === "relation" && field.foreignKey === "id") && this.columns[revisionTable].some(
998
+ (col) => col.name === (field.kind === "relation" ? field.foreignKey || `${name2}Id` : name2)
999
+ )
1000
+ );
1001
+ this.createRevisionFields(model, revisionFieldsToRemove, down, up);
1002
+ }
1003
+ }
1004
+ }
1005
+ for (const model of getModels(rawModels)) {
1006
+ if (tables.includes(model.name)) {
1007
+ this.createFields(
1008
+ model,
1009
+ model.fields.filter(({ name: name2, deleted }) => deleted && this.columns[model.name].some((col) => col.name === name2)),
1010
+ down,
1011
+ up
1012
+ );
1013
+ if (model.updatable) {
1014
+ this.createRevisionFields(
1015
+ model,
1016
+ model.fields.filter(({ deleted, updatable }) => updatable && deleted),
1017
+ down,
1018
+ up
1019
+ );
1020
+ }
1021
+ }
1022
+ }
1023
+ this.createEnums(
1024
+ rawModels.filter(isEnumModel).filter((enm2) => enm2.deleted),
1025
+ down,
1026
+ up
1027
+ );
1028
+ writer.writeLine(`import { Knex } from 'knex';`);
1029
+ if (this.uuidUsed) {
1030
+ writer.writeLine(`import { v4 as uuid } from 'uuid';`);
1031
+ }
1032
+ if (this.nowUsed) {
1033
+ writer.writeLine(`import { date } from '../src/utils/dates';`);
1034
+ }
1035
+ writer.blankLine();
1036
+ if (this.nowUsed) {
1037
+ writer.writeLine(`const now = date();`).blankLine();
1038
+ }
1039
+ this.migration("up", up);
1040
+ this.migration("down", down.reverse());
1041
+ return writer.toString();
1042
+ }
1043
+ renameFields(model, fields2, up, down) {
1044
+ if (!fields2.length) {
1045
+ return;
1046
+ }
1047
+ up.push(() => {
1048
+ for (const field of fields2) {
1049
+ this.alterTable(model.name, () => {
1050
+ this.renameColumn(
1051
+ field.kind === "relation" ? `${field.oldName}Id` : get(field, "oldName"),
1052
+ field.kind === "relation" ? `${field.name}Id` : field.name
1053
+ );
1054
+ });
1055
+ }
1056
+ });
1057
+ down.push(() => {
1058
+ for (const field of fields2) {
1059
+ this.alterTable(model.name, () => {
1060
+ this.renameColumn(
1061
+ field.kind === "relation" ? `${field.name}Id` : field.name,
1062
+ field.kind === "relation" ? `${field.oldName}Id` : get(field, "oldName")
1063
+ );
1064
+ });
1065
+ }
1066
+ });
1067
+ for (const field of fields2) {
1068
+ summonByName(this.columns[model.name], field.kind === "relation" ? `${field.oldName}Id` : field.oldName).name = field.kind === "relation" ? `${field.name}Id` : field.name;
1069
+ }
1070
+ }
1071
+ createFields(model, fields2, up, down) {
1072
+ if (!fields2.length) {
1073
+ return;
1074
+ }
1075
+ up.push(() => {
1076
+ const alter = [];
1077
+ const updates = [];
1078
+ const postAlter = [];
1079
+ for (const field of fields2) {
1080
+ alter.push(() => this.column(field, { setNonNull: field.defaultValue !== void 0 }));
1081
+ if (field.nonNull && field.defaultValue === void 0) {
1082
+ updates.push(() => this.writer.write(`${field.name}: 'TODO',`).newLine());
1083
+ postAlter.push(() => this.column(field, { alter: true, foreign: false }));
1084
+ }
1085
+ }
1086
+ if (alter.length) {
1087
+ this.alterTable(model.name, () => {
1088
+ alter.map((cb) => cb());
1089
+ });
1090
+ }
1091
+ if (updates.length) {
1092
+ this.writer.write(`await knex('${model.name}').update(`).inlineBlock(() => {
1093
+ updates.map((cb) => cb());
1094
+ }).write(");").newLine().blankLine();
1095
+ }
1096
+ if (postAlter.length) {
1097
+ this.alterTable(model.name, () => {
1098
+ postAlter.map((cb) => cb());
1099
+ });
1100
+ }
1101
+ });
1102
+ down.push(() => {
1103
+ this.alterTable(model.name, () => {
1104
+ for (const { kind, name: name2 } of fields2) {
1105
+ this.dropColumn(kind === "relation" ? `${name2}Id` : name2);
1106
+ }
1107
+ });
1108
+ });
1109
+ }
1110
+ updateFields(model, fields2, up, down) {
1111
+ if (!fields2.length) {
1112
+ return;
1113
+ }
1114
+ up.push(() => {
1115
+ this.alterTable(model.name, () => {
1116
+ for (const field of fields2) {
1117
+ this.column(field, { alter: true });
1118
+ }
1119
+ });
1120
+ });
1121
+ down.push(() => {
1122
+ this.alterTable(model.name, () => {
1123
+ for (const field of fields2) {
1124
+ this.column(
1125
+ field,
1126
+ { alter: true },
1127
+ summonByName(this.columns[model.name], field.kind === "relation" ? `${field.name}Id` : field.name)
1128
+ );
1129
+ }
1130
+ });
1131
+ });
1132
+ if (model.updatable) {
1133
+ const updatableFields = fields2.filter(({ updatable }) => updatable);
1134
+ if (!updatableFields.length) {
1135
+ return;
1136
+ }
1137
+ up.push(() => {
1138
+ this.alterTable(`${model.name}Revision`, () => {
1139
+ for (const field of updatableFields) {
1140
+ this.column(field, { alter: true });
1141
+ }
1142
+ });
1143
+ });
1144
+ down.push(() => {
1145
+ this.alterTable(`${model.name}Revision`, () => {
1146
+ for (const field of updatableFields) {
1147
+ this.column(
1148
+ field,
1149
+ { alter: true },
1150
+ summonByName(this.columns[model.name], field.kind === "relation" ? `${field.name}Id` : field.name)
1151
+ );
1152
+ }
1153
+ });
1154
+ });
1155
+ }
1156
+ }
1157
+ createRevisionTable(model) {
1158
+ const writer = this.writer;
1159
+ this.createTable(`${model.name}Revision`, () => {
1160
+ writer.writeLine(`table.uuid('id').notNullable().primary();`);
1161
+ writer.writeLine(`table.uuid('${typeToField(model.name)}Id').notNullable();`);
1162
+ writer.write(`table.uuid('createdById')`);
1163
+ writer.write(".notNullable()");
1164
+ writer.write(";").newLine();
1165
+ writer.writeLine(`table.timestamp('createdAt').notNullable().defaultTo(knex.fn.now(0));`);
1166
+ if (model.deletable) {
1167
+ writer.writeLine(`table.boolean('deleted').notNullable();`);
1168
+ }
1169
+ for (const field of model.fields.filter((field2) => field2.updatable)) {
1170
+ this.column(field, { setUnique: false, setDefault: false });
1171
+ }
1172
+ });
1173
+ }
1174
+ createRevisionFields(model, missingRevisionFields, up, down) {
1175
+ const revisionTable = `${model.name}Revision`;
1176
+ if (missingRevisionFields.length) {
1177
+ up.push(() => {
1178
+ this.alterTable(revisionTable, () => {
1179
+ for (const field of missingRevisionFields) {
1180
+ this.column(field, { setUnique: false, setNonNull: false, setDefault: false });
1181
+ }
1182
+ });
1183
+ this.writer.write(`await knex('${model.name}Revision').update(`).inlineBlock(() => {
1184
+ for (const { name: name2, kind: type } of missingRevisionFields) {
1185
+ const col = type === "relation" ? `${name2}Id` : name2;
1186
+ this.writer.write(
1187
+ `${col}: knex.raw('(select "${col}" from "${model.name}" where "${model.name}".id = "${model.name}Revision"."${typeToField(model.name)}Id")'),`
1188
+ ).newLine();
1189
+ }
1190
+ }).write(");").newLine().blankLine();
1191
+ const nonNullableMissingRevisionFields = missingRevisionFields.filter(({ nonNull: nonNull2 }) => nonNull2);
1192
+ if (nonNullableMissingRevisionFields.length) {
1193
+ this.alterTable(revisionTable, () => {
1194
+ for (const field of nonNullableMissingRevisionFields) {
1195
+ this.column(field, { setUnique: false, setDefault: false, alter: true });
1196
+ }
1197
+ });
1198
+ }
1199
+ });
1200
+ down.push(() => {
1201
+ this.alterTable(revisionTable, () => {
1202
+ for (const field of missingRevisionFields) {
1203
+ this.dropColumn(field.kind === "relation" ? `${field.name}Id` : field.name);
1204
+ }
1205
+ });
1206
+ });
1207
+ }
1208
+ }
1209
+ createEnums(enums, up, down) {
1210
+ for (const enm2 of enums) {
1211
+ const name2 = (0, import_lowerFirst.default)(enm2.name);
1212
+ up.push(
1213
+ () => this.writer.writeLine(
1214
+ `await knex.raw(\`CREATE TYPE "${name2}" AS ENUM (${enm2.values.map((value2) => `'${value2}'`).join(",")})\`);`
1215
+ ).newLine()
1216
+ );
1217
+ down.push(() => this.writer.writeLine(`await knex.raw('DROP TYPE "${name2}"')`));
1218
+ }
1219
+ }
1220
+ migration(name2, cbs) {
1221
+ return this.writer.write(`export const ${name2} = async (knex: Knex) => `).inlineBlock(() => {
1222
+ cbs.map((cb) => cb());
1223
+ }).write(";").newLine().blankLine();
1224
+ }
1225
+ createTable(table, block) {
1226
+ return this.writer.write(`await knex.schema.createTable('${table}', (table) => `).inlineBlock(block).write(");").newLine().blankLine();
1227
+ }
1228
+ alterTable(table, block) {
1229
+ return this.writer.write(`await knex.schema.alterTable('${table}', (table) => `).inlineBlock(block).write(");").newLine().blankLine();
1230
+ }
1231
+ dropColumn(col) {
1232
+ return this.writer.writeLine(`table.dropColumn('${col}');`);
1233
+ }
1234
+ dropTable(table) {
1235
+ return this.writer.writeLine(`await knex.schema.dropTable('${table}');`).blankLine();
1236
+ }
1237
+ renameTable(from, to) {
1238
+ return this.writer.writeLine(`await knex.schema.renameTable('${from}', '${to}');`).blankLine();
1239
+ }
1240
+ renameColumn(from, to) {
1241
+ this.writer.writeLine(`table.renameColumn('${from}', '${to}')`);
1242
+ }
1243
+ value(value2) {
1244
+ if (typeof value2 === "string") {
1245
+ return `'${value2}'`;
1246
+ }
1247
+ return value2;
1248
+ }
1249
+ column({ name: name2, primary, list: list2, ...field }, { setUnique = true, setNonNull = true, alter = false, foreign = true, setDefault = true } = {}, toColumn) {
1250
+ const col = (what) => {
1251
+ if (what) {
1252
+ this.writer.write(what);
1253
+ }
1254
+ if (setNonNull) {
1255
+ if (toColumn) {
1256
+ if (toColumn.is_nullable) {
1257
+ this.writer.write(`.nullable()`);
1258
+ } else {
1259
+ this.writer.write(".notNullable()");
1260
+ }
1261
+ } else {
1262
+ if (field.nonNull) {
1263
+ this.writer.write(`.notNullable()`);
1264
+ } else {
1265
+ this.writer.write(".nullable()");
1266
+ }
1267
+ }
1268
+ }
1269
+ if (setDefault && field.defaultValue !== void 0) {
1270
+ this.writer.write(`.defaultTo(${this.value(field.defaultValue)})`);
1271
+ }
1272
+ if (primary) {
1273
+ this.writer.write(".primary()");
1274
+ } else if (setUnique && field.unique) {
1275
+ this.writer.write(".unique()");
1276
+ }
1277
+ if (alter) {
1278
+ this.writer.write(".alter()");
1279
+ }
1280
+ this.writer.write(";").newLine();
1281
+ };
1282
+ const kind = field.kind;
1283
+ switch (kind) {
1284
+ case void 0:
1285
+ case "primitive":
1286
+ switch (field.type) {
1287
+ case "Boolean":
1288
+ col(`table.boolean('${name2}')`);
1289
+ break;
1290
+ case "Int":
1291
+ col(`table.integer('${name2}')`);
1292
+ break;
1293
+ case "Float":
1294
+ if (field.double) {
1295
+ col(`table.double('${name2}')`);
1296
+ } else {
1297
+ col(`table.decimal('${name2}', ${get(field, "precision")}, ${get(field, "scale")})`);
1298
+ }
1299
+ break;
1300
+ case "String":
1301
+ if (field.large) {
1302
+ col(`table.text('${name2}')`);
1303
+ } else {
1304
+ col(`table.string('${name2}', ${field.maxLength})`);
1305
+ }
1306
+ break;
1307
+ case "DateTime":
1308
+ col(`table.timestamp('${name2}')`);
1309
+ break;
1310
+ case "ID":
1311
+ col(`table.uuid('${name2}')`);
1312
+ break;
1313
+ case "Upload":
1314
+ break;
1315
+ }
1316
+ break;
1317
+ case "relation":
1318
+ col(`table.uuid('${name2}Id')`);
1319
+ if (foreign && !alter) {
1320
+ this.writer.writeLine(`table.foreign('${name2}Id').references('id').inTable('${field.type}');`);
1321
+ }
1322
+ break;
1323
+ case "enum":
1324
+ if (list2) {
1325
+ this.writer.write(`table.specificType('${name2}', '"${typeToField(field.type)}"[]');`);
1326
+ } else {
1327
+ this.writer.write(`table.enum('${name2}', null as any, `).inlineBlock(() => {
1328
+ this.writer.writeLine(`useNative: true,`);
1329
+ this.writer.writeLine(`existingType: true,`);
1330
+ this.writer.writeLine(`enumName: '${typeToField(field.type)}',`);
1331
+ }).write(")");
1332
+ }
1333
+ col();
1334
+ break;
1335
+ case "json":
1336
+ this.writer.write(`table.json('${typeToField(field.type)}')`);
1337
+ break;
1338
+ case "custom":
1339
+ throw new Error("Custom fields aren't stored in the database");
1340
+ default: {
1341
+ const exhaustiveCheck = kind;
1342
+ throw new Error(exhaustiveCheck);
1343
+ }
1344
+ }
1345
+ }
1346
+ };
1347
+ var getMigrationDate = () => {
1348
+ const date = /* @__PURE__ */ new Date();
1349
+ const year = date.getFullYear();
1350
+ const month = String(date.getMonth() + 1).padStart(2, "0");
1351
+ const day = String(date.getDate()).padStart(2, "0");
1352
+ const hours = String(date.getHours()).padStart(2, "0");
1353
+ const minutes = String(date.getMinutes()).padStart(2, "0");
1354
+ const seconds = String(date.getSeconds()).padStart(2, "0");
1355
+ return `${year}${month}${day}${hours}${minutes}${seconds}`;
1356
+ };
1357
+
1358
+ // src/errors.ts
1359
+ var import_graphql2 = require("graphql");
1360
+
1361
+ // src/resolvers/utils.ts
1362
+ var import_graphql3 = require("graphql");
1363
+
1364
+ // src/resolvers/arguments.ts
1365
+ var import_graphql4 = require("graphql");
1366
+
1367
+ // src/resolvers/mutations.ts
1368
+ var import_uuid = require("uuid");
1369
+
1370
+ // src/resolvers/resolver.ts
1371
+ var import_cloneDeep = __toESM(require("lodash/cloneDeep"), 1);
1372
+ var import_flatMap = __toESM(require("lodash/flatMap"), 1);
1373
+
1374
+ // src/schema/generate.ts
1375
+ var import_graphql5 = require("graphql");
1376
+ var import_flatMap2 = __toESM(require("lodash/flatMap"), 1);
1377
+
1378
+ // src/schema/utils.ts
1379
+ var import_luxon = require("luxon");
1380
+
1381
+ // src/values.ts
1382
+ var Enum = class {
1383
+ constructor(value2) {
1384
+ this.value = value2;
1385
+ }
1386
+ };
1387
+
1388
+ // src/schema/utils.ts
1389
+ var document = (definitions) => ({
1390
+ kind: "Document",
1391
+ definitions
1392
+ });
1393
+ var scalar = (nme) => ({
1394
+ name: name(nme),
1395
+ kind: "ScalarTypeDefinition"
1396
+ });
1397
+ var input = (nme, fields2, dvs) => ({
1398
+ name: name(nme),
1399
+ fields: inputValues(fields2),
1400
+ kind: "InputObjectTypeDefinition",
1401
+ directives: directives(dvs)
1402
+ });
1403
+ var object = (nme, fds, interfaces, dvs) => ({
1404
+ name: name(nme),
1405
+ fields: fields(fds),
1406
+ kind: "ObjectTypeDefinition",
1407
+ interfaces: interfaces && interfaces.map((i) => namedType(i)),
1408
+ directives: directives(dvs)
1409
+ });
1410
+ var inputValues = (fields2) => fields2.map(
1411
+ (field) => ({
1412
+ kind: "InputValueDefinition",
1413
+ name: name(field.name),
1414
+ type: fieldType(field),
1415
+ defaultValue: field.defaultValue === void 0 ? void 0 : value(field.defaultValue),
1416
+ directives: directives(field.directives)
1417
+ })
1418
+ );
1419
+ var fields = (fields2) => fields2.map(
1420
+ (field) => ({
1421
+ kind: "FieldDefinition",
1422
+ name: name(field.name),
1423
+ type: fieldType(field),
1424
+ arguments: field.args?.map((arg) => ({
1425
+ kind: "InputValueDefinition",
1426
+ name: name(arg.name),
1427
+ type: fieldType(arg),
1428
+ defaultValue: arg.defaultValue === void 0 ? void 0 : value(arg.defaultValue)
1429
+ })),
1430
+ directives: directives(field.directives)
1431
+ })
1432
+ );
1433
+ var directives = (directives2) => directives2?.map(
1434
+ (directive) => ({
1435
+ kind: "Directive",
1436
+ name: name(directive.name),
1437
+ arguments: args(directive.values)
1438
+ })
1439
+ );
1440
+ var args = (ags) => ags?.map(
1441
+ (argument) => ({
1442
+ kind: "Argument",
1443
+ name: name(argument.name),
1444
+ value: value(argument.values)
1445
+ })
1446
+ );
1447
+ var enm = (nme, values) => ({
1448
+ name: name(nme),
1449
+ kind: "EnumTypeDefinition",
1450
+ values: values.map(
1451
+ (v) => ({
1452
+ kind: "EnumValueDefinition",
1453
+ name: name(v)
1454
+ })
1455
+ )
1456
+ });
1457
+ var nonNull = (type) => ({
1458
+ type,
1459
+ kind: "NonNullType"
1460
+ });
1461
+ var namedType = (nme) => ({
1462
+ kind: "NamedType",
1463
+ name: name(nme)
1464
+ });
1465
+ var list = (type) => ({
1466
+ type,
1467
+ kind: "ListType"
1468
+ });
1469
+ var name = (name2) => ({
1470
+ kind: "Name",
1471
+ value: name2
1472
+ });
1473
+ var fieldType = (field) => {
1474
+ let type = namedType(field.type);
1475
+ if (field.list) {
1476
+ type = list(nonNull(type));
1477
+ }
1478
+ if (field.nonNull) {
1479
+ type = nonNull(type);
1480
+ }
1481
+ return type;
1482
+ };
1483
+ var value = (val = null) => val === null ? {
1484
+ kind: "NullValue"
1485
+ } : typeof val === "boolean" ? {
1486
+ kind: "BooleanValue",
1487
+ value: val
1488
+ } : typeof val === "number" ? {
1489
+ kind: "IntValue",
1490
+ value: `${val}`
1491
+ } : typeof val === "string" ? {
1492
+ kind: "StringValue",
1493
+ value: val
1494
+ } : val instanceof Enum ? {
1495
+ kind: "EnumValue",
1496
+ value: val.value
1497
+ } : Array.isArray(val) ? {
1498
+ kind: "ListValue",
1499
+ values: val.map(value)
1500
+ } : val instanceof import_luxon.DateTime ? {
1501
+ kind: "StringValue",
1502
+ value: val.toString()
1503
+ } : {
1504
+ kind: "ObjectValue",
1505
+ fields: Object.keys(val).map(
1506
+ (nme) => ({
1507
+ kind: "ObjectField",
1508
+ name: name(nme),
1509
+ value: value(val[nme])
1510
+ })
1511
+ )
1512
+ };
1513
+
1514
+ // src/schema/generate.ts
1515
+ var generateDefinitions = (rawModels) => {
1516
+ const models = getModels(rawModels);
1517
+ return [
1518
+ // Predefined types
1519
+ enm("Order", ["ASC", "DESC"]),
1520
+ scalar("DateTime"),
1521
+ scalar("Upload"),
1522
+ ...rawModels.filter(isEnumModel).map((model) => enm(model.name, model.values)),
1523
+ ...rawModels.filter(isRawEnumModel).map((model) => enm(model.name, model.values)),
1524
+ ...rawModels.filter(isScalarModel).map((model) => scalar(model.name)),
1525
+ ...rawModels.filter(isObjectModel).filter(({ name: name2 }) => !["Query", "Mutation"].includes(name2)).map((model) => object(model.name, model.fields)),
1526
+ ...rawModels.filter(isInputModel).map((model) => input(model.name, model.fields)),
1527
+ ...rawModels.filter(isObjectModel).filter(
1528
+ (model) => models.some((m) => m.creatable && m.fields.some((f) => f.creatable && f.kind === "json" && f.type === model.name))
1529
+ ).map((model) => input(`Create${model.name}`, model.fields)),
1530
+ ...rawModels.filter(isObjectModel).filter(
1531
+ (model) => models.some((m) => m.creatable && m.fields.some((f) => f.creatable && f.kind === "json" && f.type === model.name))
1532
+ ).map((model) => input(`Update${model.name}`, model.fields)),
1533
+ ...(0, import_flatMap2.default)(
1534
+ models.map((model) => {
1535
+ const types = [
1536
+ object(
1537
+ model.name,
1538
+ [
1539
+ ...model.fields.filter(isQueriableField).map((field) => ({
1540
+ ...field,
1541
+ type: field.type,
1542
+ args: [...field.args || []],
1543
+ directives: field.directives
1544
+ })),
1545
+ ...model.reverseRelations.map(({ name: name2, field, model: model2 }) => ({
1546
+ name: name2,
1547
+ type: model2.name,
1548
+ list: !field.toOne,
1549
+ nonNull: !field.toOne,
1550
+ args: [
1551
+ { name: "where", type: `${model2.name}Where` },
1552
+ ...model2.fields.some(({ searchable }) => searchable) ? [{ name: "search", type: "String" }] : [],
1553
+ ...model2.fields.some(({ orderable }) => orderable) ? [{ name: "orderBy", type: `${model2.name}OrderBy`, list: true }] : [],
1554
+ { name: "limit", type: "Int" },
1555
+ { name: "offset", type: "Int" }
1556
+ ]
1557
+ }))
1558
+ ],
1559
+ model.interfaces
1560
+ ),
1561
+ input(`${model.name}Where`, [
1562
+ ...model.fields.filter(({ kind, unique, filterable }) => (unique || filterable) && kind !== "relation").map((field) => ({
1563
+ name: field.name,
1564
+ type: field.type,
1565
+ list: true,
1566
+ default: typeof field.filterable === "object" ? field.filterable.default : void 0
1567
+ })),
1568
+ ...(0, import_flatMap2.default)(
1569
+ model.fields.filter(({ comparable }) => comparable),
1570
+ (field) => [
1571
+ { name: `${field.name}_GT`, type: field.type },
1572
+ { name: `${field.name}_GTE`, type: field.type },
1573
+ { name: `${field.name}_LT`, type: field.type },
1574
+ { name: `${field.name}_LTE`, type: field.type }
1575
+ ]
1576
+ ),
1577
+ ...model.fields.filter(isRelation).filter(({ filterable }) => filterable).map(({ name: name2, type }) => ({
1578
+ name: name2,
1579
+ type: `${type}Where`
1580
+ }))
1581
+ ]),
1582
+ input(
1583
+ `${model.name}WhereUnique`,
1584
+ model.fields.filter(({ unique }) => unique).map((field) => ({ name: field.name, type: field.type }))
1585
+ ),
1586
+ ...model.fields.some(({ orderable }) => orderable) ? [
1587
+ input(
1588
+ `${model.name}OrderBy`,
1589
+ model.fields.filter(({ orderable }) => orderable).map(({ name: name2 }) => ({ name: name2, type: "Order" }))
1590
+ )
1591
+ ] : []
1592
+ ];
1593
+ if (model.creatable) {
1594
+ types.push(
1595
+ input(
1596
+ `Create${model.name}`,
1597
+ model.fields.filter(({ creatable }) => creatable).map(
1598
+ (field) => field.kind === "relation" ? { name: `${field.name}Id`, type: "ID", nonNull: field.nonNull } : {
1599
+ name: field.name,
1600
+ type: field.kind === "json" ? `Create${field.type}` : field.type,
1601
+ list: field.list,
1602
+ nonNull: field.nonNull && field.defaultValue === void 0
1603
+ }
1604
+ )
1605
+ )
1606
+ );
1607
+ }
1608
+ if (model.updatable) {
1609
+ types.push(
1610
+ input(
1611
+ `Update${model.name}`,
1612
+ model.fields.filter(({ updatable }) => updatable).map(
1613
+ (field) => field.kind === "relation" ? { name: `${field.name}Id`, type: "ID" } : {
1614
+ name: field.name,
1615
+ type: field.kind === "json" ? `Update${field.type}` : field.type,
1616
+ list: field.list
1617
+ }
1618
+ )
1619
+ )
1620
+ );
1621
+ }
1622
+ return types;
1623
+ })
1624
+ ),
1625
+ object("Query", [
1626
+ {
1627
+ name: "me",
1628
+ type: "User"
1629
+ },
1630
+ ...models.filter(({ queriable }) => queriable).map(({ name: name2 }) => ({
1631
+ name: typeToField(name2),
1632
+ type: name2,
1633
+ nonNull: true,
1634
+ args: [
1635
+ {
1636
+ name: "where",
1637
+ type: `${name2}WhereUnique`,
1638
+ nonNull: true
1639
+ }
1640
+ ]
1641
+ })),
1642
+ ...models.filter(({ listQueriable }) => listQueriable).map((model) => ({
1643
+ name: getModelPluralField(model),
1644
+ type: model.name,
1645
+ list: true,
1646
+ nonNull: true,
1647
+ args: [
1648
+ { name: "where", type: `${model.name}Where` },
1649
+ ...model.fields.some(({ searchable }) => searchable) ? [{ name: "search", type: "String" }] : [],
1650
+ ...model.fields.some(({ orderable }) => orderable) ? [{ name: "orderBy", type: `${model.name}OrderBy`, list: true }] : [],
1651
+ { name: "limit", type: "Int" },
1652
+ { name: "offset", type: "Int" }
1653
+ ]
1654
+ })),
1655
+ ...rawModels.filter(isObjectModel).filter((model) => model.name === "Query").flatMap((model) => model.fields)
1656
+ ]),
1657
+ object("Mutation", [
1658
+ ...(0, import_flatMap2.default)(
1659
+ models.map((model) => {
1660
+ const mutations = [];
1661
+ if (model.creatable) {
1662
+ mutations.push({
1663
+ name: `create${model.name}`,
1664
+ type: model.name,
1665
+ nonNull: true,
1666
+ args: [
1667
+ {
1668
+ name: "data",
1669
+ type: `Create${model.name}`,
1670
+ nonNull: true
1671
+ }
1672
+ ]
1673
+ });
1674
+ }
1675
+ if (model.updatable) {
1676
+ mutations.push({
1677
+ name: `update${model.name}`,
1678
+ type: model.name,
1679
+ nonNull: true,
1680
+ args: [
1681
+ {
1682
+ name: "where",
1683
+ type: `${model.name}WhereUnique`,
1684
+ nonNull: true
1685
+ },
1686
+ {
1687
+ name: "data",
1688
+ type: `Update${model.name}`,
1689
+ nonNull: true
1690
+ }
1691
+ ]
1692
+ });
1693
+ }
1694
+ if (model.deletable) {
1695
+ mutations.push({
1696
+ name: `delete${model.name}`,
1697
+ type: "ID",
1698
+ nonNull: true,
1699
+ args: [
1700
+ {
1701
+ name: "where",
1702
+ type: `${model.name}WhereUnique`,
1703
+ nonNull: true
1704
+ },
1705
+ {
1706
+ name: "dryRun",
1707
+ type: "Boolean"
1708
+ }
1709
+ ]
1710
+ });
1711
+ mutations.push({
1712
+ name: `restore${model.name}`,
1713
+ type: "ID",
1714
+ nonNull: true,
1715
+ args: [
1716
+ {
1717
+ name: "where",
1718
+ type: `${model.name}WhereUnique`,
1719
+ nonNull: true
1720
+ }
1721
+ ]
1722
+ });
1723
+ }
1724
+ return mutations;
1725
+ })
1726
+ ),
1727
+ ...rawModels.filter(isObjectModel).filter((model) => model.name === "Mutation").flatMap((model) => model.fields)
1728
+ ])
1729
+ ];
1730
+ };
1731
+ var generate = (rawModels) => document(generateDefinitions(rawModels));
1732
+ var printSchema = (schema) => [
1733
+ ...schema.getDirectives().map((d) => d.astNode && (0, import_graphql5.print)(d.astNode)),
1734
+ ...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))
1735
+ ].filter(Boolean).map((s) => `${s}
1736
+ `).join("\n");
1737
+ var printSchemaFromModels = (models) => printSchema((0, import_graphql5.buildASTSchema)(generate(models)));
1738
+
1739
+ // src/bin/gqm.ts
1740
+ (0, import_dotenv.config)({
1741
+ path: ".env"
1742
+ });
1743
+ (0, import_dotenv.config)({
1744
+ path: ".env.local"
1745
+ });
1746
+ import_commander.program.description("The graphql-magic cli.");
1747
+ import_commander.program.command("setup").description("Set up the project").action(async () => {
1748
+ await getSettings();
1749
+ ensureFileExists(KNEXFILE_PATH, KNEXFILE);
1750
+ });
1751
+ import_commander.program.command("generate").description("Generate all the things").action(async () => {
1752
+ const rawModels = await parseModels();
1753
+ const generatedFolderPath = await getSetting("generatedFolderPath");
1754
+ writeToFile(`${generatedFolderPath}/schema.graphql`, printSchemaFromModels(rawModels));
1755
+ writeToFile(`${generatedFolderPath}/client/mutations.ts`, generateMutations(rawModels));
1756
+ writeToFile(`${generatedFolderPath}/db/index.ts`, generateDBModels(rawModels));
1757
+ writeToFile(`${generatedFolderPath}/db/knex.ts`, generateKnexTables(rawModels));
1758
+ await generateGraphqlApiTypes();
1759
+ await generateGraphqlClientTypes();
1760
+ });
1761
+ import_commander.program.command("generate-models").description("Generate models.json").action(async () => {
1762
+ const rawModels = await parseModels();
1763
+ const generatedFolderPath = await getSetting("generatedFolderPath");
1764
+ writeToFile(`${generatedFolderPath}/models.json`, JSON.stringify(rawModels, null, 2));
1765
+ });
1766
+ import_commander.program.command("generate-schema").description("Generate schema").action(async () => {
1767
+ const rawModels = await parseModels();
1768
+ const generatedFolderPath = await getSetting("generatedFolderPath");
1769
+ writeToFile(`${generatedFolderPath}/schema.graphql`, printSchemaFromModels(rawModels));
1770
+ });
1771
+ import_commander.program.command("generate-mutation-queries").description("Generate mutation-queries").action(async () => {
1772
+ const rawModels = await parseModels();
1773
+ const generatedFolderPath = await getSetting("generatedFolderPath");
1774
+ writeToFile(`${generatedFolderPath}/client/mutations.ts`, generateMutations(rawModels));
1775
+ });
1776
+ import_commander.program.command("generate-db-types").description("Generate DB types").action(async () => {
1777
+ const rawModels = await parseModels();
1778
+ const generatedFolderPath = await getSetting("generatedFolderPath");
1779
+ writeToFile(`${generatedFolderPath}/db/index.ts`, generateMutations(rawModels));
1780
+ });
1781
+ import_commander.program.command("generate-knex-types").description("Generate Knex types").action(async () => {
1782
+ const rawModels = await parseModels();
1783
+ const generatedFolderPath = await getSetting("generatedFolderPath");
1784
+ writeToFile(`${generatedFolderPath}/db/knex.ts`, generateKnexTables(rawModels));
1785
+ });
1786
+ import_commander.program.command("generate-graphql-api-types").description("Generate Graphql API types").action(async () => {
1787
+ await generateGraphqlApiTypes();
1788
+ });
1789
+ import_commander.program.command("generate-graphql-client-types").description("Generate Graphql client types").action(async () => {
1790
+ await generateGraphqlClientTypes();
1791
+ });
1792
+ import_commander.program.command("generate-migration").description("Generate Migration").action(async () => {
1793
+ const git = (0, import_simple_git.simpleGit)();
1794
+ let name2 = process.argv[2] || (await git.branch()).current.split("/").pop();
1795
+ if (name2 && ["staging", "production"].includes(name2)) {
1796
+ name2 = await readLine("Migration name:");
1797
+ }
1798
+ const knexfile = await parseKnexfile();
1799
+ const db = (0, import_knex.default)(knexfile);
1800
+ try {
1801
+ const rawModels = await parseModels();
1802
+ const migrations = await new MigrationGenerator(db, rawModels).generate();
1803
+ writeToFile(`migrations/${getMigrationDate()}_${name2}.ts`, migrations);
1804
+ } finally {
1805
+ await db.destroy();
1806
+ }
1807
+ });
1808
+ import_commander.program.command("*", { noHelp: true }).description("Invalid command").action(() => {
1809
+ console.error("Invalid command: %s\nSee --help for a list of available commands.", import_commander.program.args.join(" "));
1810
+ process.exit(1);
1811
+ });
1812
+ import_commander.program.parse(process.argv);