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.
Files changed (56) hide show
  1. package/lib/generatorv2/codegen/gql/generateTypeDefs.js +24 -12
  2. package/lib/generatorv2/codegen/ts/generateQueryResolver.js +71 -2
  3. package/lib/generatorv2/codegen/ts/generateUserDefinedCondition.d.ts +2 -0
  4. package/lib/generatorv2/codegen/ts/generateUserDefinedCondition.js +58 -0
  5. package/lib/generatorv2/codegen/ts/relationMap/getRequiredColumnNames.d.ts +0 -1
  6. package/lib/generatorv2/codegen/ts/relationMap/getRequiredColumnNames.js +6 -14
  7. package/lib/generatorv2/codegen/ts/relationMap/index.js +8 -10
  8. package/lib/generatorv2/codegen/ts/relationMap/makeCondition.js +9 -3
  9. package/lib/generatorv2/codegen/ts/relationMap/makeJoinConditionValue.d.ts +5 -0
  10. package/lib/generatorv2/codegen/ts/relationMap/makeJoinConditionValue.js +73 -0
  11. package/lib/generatorv2/codegen/ts/relationMap/makeNoContexError.d.ts +2 -2
  12. package/lib/generatorv2/codegen/ts/relationMap/makeNoContexError.js +7 -5
  13. package/lib/generatorv2/codegen/ts/scripts/makeConditonValueExpr.d.ts +3 -0
  14. package/lib/generatorv2/codegen/ts/scripts/makeConditonValueExpr.js +48 -0
  15. package/lib/generatorv2/codegen/ts/scripts/makeQueryConditionExpr.d.ts +2 -0
  16. package/lib/generatorv2/codegen/ts/scripts/makeQueryConditionExpr.js +15 -0
  17. package/lib/generatorv2/codegen/tscodegen_v2.d.ts +1 -0
  18. package/lib/generatorv2/codegen/tscodegen_v2.js +4 -0
  19. package/lib/generatorv2/codegen_v2.d.ts +1 -0
  20. package/lib/generatorv2/codegen_v2.js +8 -0
  21. package/lib/generatorv2/nodes/ConditionNode.d.ts +15 -7
  22. package/lib/generatorv2/nodes/ConditionValues.d.ts +26 -0
  23. package/lib/generatorv2/nodes/ConditionValues.js +1 -0
  24. package/lib/generatorv2/nodes/JoinConditionNode.d.ts +34 -0
  25. package/lib/generatorv2/nodes/JoinConditionNode.js +1 -0
  26. package/lib/generatorv2/nodes/QueryConditionNode.d.ts +23 -0
  27. package/lib/generatorv2/nodes/QueryConditionNode.js +1 -0
  28. package/lib/generatorv2/nodes/entityNode.d.ts +6 -3
  29. package/lib/generatorv2/nodes/entityNode.js +19 -20
  30. package/lib/generatorv2/nodes/rootNode.d.ts +0 -2
  31. package/lib/generatorv2/parse.js +0 -2
  32. package/lib/generatorv2/parser/makeQueryNodes.d.ts +0 -3
  33. package/lib/generatorv2/parser/makeQueryNodes.js +1 -68
  34. package/lib/generatorv2/scripts/gqlTypes.d.ts +2 -2
  35. package/lib/generatorv2/scripts/gqlTypes.js +11 -1
  36. package/lib/index.d.ts +5 -1
  37. package/lib/index.js +4 -1
  38. package/lib/migration/creators/tableCreator.d.ts +3 -1
  39. package/lib/migration/creators/tableCreator.js +6 -0
  40. package/lib/migration/data/GQLOption.d.ts +13 -4
  41. package/lib/migration/data/GQLOption.js +32 -4
  42. package/lib/migration/data/virtualRelation.d.ts +4 -4
  43. package/lib/migration/makeCondition.d.ts +21 -8
  44. package/lib/migration/makeCondition.js +63 -21
  45. package/lib/migration/makeQuery.d.ts +8 -0
  46. package/lib/migration/makeQuery.js +25 -0
  47. package/lib/runtime/date.d.ts +8 -0
  48. package/lib/runtime/date.js +56 -0
  49. package/lib/runtime/dsl/query/createQueryResolveInfo.d.ts +1 -2
  50. package/lib/runtime/pagingOption.d.ts +10 -0
  51. package/lib/runtime/pagingOption.js +9 -0
  52. package/lib/runtime/types.d.ts +3 -0
  53. package/lib/runtime/types.js +1 -0
  54. package/lib/runtime/util.d.ts +0 -6
  55. package/lib/runtime/util.js +0 -55
  56. 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.queries),
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 makeQuery = (queries) => {
65
- if (queries.length === 0)
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(...queries.map(query => {
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.queries.map(makeQuery)))
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('GENERATED', 'BASE', 'context')), tsg.typeLiteral(node.args.map(it => tsg.propertySignature(it.name, tsg.typeRef(it.type.entity
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,2 @@
1
+ import { RootNode } from '../../nodes/rootNode.js';
2
+ export declare const generateUserDefinedCondition: (root: RootNode, content: string) => string;
@@ -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.type === 'child') {
3
+ if (cv.kind === 'child') {
10
4
  return cv.field;
11
5
  }
12
6
  return null;
13
7
  };
14
- const getConditionParentColumnNames = (getConditionValue) => (c) => {
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.type === 'range') {
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 = getConditionParentColumnNames(getChildConditionValue);
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 { makeCondition } from './makeCondition.js';
5
- import { getChildRequiredNames, } from './getRequiredColumnNames.js';
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, root))), tsg
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, root) => {
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)), makeCondition(node, ref), tsg.propertyAssign('array', tsg.boolean(ref.isArray)), tsg.propertyAssign('nullable', tsg.boolean(ref.isNullable)), tsg.propertyAssign('requiredColumns', tsg.array(getChildRequiredNames(ref)
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 parentEntity = root.entities.find(it => it.tableName === rel.childTable);
34
- const toColumnName = fieldNameToColumnNameAndFilterPrimary(parentEntity);
35
- const toColumnName2 = fieldNameToColumnNameAndFilterPrimary(rel.entity);
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.type) {
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('getTodayDateString').importFrom('sasat').call());
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.type === '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 { ConditionNode } from '../../../nodes/ConditionNode.js';
1
+ import { JoinConditionNode } from '../../../nodes/JoinConditionNode.js';
2
2
  import { IfStatement } from '../../../../tsg/index.js';
3
- export declare const makeThrowExpressions: (condition: ConditionNode) => (IfStatement | null)[];
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.type === 'range') {
3
+ if (cv.kind === 'range') {
4
4
  const result = [];
5
- if (cv.begin.type === 'context')
5
+ if (cv.begin.kind === 'context')
6
6
  result.push(makeJoinConditionThrowExpressions(cv.begin));
7
- if (cv.end.type === 'context')
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.type !== 'context')
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.type === 'range'
26
+ ...(condition.right.kind === 'range'
25
27
  ? makeJoinRangeConditionThrowExpressions(condition.right)
26
28
  : []),
27
29
  ];
@@ -0,0 +1,3 @@
1
+ import { TsExpression } from '../../../../tsg/index.js';
2
+ import { QueryConditionValue } from '../../../nodes/QueryConditionNode.js';
3
+ export declare const makeConditionValueQExpr: (cv: QueryConditionValue) => TsExpression;
@@ -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,2 @@
1
+ import { QueryConditionNode } from '../../../nodes/QueryConditionNode.js';
2
+ export declare const makeQueryConditionExpr: (condition: QueryConditionNode) => import("../../../../tsg/index.js").CallExpression;
@@ -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
+ };
@@ -17,4 +17,5 @@ export declare class TsCodegen_v2 {
17
17
  generateGQLContext: (root: RootNode) => string;
18
18
  generateFiles: (root: RootNode) => FileData[];
19
19
  generateOnceFiles: () => FileData[];
20
+ generateConditions: (root: RootNode, currentFile: string) => string;
20
21
  }
@@ -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
  }
@@ -17,4 +17,5 @@ export declare class CodeGen_v2 {
17
17
  private generateGql;
18
18
  private generateFiles;
19
19
  private generateOnceFiles;
20
+ private generateCondition;
20
21
  }
@@ -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
  }