@smartive/graphql-magic 8.1.0 → 8.1.2
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 +1 -1
- package/CHANGELOG.md +3 -3
- package/dist/bin/gqm.cjs +1099 -1099
- package/dist/cjs/index.cjs +2 -521
- package/dist/esm/index.d.ts +0 -1
- package/dist/esm/index.js +0 -1
- package/dist/esm/index.js.map +1 -1
- package/package.json +3 -3
- package/src/bin/{gqm.ts → gqm/gqm.ts} +8 -8
- package/src/{gqm → bin/gqm}/parse-models.ts +1 -1
- package/src/{gqm → bin/gqm}/visitor.ts +1 -1
- package/src/index.ts +0 -1
- package/tsconfig.eslint.json +4 -0
- package/tsconfig.json +1 -1
- package/dist/esm/bin/gqm.d.ts +0 -2
- package/dist/esm/bin/gqm.js +0 -121
- package/dist/esm/bin/gqm.js.map +0 -1
- package/dist/esm/gqm/codegen.d.ts +0 -2
- package/dist/esm/gqm/codegen.js +0 -46
- package/dist/esm/gqm/codegen.js.map +0 -1
- package/dist/esm/gqm/index.d.ts +0 -9
- package/dist/esm/gqm/index.js +0 -11
- package/dist/esm/gqm/index.js.map +0 -1
- package/dist/esm/gqm/parse-knexfile.d.ts +0 -2
- package/dist/esm/gqm/parse-knexfile.js +0 -19
- package/dist/esm/gqm/parse-knexfile.js.map +0 -1
- package/dist/esm/gqm/parse-models.d.ts +0 -2
- package/dist/esm/gqm/parse-models.js +0 -19
- package/dist/esm/gqm/parse-models.js.map +0 -1
- package/dist/esm/gqm/readline.d.ts +0 -1
- package/dist/esm/gqm/readline.js +0 -14
- package/dist/esm/gqm/readline.js.map +0 -1
- package/dist/esm/gqm/settings.d.ts +0 -9
- package/dist/esm/gqm/settings.js +0 -98
- package/dist/esm/gqm/settings.js.map +0 -1
- package/dist/esm/gqm/static-eval.d.ts +0 -3
- package/dist/esm/gqm/static-eval.js +0 -188
- package/dist/esm/gqm/static-eval.js.map +0 -1
- package/dist/esm/gqm/templates.d.ts +0 -4
- package/dist/esm/gqm/templates.js +0 -62
- package/dist/esm/gqm/templates.js.map +0 -1
- package/dist/esm/gqm/utils.d.ts +0 -2
- package/dist/esm/gqm/utils.js +0 -22
- package/dist/esm/gqm/utils.js.map +0 -1
- package/dist/esm/gqm/visitor.d.ts +0 -8
- package/dist/esm/gqm/visitor.js +0 -15
- package/dist/esm/gqm/visitor.js.map +0 -1
- package/src/gqm/index.ts +0 -11
- /package/src/{gqm → bin/gqm}/codegen.ts +0 -0
- /package/src/{gqm → bin/gqm}/parse-knexfile.ts +0 -0
- /package/src/{gqm → bin/gqm}/readline.ts +0 -0
- /package/src/{gqm → bin/gqm}/settings.ts +0 -0
- /package/src/{gqm → bin/gqm}/static-eval.ts +0 -0
- /package/src/{gqm → bin/gqm}/templates.ts +0 -0
- /package/src/{gqm → bin/gqm}/utils.ts +0 -0
package/dist/bin/gqm.cjs
CHANGED
|
@@ -22,7 +22,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
22
22
|
mod
|
|
23
23
|
));
|
|
24
24
|
|
|
25
|
-
// src/bin/gqm.ts
|
|
25
|
+
// src/bin/gqm/gqm.ts
|
|
26
26
|
var import_commander = require("commander");
|
|
27
27
|
var import_dotenv = require("dotenv");
|
|
28
28
|
var import_knex = __toESM(require("knex"), 1);
|
|
@@ -350,742 +350,257 @@ var generateKnexTables = (rawModels) => {
|
|
|
350
350
|
return writer.toString();
|
|
351
351
|
};
|
|
352
352
|
|
|
353
|
-
// src/
|
|
354
|
-
var
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
var
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
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}`);
|
|
353
|
+
// src/migrations/generate.ts
|
|
354
|
+
var import_code_block_writer2 = __toESM(require("code-block-writer"), 1);
|
|
355
|
+
var import_knex_schema_inspector = require("knex-schema-inspector");
|
|
356
|
+
var import_lowerFirst = __toESM(require("lodash/lowerFirst"), 1);
|
|
357
|
+
var MigrationGenerator = class {
|
|
358
|
+
constructor(knex2, rawModels) {
|
|
359
|
+
this.rawModels = rawModels;
|
|
360
|
+
this.schema = (0, import_knex_schema_inspector.SchemaInspector)(knex2);
|
|
361
|
+
this.models = getModels(rawModels);
|
|
526
362
|
}
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
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
|
-
}
|
|
363
|
+
writer = new import_code_block_writer2.default["default"]({
|
|
364
|
+
useSingleQuote: true,
|
|
365
|
+
indentNumberOfSpaces: 2
|
|
546
366
|
});
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
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
|
-
}
|
|
367
|
+
schema;
|
|
368
|
+
columns = {};
|
|
369
|
+
uuidUsed;
|
|
370
|
+
nowUsed;
|
|
371
|
+
models;
|
|
372
|
+
async generate() {
|
|
373
|
+
const { writer, schema, rawModels, models } = this;
|
|
374
|
+
const enums = (await schema.knex("pg_type").where({ typtype: "e" }).select("typname")).map(({ typname }) => typname);
|
|
375
|
+
const tables = await schema.tables();
|
|
376
|
+
for (const table of tables) {
|
|
377
|
+
this.columns[table] = await schema.columnInfo(table);
|
|
574
378
|
}
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
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));
|
|
379
|
+
const up = [];
|
|
380
|
+
const down = [];
|
|
381
|
+
this.createEnums(
|
|
382
|
+
rawModels.filter(isEnumModel).filter((enm2) => !enums.includes((0, import_lowerFirst.default)(enm2.name))),
|
|
383
|
+
up,
|
|
384
|
+
down
|
|
385
|
+
);
|
|
386
|
+
for (const model of models) {
|
|
387
|
+
if (model.deleted) {
|
|
388
|
+
up.push(() => {
|
|
389
|
+
this.dropTable(model.name);
|
|
390
|
+
});
|
|
391
|
+
down.push(() => {
|
|
392
|
+
this.createTable(model.name, () => {
|
|
393
|
+
for (const field of model.fields) {
|
|
394
|
+
this.column(field);
|
|
395
|
+
}
|
|
396
|
+
});
|
|
397
|
+
});
|
|
398
|
+
if (model.updatable) {
|
|
399
|
+
up.push(() => {
|
|
400
|
+
this.dropTable(`${model.name}Revision`);
|
|
401
|
+
});
|
|
402
|
+
down.push(() => {
|
|
403
|
+
this.createRevisionTable(model);
|
|
404
|
+
});
|
|
405
|
+
}
|
|
616
406
|
}
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
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);
|
|
407
|
+
if (model.oldName) {
|
|
408
|
+
up.push(() => {
|
|
409
|
+
this.renameTable(model.oldName, model.name);
|
|
410
|
+
});
|
|
411
|
+
down.push(() => {
|
|
412
|
+
this.renameTable(model.name, model.oldName);
|
|
413
|
+
});
|
|
414
|
+
tables[tables.indexOf(model.oldName)] = model.name;
|
|
415
|
+
this.columns[model.name] = this.columns[model.oldName];
|
|
416
|
+
delete this.columns[model.oldName];
|
|
417
|
+
if (model.updatable) {
|
|
418
|
+
up.push(() => {
|
|
419
|
+
this.renameTable(`${model.oldName}Revision`, `${model.name}Revision`);
|
|
420
|
+
this.alterTable(`${model.name}Revision`, () => {
|
|
421
|
+
this.renameColumn(`${typeToField(get(model, "oldName"))}Id`, `${typeToField(model.name)}Id`);
|
|
422
|
+
});
|
|
423
|
+
});
|
|
424
|
+
down.push(() => {
|
|
425
|
+
this.renameTable(`${model.name}Revision`, `${model.oldName}Revision`);
|
|
426
|
+
this.alterTable(`${model.oldName}Revision`, () => {
|
|
427
|
+
this.renameColumn(`${typeToField(model.name)}Id`, `${typeToField(get(model, "oldName"))}Id`);
|
|
428
|
+
});
|
|
429
|
+
});
|
|
430
|
+
tables[tables.indexOf(`${model.oldName}Revision`)] = `${model.name}Revision`;
|
|
431
|
+
this.columns[`${model.name}Revision`] = this.columns[`${model.oldName}Revision`];
|
|
432
|
+
delete this.columns[`${model.oldName}Revision`];
|
|
673
433
|
}
|
|
674
|
-
}
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
434
|
+
}
|
|
435
|
+
if (!tables.includes(model.name)) {
|
|
436
|
+
up.push(() => {
|
|
437
|
+
this.createTable(model.name, () => {
|
|
438
|
+
for (const field of model.fields) {
|
|
439
|
+
this.column(field);
|
|
440
|
+
}
|
|
441
|
+
});
|
|
442
|
+
});
|
|
443
|
+
down.push(() => {
|
|
444
|
+
this.dropTable(model.name);
|
|
445
|
+
});
|
|
446
|
+
} else {
|
|
447
|
+
this.renameFields(
|
|
448
|
+
model,
|
|
449
|
+
model.fields.filter(({ oldName }) => oldName),
|
|
450
|
+
up,
|
|
451
|
+
down
|
|
452
|
+
);
|
|
453
|
+
this.createFields(
|
|
454
|
+
model,
|
|
455
|
+
model.fields.filter(
|
|
456
|
+
({ name: name2, ...field }) => field.kind !== "custom" && !this.columns[model.name].some(
|
|
457
|
+
(col) => col.name === (field.kind === "relation" ? field.foreignKey || `${name2}Id` : name2)
|
|
458
|
+
)
|
|
459
|
+
),
|
|
460
|
+
up,
|
|
461
|
+
down
|
|
462
|
+
);
|
|
463
|
+
const existingFields = model.fields.filter(({ name: name2, kind, nonNull: nonNull2 }) => {
|
|
464
|
+
const col = this.columns[model.name].find((col2) => col2.name === (kind === "relation" ? `${name2}Id` : name2));
|
|
465
|
+
if (!col) {
|
|
466
|
+
return false;
|
|
467
|
+
}
|
|
468
|
+
return !nonNull2 && !col.is_nullable;
|
|
469
|
+
});
|
|
470
|
+
this.updateFields(model, existingFields, up, down);
|
|
471
|
+
}
|
|
472
|
+
if (model.updatable) {
|
|
473
|
+
if (!tables.includes(`${model.name}Revision`)) {
|
|
474
|
+
up.push(() => {
|
|
475
|
+
this.createRevisionTable(model);
|
|
476
|
+
});
|
|
477
|
+
if (tables.includes(model.name)) {
|
|
478
|
+
up.push(() => {
|
|
479
|
+
writer.block(() => {
|
|
480
|
+
writer.writeLine(`const data = await knex('${model.name}');`);
|
|
481
|
+
writer.write(`if (data.length)`).block(() => {
|
|
482
|
+
writer.write(`await knex.batchInsert('${model.name}Revision', data.map((row) => (`).inlineBlock(() => {
|
|
483
|
+
writer.writeLine(`id: uuid(),`);
|
|
484
|
+
writer.writeLine(`${typeToField(model.name)}Id: row.id,`);
|
|
485
|
+
this.nowUsed = true;
|
|
486
|
+
writer.writeLine(`createdAt: row.updatedAt || row.createdAt || now,`);
|
|
487
|
+
writer.writeLine(`createdById: row.updatedById || row.createdById,`);
|
|
488
|
+
if (model.deletable) {
|
|
489
|
+
writer.writeLine(`deleted: row.deleted,`);
|
|
490
|
+
}
|
|
491
|
+
for (const { name: name2, kind } of model.fields.filter(({ updatable }) => updatable)) {
|
|
492
|
+
const col = kind === "relation" ? `${name2}Id` : name2;
|
|
493
|
+
writer.writeLine(`${col}: row.${col},`);
|
|
494
|
+
}
|
|
495
|
+
}).write(")));").newLine();
|
|
496
|
+
});
|
|
497
|
+
}).blankLine();
|
|
498
|
+
});
|
|
499
|
+
}
|
|
500
|
+
down.push(() => {
|
|
501
|
+
this.dropTable(`${model.name}Revision`);
|
|
502
|
+
});
|
|
503
|
+
} else {
|
|
504
|
+
const revisionTable = `${model.name}Revision`;
|
|
505
|
+
const missingRevisionFields = model.fields.filter(
|
|
506
|
+
({ name: name2, updatable, ...field }) => field.kind !== "custom" && updatable && !this.columns[revisionTable].some(
|
|
507
|
+
(col) => col.name === (field.kind === "relation" ? field.foreignKey || `${name2}Id` : name2)
|
|
508
|
+
)
|
|
509
|
+
);
|
|
510
|
+
this.createRevisionFields(model, missingRevisionFields, up, down);
|
|
511
|
+
const revisionFieldsToRemove = model.fields.filter(
|
|
512
|
+
({ name: name2, updatable, generated, ...field }) => !generated && field.kind !== "custom" && !updatable && !(field.kind === "relation" && field.foreignKey === "id") && this.columns[revisionTable].some(
|
|
513
|
+
(col) => col.name === (field.kind === "relation" ? field.foreignKey || `${name2}Id` : name2)
|
|
514
|
+
)
|
|
515
|
+
);
|
|
516
|
+
this.createRevisionFields(model, revisionFieldsToRemove, down, up);
|
|
681
517
|
}
|
|
682
518
|
}
|
|
683
|
-
throw new Error(`Cannot handle method ${node.getName()} on type ${typeof target}`);
|
|
684
519
|
}
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
520
|
+
for (const model of getModels(rawModels)) {
|
|
521
|
+
if (tables.includes(model.name)) {
|
|
522
|
+
this.createFields(
|
|
523
|
+
model,
|
|
524
|
+
model.fields.filter(({ name: name2, deleted }) => deleted && this.columns[model.name].some((col) => col.name === name2)),
|
|
525
|
+
down,
|
|
526
|
+
up
|
|
527
|
+
);
|
|
528
|
+
if (model.updatable) {
|
|
529
|
+
this.createRevisionFields(
|
|
530
|
+
model,
|
|
531
|
+
model.fields.filter(({ deleted, updatable }) => updatable && deleted),
|
|
532
|
+
down,
|
|
533
|
+
up
|
|
534
|
+
);
|
|
535
|
+
}
|
|
694
536
|
}
|
|
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
537
|
}
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
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()}`);
|
|
538
|
+
this.createEnums(
|
|
539
|
+
rawModels.filter(isEnumModel).filter((enm2) => enm2.deleted),
|
|
540
|
+
down,
|
|
541
|
+
up
|
|
542
|
+
);
|
|
543
|
+
writer.writeLine(`import { Knex } from 'knex';`);
|
|
544
|
+
if (this.uuidUsed) {
|
|
545
|
+
writer.writeLine(`import { v4 as uuid } from 'uuid';`);
|
|
754
546
|
}
|
|
755
|
-
|
|
756
|
-
|
|
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.`);
|
|
547
|
+
if (this.nowUsed) {
|
|
548
|
+
writer.writeLine(`import { date } from '../src/utils/dates';`);
|
|
773
549
|
}
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
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
|
-
}
|
|
550
|
+
writer.blankLine();
|
|
551
|
+
if (this.nowUsed) {
|
|
552
|
+
writer.writeLine(`const now = date();`).blankLine();
|
|
802
553
|
}
|
|
554
|
+
this.migration("up", up);
|
|
555
|
+
this.migration("down", down.reverse());
|
|
556
|
+
return writer.toString();
|
|
803
557
|
}
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
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
|
|
558
|
+
renameFields(model, fields2, up, down) {
|
|
559
|
+
if (!fields2.length) {
|
|
560
|
+
return;
|
|
812
561
|
}
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
562
|
+
up.push(() => {
|
|
563
|
+
for (const field of fields2) {
|
|
564
|
+
this.alterTable(model.name, () => {
|
|
565
|
+
this.renameColumn(
|
|
566
|
+
field.kind === "relation" ? `${field.oldName}Id` : get(field, "oldName"),
|
|
567
|
+
field.kind === "relation" ? `${field.name}Id` : field.name
|
|
568
|
+
);
|
|
569
|
+
});
|
|
570
|
+
}
|
|
571
|
+
});
|
|
572
|
+
down.push(() => {
|
|
573
|
+
for (const field of fields2) {
|
|
574
|
+
this.alterTable(model.name, () => {
|
|
575
|
+
this.renameColumn(
|
|
576
|
+
field.kind === "relation" ? `${field.name}Id` : field.name,
|
|
577
|
+
field.kind === "relation" ? `${field.oldName}Id` : get(field, "oldName")
|
|
578
|
+
);
|
|
579
|
+
});
|
|
580
|
+
}
|
|
581
|
+
});
|
|
582
|
+
for (const field of fields2) {
|
|
583
|
+
summonByName(this.columns[model.name], field.kind === "relation" ? `${field.oldName}Id` : field.oldName).name = field.kind === "relation" ? `${field.name}Id` : field.name;
|
|
827
584
|
}
|
|
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
585
|
}
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
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);
|
|
586
|
+
createFields(model, fields2, up, down) {
|
|
587
|
+
if (!fields2.length) {
|
|
588
|
+
return;
|
|
863
589
|
}
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
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
|
-
});
|
|
590
|
+
up.push(() => {
|
|
591
|
+
const alter = [];
|
|
592
|
+
const updates = [];
|
|
593
|
+
const postAlter = [];
|
|
594
|
+
for (const field of fields2) {
|
|
595
|
+
alter.push(() => this.column(field, { setNonNull: field.defaultValue !== void 0 }));
|
|
596
|
+
if (field.nonNull && field.defaultValue === void 0) {
|
|
597
|
+
updates.push(() => this.writer.write(`${field.name}: 'TODO',`).newLine());
|
|
598
|
+
postAlter.push(() => this.column(field, { alter: true, foreign: false }));
|
|
890
599
|
}
|
|
891
600
|
}
|
|
892
|
-
if (
|
|
893
|
-
|
|
894
|
-
|
|
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());
|
|
601
|
+
if (alter.length) {
|
|
602
|
+
this.alterTable(model.name, () => {
|
|
603
|
+
alter.map((cb) => cb());
|
|
1089
604
|
});
|
|
1090
605
|
}
|
|
1091
606
|
if (updates.length) {
|
|
@@ -1344,399 +859,884 @@ var MigrationGenerator = class {
|
|
|
1344
859
|
}
|
|
1345
860
|
}
|
|
1346
861
|
};
|
|
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}`;
|
|
862
|
+
var getMigrationDate = () => {
|
|
863
|
+
const date = /* @__PURE__ */ new Date();
|
|
864
|
+
const year = date.getFullYear();
|
|
865
|
+
const month = String(date.getMonth() + 1).padStart(2, "0");
|
|
866
|
+
const day = String(date.getDate()).padStart(2, "0");
|
|
867
|
+
const hours = String(date.getHours()).padStart(2, "0");
|
|
868
|
+
const minutes = String(date.getMinutes()).padStart(2, "0");
|
|
869
|
+
const seconds = String(date.getSeconds()).padStart(2, "0");
|
|
870
|
+
return `${year}${month}${day}${hours}${minutes}${seconds}`;
|
|
871
|
+
};
|
|
872
|
+
|
|
873
|
+
// src/errors.ts
|
|
874
|
+
var import_graphql2 = require("graphql");
|
|
875
|
+
|
|
876
|
+
// src/resolvers/utils.ts
|
|
877
|
+
var import_graphql3 = require("graphql");
|
|
878
|
+
|
|
879
|
+
// src/resolvers/arguments.ts
|
|
880
|
+
var import_graphql4 = require("graphql");
|
|
881
|
+
|
|
882
|
+
// src/resolvers/mutations.ts
|
|
883
|
+
var import_uuid = require("uuid");
|
|
884
|
+
|
|
885
|
+
// src/resolvers/resolver.ts
|
|
886
|
+
var import_cloneDeep = __toESM(require("lodash/cloneDeep"), 1);
|
|
887
|
+
var import_flatMap = __toESM(require("lodash/flatMap"), 1);
|
|
888
|
+
|
|
889
|
+
// src/schema/generate.ts
|
|
890
|
+
var import_graphql5 = require("graphql");
|
|
891
|
+
var import_flatMap2 = __toESM(require("lodash/flatMap"), 1);
|
|
892
|
+
|
|
893
|
+
// src/schema/utils.ts
|
|
894
|
+
var import_luxon = require("luxon");
|
|
895
|
+
|
|
896
|
+
// src/values.ts
|
|
897
|
+
var Enum = class {
|
|
898
|
+
constructor(value2) {
|
|
899
|
+
this.value = value2;
|
|
900
|
+
}
|
|
901
|
+
};
|
|
902
|
+
|
|
903
|
+
// src/schema/utils.ts
|
|
904
|
+
var document = (definitions) => ({
|
|
905
|
+
kind: "Document",
|
|
906
|
+
definitions
|
|
907
|
+
});
|
|
908
|
+
var scalar = (nme) => ({
|
|
909
|
+
name: name(nme),
|
|
910
|
+
kind: "ScalarTypeDefinition"
|
|
911
|
+
});
|
|
912
|
+
var input = (nme, fields2, dvs) => ({
|
|
913
|
+
name: name(nme),
|
|
914
|
+
fields: inputValues(fields2),
|
|
915
|
+
kind: "InputObjectTypeDefinition",
|
|
916
|
+
directives: directives(dvs)
|
|
917
|
+
});
|
|
918
|
+
var object = (nme, fds, interfaces, dvs) => ({
|
|
919
|
+
name: name(nme),
|
|
920
|
+
fields: fields(fds),
|
|
921
|
+
kind: "ObjectTypeDefinition",
|
|
922
|
+
interfaces: interfaces && interfaces.map((i) => namedType(i)),
|
|
923
|
+
directives: directives(dvs)
|
|
924
|
+
});
|
|
925
|
+
var inputValues = (fields2) => fields2.map(
|
|
926
|
+
(field) => ({
|
|
927
|
+
kind: "InputValueDefinition",
|
|
928
|
+
name: name(field.name),
|
|
929
|
+
type: fieldType(field),
|
|
930
|
+
defaultValue: field.defaultValue === void 0 ? void 0 : value(field.defaultValue),
|
|
931
|
+
directives: directives(field.directives)
|
|
932
|
+
})
|
|
933
|
+
);
|
|
934
|
+
var fields = (fields2) => fields2.map(
|
|
935
|
+
(field) => ({
|
|
936
|
+
kind: "FieldDefinition",
|
|
937
|
+
name: name(field.name),
|
|
938
|
+
type: fieldType(field),
|
|
939
|
+
arguments: field.args?.map((arg) => ({
|
|
940
|
+
kind: "InputValueDefinition",
|
|
941
|
+
name: name(arg.name),
|
|
942
|
+
type: fieldType(arg),
|
|
943
|
+
defaultValue: arg.defaultValue === void 0 ? void 0 : value(arg.defaultValue)
|
|
944
|
+
})),
|
|
945
|
+
directives: directives(field.directives)
|
|
946
|
+
})
|
|
947
|
+
);
|
|
948
|
+
var directives = (directives2) => directives2?.map(
|
|
949
|
+
(directive) => ({
|
|
950
|
+
kind: "Directive",
|
|
951
|
+
name: name(directive.name),
|
|
952
|
+
arguments: args(directive.values)
|
|
953
|
+
})
|
|
954
|
+
);
|
|
955
|
+
var args = (ags) => ags?.map(
|
|
956
|
+
(argument) => ({
|
|
957
|
+
kind: "Argument",
|
|
958
|
+
name: name(argument.name),
|
|
959
|
+
value: value(argument.values)
|
|
960
|
+
})
|
|
961
|
+
);
|
|
962
|
+
var enm = (nme, values) => ({
|
|
963
|
+
name: name(nme),
|
|
964
|
+
kind: "EnumTypeDefinition",
|
|
965
|
+
values: values.map(
|
|
966
|
+
(v) => ({
|
|
967
|
+
kind: "EnumValueDefinition",
|
|
968
|
+
name: name(v)
|
|
969
|
+
})
|
|
970
|
+
)
|
|
971
|
+
});
|
|
972
|
+
var nonNull = (type) => ({
|
|
973
|
+
type,
|
|
974
|
+
kind: "NonNullType"
|
|
975
|
+
});
|
|
976
|
+
var namedType = (nme) => ({
|
|
977
|
+
kind: "NamedType",
|
|
978
|
+
name: name(nme)
|
|
979
|
+
});
|
|
980
|
+
var list = (type) => ({
|
|
981
|
+
type,
|
|
982
|
+
kind: "ListType"
|
|
983
|
+
});
|
|
984
|
+
var name = (name2) => ({
|
|
985
|
+
kind: "Name",
|
|
986
|
+
value: name2
|
|
987
|
+
});
|
|
988
|
+
var fieldType = (field) => {
|
|
989
|
+
let type = namedType(field.type);
|
|
990
|
+
if (field.list) {
|
|
991
|
+
type = list(nonNull(type));
|
|
992
|
+
}
|
|
993
|
+
if (field.nonNull) {
|
|
994
|
+
type = nonNull(type);
|
|
995
|
+
}
|
|
996
|
+
return type;
|
|
997
|
+
};
|
|
998
|
+
var value = (val = null) => val === null ? {
|
|
999
|
+
kind: "NullValue"
|
|
1000
|
+
} : typeof val === "boolean" ? {
|
|
1001
|
+
kind: "BooleanValue",
|
|
1002
|
+
value: val
|
|
1003
|
+
} : typeof val === "number" ? {
|
|
1004
|
+
kind: "IntValue",
|
|
1005
|
+
value: `${val}`
|
|
1006
|
+
} : typeof val === "string" ? {
|
|
1007
|
+
kind: "StringValue",
|
|
1008
|
+
value: val
|
|
1009
|
+
} : val instanceof Enum ? {
|
|
1010
|
+
kind: "EnumValue",
|
|
1011
|
+
value: val.value
|
|
1012
|
+
} : Array.isArray(val) ? {
|
|
1013
|
+
kind: "ListValue",
|
|
1014
|
+
values: val.map(value)
|
|
1015
|
+
} : val instanceof import_luxon.DateTime ? {
|
|
1016
|
+
kind: "StringValue",
|
|
1017
|
+
value: val.toString()
|
|
1018
|
+
} : {
|
|
1019
|
+
kind: "ObjectValue",
|
|
1020
|
+
fields: Object.keys(val).map(
|
|
1021
|
+
(nme) => ({
|
|
1022
|
+
kind: "ObjectField",
|
|
1023
|
+
name: name(nme),
|
|
1024
|
+
value: value(val[nme])
|
|
1025
|
+
})
|
|
1026
|
+
)
|
|
1027
|
+
};
|
|
1028
|
+
|
|
1029
|
+
// src/schema/generate.ts
|
|
1030
|
+
var generateDefinitions = (rawModels) => {
|
|
1031
|
+
const models = getModels(rawModels);
|
|
1032
|
+
return [
|
|
1033
|
+
// Predefined types
|
|
1034
|
+
enm("Order", ["ASC", "DESC"]),
|
|
1035
|
+
scalar("DateTime"),
|
|
1036
|
+
scalar("Upload"),
|
|
1037
|
+
...rawModels.filter(isEnumModel).map((model) => enm(model.name, model.values)),
|
|
1038
|
+
...rawModels.filter(isRawEnumModel).map((model) => enm(model.name, model.values)),
|
|
1039
|
+
...rawModels.filter(isScalarModel).map((model) => scalar(model.name)),
|
|
1040
|
+
...rawModels.filter(isObjectModel).filter(({ name: name2 }) => !["Query", "Mutation"].includes(name2)).map((model) => object(model.name, model.fields)),
|
|
1041
|
+
...rawModels.filter(isInputModel).map((model) => input(model.name, model.fields)),
|
|
1042
|
+
...rawModels.filter(isObjectModel).filter(
|
|
1043
|
+
(model) => models.some((m) => m.creatable && m.fields.some((f) => f.creatable && f.kind === "json" && f.type === model.name))
|
|
1044
|
+
).map((model) => input(`Create${model.name}`, model.fields)),
|
|
1045
|
+
...rawModels.filter(isObjectModel).filter(
|
|
1046
|
+
(model) => models.some((m) => m.creatable && m.fields.some((f) => f.creatable && f.kind === "json" && f.type === model.name))
|
|
1047
|
+
).map((model) => input(`Update${model.name}`, model.fields)),
|
|
1048
|
+
...(0, import_flatMap2.default)(
|
|
1049
|
+
models.map((model) => {
|
|
1050
|
+
const types = [
|
|
1051
|
+
object(
|
|
1052
|
+
model.name,
|
|
1053
|
+
[
|
|
1054
|
+
...model.fields.filter(isQueriableField).map((field) => ({
|
|
1055
|
+
...field,
|
|
1056
|
+
type: field.type,
|
|
1057
|
+
args: [...field.args || []],
|
|
1058
|
+
directives: field.directives
|
|
1059
|
+
})),
|
|
1060
|
+
...model.reverseRelations.map(({ name: name2, field, model: model2 }) => ({
|
|
1061
|
+
name: name2,
|
|
1062
|
+
type: model2.name,
|
|
1063
|
+
list: !field.toOne,
|
|
1064
|
+
nonNull: !field.toOne,
|
|
1065
|
+
args: [
|
|
1066
|
+
{ name: "where", type: `${model2.name}Where` },
|
|
1067
|
+
...model2.fields.some(({ searchable }) => searchable) ? [{ name: "search", type: "String" }] : [],
|
|
1068
|
+
...model2.fields.some(({ orderable }) => orderable) ? [{ name: "orderBy", type: `${model2.name}OrderBy`, list: true }] : [],
|
|
1069
|
+
{ name: "limit", type: "Int" },
|
|
1070
|
+
{ name: "offset", type: "Int" }
|
|
1071
|
+
]
|
|
1072
|
+
}))
|
|
1073
|
+
],
|
|
1074
|
+
model.interfaces
|
|
1075
|
+
),
|
|
1076
|
+
input(`${model.name}Where`, [
|
|
1077
|
+
...model.fields.filter(({ kind, unique, filterable }) => (unique || filterable) && kind !== "relation").map((field) => ({
|
|
1078
|
+
name: field.name,
|
|
1079
|
+
type: field.type,
|
|
1080
|
+
list: true,
|
|
1081
|
+
default: typeof field.filterable === "object" ? field.filterable.default : void 0
|
|
1082
|
+
})),
|
|
1083
|
+
...(0, import_flatMap2.default)(
|
|
1084
|
+
model.fields.filter(({ comparable }) => comparable),
|
|
1085
|
+
(field) => [
|
|
1086
|
+
{ name: `${field.name}_GT`, type: field.type },
|
|
1087
|
+
{ name: `${field.name}_GTE`, type: field.type },
|
|
1088
|
+
{ name: `${field.name}_LT`, type: field.type },
|
|
1089
|
+
{ name: `${field.name}_LTE`, type: field.type }
|
|
1090
|
+
]
|
|
1091
|
+
),
|
|
1092
|
+
...model.fields.filter(isRelation).filter(({ filterable }) => filterable).map(({ name: name2, type }) => ({
|
|
1093
|
+
name: name2,
|
|
1094
|
+
type: `${type}Where`
|
|
1095
|
+
}))
|
|
1096
|
+
]),
|
|
1097
|
+
input(
|
|
1098
|
+
`${model.name}WhereUnique`,
|
|
1099
|
+
model.fields.filter(({ unique }) => unique).map((field) => ({ name: field.name, type: field.type }))
|
|
1100
|
+
),
|
|
1101
|
+
...model.fields.some(({ orderable }) => orderable) ? [
|
|
1102
|
+
input(
|
|
1103
|
+
`${model.name}OrderBy`,
|
|
1104
|
+
model.fields.filter(({ orderable }) => orderable).map(({ name: name2 }) => ({ name: name2, type: "Order" }))
|
|
1105
|
+
)
|
|
1106
|
+
] : []
|
|
1107
|
+
];
|
|
1108
|
+
if (model.creatable) {
|
|
1109
|
+
types.push(
|
|
1110
|
+
input(
|
|
1111
|
+
`Create${model.name}`,
|
|
1112
|
+
model.fields.filter(({ creatable }) => creatable).map(
|
|
1113
|
+
(field) => field.kind === "relation" ? { name: `${field.name}Id`, type: "ID", nonNull: field.nonNull } : {
|
|
1114
|
+
name: field.name,
|
|
1115
|
+
type: field.kind === "json" ? `Create${field.type}` : field.type,
|
|
1116
|
+
list: field.list,
|
|
1117
|
+
nonNull: field.nonNull && field.defaultValue === void 0
|
|
1118
|
+
}
|
|
1119
|
+
)
|
|
1120
|
+
)
|
|
1121
|
+
);
|
|
1122
|
+
}
|
|
1123
|
+
if (model.updatable) {
|
|
1124
|
+
types.push(
|
|
1125
|
+
input(
|
|
1126
|
+
`Update${model.name}`,
|
|
1127
|
+
model.fields.filter(({ updatable }) => updatable).map(
|
|
1128
|
+
(field) => field.kind === "relation" ? { name: `${field.name}Id`, type: "ID" } : {
|
|
1129
|
+
name: field.name,
|
|
1130
|
+
type: field.kind === "json" ? `Update${field.type}` : field.type,
|
|
1131
|
+
list: field.list
|
|
1132
|
+
}
|
|
1133
|
+
)
|
|
1134
|
+
)
|
|
1135
|
+
);
|
|
1136
|
+
}
|
|
1137
|
+
return types;
|
|
1138
|
+
})
|
|
1139
|
+
),
|
|
1140
|
+
object("Query", [
|
|
1141
|
+
{
|
|
1142
|
+
name: "me",
|
|
1143
|
+
type: "User"
|
|
1144
|
+
},
|
|
1145
|
+
...models.filter(({ queriable }) => queriable).map(({ name: name2 }) => ({
|
|
1146
|
+
name: typeToField(name2),
|
|
1147
|
+
type: name2,
|
|
1148
|
+
nonNull: true,
|
|
1149
|
+
args: [
|
|
1150
|
+
{
|
|
1151
|
+
name: "where",
|
|
1152
|
+
type: `${name2}WhereUnique`,
|
|
1153
|
+
nonNull: true
|
|
1154
|
+
}
|
|
1155
|
+
]
|
|
1156
|
+
})),
|
|
1157
|
+
...models.filter(({ listQueriable }) => listQueriable).map((model) => ({
|
|
1158
|
+
name: getModelPluralField(model),
|
|
1159
|
+
type: model.name,
|
|
1160
|
+
list: true,
|
|
1161
|
+
nonNull: true,
|
|
1162
|
+
args: [
|
|
1163
|
+
{ name: "where", type: `${model.name}Where` },
|
|
1164
|
+
...model.fields.some(({ searchable }) => searchable) ? [{ name: "search", type: "String" }] : [],
|
|
1165
|
+
...model.fields.some(({ orderable }) => orderable) ? [{ name: "orderBy", type: `${model.name}OrderBy`, list: true }] : [],
|
|
1166
|
+
{ name: "limit", type: "Int" },
|
|
1167
|
+
{ name: "offset", type: "Int" }
|
|
1168
|
+
]
|
|
1169
|
+
})),
|
|
1170
|
+
...rawModels.filter(isObjectModel).filter((model) => model.name === "Query").flatMap((model) => model.fields)
|
|
1171
|
+
]),
|
|
1172
|
+
object("Mutation", [
|
|
1173
|
+
...(0, import_flatMap2.default)(
|
|
1174
|
+
models.map((model) => {
|
|
1175
|
+
const mutations = [];
|
|
1176
|
+
if (model.creatable) {
|
|
1177
|
+
mutations.push({
|
|
1178
|
+
name: `create${model.name}`,
|
|
1179
|
+
type: model.name,
|
|
1180
|
+
nonNull: true,
|
|
1181
|
+
args: [
|
|
1182
|
+
{
|
|
1183
|
+
name: "data",
|
|
1184
|
+
type: `Create${model.name}`,
|
|
1185
|
+
nonNull: true
|
|
1186
|
+
}
|
|
1187
|
+
]
|
|
1188
|
+
});
|
|
1189
|
+
}
|
|
1190
|
+
if (model.updatable) {
|
|
1191
|
+
mutations.push({
|
|
1192
|
+
name: `update${model.name}`,
|
|
1193
|
+
type: model.name,
|
|
1194
|
+
nonNull: true,
|
|
1195
|
+
args: [
|
|
1196
|
+
{
|
|
1197
|
+
name: "where",
|
|
1198
|
+
type: `${model.name}WhereUnique`,
|
|
1199
|
+
nonNull: true
|
|
1200
|
+
},
|
|
1201
|
+
{
|
|
1202
|
+
name: "data",
|
|
1203
|
+
type: `Update${model.name}`,
|
|
1204
|
+
nonNull: true
|
|
1205
|
+
}
|
|
1206
|
+
]
|
|
1207
|
+
});
|
|
1208
|
+
}
|
|
1209
|
+
if (model.deletable) {
|
|
1210
|
+
mutations.push({
|
|
1211
|
+
name: `delete${model.name}`,
|
|
1212
|
+
type: "ID",
|
|
1213
|
+
nonNull: true,
|
|
1214
|
+
args: [
|
|
1215
|
+
{
|
|
1216
|
+
name: "where",
|
|
1217
|
+
type: `${model.name}WhereUnique`,
|
|
1218
|
+
nonNull: true
|
|
1219
|
+
},
|
|
1220
|
+
{
|
|
1221
|
+
name: "dryRun",
|
|
1222
|
+
type: "Boolean"
|
|
1223
|
+
}
|
|
1224
|
+
]
|
|
1225
|
+
});
|
|
1226
|
+
mutations.push({
|
|
1227
|
+
name: `restore${model.name}`,
|
|
1228
|
+
type: "ID",
|
|
1229
|
+
nonNull: true,
|
|
1230
|
+
args: [
|
|
1231
|
+
{
|
|
1232
|
+
name: "where",
|
|
1233
|
+
type: `${model.name}WhereUnique`,
|
|
1234
|
+
nonNull: true
|
|
1235
|
+
}
|
|
1236
|
+
]
|
|
1237
|
+
});
|
|
1238
|
+
}
|
|
1239
|
+
return mutations;
|
|
1240
|
+
})
|
|
1241
|
+
),
|
|
1242
|
+
...rawModels.filter(isObjectModel).filter((model) => model.name === "Mutation").flatMap((model) => model.fields)
|
|
1243
|
+
])
|
|
1244
|
+
];
|
|
1245
|
+
};
|
|
1246
|
+
var generate = (rawModels) => document(generateDefinitions(rawModels));
|
|
1247
|
+
var printSchema = (schema) => [
|
|
1248
|
+
...schema.getDirectives().map((d) => d.astNode && (0, import_graphql5.print)(d.astNode)),
|
|
1249
|
+
...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))
|
|
1250
|
+
].filter(Boolean).map((s) => `${s}
|
|
1251
|
+
`).join("\n");
|
|
1252
|
+
var printSchemaFromModels = (models) => printSchema((0, import_graphql5.buildASTSchema)(generate(models)));
|
|
1253
|
+
|
|
1254
|
+
// src/bin/gqm/codegen.ts
|
|
1255
|
+
var import_cli = require("@graphql-codegen/cli");
|
|
1256
|
+
|
|
1257
|
+
// src/bin/gqm/settings.ts
|
|
1258
|
+
var import_fs = require("fs");
|
|
1259
|
+
var import_path = require("path");
|
|
1260
|
+
|
|
1261
|
+
// src/bin/gqm/readline.ts
|
|
1262
|
+
var import_readline = __toESM(require("readline"), 1);
|
|
1263
|
+
var readLine = (prompt) => {
|
|
1264
|
+
const rl = import_readline.default.createInterface({
|
|
1265
|
+
input: process.stdin,
|
|
1266
|
+
output: process.stdout
|
|
1267
|
+
});
|
|
1268
|
+
return new Promise((resolve2) => {
|
|
1269
|
+
rl.question(prompt, (answer) => {
|
|
1270
|
+
rl.close();
|
|
1271
|
+
resolve2(answer);
|
|
1272
|
+
});
|
|
1273
|
+
});
|
|
1274
|
+
};
|
|
1275
|
+
|
|
1276
|
+
// src/bin/gqm/templates.ts
|
|
1277
|
+
var EMPTY_MODELS = `
|
|
1278
|
+
import { RawModels, getModels } from '@smartive/graphql-magic';
|
|
1279
|
+
|
|
1280
|
+
export const rawModels: RawModels = [
|
|
1281
|
+
{
|
|
1282
|
+
kind: 'entity',
|
|
1283
|
+
name: 'User',
|
|
1284
|
+
fields: []
|
|
1285
|
+
},
|
|
1286
|
+
]
|
|
1287
|
+
|
|
1288
|
+
export const models = getModels(rawModels);
|
|
1289
|
+
`;
|
|
1290
|
+
var GRAPHQL_CODEGEN = (path) => `
|
|
1291
|
+
overwrite: true
|
|
1292
|
+
schema: '${path}/schema.graphql'
|
|
1293
|
+
documents: null
|
|
1294
|
+
generates:
|
|
1295
|
+
${path}/api/index.ts:
|
|
1296
|
+
plugins:
|
|
1297
|
+
- 'typescript'
|
|
1298
|
+
- 'typescript-resolvers'
|
|
1299
|
+
- add:
|
|
1300
|
+
content: "import { DateTime } from 'luxon'"
|
|
1301
|
+
config:
|
|
1302
|
+
scalars:
|
|
1303
|
+
DateTime: DateTime
|
|
1304
|
+
`;
|
|
1305
|
+
var CLIENT_CODEGEN = (path) => `
|
|
1306
|
+
schema: ${path}/schema.graphql
|
|
1307
|
+
documents: [ './src/**/*.ts', './src/**/*.tsx' ]
|
|
1308
|
+
generates:
|
|
1309
|
+
${path}/client/index.ts:
|
|
1310
|
+
plugins:
|
|
1311
|
+
- typescript
|
|
1312
|
+
- typescript-operations
|
|
1313
|
+
- typescript-compatibility
|
|
1314
|
+
|
|
1315
|
+
config:
|
|
1316
|
+
preResolveTypes: true # Simplifies the generated types
|
|
1317
|
+
namingConvention: keep # Keeps naming as-is
|
|
1318
|
+
nonOptionalTypename: true # Forces \`__typename\` on all selection sets
|
|
1319
|
+
skipTypeNameForRoot: true # Don't generate __typename for root types
|
|
1320
|
+
avoidOptionals: # Avoids optionals on the level of the field
|
|
1321
|
+
field: true
|
|
1322
|
+
scalars:
|
|
1323
|
+
DateTime: string
|
|
1324
|
+
`;
|
|
1325
|
+
var KNEXFILE = `
|
|
1326
|
+
const config = {
|
|
1327
|
+
client: 'postgresql',
|
|
1328
|
+
connection: {
|
|
1329
|
+
host: process.env.DATABASE_HOST,
|
|
1330
|
+
database: process.env.DATABASE_NAME,
|
|
1331
|
+
user: process.env.DATABASE_USER,
|
|
1332
|
+
password: process.env.DATABASE_PASSWORD,
|
|
1333
|
+
},
|
|
1334
|
+
} as const;
|
|
1335
|
+
|
|
1336
|
+
export default config;
|
|
1337
|
+
`;
|
|
1338
|
+
|
|
1339
|
+
// src/bin/gqm/settings.ts
|
|
1340
|
+
var SETTINGS_PATH = ".gqmrc.json";
|
|
1341
|
+
var DEFAULTS = {
|
|
1342
|
+
modelsPath: {
|
|
1343
|
+
question: "What is the models path?",
|
|
1344
|
+
defaultValue: "src/config/models.ts",
|
|
1345
|
+
init: (path) => {
|
|
1346
|
+
ensureFileExists(path, EMPTY_MODELS);
|
|
1347
|
+
}
|
|
1348
|
+
},
|
|
1349
|
+
generatedFolderPath: {
|
|
1350
|
+
question: "What is the path for generated stuff?",
|
|
1351
|
+
defaultValue: "src/generated",
|
|
1352
|
+
init: (path) => {
|
|
1353
|
+
ensureFileExists(`${path}/.gitkeep`, "");
|
|
1354
|
+
ensureFileExists(`${path}/db/.gitkeep`, "");
|
|
1355
|
+
ensureFileExists(`${path}/api/.gitkeep`, "");
|
|
1356
|
+
ensureFileExists(`${path}/client/.gitkeep`, "");
|
|
1357
|
+
ensureFileExists(`graphql-codegen.yml`, GRAPHQL_CODEGEN(path));
|
|
1358
|
+
ensureFileExists(`client-codegen.yml`, CLIENT_CODEGEN(path));
|
|
1359
|
+
}
|
|
1360
|
+
}
|
|
1361
|
+
};
|
|
1362
|
+
var initSetting = async (name2) => {
|
|
1363
|
+
const { question, defaultValue, init } = DEFAULTS[name2];
|
|
1364
|
+
const value2 = await readLine(`${question} (${defaultValue})`) || defaultValue;
|
|
1365
|
+
init(value2);
|
|
1366
|
+
return value2;
|
|
1356
1367
|
};
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1368
|
+
var initSettings = async () => {
|
|
1369
|
+
const settings = {};
|
|
1370
|
+
for (const name2 of Object.keys(DEFAULTS)) {
|
|
1371
|
+
settings[name2] = await initSetting(name2);
|
|
1372
|
+
}
|
|
1373
|
+
saveSettings(settings);
|
|
1374
|
+
};
|
|
1375
|
+
var saveSettings = (settings) => {
|
|
1376
|
+
writeToFile(SETTINGS_PATH, JSON.stringify(settings, null, 2));
|
|
1377
|
+
};
|
|
1378
|
+
var getSettings = async () => {
|
|
1379
|
+
if (!(0, import_fs.existsSync)(SETTINGS_PATH)) {
|
|
1380
|
+
await initSettings();
|
|
1381
|
+
}
|
|
1382
|
+
return JSON.parse((0, import_fs.readFileSync)(SETTINGS_PATH, "utf8"));
|
|
1383
|
+
};
|
|
1384
|
+
var getSetting = async (name2) => {
|
|
1385
|
+
const settings = await getSettings();
|
|
1386
|
+
if (!(name2 in settings)) {
|
|
1387
|
+
settings[name2] = await initSetting(name2);
|
|
1388
|
+
saveSettings(settings);
|
|
1389
|
+
}
|
|
1390
|
+
return settings[name2];
|
|
1391
|
+
};
|
|
1392
|
+
var ensureDirectoryExists = (filePath) => {
|
|
1393
|
+
const dir = (0, import_path.dirname)(filePath);
|
|
1394
|
+
if ((0, import_fs.existsSync)(dir)) {
|
|
1395
|
+
return true;
|
|
1396
|
+
}
|
|
1397
|
+
ensureDirectoryExists(dir);
|
|
1398
|
+
try {
|
|
1399
|
+
(0, import_fs.mkdirSync)(dir);
|
|
1400
|
+
return true;
|
|
1401
|
+
} catch (err) {
|
|
1402
|
+
if (err.code === "EEXIST") {
|
|
1403
|
+
return true;
|
|
1404
|
+
}
|
|
1405
|
+
throw err;
|
|
1406
|
+
}
|
|
1407
|
+
};
|
|
1408
|
+
var ensureFileExists = (filePath, content) => {
|
|
1409
|
+
if (!(0, import_fs.existsSync)(filePath)) {
|
|
1410
|
+
console.info(`Creating ${filePath}`);
|
|
1411
|
+
ensureDirectoryExists(filePath);
|
|
1412
|
+
(0, import_fs.writeFileSync)(filePath, content);
|
|
1413
|
+
}
|
|
1414
|
+
};
|
|
1415
|
+
var writeToFile = (filePath, content) => {
|
|
1416
|
+
ensureDirectoryExists(filePath);
|
|
1417
|
+
if ((0, import_fs.existsSync)(filePath)) {
|
|
1418
|
+
const currentContent = (0, import_fs.readFileSync)(filePath, "utf-8");
|
|
1419
|
+
if (content === currentContent) {
|
|
1420
|
+
} else {
|
|
1421
|
+
(0, import_fs.writeFileSync)(filePath, content);
|
|
1422
|
+
console.info(`${filePath} updated`);
|
|
1423
|
+
}
|
|
1424
|
+
} else {
|
|
1425
|
+
(0, import_fs.writeFileSync)(filePath, content);
|
|
1426
|
+
console.info(`Created ${filePath}`);
|
|
1385
1427
|
}
|
|
1386
1428
|
};
|
|
1387
1429
|
|
|
1388
|
-
// src/
|
|
1389
|
-
var
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
}
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
);
|
|
1447
|
-
|
|
1448
|
-
|
|
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));
|
|
1430
|
+
// src/bin/gqm/codegen.ts
|
|
1431
|
+
var generateGraphqlApiTypes = async () => {
|
|
1432
|
+
const generatedFolderPath = await getSetting("generatedFolderPath");
|
|
1433
|
+
await (0, import_cli.generate)({
|
|
1434
|
+
overwrite: true,
|
|
1435
|
+
schema: `${generatedFolderPath}/schema.graphql`,
|
|
1436
|
+
documents: null,
|
|
1437
|
+
generates: {
|
|
1438
|
+
[`${generatedFolderPath}/api/index.ts`]: {
|
|
1439
|
+
plugins: ["typescript", "typescript-resolvers", { add: { content: `import { DateTime } from 'luxon';` } }]
|
|
1440
|
+
}
|
|
1441
|
+
},
|
|
1442
|
+
config: {
|
|
1443
|
+
scalars: {
|
|
1444
|
+
DateTime: "DateTime"
|
|
1445
|
+
}
|
|
1446
|
+
}
|
|
1447
|
+
});
|
|
1448
|
+
};
|
|
1449
|
+
var generateGraphqlClientTypes = async () => {
|
|
1450
|
+
const generatedFolderPath = await getSetting("generatedFolderPath");
|
|
1451
|
+
await (0, import_cli.generate)({
|
|
1452
|
+
schema: `${generatedFolderPath}/schema.graphql`,
|
|
1453
|
+
documents: ["./src/**/*.ts", "./src/**/*.tsx"],
|
|
1454
|
+
generates: {
|
|
1455
|
+
[`${generatedFolderPath}/client/index.ts`]: {
|
|
1456
|
+
plugins: ["typescript", "typescript-operations", "typescript-compatibility"]
|
|
1457
|
+
}
|
|
1458
|
+
},
|
|
1459
|
+
config: {
|
|
1460
|
+
preResolveTypes: true,
|
|
1461
|
+
// Simplifies the generated types
|
|
1462
|
+
namingConvention: "keep",
|
|
1463
|
+
// Keeps naming as-is
|
|
1464
|
+
nonOptionalTypename: true,
|
|
1465
|
+
// Forces `__typename` on all selection sets
|
|
1466
|
+
skipTypeNameForRoot: true,
|
|
1467
|
+
// Don't generate __typename for root types
|
|
1468
|
+
avoidOptionals: {
|
|
1469
|
+
// Avoids optionals on the level of the field
|
|
1470
|
+
field: true
|
|
1471
|
+
},
|
|
1472
|
+
scalars: {
|
|
1473
|
+
DateTime: "string"
|
|
1474
|
+
}
|
|
1475
|
+
}
|
|
1476
|
+
});
|
|
1477
|
+
};
|
|
1478
|
+
|
|
1479
|
+
// src/bin/gqm/parse-knexfile.ts
|
|
1480
|
+
var import_ts_morph4 = require("ts-morph");
|
|
1481
|
+
|
|
1482
|
+
// src/bin/gqm/static-eval.ts
|
|
1483
|
+
var import_ts_morph2 = require("ts-morph");
|
|
1484
|
+
|
|
1485
|
+
// src/bin/gqm/visitor.ts
|
|
1486
|
+
var import_ts_morph = require("ts-morph");
|
|
1487
|
+
var visit = (node, context, visitor2) => {
|
|
1488
|
+
const kind = node?.getKind();
|
|
1489
|
+
if (kind in visitor2) {
|
|
1490
|
+
return visitor2[kind](node.asKindOrThrow(kind), context);
|
|
1477
1491
|
}
|
|
1478
|
-
if (
|
|
1479
|
-
|
|
1492
|
+
if ("unknown" in visitor2) {
|
|
1493
|
+
return visitor2.unknown(node);
|
|
1480
1494
|
}
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
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
|
-
)
|
|
1495
|
+
console.error(node.getText());
|
|
1496
|
+
console.error(node.getParent().getText());
|
|
1497
|
+
throw new Error(
|
|
1498
|
+
`Cannot handle kind ${get(
|
|
1499
|
+
Object.entries(import_ts_morph.SyntaxKind).find(([, val]) => val === kind),
|
|
1500
|
+
0
|
|
1501
|
+
)}`
|
|
1502
|
+
);
|
|
1512
1503
|
};
|
|
1513
1504
|
|
|
1514
|
-
// src/
|
|
1515
|
-
var
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
)
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
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
|
-
});
|
|
1505
|
+
// src/bin/gqm/static-eval.ts
|
|
1506
|
+
var staticEval = (node, context) => visit(node, context, visitor);
|
|
1507
|
+
var visitor = {
|
|
1508
|
+
undefined: () => void 0,
|
|
1509
|
+
[import_ts_morph2.SyntaxKind.VariableDeclaration]: (node, context) => staticEval(node.getInitializer(), context),
|
|
1510
|
+
[import_ts_morph2.SyntaxKind.ArrayLiteralExpression]: (node, context) => {
|
|
1511
|
+
const values = [];
|
|
1512
|
+
for (const value2 of node.getElements()) {
|
|
1513
|
+
if (value2.isKind(import_ts_morph2.SyntaxKind.SpreadElement)) {
|
|
1514
|
+
values.push(...staticEval(value2, context));
|
|
1515
|
+
} else {
|
|
1516
|
+
values.push(staticEval(value2, context));
|
|
1517
|
+
}
|
|
1518
|
+
}
|
|
1519
|
+
return values;
|
|
1520
|
+
},
|
|
1521
|
+
[import_ts_morph2.SyntaxKind.ObjectLiteralExpression]: (node, context) => {
|
|
1522
|
+
const result = {};
|
|
1523
|
+
for (const property of node.getProperties()) {
|
|
1524
|
+
Object.assign(result, staticEval(property, context));
|
|
1525
|
+
}
|
|
1526
|
+
return result;
|
|
1527
|
+
},
|
|
1528
|
+
[import_ts_morph2.SyntaxKind.StringLiteral]: (node) => node.getLiteralValue(),
|
|
1529
|
+
[import_ts_morph2.SyntaxKind.PropertyAssignment]: (node, context) => ({
|
|
1530
|
+
[node.getName()]: staticEval(node.getInitializer(), context)
|
|
1531
|
+
}),
|
|
1532
|
+
[import_ts_morph2.SyntaxKind.ShorthandPropertyAssignment]: (node, context) => ({
|
|
1533
|
+
[node.getName()]: staticEval(node.getNameNode(), context)
|
|
1534
|
+
}),
|
|
1535
|
+
[import_ts_morph2.SyntaxKind.SpreadElement]: (node, context) => staticEval(node.getExpression(), context),
|
|
1536
|
+
[import_ts_morph2.SyntaxKind.SpreadAssignment]: (node, context) => staticEval(node.getExpression(), context),
|
|
1537
|
+
[import_ts_morph2.SyntaxKind.Identifier]: (node, context) => {
|
|
1538
|
+
switch (node.getText()) {
|
|
1539
|
+
case "undefined":
|
|
1540
|
+
return void 0;
|
|
1541
|
+
case "process":
|
|
1542
|
+
return process;
|
|
1543
|
+
}
|
|
1544
|
+
const definitionNodes = node.getDefinitionNodes();
|
|
1545
|
+
if (!definitionNodes.length) {
|
|
1546
|
+
throw new Error(`No definition node found for identifier ${node.getText()}.`);
|
|
1547
|
+
}
|
|
1548
|
+
return staticEval(definitionNodes[0], context);
|
|
1549
|
+
},
|
|
1550
|
+
[import_ts_morph2.SyntaxKind.ParenthesizedExpression]: (node, context) => staticEval(node.getExpression(), context),
|
|
1551
|
+
[import_ts_morph2.SyntaxKind.AsExpression]: (node, context) => staticEval(node.getExpression(), context),
|
|
1552
|
+
[import_ts_morph2.SyntaxKind.ConditionalExpression]: (node, context) => staticEval(node.getCondition(), context) ? staticEval(node.getWhenTrue(), context) : staticEval(node.getWhenFalse(), context),
|
|
1553
|
+
[import_ts_morph2.SyntaxKind.TrueKeyword]: () => true,
|
|
1554
|
+
[import_ts_morph2.SyntaxKind.FalseKeyword]: () => false,
|
|
1555
|
+
[import_ts_morph2.SyntaxKind.NumericLiteral]: (node) => node.getLiteralValue(),
|
|
1556
|
+
[import_ts_morph2.SyntaxKind.CallExpression]: (node, context) => {
|
|
1557
|
+
const method = staticEval(node.getExpression(), context);
|
|
1558
|
+
const args2 = node.getArguments().map((arg) => staticEval(arg, context));
|
|
1559
|
+
return method(...args2);
|
|
1560
|
+
},
|
|
1561
|
+
[import_ts_morph2.SyntaxKind.PropertyAccessExpression]: (node, context) => {
|
|
1562
|
+
const target = staticEval(node.getExpression(), context);
|
|
1563
|
+
const property = target[node.getName()];
|
|
1564
|
+
if (typeof property === "function") {
|
|
1565
|
+
if (Array.isArray(target)) {
|
|
1566
|
+
switch (node.getName()) {
|
|
1567
|
+
case "map":
|
|
1568
|
+
case "flatMap":
|
|
1569
|
+
case "includes":
|
|
1570
|
+
case "some":
|
|
1571
|
+
case "find":
|
|
1572
|
+
case "filter":
|
|
1573
|
+
return target[node.getName()].bind(target);
|
|
1574
|
+
}
|
|
1575
|
+
} else if (typeof target === "string") {
|
|
1576
|
+
const name2 = node.getName();
|
|
1577
|
+
switch (name2) {
|
|
1578
|
+
case "slice":
|
|
1579
|
+
case "toUpperCase":
|
|
1580
|
+
case "toLowerCase":
|
|
1581
|
+
return target[name2].bind(target);
|
|
1582
|
+
}
|
|
1583
|
+
}
|
|
1584
|
+
throw new Error(`Cannot handle method ${node.getName()} on type ${typeof target}`);
|
|
1585
|
+
}
|
|
1586
|
+
return property;
|
|
1587
|
+
},
|
|
1588
|
+
[import_ts_morph2.SyntaxKind.ArrowFunction]: (node, context) => {
|
|
1589
|
+
return (...args2) => {
|
|
1590
|
+
const parameters = {};
|
|
1591
|
+
let i = 0;
|
|
1592
|
+
for (const parameter of node.getParameters()) {
|
|
1593
|
+
parameters[parameter.getName()] = args2[i];
|
|
1594
|
+
i++;
|
|
1595
|
+
}
|
|
1596
|
+
return staticEval(node.getBody(), { ...context, ...parameters });
|
|
1597
|
+
};
|
|
1598
|
+
},
|
|
1599
|
+
[import_ts_morph2.SyntaxKind.Block]: (node, context) => {
|
|
1600
|
+
for (const statement of node.getStatements()) {
|
|
1601
|
+
return staticEval(statement, context);
|
|
1602
|
+
}
|
|
1603
|
+
},
|
|
1604
|
+
[import_ts_morph2.SyntaxKind.CaseClause]: (node, context) => {
|
|
1605
|
+
const statements = node.getStatements();
|
|
1606
|
+
if (statements.length !== 1) {
|
|
1607
|
+
console.error(node.getText());
|
|
1608
|
+
throw new Error(`Can only handle code blocks with 1 statement.`);
|
|
1609
|
+
}
|
|
1610
|
+
return staticEval(statements[0], context);
|
|
1611
|
+
},
|
|
1612
|
+
[import_ts_morph2.SyntaxKind.DefaultClause]: (node, context) => {
|
|
1613
|
+
const statements = node.getStatements();
|
|
1614
|
+
if (statements.length !== 1) {
|
|
1615
|
+
console.error(node.getText());
|
|
1616
|
+
throw new Error(`Can only handle code blocks with exactly 1 statement.`);
|
|
1617
|
+
}
|
|
1618
|
+
return staticEval(statements[0], context);
|
|
1619
|
+
},
|
|
1620
|
+
[import_ts_morph2.SyntaxKind.ReturnStatement]: (node, context) => {
|
|
1621
|
+
return staticEval(node.getExpression(), context);
|
|
1622
|
+
},
|
|
1623
|
+
[import_ts_morph2.SyntaxKind.SwitchStatement]: (node, context) => {
|
|
1624
|
+
const value2 = staticEval(node.getExpression(), context);
|
|
1625
|
+
let active = false;
|
|
1626
|
+
for (const clause of node.getCaseBlock().getClauses()) {
|
|
1627
|
+
switch (clause.getKind()) {
|
|
1628
|
+
case import_ts_morph2.SyntaxKind.DefaultClause:
|
|
1629
|
+
return staticEval(clause, context);
|
|
1630
|
+
case import_ts_morph2.SyntaxKind.CaseClause: {
|
|
1631
|
+
const caseClause = clause.asKindOrThrow(import_ts_morph2.SyntaxKind.CaseClause);
|
|
1632
|
+
if (caseClause.getStatements().length && active) {
|
|
1633
|
+
return staticEval(clause, context);
|
|
1693
1634
|
}
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
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
|
-
});
|
|
1635
|
+
const caseValue = staticEval(caseClause.getExpression(), context);
|
|
1636
|
+
if (value2 === caseValue) {
|
|
1637
|
+
active = true;
|
|
1638
|
+
if (caseClause.getStatements().length) {
|
|
1639
|
+
return staticEval(clause, context);
|
|
1640
|
+
}
|
|
1723
1641
|
}
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
]
|
|
1642
|
+
}
|
|
1643
|
+
}
|
|
1644
|
+
}
|
|
1645
|
+
},
|
|
1646
|
+
[import_ts_morph2.SyntaxKind.Parameter]: (node, context) => context[node.getName()],
|
|
1647
|
+
[import_ts_morph2.SyntaxKind.BinaryExpression]: (node, context) => {
|
|
1648
|
+
switch (node.getOperatorToken().getKind()) {
|
|
1649
|
+
case import_ts_morph2.SyntaxKind.EqualsEqualsEqualsToken:
|
|
1650
|
+
return staticEval(node.getLeft(), context) === staticEval(node.getRight(), context);
|
|
1651
|
+
case import_ts_morph2.SyntaxKind.BarBarToken:
|
|
1652
|
+
return staticEval(node.getLeft(), context) || staticEval(node.getRight(), context);
|
|
1653
|
+
default:
|
|
1654
|
+
throw new Error(`Cannot handle operator of kind ${node.getOperatorToken().getKindName()}`);
|
|
1655
|
+
}
|
|
1656
|
+
},
|
|
1657
|
+
[import_ts_morph2.SyntaxKind.SatisfiesExpression]: (node, context) => staticEval(node.getExpression(), context),
|
|
1658
|
+
[import_ts_morph2.SyntaxKind.TemplateExpression]: (node, context) => node.getHead().getLiteralText() + node.getTemplateSpans().map((span) => staticEval(span.getExpression(), context) + staticEval(span.getLiteral(), context)).join(""),
|
|
1659
|
+
[import_ts_morph2.SyntaxKind.TemplateTail]: (node) => node.getLiteralText(),
|
|
1660
|
+
[import_ts_morph2.SyntaxKind.TemplateMiddle]: (node) => node.getLiteralText(),
|
|
1661
|
+
[import_ts_morph2.SyntaxKind.PrefixUnaryExpression]: (node, context) => {
|
|
1662
|
+
switch (node.getOperatorToken()) {
|
|
1663
|
+
case import_ts_morph2.SyntaxKind.PlusToken:
|
|
1664
|
+
return +staticEval(node.getOperand(), context);
|
|
1665
|
+
case import_ts_morph2.SyntaxKind.MinusToken:
|
|
1666
|
+
return -staticEval(node.getOperand(), context);
|
|
1667
|
+
case import_ts_morph2.SyntaxKind.TildeToken:
|
|
1668
|
+
return ~staticEval(node.getOperand(), context);
|
|
1669
|
+
case import_ts_morph2.SyntaxKind.ExclamationToken:
|
|
1670
|
+
return !staticEval(node.getOperand(), context);
|
|
1671
|
+
case import_ts_morph2.SyntaxKind.PlusPlusToken:
|
|
1672
|
+
case import_ts_morph2.SyntaxKind.MinusMinusToken:
|
|
1673
|
+
throw new Error(`Cannot handle assignments.`);
|
|
1674
|
+
}
|
|
1675
|
+
},
|
|
1676
|
+
[import_ts_morph2.SyntaxKind.ElementAccessExpression]: (node, context) => {
|
|
1677
|
+
const target = staticEval(node.getExpression(), context);
|
|
1678
|
+
const argument = staticEval(node.getArgumentExpression(), context);
|
|
1679
|
+
return target[argument];
|
|
1680
|
+
},
|
|
1681
|
+
[import_ts_morph2.SyntaxKind.NoSubstitutionTemplateLiteral]: (node) => node.getLiteralValue()
|
|
1682
|
+
};
|
|
1683
|
+
|
|
1684
|
+
// src/bin/gqm/utils.ts
|
|
1685
|
+
var import_ts_morph3 = require("ts-morph");
|
|
1686
|
+
var findDeclarationInFile = (sourceFile, name2) => {
|
|
1687
|
+
const syntaxList = sourceFile.getChildrenOfKind(import_ts_morph3.SyntaxKind.SyntaxList)[0];
|
|
1688
|
+
if (!syntaxList) {
|
|
1689
|
+
throw new Error("No SyntaxList");
|
|
1690
|
+
}
|
|
1691
|
+
const declaration = findDeclaration(syntaxList, name2);
|
|
1692
|
+
if (!declaration) {
|
|
1693
|
+
throw new Error(`No ${name2} declaration`);
|
|
1694
|
+
}
|
|
1695
|
+
return declaration;
|
|
1696
|
+
};
|
|
1697
|
+
var findDeclaration = (syntaxList, name2) => {
|
|
1698
|
+
for (const variableStatement of syntaxList.getChildrenOfKind(import_ts_morph3.SyntaxKind.VariableStatement)) {
|
|
1699
|
+
for (const declaration of variableStatement.getDeclarationList().getDeclarations()) {
|
|
1700
|
+
if (declaration.getName() === name2) {
|
|
1701
|
+
return declaration;
|
|
1702
|
+
}
|
|
1703
|
+
}
|
|
1704
|
+
}
|
|
1705
|
+
};
|
|
1706
|
+
|
|
1707
|
+
// src/bin/gqm/parse-knexfile.ts
|
|
1708
|
+
var KNEXFILE_PATH = `knexfile.ts`;
|
|
1709
|
+
var parseKnexfile = async () => {
|
|
1710
|
+
const project = new import_ts_morph4.Project({
|
|
1711
|
+
manipulationSettings: {
|
|
1712
|
+
indentationText: import_ts_morph4.IndentationText.TwoSpaces
|
|
1713
|
+
}
|
|
1714
|
+
});
|
|
1715
|
+
ensureFileExists(KNEXFILE_PATH, KNEXFILE);
|
|
1716
|
+
const sourceFile = project.addSourceFileAtPath(KNEXFILE_PATH);
|
|
1717
|
+
const configDeclaration = findDeclarationInFile(sourceFile, "config");
|
|
1718
|
+
const config2 = staticEval(configDeclaration, {});
|
|
1719
|
+
return config2;
|
|
1720
|
+
};
|
|
1721
|
+
|
|
1722
|
+
// src/bin/gqm/parse-models.ts
|
|
1723
|
+
var import_ts_morph5 = require("ts-morph");
|
|
1724
|
+
var parseModels = async () => {
|
|
1725
|
+
const project = new import_ts_morph5.Project({
|
|
1726
|
+
manipulationSettings: {
|
|
1727
|
+
indentationText: import_ts_morph5.IndentationText.TwoSpaces
|
|
1728
|
+
}
|
|
1729
|
+
});
|
|
1730
|
+
const modelsPath = await getSetting("modelsPath");
|
|
1731
|
+
const sourceFile = project.addSourceFileAtPath(modelsPath);
|
|
1732
|
+
const modelsDeclaration = findDeclarationInFile(sourceFile, "rawModels");
|
|
1733
|
+
const rawModels = staticEval(modelsDeclaration, {});
|
|
1734
|
+
const generatedFolderPath = await getSetting("generatedFolderPath");
|
|
1735
|
+
writeToFile(`${generatedFolderPath}/models.json`, JSON.stringify(rawModels, null, 2));
|
|
1736
|
+
return rawModels;
|
|
1730
1737
|
};
|
|
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
1738
|
|
|
1739
|
-
// src/bin/gqm.ts
|
|
1739
|
+
// src/bin/gqm/gqm.ts
|
|
1740
1740
|
(0, import_dotenv.config)({
|
|
1741
1741
|
path: ".env"
|
|
1742
1742
|
});
|
|
@@ -1791,7 +1791,7 @@ import_commander.program.command("generate-graphql-client-types").description("G
|
|
|
1791
1791
|
});
|
|
1792
1792
|
import_commander.program.command("generate-migration").description("Generate Migration").action(async () => {
|
|
1793
1793
|
const git = (0, import_simple_git.simpleGit)();
|
|
1794
|
-
let name2 = process.argv[
|
|
1794
|
+
let name2 = process.argv[process.argv.indexOf("gqm") + 1] || (await git.branch()).current.split("/").pop();
|
|
1795
1795
|
if (name2 && ["staging", "production"].includes(name2)) {
|
|
1796
1796
|
name2 = await readLine("Migration name:");
|
|
1797
1797
|
}
|