sasat 0.19.6 → 0.19.8
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/lib/generatorv2/codegen/gql/generateTypeDefs.js +24 -12
- package/lib/generatorv2/codegen/ts/generateQueryResolver.js +71 -2
- package/lib/generatorv2/codegen/ts/generateUserDefinedCondition.d.ts +2 -0
- package/lib/generatorv2/codegen/ts/generateUserDefinedCondition.js +58 -0
- package/lib/generatorv2/codegen/ts/relationMap/getRequiredColumnNames.d.ts +0 -1
- package/lib/generatorv2/codegen/ts/relationMap/getRequiredColumnNames.js +6 -14
- package/lib/generatorv2/codegen/ts/relationMap/index.js +8 -10
- package/lib/generatorv2/codegen/ts/relationMap/makeCondition.js +9 -3
- package/lib/generatorv2/codegen/ts/relationMap/makeJoinConditionValue.d.ts +5 -0
- package/lib/generatorv2/codegen/ts/relationMap/makeJoinConditionValue.js +73 -0
- package/lib/generatorv2/codegen/ts/relationMap/makeNoContexError.d.ts +2 -2
- package/lib/generatorv2/codegen/ts/relationMap/makeNoContexError.js +7 -5
- package/lib/generatorv2/codegen/ts/scripts/makeConditonValueExpr.d.ts +3 -0
- package/lib/generatorv2/codegen/ts/scripts/makeConditonValueExpr.js +48 -0
- package/lib/generatorv2/codegen/ts/scripts/makeQueryConditionExpr.d.ts +2 -0
- package/lib/generatorv2/codegen/ts/scripts/makeQueryConditionExpr.js +15 -0
- package/lib/generatorv2/codegen/tscodegen_v2.d.ts +1 -0
- package/lib/generatorv2/codegen/tscodegen_v2.js +4 -0
- package/lib/generatorv2/codegen_v2.d.ts +1 -0
- package/lib/generatorv2/codegen_v2.js +8 -0
- package/lib/generatorv2/nodes/ConditionNode.d.ts +15 -7
- package/lib/generatorv2/nodes/ConditionValues.d.ts +26 -0
- package/lib/generatorv2/nodes/ConditionValues.js +1 -0
- package/lib/generatorv2/nodes/JoinConditionNode.d.ts +34 -0
- package/lib/generatorv2/nodes/JoinConditionNode.js +1 -0
- package/lib/generatorv2/nodes/QueryConditionNode.d.ts +23 -0
- package/lib/generatorv2/nodes/QueryConditionNode.js +1 -0
- package/lib/generatorv2/nodes/entityNode.d.ts +6 -3
- package/lib/generatorv2/nodes/entityNode.js +19 -20
- package/lib/generatorv2/nodes/rootNode.d.ts +0 -2
- package/lib/generatorv2/parse.js +0 -2
- package/lib/generatorv2/parser/makeQueryNodes.d.ts +0 -3
- package/lib/generatorv2/parser/makeQueryNodes.js +1 -68
- package/lib/generatorv2/scripts/gqlTypes.d.ts +2 -2
- package/lib/generatorv2/scripts/gqlTypes.js +11 -1
- package/lib/index.d.ts +5 -1
- package/lib/index.js +4 -1
- package/lib/migration/creators/tableCreator.d.ts +3 -1
- package/lib/migration/creators/tableCreator.js +6 -0
- package/lib/migration/data/GQLOption.d.ts +13 -4
- package/lib/migration/data/GQLOption.js +32 -4
- package/lib/migration/data/virtualRelation.d.ts +4 -4
- package/lib/migration/makeCondition.d.ts +21 -8
- package/lib/migration/makeCondition.js +63 -21
- package/lib/migration/makeQuery.d.ts +8 -0
- package/lib/migration/makeQuery.js +25 -0
- package/lib/runtime/date.d.ts +8 -0
- package/lib/runtime/date.js +56 -0
- package/lib/runtime/dsl/query/createQueryResolveInfo.d.ts +1 -2
- package/lib/runtime/pagingOption.d.ts +10 -0
- package/lib/runtime/pagingOption.js +9 -0
- package/lib/runtime/types.d.ts +3 -0
- package/lib/runtime/types.js +1 -0
- package/lib/runtime/util.d.ts +0 -6
- package/lib/runtime/util.js +0 -55
- package/package.json +9 -9
|
@@ -3,10 +3,11 @@ import { nonNullableFilter } from '../../../util/type.js';
|
|
|
3
3
|
import { GQLString, makeGQLType } from './gqlString.js';
|
|
4
4
|
import { typeFieldDefinitionToTsg } from './typeDefinition.js';
|
|
5
5
|
import { EntityName } from '../../nodes/entityName.js';
|
|
6
|
+
import { getArgs } from '../../../migration/data/GQLOption.js';
|
|
6
7
|
export const generateTypeDefs = (root) => {
|
|
7
8
|
const types = [
|
|
8
9
|
...root.entities.map(makeEntityType),
|
|
9
|
-
makeQuery(root
|
|
10
|
+
makeQuery(root),
|
|
10
11
|
makeMutation(root.mutations),
|
|
11
12
|
makeSubscription(root.subscriptions.filter(it => it.gqlEnabled)),
|
|
12
13
|
].filter(nonNullableFilter);
|
|
@@ -61,18 +62,29 @@ const makeUpdateInput = (node) => {
|
|
|
61
62
|
return null;
|
|
62
63
|
return makeInput(node.name.updateInputName(), node.updateInput.fields);
|
|
63
64
|
};
|
|
64
|
-
const
|
|
65
|
-
|
|
65
|
+
const makeQueryTypeDef = (entity, query) => {
|
|
66
|
+
const args = getArgs(query, entity);
|
|
67
|
+
return tsg.propertyAssign(query.type === 'primary' ? entity.primaryQueryName() : query.name, typeFieldDefinitionToTsg({
|
|
68
|
+
return: GQLString.type({
|
|
69
|
+
typeName: entity.name.name,
|
|
70
|
+
entity: true,
|
|
71
|
+
array: query.type === 'list-paging' || query.type === 'list-all',
|
|
72
|
+
nullable: query.type !== 'list-paging' && query.type !== 'list-all',
|
|
73
|
+
}),
|
|
74
|
+
args: args.map(it => ({
|
|
75
|
+
name: it.name,
|
|
76
|
+
type: it.type + '!',
|
|
77
|
+
})),
|
|
78
|
+
}));
|
|
79
|
+
};
|
|
80
|
+
const makeQueryProperties = (root) => {
|
|
81
|
+
return root.entities.flatMap(entity => entity.queries.map(it => makeQueryTypeDef(entity, it)));
|
|
82
|
+
};
|
|
83
|
+
const makeQuery = (root) => {
|
|
84
|
+
const properties = makeQueryProperties(root);
|
|
85
|
+
if (properties.length === 0)
|
|
66
86
|
return null;
|
|
67
|
-
return tsg.propertyAssign('Query', tsg.object(...
|
|
68
|
-
return tsg.propertyAssign(query.queryName, typeFieldDefinitionToTsg({
|
|
69
|
-
return: GQLString.type(query.returnType),
|
|
70
|
-
args: query.args.map(arg => ({
|
|
71
|
-
name: arg.name,
|
|
72
|
-
type: GQLString.type(arg.type),
|
|
73
|
-
})),
|
|
74
|
-
}));
|
|
75
|
-
})));
|
|
87
|
+
return tsg.propertyAssign('Query', tsg.object(...properties));
|
|
76
88
|
};
|
|
77
89
|
const makeMutation = (mutations) => {
|
|
78
90
|
if (mutations.length === 0)
|
|
@@ -3,9 +3,16 @@ import { columnTypeToTsType } from '../../../migration/column/columnTypes.js';
|
|
|
3
3
|
import { makeTypeRef } from './scripts/getEntityTypeRefs.js';
|
|
4
4
|
import { makeDatasource } from './scripts/makeDatasource.js';
|
|
5
5
|
import { Directory } from '../../directory.js';
|
|
6
|
+
import { nonNullable } from '../../../runtime/util.js';
|
|
7
|
+
import { getArgs } from '../../../migration/data/GQLOption.js';
|
|
8
|
+
import { toTsType } from '../../scripts/gqlTypes.js';
|
|
9
|
+
import { makeQueryConditionExpr } from './scripts/makeQueryConditionExpr.js';
|
|
10
|
+
const DIR = 'GENERATED';
|
|
6
11
|
export const generateQueryResolver = (root) => {
|
|
7
12
|
return new TsFile(tsg
|
|
8
|
-
.variable('const', 'query', tsg.object(...root.
|
|
13
|
+
.variable('const', 'query', tsg.object(...root.entities
|
|
14
|
+
.flatMap(entity => entity.queries.map(query => makeGQLQuery(entity, query)))
|
|
15
|
+
.filter(nonNullable)))
|
|
9
16
|
.export()).disableEsLint();
|
|
10
17
|
};
|
|
11
18
|
const makeResolver = () => tsg.identifier('makeResolver').importFrom('sasat');
|
|
@@ -22,10 +29,72 @@ const makeQuery = (node) => {
|
|
|
22
29
|
.toAsync())
|
|
23
30
|
.typeArgs(tsg
|
|
24
31
|
.typeRef('GQLContext')
|
|
25
|
-
.importFrom(Directory.resolve(
|
|
32
|
+
.importFrom(Directory.resolve(DIR, 'BASE', 'context')), tsg.typeLiteral(node.args.map(it => tsg.propertySignature(it.name, tsg.typeRef(it.type.entity
|
|
26
33
|
? it.type.typeName
|
|
27
34
|
: columnTypeToTsType(it.type.dbType)))))));
|
|
28
35
|
};
|
|
36
|
+
const pagingOption = {
|
|
37
|
+
kind: 'paging-option',
|
|
38
|
+
name: 'option',
|
|
39
|
+
type: 'PagingOption',
|
|
40
|
+
};
|
|
41
|
+
const makeGQLQuery = (entity, query) => {
|
|
42
|
+
const args = getArgs(query, entity);
|
|
43
|
+
return tsg.propertyAssign(query.type === 'primary' ? entity.name.lowerCase() : query.name, makeResolver()
|
|
44
|
+
.call(tsg
|
|
45
|
+
.arrowFunc([
|
|
46
|
+
tsg.parameter('_'),
|
|
47
|
+
tsg.parameter(`{${args.map(it => it.name).join(',')}}`),
|
|
48
|
+
tsg.parameter('context'),
|
|
49
|
+
tsg.parameter('info'),
|
|
50
|
+
], undefined, makeGQLQueryBody(entity, query))
|
|
51
|
+
.toAsync())
|
|
52
|
+
.typeArgs(tsg
|
|
53
|
+
.typeRef('GQLContext')
|
|
54
|
+
.importFrom(Directory.resolve('GENERATED', 'BASE', 'context')), tsg.typeLiteral(args.map(it => tsg.propertySignature(it.name, it.type === 'PagingOption'
|
|
55
|
+
? tsg.typeRef(it.type).importFrom('sasat')
|
|
56
|
+
: tsg.typeRef(toTsType(it.type)))))));
|
|
57
|
+
};
|
|
58
|
+
const qExpr = tsg.identifier('QExpr').importFrom('sasat');
|
|
59
|
+
const makeGQLQueryBody = (entity, query) => {
|
|
60
|
+
const fields = tsg.variable('const', 'fields', tsg
|
|
61
|
+
.identifier('gqlResolveInfoToField')
|
|
62
|
+
.importFrom('sasat')
|
|
63
|
+
.call(tsg.identifier('info'))
|
|
64
|
+
.as(makeTypeRef(entity.name, 'fields', 'GENERATED')));
|
|
65
|
+
const where = query.conditions && query.conditions.length !== 0
|
|
66
|
+
? tsg.variable('const', 'where', qExpr
|
|
67
|
+
.property('conditions')
|
|
68
|
+
.property('and')
|
|
69
|
+
.call(...(query.conditions || []).map(makeQueryConditionExpr)))
|
|
70
|
+
: null;
|
|
71
|
+
const method = {
|
|
72
|
+
single: 'first',
|
|
73
|
+
primary: entity.primaryQueryName(),
|
|
74
|
+
'list-all': 'find',
|
|
75
|
+
'list-paging': 'findPageable',
|
|
76
|
+
};
|
|
77
|
+
const queryArgs = getArgs(query, entity);
|
|
78
|
+
const primaryArgs = query.type === 'primary'
|
|
79
|
+
? queryArgs.map(it => tsg.identifier(it.name))
|
|
80
|
+
: [];
|
|
81
|
+
const args = [
|
|
82
|
+
...primaryArgs,
|
|
83
|
+
query.type === 'list-paging'
|
|
84
|
+
? tsg
|
|
85
|
+
.identifier('pagingOption')
|
|
86
|
+
.importFrom('sasat')
|
|
87
|
+
.call(tsg.identifier('option'))
|
|
88
|
+
: null,
|
|
89
|
+
tsg.identifier('fields'),
|
|
90
|
+
tsg.identifier(where ? '{ where }' : 'undefined'),
|
|
91
|
+
tsg.identifier('context'),
|
|
92
|
+
].filter(nonNullable);
|
|
93
|
+
const result = makeDatasource(entity.name, DIR)
|
|
94
|
+
.property(method[query.type])
|
|
95
|
+
.call(...args);
|
|
96
|
+
return tsg.block(fields, where, tsg.return(result));
|
|
97
|
+
};
|
|
29
98
|
const makeQueryBody = (node) => {
|
|
30
99
|
if (node.type === 'primary')
|
|
31
100
|
return makePrimaryQuery(node);
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import typescript from 'typescript';
|
|
2
|
+
import { unique } from '../../../runtime/util.js';
|
|
3
|
+
import { TsFile, tsg } from '../../../tsg/index.js';
|
|
4
|
+
import { ImportDeclaration as TsgImport } from '../../../tsg/importDeclaration.js';
|
|
5
|
+
const { createSourceFile, ScriptTarget, SyntaxKind } = typescript;
|
|
6
|
+
const isImported = (sourceFile, type, paths) => {
|
|
7
|
+
const importDeclarations = sourceFile.statements.filter(it => it.kind === SyntaxKind.ImportDeclaration);
|
|
8
|
+
return importDeclarations.some(it => {
|
|
9
|
+
if (!paths.includes(it.moduleSpecifier.getText(sourceFile)))
|
|
10
|
+
return false;
|
|
11
|
+
const binding = it.importClause?.namedBindings;
|
|
12
|
+
if (binding?.kind !== SyntaxKind.NamedImports)
|
|
13
|
+
return false;
|
|
14
|
+
return binding.elements.some(it => {
|
|
15
|
+
return it.name.text.trim() === type;
|
|
16
|
+
});
|
|
17
|
+
});
|
|
18
|
+
};
|
|
19
|
+
export const generateUserDefinedCondition = (root, content) => {
|
|
20
|
+
const sourceFile = createSourceFile('conditions.ts', content, ScriptTarget.ESNext);
|
|
21
|
+
sourceFile.getChildren().map(it => it);
|
|
22
|
+
const exportedVariables = sourceFile.statements.filter(it => it.kind === SyntaxKind.VariableStatement &&
|
|
23
|
+
it.modifiers?.some(it => it.kind === SyntaxKind.ExportKeyword));
|
|
24
|
+
const contextImported = isImported(sourceFile, 'GQLContext', [
|
|
25
|
+
'"./context"',
|
|
26
|
+
'"./context.js"',
|
|
27
|
+
]);
|
|
28
|
+
const customConditionImported = isImported(sourceFile, 'CustomCondition', [
|
|
29
|
+
'"sasat"',
|
|
30
|
+
]);
|
|
31
|
+
const customConditionNames = unique(root.entities.flatMap(it => [
|
|
32
|
+
...it.references.flatMap(it => it.joinCondition
|
|
33
|
+
.filter(it => it.kind === 'custom')
|
|
34
|
+
.map(it => it.conditionName)),
|
|
35
|
+
...it.referencedBy.flatMap(it => it.joinCondition
|
|
36
|
+
.filter(it => it.kind === 'custom')
|
|
37
|
+
.map(it => it.conditionName)),
|
|
38
|
+
]));
|
|
39
|
+
const statements = [];
|
|
40
|
+
customConditionNames.forEach(conditionName => {
|
|
41
|
+
const exists = exportedVariables.some(it => {
|
|
42
|
+
return (it.declarationList.declarations[0].name.getText(sourceFile) ===
|
|
43
|
+
conditionName);
|
|
44
|
+
});
|
|
45
|
+
if (!exists) {
|
|
46
|
+
statements.push(tsg
|
|
47
|
+
.variable('const', conditionName, tsg.arrowFunc([], undefined, tsg.block(tsg.throw(tsg.new(tsg.identifier('Error'), tsg.string('TODO: Not Implemented'))))), tsg.typeRef('CustomCondition', [tsg.typeRef('GQLContext')]))
|
|
48
|
+
.export());
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
const context = contextImported
|
|
52
|
+
? ''
|
|
53
|
+
: new TsgImport(['GQLContext'], './context').toString() + '\n';
|
|
54
|
+
const condition = customConditionImported
|
|
55
|
+
? ''
|
|
56
|
+
: new TsgImport(['CustomCondition'], 'sasat').toString() + '\n';
|
|
57
|
+
return (context + condition + content + '\n' + new TsFile(...statements).toString());
|
|
58
|
+
};
|
|
@@ -1,3 +1,2 @@
|
|
|
1
1
|
import { ReferencedNode, ReferenceNode } from '../../../nodes/entityNode.js';
|
|
2
|
-
export declare const getParentRequiredFieldNames: (ref: ReferenceNode | ReferencedNode) => string[];
|
|
3
2
|
export declare const getChildRequiredNames: (ref: ReferencedNode | ReferenceNode) => string[];
|
|
@@ -1,33 +1,25 @@
|
|
|
1
1
|
import { nonNullable } from '../../../../runtime/util.js';
|
|
2
|
-
const getParentConditionValue = cv => {
|
|
3
|
-
if (cv.type === 'parent') {
|
|
4
|
-
return cv.field;
|
|
5
|
-
}
|
|
6
|
-
return null;
|
|
7
|
-
};
|
|
8
2
|
const getChildConditionValue = cv => {
|
|
9
|
-
if (cv.
|
|
3
|
+
if (cv.kind === 'child') {
|
|
10
4
|
return cv.field;
|
|
11
5
|
}
|
|
12
6
|
return null;
|
|
13
7
|
};
|
|
14
|
-
const
|
|
8
|
+
const getConditionChildColumnNames = (getConditionValue) => (c) => {
|
|
9
|
+
if (c.kind === 'custom')
|
|
10
|
+
return c.childRequiredFields || [];
|
|
15
11
|
const result = [getConditionValue(c.left)];
|
|
16
12
|
if (c.operator !== 'BETWEEN') {
|
|
17
13
|
result.push(getConditionValue(c.right));
|
|
18
14
|
}
|
|
19
15
|
else {
|
|
20
|
-
if (c.right.
|
|
16
|
+
if (c.right.kind === 'range') {
|
|
21
17
|
result.push(getConditionValue(c.right.begin), getConditionValue(c.right.end));
|
|
22
18
|
}
|
|
23
19
|
}
|
|
24
20
|
return result;
|
|
25
21
|
};
|
|
26
|
-
export const getParentRequiredFieldNames = (ref) => {
|
|
27
|
-
const getNames = getConditionParentColumnNames(getParentConditionValue);
|
|
28
|
-
return ref.joinCondition.flatMap(getNames).filter(nonNullable);
|
|
29
|
-
};
|
|
30
22
|
export const getChildRequiredNames = (ref) => {
|
|
31
|
-
const getNames =
|
|
23
|
+
const getNames = getConditionChildColumnNames(getChildConditionValue);
|
|
32
24
|
return ref.joinCondition.flatMap(getNames).filter(nonNullable);
|
|
33
25
|
};
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import { TsFile, tsg } from '../../../../tsg/index.js';
|
|
2
2
|
import { EntityName } from '../../../nodes/entityName.js';
|
|
3
3
|
import { makeContextTypeRef, makeTypeRef, } from './../scripts/getEntityTypeRefs.js';
|
|
4
|
-
import {
|
|
5
|
-
import { getChildRequiredNames
|
|
4
|
+
import { makeJoinConditionValue } from './makeJoinConditionValue.js';
|
|
5
|
+
import { getChildRequiredNames } from './getRequiredColumnNames.js';
|
|
6
6
|
import { nonNullable } from '../../../../runtime/util.js';
|
|
7
7
|
export const generateRelationMap = (root) => {
|
|
8
8
|
return new TsFile(makeRelationMap(root), makeTableInfo(root), ...root.entities.flatMap(entityRelationType)).disableEsLint();
|
|
9
9
|
};
|
|
10
10
|
const makeRelationMap = (root) => {
|
|
11
11
|
return tsg
|
|
12
|
-
.variable('const', tsg.identifier('relationMap'), tsg.object(...root.entities.map(it => makeEntityRelationMap(it
|
|
12
|
+
.variable('const', tsg.identifier('relationMap'), tsg.object(...root.entities.map(it => makeEntityRelationMap(it))), tsg
|
|
13
13
|
.typeRef('RelationMap', [makeContextTypeRef('GENERATED')])
|
|
14
14
|
.importFrom('sasat'))
|
|
15
15
|
.export();
|
|
@@ -22,19 +22,17 @@ const fieldNameToColumnNameAndFilterPrimary = (node) => (field) => {
|
|
|
22
22
|
return null;
|
|
23
23
|
return column.columnName;
|
|
24
24
|
};
|
|
25
|
-
const makeEntityRelationMap = (node
|
|
25
|
+
const makeEntityRelationMap = (node) => {
|
|
26
26
|
return tsg.propertyAssign(node.tableName, tsg.object(...node.references.map(ref => {
|
|
27
27
|
const toColumnName = fieldNameToColumnNameAndFilterPrimary(ref.entity);
|
|
28
|
-
return tsg.propertyAssign(ref.fieldName, tsg.object(tsg.propertyAssign('table', tsg.string(ref.parentTableName)),
|
|
28
|
+
return tsg.propertyAssign(ref.fieldName, tsg.object(tsg.propertyAssign('table', tsg.string(ref.parentTableName)), makeJoinConditionValue(node, ref), tsg.propertyAssign('array', tsg.boolean(ref.isArray)), tsg.propertyAssign('nullable', tsg.boolean(ref.isNullable)), tsg.propertyAssign('requiredColumns', tsg.array(getChildRequiredNames(ref)
|
|
29
29
|
.map(toColumnName)
|
|
30
30
|
.filter(nonNullable)
|
|
31
31
|
.map(tsg.string)))));
|
|
32
32
|
}), ...node.referencedBy.map(rel => {
|
|
33
|
-
const
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
return tsg.propertyAssign(rel.fieldName, tsg.object(tsg.propertyAssign('table', tsg.string(rel.childTable)), makeCondition(node, rel), tsg.propertyAssign('array', tsg.boolean(rel.isArray)), tsg.propertyAssign('nullable', tsg.boolean(rel.isNullable)), tsg.propertyAssign('requiredColumns', tsg.array(getChildRequiredNames(rel)
|
|
37
|
-
.map(toColumnName2)
|
|
33
|
+
const toColumnName = fieldNameToColumnNameAndFilterPrimary(rel.entity);
|
|
34
|
+
return tsg.propertyAssign(rel.fieldName, tsg.object(tsg.propertyAssign('table', tsg.string(rel.childTable)), makeJoinConditionValue(node, rel), tsg.propertyAssign('array', tsg.boolean(rel.isArray)), tsg.propertyAssign('nullable', tsg.boolean(rel.isNullable)), tsg.propertyAssign('requiredColumns', tsg.array(getChildRequiredNames(rel)
|
|
35
|
+
.map(toColumnName)
|
|
38
36
|
.filter(nonNullable)
|
|
39
37
|
.map(tsg.string)))));
|
|
40
38
|
})));
|
|
@@ -7,7 +7,7 @@ const qExpr = tsg.identifier('QExpr').importFrom('sasat');
|
|
|
7
7
|
const makeConditionValueQExpr = (node, cv) => {
|
|
8
8
|
const arg = tsg.identifier('arg');
|
|
9
9
|
const context = arg.property('context?');
|
|
10
|
-
switch (cv.
|
|
10
|
+
switch (cv.kind) {
|
|
11
11
|
case 'context': {
|
|
12
12
|
const value = context.property(cv.field);
|
|
13
13
|
if (cv.onNotDefined.action !== 'defaultValue') {
|
|
@@ -45,7 +45,7 @@ const makeConditionValueQExpr = (node, cv) => {
|
|
|
45
45
|
case 'today': {
|
|
46
46
|
return qExpr
|
|
47
47
|
.property('value')
|
|
48
|
-
.call(tsg.identifier('
|
|
48
|
+
.call(tsg.identifier('getTodayDateTimeString').importFrom('sasat').call());
|
|
49
49
|
}
|
|
50
50
|
case 'now': {
|
|
51
51
|
return qExpr.property('value').call(tsg
|
|
@@ -56,7 +56,7 @@ const makeConditionValueQExpr = (node, cv) => {
|
|
|
56
56
|
}
|
|
57
57
|
};
|
|
58
58
|
const makeRangeCondition = (entity, range) => {
|
|
59
|
-
if (range.
|
|
59
|
+
if (range.kind === 'range') {
|
|
60
60
|
return [
|
|
61
61
|
makeConditionValueQExpr(entity, range.begin),
|
|
62
62
|
makeConditionValueQExpr(entity, range.end),
|
|
@@ -72,6 +72,12 @@ const makeRangeCondition = (entity, range) => {
|
|
|
72
72
|
];
|
|
73
73
|
};
|
|
74
74
|
const makeConditionExpr = (entity, condition) => {
|
|
75
|
+
if (condition.kind === 'custom') {
|
|
76
|
+
return tsg
|
|
77
|
+
.identifier(condition.conditionName)
|
|
78
|
+
.importFrom('../conditions')
|
|
79
|
+
.call(tsg.identifier('arg'));
|
|
80
|
+
}
|
|
75
81
|
if (condition.operator === 'BETWEEN') {
|
|
76
82
|
return qExpr
|
|
77
83
|
.property('conditions')
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { EntityNode, ReferencedNode, ReferenceNode } from '../../../nodes/entityNode.js';
|
|
2
|
+
import { JoinConditionValue } from '../../../nodes/JoinConditionNode.js';
|
|
3
|
+
import { TsExpression } from '../../../../tsg/index.js';
|
|
4
|
+
export declare const makeJoinConditionValueQExpr: (node: EntityNode, cv: JoinConditionValue) => TsExpression;
|
|
5
|
+
export declare const makeJoinConditionValue: (node: EntityNode, ref: ReferenceNode | ReferencedNode) => import("../../../../tsg/index.js").PropertyAssignment;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { tsg } from '../../../../tsg/index.js';
|
|
2
|
+
import { makeThrowExpressions } from './makeNoContexError.js';
|
|
3
|
+
import { nonNullableFilter } from '../../../../util/type.js';
|
|
4
|
+
import { makeConditionValueQExpr } from '../scripts/makeConditonValueExpr.js';
|
|
5
|
+
const qExpr = tsg.identifier('QExpr').importFrom('sasat');
|
|
6
|
+
const parentTableAlias = 'parentTableAlias';
|
|
7
|
+
const childTableAlias = 'childTableAlias';
|
|
8
|
+
export const makeJoinConditionValueQExpr = (node, cv) => {
|
|
9
|
+
const arg = tsg.identifier('arg');
|
|
10
|
+
switch (cv.kind) {
|
|
11
|
+
case 'parent': {
|
|
12
|
+
const columnName = node.fields.find(it => it.fieldName === cv.field)?.columnName ||
|
|
13
|
+
cv.field;
|
|
14
|
+
return qExpr
|
|
15
|
+
.property('field')
|
|
16
|
+
.call(arg.property(childTableAlias), tsg.string(columnName));
|
|
17
|
+
}
|
|
18
|
+
case 'child': {
|
|
19
|
+
const columnName = node.fields.find(it => it.fieldName === cv.field)?.columnName ||
|
|
20
|
+
cv.field;
|
|
21
|
+
return tsg.ternary(arg.property(parentTableAlias), qExpr
|
|
22
|
+
.property('field')
|
|
23
|
+
.call(arg.property(parentTableAlias), tsg.string(columnName)), qExpr
|
|
24
|
+
.property('value')
|
|
25
|
+
.call(arg.property('parent?').property(cv.field)));
|
|
26
|
+
}
|
|
27
|
+
default:
|
|
28
|
+
return makeConditionValueQExpr(cv);
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
const makeRangeCondition = (entity, range) => {
|
|
32
|
+
if (range.kind === 'range') {
|
|
33
|
+
return [
|
|
34
|
+
makeJoinConditionValueQExpr(entity, range.begin),
|
|
35
|
+
makeJoinConditionValueQExpr(entity, range.end),
|
|
36
|
+
];
|
|
37
|
+
}
|
|
38
|
+
return [
|
|
39
|
+
tsg.spread(tsg
|
|
40
|
+
.identifier('getDayRangeQExpr')
|
|
41
|
+
.importFrom('sasat')
|
|
42
|
+
.call(tsg.new(tsg.identifier('Date')), range.thresholdHour
|
|
43
|
+
? tsg.number(range.thresholdHour)
|
|
44
|
+
: tsg.identifier('undefined'))),
|
|
45
|
+
];
|
|
46
|
+
};
|
|
47
|
+
const makeConditionExpr = (entity, condition) => {
|
|
48
|
+
if (condition.kind === 'custom') {
|
|
49
|
+
return tsg
|
|
50
|
+
.identifier(condition.conditionName)
|
|
51
|
+
.importFrom('../conditions')
|
|
52
|
+
.call(tsg.identifier('arg'));
|
|
53
|
+
}
|
|
54
|
+
if (condition.operator === 'BETWEEN') {
|
|
55
|
+
return qExpr
|
|
56
|
+
.property('conditions')
|
|
57
|
+
.property('between')
|
|
58
|
+
.call(makeJoinConditionValueQExpr(entity, condition.left), ...makeRangeCondition(entity, condition.right));
|
|
59
|
+
}
|
|
60
|
+
return qExpr
|
|
61
|
+
.property('conditions')
|
|
62
|
+
.property('comparison')
|
|
63
|
+
.call(makeJoinConditionValueQExpr(entity, condition.left), tsg.string(condition.operator), makeJoinConditionValueQExpr(entity, condition.right));
|
|
64
|
+
};
|
|
65
|
+
export const makeJoinConditionValue = (node, ref) => {
|
|
66
|
+
const arg = tsg.identifier('arg');
|
|
67
|
+
return tsg.propertyAssign('condition', tsg.arrowFunc([tsg.parameter(arg.toString())], tsg.typeRef('BooleanValueExpression').importFrom('sasat'), tsg.block(...ref.joinCondition
|
|
68
|
+
.flatMap(it => makeThrowExpressions(it))
|
|
69
|
+
.filter(nonNullableFilter), tsg.return(qExpr
|
|
70
|
+
.property('conditions')
|
|
71
|
+
.property('and')
|
|
72
|
+
.call(...ref.joinCondition.map(it => makeConditionExpr(node, it)))))));
|
|
73
|
+
};
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { JoinConditionNode } from '../../../nodes/JoinConditionNode.js';
|
|
2
2
|
import { IfStatement } from '../../../../tsg/index.js';
|
|
3
|
-
export declare const makeThrowExpressions: (condition:
|
|
3
|
+
export declare const makeThrowExpressions: (condition: JoinConditionNode) => (IfStatement | null)[];
|
|
@@ -1,27 +1,29 @@
|
|
|
1
1
|
import { tsg } from '../../../../tsg/index.js';
|
|
2
2
|
const makeJoinRangeConditionThrowExpressions = (cv) => {
|
|
3
|
-
if (cv.
|
|
3
|
+
if (cv.kind === 'range') {
|
|
4
4
|
const result = [];
|
|
5
|
-
if (cv.begin.
|
|
5
|
+
if (cv.begin.kind === 'context')
|
|
6
6
|
result.push(makeJoinConditionThrowExpressions(cv.begin));
|
|
7
|
-
if (cv.end.
|
|
7
|
+
if (cv.end.kind === 'context')
|
|
8
8
|
result.push(makeJoinConditionThrowExpressions(cv.end));
|
|
9
9
|
return result;
|
|
10
10
|
}
|
|
11
11
|
return [];
|
|
12
12
|
};
|
|
13
13
|
const makeJoinConditionThrowExpressions = (cv) => {
|
|
14
|
-
if (cv.
|
|
14
|
+
if (cv.kind !== 'context')
|
|
15
15
|
return null;
|
|
16
16
|
if (cv.onNotDefined.action !== 'error')
|
|
17
17
|
return null;
|
|
18
18
|
return tsg.if(tsg.binary(tsg.identifier('!arg.context'), '||', tsg.binary(tsg.identifier('arg.context').property(cv.field), '===', tsg.identifier('undefined'))), tsg.throw(tsg.new(tsg.identifier('Error'), tsg.string(cv.onNotDefined.message))));
|
|
19
19
|
};
|
|
20
20
|
export const makeThrowExpressions = (condition) => {
|
|
21
|
+
if (condition.kind === 'custom')
|
|
22
|
+
return [];
|
|
21
23
|
if (condition.operator === 'BETWEEN') {
|
|
22
24
|
return [
|
|
23
25
|
makeJoinConditionThrowExpressions(condition.left),
|
|
24
|
-
...(condition.right.
|
|
26
|
+
...(condition.right.kind === 'range'
|
|
25
27
|
? makeJoinRangeConditionThrowExpressions(condition.right)
|
|
26
28
|
: []),
|
|
27
29
|
];
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { tsg } from '../../../../tsg/index.js';
|
|
2
|
+
const qExpr = tsg.identifier('QExpr').importFrom('sasat');
|
|
3
|
+
export const makeConditionValueQExpr = (cv) => {
|
|
4
|
+
const arg = tsg.identifier('arg');
|
|
5
|
+
const context = arg.property('context?');
|
|
6
|
+
switch (cv.kind) {
|
|
7
|
+
case 'context': {
|
|
8
|
+
const value = context.property(cv.field);
|
|
9
|
+
if (cv.onNotDefined.action !== 'defaultValue') {
|
|
10
|
+
return qExpr.property('value').call(value);
|
|
11
|
+
}
|
|
12
|
+
return qExpr
|
|
13
|
+
.property('value')
|
|
14
|
+
.call(tsg.binary(context.property(cv.field), '||', typeof cv.onNotDefined.value === 'string'
|
|
15
|
+
? tsg.string(cv.onNotDefined.value)
|
|
16
|
+
: tsg.number(cv.onNotDefined.value)));
|
|
17
|
+
}
|
|
18
|
+
case 'fixed': {
|
|
19
|
+
return qExpr
|
|
20
|
+
.property('value')
|
|
21
|
+
.call(typeof cv.value === 'string'
|
|
22
|
+
? tsg.string(cv.value)
|
|
23
|
+
: tsg.number(cv.value));
|
|
24
|
+
}
|
|
25
|
+
case 'today': {
|
|
26
|
+
return qExpr.property('value').call(tsg
|
|
27
|
+
.identifier(cv.type === 'datetime'
|
|
28
|
+
? 'getTodayDateTimeString'
|
|
29
|
+
: 'getTodayDateString')
|
|
30
|
+
.importFrom('sasat')
|
|
31
|
+
.call());
|
|
32
|
+
}
|
|
33
|
+
case 'now': {
|
|
34
|
+
return qExpr.property('value').call(tsg
|
|
35
|
+
.identifier('dateString')
|
|
36
|
+
.importFrom('sasat')
|
|
37
|
+
.call(tsg.new(tsg.identifier('Date'))));
|
|
38
|
+
}
|
|
39
|
+
case 'arg': {
|
|
40
|
+
return qExpr.property('value').call(tsg.identifier(cv.name));
|
|
41
|
+
}
|
|
42
|
+
case 'field': {
|
|
43
|
+
return qExpr
|
|
44
|
+
.property('field')
|
|
45
|
+
.call(tsg.string('t0'), tsg.string(cv.column));
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { tsg } from '../../../../tsg/index.js';
|
|
2
|
+
import { makeConditionValueQExpr } from './makeConditonValueExpr.js';
|
|
3
|
+
const qExpr = tsg.identifier('QExpr').importFrom('sasat');
|
|
4
|
+
export const makeQueryConditionExpr = (condition) => {
|
|
5
|
+
if (condition.kind === 'between') {
|
|
6
|
+
return qExpr
|
|
7
|
+
.property('conditions')
|
|
8
|
+
.property('between')
|
|
9
|
+
.call(makeConditionValueQExpr(condition.left), makeConditionValueQExpr(condition.begin), makeConditionValueQExpr(condition.end));
|
|
10
|
+
}
|
|
11
|
+
return qExpr
|
|
12
|
+
.property('conditions')
|
|
13
|
+
.property('comparison')
|
|
14
|
+
.call(makeConditionValueQExpr(condition.left), tsg.string(condition.operator), makeConditionValueQExpr(condition.right));
|
|
15
|
+
};
|
|
@@ -10,6 +10,7 @@ import { generateDatasource } from './ts/generateDatasource.js';
|
|
|
10
10
|
import { generateResolver } from './ts/generateResolver.js';
|
|
11
11
|
import { generateContext } from './ts/generateContext.js';
|
|
12
12
|
import { generateSubscription } from './ts/generateSubscription.js';
|
|
13
|
+
import { generateUserDefinedCondition } from './ts/generateUserDefinedCondition.js';
|
|
13
14
|
export class TsCodegen_v2 {
|
|
14
15
|
constructor() {
|
|
15
16
|
this.fileExtension = 'ts';
|
|
@@ -34,5 +35,8 @@ export class TsCodegen_v2 {
|
|
|
34
35
|
this.generateOnceFiles = () => {
|
|
35
36
|
return staticFiles;
|
|
36
37
|
};
|
|
38
|
+
this.generateConditions = (root, currentFile) => {
|
|
39
|
+
return generateUserDefinedCondition(root, currentFile);
|
|
40
|
+
};
|
|
37
41
|
}
|
|
38
42
|
}
|
|
@@ -5,6 +5,7 @@ import { mkDirIfNotExist, writeFileIfNotExist } from '../util/fsUtil.js';
|
|
|
5
5
|
import { TsCodegen_v2 } from './codegen/tscodegen_v2.js';
|
|
6
6
|
import { parse } from './parse.js';
|
|
7
7
|
import { Directory } from './directory.js';
|
|
8
|
+
import { readFileSync, writeFileSync } from 'fs';
|
|
8
9
|
const { emptyDir, writeFile } = fs;
|
|
9
10
|
export class CodeGen_v2 {
|
|
10
11
|
constructor(store) {
|
|
@@ -25,6 +26,7 @@ export class CodeGen_v2 {
|
|
|
25
26
|
...this.generateGql(this.root),
|
|
26
27
|
...this.generateFiles(this.root),
|
|
27
28
|
...this.generateOnceFiles(),
|
|
29
|
+
this.generateCondition(this.root),
|
|
28
30
|
]);
|
|
29
31
|
}
|
|
30
32
|
async prepareDirs() {
|
|
@@ -66,4 +68,10 @@ export class CodeGen_v2 {
|
|
|
66
68
|
.generateOnceFiles()
|
|
67
69
|
.map(it => writeFileIfNotExist(this.getFullPath(this.outDir, it.name), it.body));
|
|
68
70
|
}
|
|
71
|
+
async generateCondition(rootNode) {
|
|
72
|
+
const filePath = this.getFullPath(this.outDir, 'conditions');
|
|
73
|
+
await writeFileIfNotExist(filePath, '');
|
|
74
|
+
const content = readFileSync(filePath).toString();
|
|
75
|
+
writeFileSync(filePath, this.codeGen.generateConditions(rootNode, content));
|
|
76
|
+
}
|
|
69
77
|
}
|