@smartive/graphql-magic 9.1.2 → 10.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc +2 -10
- package/.github/workflows/release.yml +1 -1
- package/.gqmrc.json +6 -0
- package/CHANGELOG.md +2 -2
- package/README.md +1 -1
- package/dist/bin/gqm.cjs +684 -330
- package/dist/cjs/index.cjs +998 -554
- package/dist/esm/api/execute.js +1 -1
- package/dist/esm/api/execute.js.map +1 -1
- package/dist/esm/client/mutations.d.ts +2 -2
- package/dist/esm/client/mutations.js +5 -4
- package/dist/esm/client/mutations.js.map +1 -1
- package/dist/esm/client/queries.d.ts +12 -17
- package/dist/esm/client/queries.js +30 -50
- package/dist/esm/client/queries.js.map +1 -1
- package/dist/esm/context.d.ts +1 -2
- package/dist/esm/db/generate.d.ts +3 -3
- package/dist/esm/db/generate.js +31 -29
- package/dist/esm/db/generate.js.map +1 -1
- package/dist/esm/migrations/generate.d.ts +3 -4
- package/dist/esm/migrations/generate.js +114 -107
- package/dist/esm/migrations/generate.js.map +1 -1
- package/dist/esm/models/index.d.ts +1 -0
- package/dist/esm/models/index.js +1 -0
- package/dist/esm/models/index.js.map +1 -1
- package/dist/esm/models/model-definitions.d.ts +189 -0
- package/dist/esm/models/model-definitions.js +2 -0
- package/dist/esm/models/model-definitions.js.map +1 -0
- package/dist/esm/models/models.d.ts +128 -174
- package/dist/esm/models/models.js +411 -1
- package/dist/esm/models/models.js.map +1 -1
- package/dist/esm/models/mutation-hook.d.ts +2 -2
- package/dist/esm/models/utils.d.ts +35 -497
- package/dist/esm/models/utils.js +21 -144
- package/dist/esm/models/utils.js.map +1 -1
- package/dist/esm/permissions/check.d.ts +3 -3
- package/dist/esm/permissions/check.js +14 -7
- package/dist/esm/permissions/check.js.map +1 -1
- package/dist/esm/permissions/generate.js +6 -6
- package/dist/esm/permissions/generate.js.map +1 -1
- package/dist/esm/resolvers/filters.d.ts +8 -0
- package/dist/esm/resolvers/filters.js +28 -25
- package/dist/esm/resolvers/filters.js.map +1 -1
- package/dist/esm/resolvers/index.d.ts +1 -0
- package/dist/esm/resolvers/index.js +1 -0
- package/dist/esm/resolvers/index.js.map +1 -1
- package/dist/esm/resolvers/mutations.js +85 -21
- package/dist/esm/resolvers/mutations.js.map +1 -1
- package/dist/esm/resolvers/node.d.ts +13 -15
- package/dist/esm/resolvers/node.js +41 -36
- package/dist/esm/resolvers/node.js.map +1 -1
- package/dist/esm/resolvers/resolver.js +19 -49
- package/dist/esm/resolvers/resolver.js.map +1 -1
- package/dist/esm/resolvers/resolvers.d.ts +1 -8
- package/dist/esm/resolvers/resolvers.js +15 -7
- package/dist/esm/resolvers/resolvers.js.map +1 -1
- package/dist/esm/resolvers/selects.d.ts +3 -0
- package/dist/esm/resolvers/selects.js +50 -0
- package/dist/esm/resolvers/selects.js.map +1 -0
- package/dist/esm/resolvers/utils.d.ts +12 -4
- package/dist/esm/resolvers/utils.js +30 -22
- package/dist/esm/resolvers/utils.js.map +1 -1
- package/dist/esm/schema/generate.d.ts +4 -4
- package/dist/esm/schema/generate.js +122 -131
- package/dist/esm/schema/generate.js.map +1 -1
- package/dist/esm/schema/utils.d.ts +1 -1
- package/dist/esm/schema/utils.js +2 -1
- package/dist/esm/schema/utils.js.map +1 -1
- package/knexfile.ts +31 -0
- package/migrations/20230912185644_setup.ts +127 -0
- package/package.json +16 -14
- package/src/api/execute.ts +1 -1
- package/src/bin/gqm/gqm.ts +25 -23
- package/src/bin/gqm/parse-models.ts +5 -5
- package/src/bin/gqm/settings.ts +13 -4
- package/src/bin/gqm/static-eval.ts +5 -0
- package/src/bin/gqm/templates.ts +23 -3
- package/src/client/mutations.ts +11 -5
- package/src/client/queries.ts +43 -80
- package/src/context.ts +1 -2
- package/src/db/generate.ts +41 -41
- package/src/migrations/generate.ts +165 -146
- package/src/models/index.ts +1 -0
- package/src/models/model-definitions.ts +168 -0
- package/src/models/models.ts +510 -166
- package/src/models/mutation-hook.ts +2 -2
- package/src/models/utils.ts +53 -187
- package/src/permissions/check.ts +19 -11
- package/src/permissions/generate.ts +6 -6
- package/src/resolvers/filters.ts +44 -28
- package/src/resolvers/index.ts +1 -0
- package/src/resolvers/mutations.ts +98 -36
- package/src/resolvers/node.ts +79 -51
- package/src/resolvers/resolver.ts +20 -74
- package/src/resolvers/resolvers.ts +18 -7
- package/src/resolvers/selects.ts +77 -0
- package/src/resolvers/utils.ts +41 -25
- package/src/schema/generate.ts +106 -127
- package/src/schema/utils.ts +2 -1
- package/tests/api/__snapshots__/inheritance.spec.ts.snap +83 -0
- package/tests/api/inheritance.spec.ts +130 -0
- package/tests/generated/api/index.ts +1174 -0
- package/tests/generated/client/index.ts +1163 -0
- package/tests/generated/client/mutations.ts +109 -0
- package/tests/generated/db/index.ts +291 -0
- package/tests/generated/db/knex.ts +14 -0
- package/tests/generated/models.json +675 -0
- package/tests/generated/schema.graphql +325 -0
- package/tests/unit/__snapshots__/resolve.spec.ts.snap +23 -0
- package/tests/unit/queries.spec.ts +5 -5
- package/tests/unit/resolve.spec.ts +8 -8
- package/tests/utils/database/knex.ts +5 -13
- package/tests/utils/database/seed.ts +57 -18
- package/tests/utils/models.ts +62 -7
- package/tests/utils/server.ts +5 -5
- package/tsconfig.eslint.json +1 -0
- package/tests/unit/__snapshots__/generate.spec.ts.snap +0 -128
- package/tests/unit/generate.spec.ts +0 -8
- package/tests/utils/database/schema.ts +0 -64
- package/tests/utils/generate-migration.ts +0 -24
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@smartive/graphql-magic",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "10.0.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"source": "src/index.ts",
|
|
6
6
|
"type": "module",
|
|
@@ -13,16 +13,17 @@
|
|
|
13
13
|
"sideEffecs": false,
|
|
14
14
|
"scripts": {
|
|
15
15
|
"bootstrap": "npm ci && npm run generate",
|
|
16
|
-
"generate": "npm run generate:index-files",
|
|
16
|
+
"generate": "npm run generate:index-files && npm run build:bin && npm run generate:gqm-stuff && npm run generate:setup-migration",
|
|
17
17
|
"generate:index-files": "cti create ./src --excludes bin --withoutbackup",
|
|
18
|
+
"generate:gqm-stuff": "npx gqm generate",
|
|
19
|
+
"generate:setup-migration": "npm run build:bin && npx gqm generate-migration setup 20230912185644",
|
|
18
20
|
"lint": "eslint src",
|
|
19
21
|
"lint:fix": "eslint src --fix",
|
|
20
22
|
"deps": "docker-compose up",
|
|
21
23
|
"test": "npm run lint && npm run test:all && npm run build",
|
|
22
|
-
"test:all": "jest tests --no-cache --no-watchman",
|
|
23
|
-
"test:unit": "jest tests/unit --no-cache --no-watchman",
|
|
24
|
-
"test:api": "jest tests/api --no-cache --no-watchman",
|
|
25
|
-
"generate-migration": "esbuild tests/utils/generate-migration.ts --bundle --platform=node --outdir=tmp --out-extension:.js=.cjs --format=cjs --packages=external && node tmp/generate-migration.cjs",
|
|
24
|
+
"test:all": "jest tests --no-cache --no-watchman --setupFiles dotenv/config",
|
|
25
|
+
"test:unit": "jest tests/unit --no-cache --no-watchman --setupFiles dotenv/config",
|
|
26
|
+
"test:api": "jest tests/api --no-cache --no-watchman --setupFiles dotenv/config",
|
|
26
27
|
"clean": "del-cli dist/**",
|
|
27
28
|
"prebuild": "npm run clean",
|
|
28
29
|
"build": "npm run build:esm && npm run build:cjs && npm run build:bin",
|
|
@@ -35,7 +36,7 @@
|
|
|
35
36
|
},
|
|
36
37
|
"overrides": {
|
|
37
38
|
"graphql": "$graphql",
|
|
38
|
-
"rollup": "3.29.
|
|
39
|
+
"rollup": "3.29.4"
|
|
39
40
|
},
|
|
40
41
|
"browserslist": "> 0.25%, not dead",
|
|
41
42
|
"publishConfig": {
|
|
@@ -62,16 +63,17 @@
|
|
|
62
63
|
"uuid": "^9.0.0"
|
|
63
64
|
},
|
|
64
65
|
"devDependencies": {
|
|
65
|
-
"@smartive/eslint-config": "3.
|
|
66
|
+
"@smartive/eslint-config": "3.3.0",
|
|
66
67
|
"@smartive/prettier-config": "3.1.2",
|
|
67
|
-
"@types/jest": "29.5.
|
|
68
|
-
"@types/lodash": "4.14.
|
|
69
|
-
"@types/luxon": "3.3.
|
|
70
|
-
"@types/
|
|
68
|
+
"@types/jest": "29.5.6",
|
|
69
|
+
"@types/lodash": "4.14.200",
|
|
70
|
+
"@types/luxon": "3.3.3",
|
|
71
|
+
"@types/pg": "8.10.2",
|
|
72
|
+
"@types/uuid": "9.0.6",
|
|
71
73
|
"create-ts-index": "1.14.0",
|
|
72
74
|
"del-cli": "5.1.0",
|
|
73
|
-
"esbuild": "0.19.
|
|
74
|
-
"eslint": "8.
|
|
75
|
+
"esbuild": "0.19.5",
|
|
76
|
+
"eslint": "8.52.0",
|
|
75
77
|
"graphql-request": "6.1.0",
|
|
76
78
|
"jest": "29.7.0",
|
|
77
79
|
"mock-knex": "0.4.12",
|
package/src/api/execute.ts
CHANGED
|
@@ -12,7 +12,7 @@ export const execute = async ({
|
|
|
12
12
|
additionalResolvers?: IResolvers<any, any>;
|
|
13
13
|
body: any;
|
|
14
14
|
} & Omit<Context, 'document'>) => {
|
|
15
|
-
const document = generate(ctx.
|
|
15
|
+
const document = generate(ctx.models);
|
|
16
16
|
|
|
17
17
|
const generatedResolvers = getResolvers(ctx.models);
|
|
18
18
|
|
package/src/bin/gqm/gqm.ts
CHANGED
|
@@ -40,12 +40,13 @@ program
|
|
|
40
40
|
.command('generate')
|
|
41
41
|
.description('Generate all the things')
|
|
42
42
|
.action(async () => {
|
|
43
|
-
const
|
|
43
|
+
const models = await parseModels();
|
|
44
44
|
const generatedFolderPath = await getSetting('generatedFolderPath');
|
|
45
|
-
|
|
46
|
-
writeToFile(`${generatedFolderPath}/
|
|
47
|
-
writeToFile(`${generatedFolderPath}/
|
|
48
|
-
writeToFile(`${generatedFolderPath}/db/
|
|
45
|
+
const gqlModule = await getSetting('gqlModule');
|
|
46
|
+
writeToFile(`${generatedFolderPath}/schema.graphql`, printSchemaFromModels(models));
|
|
47
|
+
writeToFile(`${generatedFolderPath}/client/mutations.ts`, generateMutations(models, gqlModule));
|
|
48
|
+
writeToFile(`${generatedFolderPath}/db/index.ts`, generateDBModels(models));
|
|
49
|
+
writeToFile(`${generatedFolderPath}/db/knex.ts`, generateKnexTables(models));
|
|
49
50
|
await generateGraphqlApiTypes();
|
|
50
51
|
await generateGraphqlClientTypes();
|
|
51
52
|
});
|
|
@@ -54,45 +55,44 @@ program
|
|
|
54
55
|
.command('generate-models')
|
|
55
56
|
.description('Generate models.json')
|
|
56
57
|
.action(async () => {
|
|
57
|
-
|
|
58
|
-
const generatedFolderPath = await getSetting('generatedFolderPath');
|
|
59
|
-
writeToFile(`${generatedFolderPath}/models.json`, JSON.stringify(rawModels, null, 2));
|
|
58
|
+
await parseModels();
|
|
60
59
|
});
|
|
61
60
|
|
|
62
61
|
program
|
|
63
62
|
.command('generate-schema')
|
|
64
63
|
.description('Generate schema')
|
|
65
64
|
.action(async () => {
|
|
66
|
-
const
|
|
65
|
+
const models = await parseModels();
|
|
67
66
|
const generatedFolderPath = await getSetting('generatedFolderPath');
|
|
68
|
-
writeToFile(`${generatedFolderPath}/schema.graphql`, printSchemaFromModels(
|
|
67
|
+
writeToFile(`${generatedFolderPath}/schema.graphql`, printSchemaFromModels(models));
|
|
69
68
|
});
|
|
70
69
|
|
|
71
70
|
program
|
|
72
71
|
.command('generate-mutation-queries')
|
|
73
72
|
.description('Generate mutation-queries')
|
|
74
73
|
.action(async () => {
|
|
75
|
-
const
|
|
74
|
+
const models = await parseModels();
|
|
76
75
|
const generatedFolderPath = await getSetting('generatedFolderPath');
|
|
77
|
-
|
|
76
|
+
const gqlModule = await getSetting('gqlModule');
|
|
77
|
+
writeToFile(`${generatedFolderPath}/client/mutations.ts`, generateMutations(models, gqlModule));
|
|
78
78
|
});
|
|
79
79
|
|
|
80
80
|
program
|
|
81
81
|
.command('generate-db-types')
|
|
82
82
|
.description('Generate DB types')
|
|
83
83
|
.action(async () => {
|
|
84
|
-
const
|
|
84
|
+
const models = await parseModels();
|
|
85
85
|
const generatedFolderPath = await getSetting('generatedFolderPath');
|
|
86
|
-
writeToFile(`${generatedFolderPath}/db/index.ts`,
|
|
86
|
+
writeToFile(`${generatedFolderPath}/db/index.ts`, generateDBModels(models));
|
|
87
87
|
});
|
|
88
88
|
|
|
89
89
|
program
|
|
90
90
|
.command('generate-knex-types')
|
|
91
91
|
.description('Generate Knex types')
|
|
92
92
|
.action(async () => {
|
|
93
|
-
const
|
|
93
|
+
const models = await parseModels();
|
|
94
94
|
const generatedFolderPath = await getSetting('generatedFolderPath');
|
|
95
|
-
writeToFile(`${generatedFolderPath}/db/knex.ts`, generateKnexTables(
|
|
95
|
+
writeToFile(`${generatedFolderPath}/db/knex.ts`, generateKnexTables(models));
|
|
96
96
|
});
|
|
97
97
|
|
|
98
98
|
program
|
|
@@ -110,14 +110,16 @@ program
|
|
|
110
110
|
});
|
|
111
111
|
|
|
112
112
|
program
|
|
113
|
-
.command('generate-migration')
|
|
113
|
+
.command('generate-migration [<name>] [<date>]')
|
|
114
114
|
.description('Generate Migration')
|
|
115
|
-
.action(async () => {
|
|
115
|
+
.action(async (name, date) => {
|
|
116
116
|
const git = simpleGit();
|
|
117
117
|
|
|
118
|
-
|
|
118
|
+
if (!name) {
|
|
119
|
+
name = (await git.branch()).current.split('/').pop();
|
|
120
|
+
}
|
|
119
121
|
|
|
120
|
-
if (name
|
|
122
|
+
if (!name || ['main', 'staging', 'production'].includes(name)) {
|
|
121
123
|
name = await readLine('Migration name:');
|
|
122
124
|
}
|
|
123
125
|
|
|
@@ -125,10 +127,10 @@ program
|
|
|
125
127
|
const db = knex(knexfile);
|
|
126
128
|
|
|
127
129
|
try {
|
|
128
|
-
const
|
|
129
|
-
const migrations = await new MigrationGenerator(db,
|
|
130
|
+
const models = await parseModels();
|
|
131
|
+
const migrations = await new MigrationGenerator(db, models).generate();
|
|
130
132
|
|
|
131
|
-
writeToFile(`migrations/${getMigrationDate()}_${name}.ts`, migrations);
|
|
133
|
+
writeToFile(`migrations/${date || getMigrationDate()}_${name}.ts`, migrations);
|
|
132
134
|
} finally {
|
|
133
135
|
await db.destroy();
|
|
134
136
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { IndentationText, Project } from 'ts-morph';
|
|
2
|
-
import {
|
|
2
|
+
import { Models } from '../..';
|
|
3
3
|
import { getSetting, writeToFile } from './settings';
|
|
4
4
|
import { staticEval } from './static-eval';
|
|
5
5
|
import { findDeclarationInFile } from './utils';
|
|
@@ -13,12 +13,12 @@ export const parseModels = async () => {
|
|
|
13
13
|
const modelsPath = await getSetting('modelsPath');
|
|
14
14
|
const sourceFile = project.addSourceFileAtPath(modelsPath);
|
|
15
15
|
|
|
16
|
-
const modelsDeclaration = findDeclarationInFile(sourceFile, '
|
|
16
|
+
const modelsDeclaration = findDeclarationInFile(sourceFile, 'models');
|
|
17
17
|
|
|
18
|
-
const
|
|
18
|
+
const models = staticEval(modelsDeclaration, {}) as Models;
|
|
19
19
|
|
|
20
20
|
const generatedFolderPath = await getSetting('generatedFolderPath');
|
|
21
|
-
writeToFile(`${generatedFolderPath}/models.json`, JSON.stringify(
|
|
21
|
+
writeToFile(`${generatedFolderPath}/models.json`, JSON.stringify(models.definitions, null, 2));
|
|
22
22
|
|
|
23
|
-
return
|
|
23
|
+
return models;
|
|
24
24
|
};
|
package/src/bin/gqm/settings.ts
CHANGED
|
@@ -30,6 +30,9 @@ const DEFAULTS = {
|
|
|
30
30
|
ensureDirectoryExists(path);
|
|
31
31
|
},
|
|
32
32
|
},
|
|
33
|
+
gqlModule: {
|
|
34
|
+
defaultValue: '@smartive/graphql-magic',
|
|
35
|
+
},
|
|
33
36
|
};
|
|
34
37
|
|
|
35
38
|
type Settings = {
|
|
@@ -45,8 +48,10 @@ const initSetting = async (name: string) => {
|
|
|
45
48
|
|
|
46
49
|
const initSettings = async () => {
|
|
47
50
|
const settings: Settings = {} as Settings;
|
|
48
|
-
for (const name of Object.
|
|
49
|
-
|
|
51
|
+
for (const [name, config] of Object.entries(DEFAULTS)) {
|
|
52
|
+
if ('queston' in config) {
|
|
53
|
+
settings[name] = await initSetting(name);
|
|
54
|
+
}
|
|
50
55
|
}
|
|
51
56
|
saveSettings(settings);
|
|
52
57
|
};
|
|
@@ -65,8 +70,12 @@ export const getSettings = async (): Promise<Settings> => {
|
|
|
65
70
|
export const getSetting = async (name: keyof Settings): Promise<string> => {
|
|
66
71
|
const settings = await getSettings();
|
|
67
72
|
if (!(name in settings)) {
|
|
68
|
-
|
|
69
|
-
|
|
73
|
+
if ('question' in DEFAULTS[name]) {
|
|
74
|
+
settings[name] = await initSetting(name);
|
|
75
|
+
saveSettings(settings);
|
|
76
|
+
} else {
|
|
77
|
+
return DEFAULTS[name].defaultValue;
|
|
78
|
+
}
|
|
70
79
|
}
|
|
71
80
|
return settings[name];
|
|
72
81
|
};
|
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
TemplateExpression,
|
|
12
12
|
TemplateTail,
|
|
13
13
|
} from 'ts-morph';
|
|
14
|
+
import { Models } from '../../models/models';
|
|
14
15
|
import { Visitor, visit } from './visitor';
|
|
15
16
|
|
|
16
17
|
export const staticEval = (node: Node | undefined, context: Dictionary<unknown>) =>
|
|
@@ -54,6 +55,8 @@ const VISITOR: Visitor<unknown, Dictionary<unknown>> = {
|
|
|
54
55
|
return process;
|
|
55
56
|
case 'Symbol':
|
|
56
57
|
return Symbol;
|
|
58
|
+
case 'Models':
|
|
59
|
+
return Models;
|
|
57
60
|
}
|
|
58
61
|
const definitionNodes = node.getDefinitionNodes();
|
|
59
62
|
if (!definitionNodes.length) {
|
|
@@ -204,4 +207,6 @@ const VISITOR: Visitor<unknown, Dictionary<unknown>> = {
|
|
|
204
207
|
},
|
|
205
208
|
[SyntaxKind.NoSubstitutionTemplateLiteral]: (node) => node.getLiteralValue(),
|
|
206
209
|
[SyntaxKind.NullKeyword]: () => null,
|
|
210
|
+
[SyntaxKind.NewExpression]: (node, context) =>
|
|
211
|
+
new (staticEval(node.getExpression(), context))(...node.getArguments().map((arg) => staticEval(arg, context))),
|
|
207
212
|
};
|
package/src/bin/gqm/templates.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export const EMPTY_MODELS = `
|
|
2
|
-
import { RawModels,
|
|
2
|
+
import { RawModels, Models } from '@smartive/graphql-magic';
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
const rawModels: RawModels = [
|
|
5
5
|
{
|
|
6
6
|
kind: 'entity',
|
|
7
7
|
name: 'User',
|
|
@@ -9,10 +9,23 @@ export const rawModels: RawModels = [
|
|
|
9
9
|
},
|
|
10
10
|
]
|
|
11
11
|
|
|
12
|
-
export const models =
|
|
12
|
+
export const models = new Models(rawModels);
|
|
13
13
|
`;
|
|
14
14
|
|
|
15
15
|
export const KNEXFILE = `
|
|
16
|
+
import { DateTime } from 'luxon';
|
|
17
|
+
import { types } from 'pg';
|
|
18
|
+
|
|
19
|
+
const dateOids = { date: 1082, timestamptz: 1184, timestamp: 1114 };
|
|
20
|
+
for (const oid of Object.values(dateOids)) {
|
|
21
|
+
types.setTypeParser(oid, (val) => DateTime.fromSQL(val));
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const numberOids = { int8: 20, float8: 701, numeric: 1700 };
|
|
25
|
+
for (const oid of Object.values(numberOids)) {
|
|
26
|
+
types.setTypeParser(oid, Number);
|
|
27
|
+
}
|
|
28
|
+
|
|
16
29
|
const config = {
|
|
17
30
|
client: 'postgresql',
|
|
18
31
|
connection: {
|
|
@@ -21,6 +34,13 @@ const config = {
|
|
|
21
34
|
user: process.env.DATABASE_USER,
|
|
22
35
|
password: process.env.DATABASE_PASSWORD,
|
|
23
36
|
},
|
|
37
|
+
migrations: {
|
|
38
|
+
tableName: 'knex_migrations',
|
|
39
|
+
},
|
|
40
|
+
pool: {
|
|
41
|
+
min: 0,
|
|
42
|
+
max: 30,
|
|
43
|
+
},
|
|
24
44
|
} as const;
|
|
25
45
|
|
|
26
46
|
export default config;
|
package/src/client/mutations.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import upperCase from 'lodash/upperCase';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { isRootModel, not } from '..';
|
|
3
|
+
import { Models } from '../models/models';
|
|
4
4
|
|
|
5
5
|
const constantCase = (str: string) => upperCase(str).replace(/ /g, '_');
|
|
6
6
|
|
|
7
|
-
export const generateMutations = (models:
|
|
7
|
+
export const generateMutations = (models: Models, gqmModule = '@smartive/graphql-magic') => {
|
|
8
8
|
const parts: string[] = [];
|
|
9
|
-
for (const { name, creatable, updatable, deletable } of models.filter(
|
|
9
|
+
for (const { name, creatable, updatable, deletable } of models.entities.filter(not(isRootModel))) {
|
|
10
10
|
if (creatable) {
|
|
11
11
|
parts.push(
|
|
12
12
|
`export const CREATE_${constantCase(
|
|
@@ -29,8 +29,14 @@ export const generateMutations = (models: RawModels) => {
|
|
|
29
29
|
name
|
|
30
30
|
)} = gql\`\n mutation Delete${name}Mutation($id: ID!) {\n delete${name}(where: { id: $id })\n }\n\`;`
|
|
31
31
|
);
|
|
32
|
+
|
|
33
|
+
parts.push(
|
|
34
|
+
`export const RESTORE_${constantCase(
|
|
35
|
+
name
|
|
36
|
+
)} = gql\`\n mutation Restore${name}Mutation($id: ID!) {\n restore${name}(where: { id: $id })\n }\n\`;`
|
|
37
|
+
);
|
|
32
38
|
}
|
|
33
39
|
}
|
|
34
40
|
|
|
35
|
-
return `import { gql } from "
|
|
41
|
+
return `import { gql } from "${gqmModule}";\n\n${parts.join('\n\n')}`;
|
|
36
42
|
};
|
package/src/client/queries.ts
CHANGED
|
@@ -1,23 +1,20 @@
|
|
|
1
1
|
import upperFirst from 'lodash/upperFirst';
|
|
2
|
-
import {
|
|
3
|
-
import { Model, Models, Relation
|
|
2
|
+
import { ManyToManyRelation } from '..';
|
|
3
|
+
import { EntityModel, Model, Models, Relation } from '../models/models';
|
|
4
4
|
import {
|
|
5
5
|
actionableRelations,
|
|
6
6
|
and,
|
|
7
|
-
getModelPlural,
|
|
8
|
-
getModelPluralField,
|
|
9
7
|
isQueriableBy,
|
|
10
8
|
isRelation,
|
|
11
9
|
isSimpleField,
|
|
12
10
|
isToOneRelation,
|
|
13
11
|
isUpdatableBy,
|
|
14
12
|
not,
|
|
15
|
-
summonByName,
|
|
16
13
|
typeToField,
|
|
17
14
|
} from '../models/utils';
|
|
18
15
|
|
|
19
16
|
export const getUpdateEntityQuery = (
|
|
20
|
-
model:
|
|
17
|
+
model: EntityModel,
|
|
21
18
|
role: any,
|
|
22
19
|
fields?: string[] | undefined,
|
|
23
20
|
additionalFields = ''
|
|
@@ -38,8 +35,7 @@ export const getUpdateEntityQuery = (
|
|
|
38
35
|
}`;
|
|
39
36
|
|
|
40
37
|
export const getEditEntityRelationsQuery = (
|
|
41
|
-
|
|
42
|
-
model: Model,
|
|
38
|
+
model: EntityModel,
|
|
43
39
|
action: 'create' | 'update' | 'filter',
|
|
44
40
|
fields?: string[],
|
|
45
41
|
ignoreFields?: string[],
|
|
@@ -53,21 +49,19 @@ export const getEditEntityRelationsQuery = (
|
|
|
53
49
|
!!relations.length &&
|
|
54
50
|
`query ${upperFirst(action)}${model.name}Relations {
|
|
55
51
|
${relations
|
|
56
|
-
.map((
|
|
57
|
-
const model = summonByName(models, type);
|
|
58
|
-
|
|
52
|
+
.map((relation) => {
|
|
59
53
|
let filters = '';
|
|
60
|
-
if (
|
|
61
|
-
const displayField =
|
|
54
|
+
if (relation.targetModel.displayField) {
|
|
55
|
+
const displayField = relation.targetModel.fieldsByName[relation.targetModel.displayField];
|
|
62
56
|
if (displayField.orderable) {
|
|
63
|
-
filters = `(orderBy: [{ ${
|
|
57
|
+
filters = `(orderBy: [{ ${relation.targetModel.displayField}: ASC }])`;
|
|
64
58
|
}
|
|
65
59
|
}
|
|
66
60
|
|
|
67
|
-
return `${name}: ${
|
|
61
|
+
return `${relation.name}: ${relation.targetModel.pluralField}${filters} {
|
|
68
62
|
id
|
|
69
|
-
display: ${
|
|
70
|
-
${additionalFields[name] || ''}
|
|
63
|
+
display: ${relation.targetModel.displayField || 'id'}
|
|
64
|
+
${additionalFields[relation.name] || ''}
|
|
71
65
|
}`;
|
|
72
66
|
})
|
|
73
67
|
.join(' ')}
|
|
@@ -75,48 +69,20 @@ export const getEditEntityRelationsQuery = (
|
|
|
75
69
|
);
|
|
76
70
|
};
|
|
77
71
|
|
|
78
|
-
export const getManyToManyRelations = (model: Model, fields?: string[], ignoreFields?: string[]) => {
|
|
79
|
-
const manyToManyRelations: [ReverseRelation, Relation][] = [];
|
|
80
|
-
for (const field of model.reverseRelations) {
|
|
81
|
-
if ((fields && !fields.includes(field.name)) || (ignoreFields && ignoreFields.includes(field.name))) {
|
|
82
|
-
continue;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
const relation = field.model.relations.find(
|
|
86
|
-
(relation) => !relation.field.generated && relation.field.name !== field.field.name
|
|
87
|
-
);
|
|
88
|
-
if (!relation) {
|
|
89
|
-
continue;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
const inapplicableFields = field.model.fields.filter(
|
|
93
|
-
(otherField) => !otherField.generated && ![field.field.name, relation.field.name].includes(otherField.name)
|
|
94
|
-
);
|
|
95
|
-
if (inapplicableFields.length) {
|
|
96
|
-
continue;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
manyToManyRelations.push([field, relation]);
|
|
100
|
-
}
|
|
101
|
-
return manyToManyRelations;
|
|
102
|
-
};
|
|
103
|
-
|
|
104
|
-
export const getManyToManyRelation = (model: Model, name: string) => getManyToManyRelations(model, [name])[0];
|
|
105
|
-
|
|
106
72
|
export const getManyToManyRelationsQuery = (
|
|
107
73
|
model: Model,
|
|
108
74
|
action: 'create' | 'update',
|
|
109
|
-
manyToManyRelations: [
|
|
75
|
+
manyToManyRelations: ManyToManyRelation[]
|
|
110
76
|
) =>
|
|
111
77
|
!!manyToManyRelations.length &&
|
|
112
78
|
(action === 'update'
|
|
113
79
|
? `query Update${model.name}ManyToManyRelations($id: ID!) {
|
|
114
80
|
${typeToField(model.name)}(where: { id: $id }) {
|
|
115
81
|
${manyToManyRelations
|
|
116
|
-
.map((
|
|
117
|
-
return `${
|
|
82
|
+
.map((relation) => {
|
|
83
|
+
return `${relation.name} {
|
|
118
84
|
id
|
|
119
|
-
${
|
|
85
|
+
${relation.relationToTarget.name} {
|
|
120
86
|
id
|
|
121
87
|
}
|
|
122
88
|
}`;
|
|
@@ -124,20 +90,20 @@ export const getManyToManyRelationsQuery = (
|
|
|
124
90
|
.join(' ')}
|
|
125
91
|
}
|
|
126
92
|
${manyToManyRelations
|
|
127
|
-
.map((
|
|
128
|
-
return `${
|
|
93
|
+
.map((relation) => {
|
|
94
|
+
return `${relation.name}: ${relation.targetModel.pluralField} {
|
|
129
95
|
id
|
|
130
|
-
${
|
|
96
|
+
${relation.targetModel.displayField || ''}
|
|
131
97
|
}`;
|
|
132
98
|
})
|
|
133
99
|
.join(' ')}
|
|
134
100
|
}`
|
|
135
101
|
: `query Create${model.name}ManyToManyRelations {
|
|
136
102
|
${manyToManyRelations
|
|
137
|
-
.map((
|
|
138
|
-
return `${
|
|
103
|
+
.map((relation) => {
|
|
104
|
+
return `${relation.name}: ${relation.targetModel.pluralField} {
|
|
139
105
|
id
|
|
140
|
-
${
|
|
106
|
+
${relation.targetModel.displayField || ''}
|
|
141
107
|
}`;
|
|
142
108
|
})
|
|
143
109
|
.join(' ')}
|
|
@@ -174,28 +140,28 @@ export const getMutationQuery = (model: Model, action: 'create' | 'update' | 'de
|
|
|
174
140
|
}
|
|
175
141
|
`;
|
|
176
142
|
|
|
177
|
-
export const displayField = (model:
|
|
143
|
+
export const displayField = (model: EntityModel) => `
|
|
178
144
|
${model.displayField ? `display: ${model.displayField}` : ''}
|
|
179
145
|
`;
|
|
180
146
|
|
|
181
147
|
export const getEntityListQuery = (
|
|
182
|
-
model:
|
|
148
|
+
model: EntityModel,
|
|
183
149
|
role: string,
|
|
184
150
|
additionalFields = '',
|
|
185
151
|
root?: {
|
|
186
|
-
model:
|
|
152
|
+
model: EntityModel;
|
|
187
153
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
188
154
|
entity: any;
|
|
189
155
|
reverseRelationName: string;
|
|
190
156
|
}
|
|
191
|
-
) => `query ${
|
|
157
|
+
) => `query ${model.plural}List(
|
|
192
158
|
${root ? '$id: ID!,' : ''}
|
|
193
159
|
$limit: Int!,
|
|
194
160
|
$where: ${model.name}Where!,
|
|
195
161
|
${model.fields.some(({ searchable }) => searchable) ? '$search: String,' : ''}
|
|
196
162
|
) {
|
|
197
163
|
${root ? `root: ${typeToField(root.model.name)}(where: { id: $id }) {` : ''}
|
|
198
|
-
data: ${root ? root.reverseRelationName :
|
|
164
|
+
data: ${root ? root.reverseRelationName : model.pluralField}(limit: $limit, where: $where, ${
|
|
199
165
|
model.fields.some(({ searchable }) => searchable) ? ', search: $search' : ''
|
|
200
166
|
}) {
|
|
201
167
|
${displayField(model)}
|
|
@@ -209,12 +175,11 @@ export type VisibleRelationsByRole = Record<string, Record<string, string[]>>;
|
|
|
209
175
|
|
|
210
176
|
export const isVisibleRelation = (visibleRelationsByRole: VisibleRelationsByRole, modelName: string, role: string) => {
|
|
211
177
|
const whitelist = visibleRelationsByRole[role]?.[modelName];
|
|
212
|
-
return (
|
|
178
|
+
return (relation: Relation) => (whitelist ? whitelist.includes(relation.name) : true);
|
|
213
179
|
};
|
|
214
180
|
|
|
215
181
|
export const getEntityQuery = (
|
|
216
|
-
|
|
217
|
-
model: Model,
|
|
182
|
+
model: EntityModel,
|
|
218
183
|
role: string,
|
|
219
184
|
visibleRelationsByRole: VisibleRelationsByRole,
|
|
220
185
|
typesWithSubRelations: string[]
|
|
@@ -223,42 +188,40 @@ export const getEntityQuery = (
|
|
|
223
188
|
${displayField(model)}
|
|
224
189
|
${model.fields.filter(and(isSimpleField, isQueriableBy(role))).map(({ name }) => name)}
|
|
225
190
|
${queryRelations(
|
|
226
|
-
models,
|
|
227
|
-
model.
|
|
191
|
+
model.models,
|
|
192
|
+
model.relations.filter(isVisibleRelation(visibleRelationsByRole, model.name, role)),
|
|
228
193
|
role,
|
|
229
194
|
typesWithSubRelations
|
|
230
195
|
)}
|
|
231
196
|
${queryRelations(
|
|
232
|
-
models,
|
|
233
|
-
model.reverseRelations.filter(
|
|
197
|
+
model.models,
|
|
198
|
+
model.reverseRelations.filter(
|
|
199
|
+
(reverseRelation) =>
|
|
200
|
+
isToOneRelation(reverseRelation.field) &&
|
|
201
|
+
isVisibleRelation(visibleRelationsByRole, model.name, role)(reverseRelation)
|
|
202
|
+
),
|
|
234
203
|
role,
|
|
235
204
|
typesWithSubRelations
|
|
236
205
|
)}
|
|
237
206
|
}
|
|
238
207
|
}`;
|
|
239
208
|
|
|
240
|
-
export const getFindEntityQuery = (model:
|
|
209
|
+
export const getFindEntityQuery = (model: EntityModel, role: string) => `query Find${model.name}($where: ${
|
|
241
210
|
model.name
|
|
242
211
|
}Where!, $orderBy: [${model.name}OrderBy!]) {
|
|
243
|
-
data: ${
|
|
212
|
+
data: ${model.pluralField}(limit: 1, where: $where, orderBy: $orderBy) {
|
|
244
213
|
${model.fields.filter(and(isSimpleField, isQueriableBy(role))).map(({ name }) => name)}
|
|
245
214
|
}
|
|
246
215
|
}`;
|
|
247
216
|
|
|
248
|
-
export const queryRelations = (
|
|
249
|
-
models: Models,
|
|
250
|
-
relations: { name: string; type: string }[],
|
|
251
|
-
role: string,
|
|
252
|
-
typesWithSubRelations: string[]
|
|
253
|
-
) =>
|
|
217
|
+
export const queryRelations = (models: Models, relations: Relation[], role: string, typesWithSubRelations: string[]) =>
|
|
254
218
|
relations
|
|
255
|
-
.map((
|
|
256
|
-
const
|
|
257
|
-
const subRelations = typesWithSubRelations.includes(type) ? relatedModel.fields.filter(isRelation) : [];
|
|
219
|
+
.map((relation): string => {
|
|
220
|
+
const subRelations = typesWithSubRelations.includes(relation.targetModel.name) ? relation.targetModel.relations : [];
|
|
258
221
|
|
|
259
|
-
return `${name} {
|
|
222
|
+
return `${relation.name} {
|
|
260
223
|
id
|
|
261
|
-
${displayField(
|
|
224
|
+
${displayField(relation.targetModel)}
|
|
262
225
|
${subRelations.length > 0 ? queryRelations(models, subRelations, role, typesWithSubRelations) : ''}
|
|
263
226
|
}`;
|
|
264
227
|
})
|
package/src/context.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { DocumentNode, GraphQLResolveInfo } from 'graphql';
|
|
|
2
2
|
import { IncomingMessage } from 'http';
|
|
3
3
|
import { Knex } from 'knex';
|
|
4
4
|
import { DateTime } from 'luxon';
|
|
5
|
-
import { Models
|
|
5
|
+
import { Models } from './models/models';
|
|
6
6
|
import { Entity, MutationHook } from './models/mutation-hook';
|
|
7
7
|
import { Permissions } from './permissions/generate';
|
|
8
8
|
import { AliasGenerator } from './resolvers/utils';
|
|
@@ -18,7 +18,6 @@ export type Context = {
|
|
|
18
18
|
locale: string;
|
|
19
19
|
locales: string[];
|
|
20
20
|
user: User;
|
|
21
|
-
rawModels: RawModels;
|
|
22
21
|
models: Models;
|
|
23
22
|
permissions: Permissions;
|
|
24
23
|
mutationHook?: MutationHook;
|