sasat 0.17.4 → 0.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/lib/db/sql/createTable/createTableParser.js +1 -1
  2. package/lib/generator/ts/code/factory.d.ts +1 -1
  3. package/lib/generator/ts/code/node/type/intersectionType.d.ts +2 -3
  4. package/lib/generator/ts/db/generatedRepositoryGenerator.js +12 -13
  5. package/lib/generator/ts/fieldGenerator.js +1 -1
  6. package/lib/generator/ts/gql/queryGenerator.js +27 -18
  7. package/lib/generator/ts/gql/resolverGenerator.js +11 -10
  8. package/lib/generator/ts/gql/typeDefGenerator.js +1 -1
  9. package/lib/generator/ts/relationMapGenerator.d.ts +1 -0
  10. package/lib/generator/ts/relationMapGenerator.js +14 -11
  11. package/lib/generator/ts/staticFiles.js +6 -5
  12. package/lib/generator/ts/tsValueString.js +1 -1
  13. package/lib/index.d.ts +2 -2
  14. package/lib/migration/creators/tableCreator.d.ts +5 -1
  15. package/lib/migration/creators/tableCreator.js +11 -0
  16. package/lib/migration/data/{gqlOption.d.ts → GQLOption.d.ts} +8 -3
  17. package/lib/migration/data/{gqlOption.js → GQLOption.js} +5 -0
  18. package/lib/migration/front/tableMigrator.d.ts +6 -1
  19. package/lib/migration/front/tableMigrator.js +14 -0
  20. package/lib/migration/serializable/table.d.ts +4 -2
  21. package/lib/migration/serializable/table.js +4 -1
  22. package/lib/migration/serialized/serializedStore.d.ts +2 -2
  23. package/lib/parser/node/entityNode.d.ts +1 -0
  24. package/lib/parser/node/entityNode.js +10 -4
  25. package/lib/parser/node/gql/queryNode.d.ts +3 -1
  26. package/lib/parser/node/gql/queryNode.js +2 -1
  27. package/lib/parser/node/gql/typeDefNode.d.ts +1 -1
  28. package/lib/parser/node/gql/typeDefNode.js +2 -1
  29. package/lib/parser/node/relationNode.d.ts +17 -7
  30. package/lib/parser/node/relationNode.js +17 -11
  31. package/lib/parser/node/repositoryNode.d.ts +2 -0
  32. package/lib/parser/node/repositoryNode.js +6 -5
  33. package/lib/parser/node/rootNode.js +1 -1
  34. package/lib/parser/node/typeNode.d.ts +1 -1
  35. package/lib/parser/node/typeNode.js +1 -1
  36. package/lib/parser/nodeFactory/mutationNodeFactory.js +2 -0
  37. package/lib/parser/nodeFactory/queryNodeFactory.d.ts +2 -1
  38. package/lib/parser/nodeFactory/queryNodeFactory.js +13 -4
  39. package/lib/runtime/dsl/factory.d.ts +2 -2
  40. package/lib/runtime/dsl/factory.js +2 -1
  41. package/lib/runtime/dsl/query/query.d.ts +2 -0
  42. package/lib/runtime/dsl/query/sql/queryToSql.js +9 -1
  43. package/lib/runtime/sasatDBDatasource.d.ts +12 -18
  44. package/lib/runtime/sql/runQuery.d.ts +2 -8
  45. package/lib/runtime/sql/runQuery.js +7 -3
  46. package/lib/runtime/util.d.ts +1 -0
  47. package/lib/runtime/util.js +1 -0
  48. package/package.json +1 -1
@@ -2,7 +2,7 @@ import { TokenKind } from './lexer/lexer.js';
2
2
  import { camelize } from '../../../util/stringUtil.js';
3
3
  import { columnTypeToGqlPrimitive } from '../../../generator/gql/columnToGqlType.js';
4
4
  import { GqlPrimitive } from '../../../generator/gql/types.js';
5
- import { getDefaultGqlOption } from '../../../migration/data/gqlOption.js';
5
+ import { getDefaultGqlOption } from '../../../migration/data/GQLOption.js';
6
6
  const splitArray = (array, callback) => {
7
7
  const indexes = [];
8
8
  array.forEach((it, i) => {
@@ -45,7 +45,7 @@ export declare const tsg: {
45
45
  methodModifiers: () => MethodModifiers;
46
46
  propertyModifiers: () => PropertyModifiers;
47
47
  arrayType: (type: import("./node/type/type.js").TsType) => ArrayType;
48
- intersectionType: (...args: (TypeReference | TypeLiteral)[]) => IntersectionType;
48
+ intersectionType: (...args: import("./node/type/type.js").TsType[]) => IntersectionType;
49
49
  unionType: (types: import("./node/type/type.js").TsType[]) => UnionType;
50
50
  typeAlias: (alias: string, type: import("./node/type/type.js").TsType) => TypeAliasDeclaration;
51
51
  typeLiteral: (properties?: PropertySignature[] | undefined) => TypeLiteral;
@@ -1,8 +1,7 @@
1
1
  import { TsCode } from '../../abstruct/tsCode.js';
2
- import { TypeLiteral } from './typeLiteral.js';
3
- import { TypeReference } from './typeReference.js';
2
+ import { TsType } from "./type.js";
4
3
  export declare class IntersectionType extends TsCode {
5
4
  private readonly types;
6
- constructor(...types: Array<TypeLiteral | TypeReference>);
5
+ constructor(...types: Array<TsType>);
7
6
  protected toTsString(): string;
8
7
  }
@@ -20,7 +20,7 @@ export class GeneratedRepositoryGenerator {
20
20
  generate() {
21
21
  const node = this.node;
22
22
  const entityPath = Directory.entityPath(Directory.paths.generatedDataSource.db, node.entityName);
23
- return new TsFile(new Class(node.entityName.generatedDataSourceName())
23
+ return new TsFile(tsg.typeAlias('QueryResult', tsg.intersectionType(tsg.typeRef('Partial', [tsg.typeRef(node.entityName.entityWithRelationTypeName()).importFrom(Directory.generatedPath(Directory.paths.generatedDataSource.db, 'relationMap'))]), node.entityName.identifiableTypeReference(Directory.paths.generatedDataSource.db))), new Class(node.entityName.generatedDataSourceName())
24
24
  .export()
25
25
  .abstract()
26
26
  .extends(new ExtendsClause(tsg.typeRef('BaseDBDataSource', [
@@ -32,6 +32,7 @@ export class GeneratedRepositoryGenerator {
32
32
  .typeRef(node.entityName.identifiableInterfaceName())
33
33
  .importFrom(entityPath),
34
34
  node.entityName.fieldTypeRef(Directory.paths.generatedDataSource.db),
35
+ tsg.typeRef('QueryResult')
35
36
  ])).addImport(['BaseDBDataSource'], Directory.basePath(Directory.paths.generatedDataSource.db, 'baseDBDataSource')))
36
37
  .addProperty(...this.properties(node))
37
38
  .addMethod(this.getDefaultValueMethod(node), ...this.findMethods(node))).disableEsLint();
@@ -99,24 +100,22 @@ export class GeneratedRepositoryGenerator {
99
100
  tsg.variable('const', 'tableName', tsg.identifier('fields?.tableAlias || "t0"')),
100
101
  tsg.return(tsg
101
102
  .identifier(it.returnType.isArray ? 'this.find' : 'this.first')
102
- .call(tsg.identifier('fields'), tsg.object().addProperties(tsg.propertyAssign('where', exps.length === 1
103
- ? exps[0]
104
- : qExpr
105
- .property('conditions')
106
- .property('and')
107
- .call(...exps))), tsg.identifier('context'))),
103
+ .call(tsg.identifier('fields'), tsg.object().addProperties(tsg.spreadAssign(tsg.identifier('options')), tsg.propertyAssign('where', qExpr
104
+ .property('conditions')
105
+ .property('and')
106
+ .call(...exps, tsg.identifier('options?').property('where')))), tsg.identifier('context'))),
108
107
  ];
109
- const returnType = tsg
110
- .typeRef('EntityResult', [
111
- tsg.typeRef(node.entityName.name),
112
- tsg.typeRef(node.entityName.identifiableInterfaceName()),
113
- ])
114
- .importFrom('sasat');
108
+ const returnType = tsg.typeRef('QueryResult');
115
109
  return new MethodDeclaration(it.name, [
116
110
  ...it.params.map(it => new Parameter(it.name, it.type.toTsType())),
117
111
  new Parameter(`fields?`, tsg
118
112
  .typeRef(`${node.entityName}Fields`)
119
113
  .importFrom(Directory.generatedPath(Directory.paths.generatedDataSource.db, 'fields'))),
114
+ tsg.parameter('options?', it.returnType.isArray ? tsg.typeRef('QueryOptions').importFrom('sasat')
115
+ : tsg.typeRef('Omit', [
116
+ tsg.typeRef('QueryOptions').importFrom('sasat'),
117
+ tsg.typeRef('"offset" | "limit" | "sort"'),
118
+ ])),
120
119
  tsg.parameter('context?', tsg
121
120
  .typeRef('GQLContext')
122
121
  .importFrom(Directory.basePath(Directory.paths.generatedDataSource.db, 'context'))),
@@ -15,7 +15,7 @@ export class FieldGenerator {
15
15
  .typeRef(`keyof ${entity.entityName}`)
16
16
  .addImport([entity.entityName.name], Directory.entityPath(Directory.paths.generated, entity.entityName)))),
17
17
  tsg.propertySignature('relations?', tsg.typeLiteral([
18
- ...entity.relations.map(it => tsg.propertySignature(`${it.refPropertyName()}?`, tsg.typeRef(`${it.toEntityName}Fields`))),
18
+ ...entity.relations.map(it => tsg.propertySignature(`${it.refPropertyName()}?`, tsg.typeRef(`${it.to.entityName}Fields`))),
19
19
  ...entity
20
20
  .findReferencedRelations()
21
21
  .map(it => tsg.propertySignature(`${it.referencedByPropertyName()}?`, tsg.typeRef(`${it.parent.entityName}Fields`))),
@@ -12,7 +12,7 @@ export class QueryGenerator {
12
12
  static createParams(node, query) {
13
13
  const context = tsg.parameter('context', tsg.typeRef('GQLContext').importFrom('../context'));
14
14
  const resolveInfo = tsg.parameter('info', tsg.typeRef('GraphQLResolveInfo'));
15
- if (query.queryParams.length === 0)
15
+ if (query.queryParams.length === 0 || query.listType === 'all')
16
16
  return [
17
17
  tsg.parameter('_1', tsg.typeRef('unknown')),
18
18
  tsg.parameter('_2', tsg.typeRef('unknown')),
@@ -23,7 +23,7 @@ export class QueryGenerator {
23
23
  return [
24
24
  tsg.parameter('_1', tsg.typeRef('unknown')),
25
25
  tsg.parameter('params', tsg.typeLiteral([
26
- tsg.propertySignature('option', query.queryParams[0].type.toTsType(), true, false),
26
+ tsg.propertySignature('option', query.queryParams[0].type.toTsType(), false, false),
27
27
  ])),
28
28
  context,
29
29
  resolveInfo,
@@ -49,28 +49,37 @@ export class QueryGenerator {
49
49
  .identifier('gqlResolveInfoToField')
50
50
  .importFrom('sasat')
51
51
  .call(tsg.identifier('info'))
52
- .as(node.entityName.fieldTypeRef(Directory.paths.generated)), tsg.identifier('context'))));
52
+ .as(node.entityName.fieldTypeRef(Directory.paths.generated)), tsg.identifier('undefined'), tsg.identifier('context'))));
53
53
  }
54
54
  listQuery(node, query) {
55
55
  const fields = tsg.identifier('fields');
56
+ const option = tsg.identifier('option');
56
57
  const ds = tsg.new(tsg
57
58
  .identifier(node.entityName.dataSourceName())
58
59
  .importFrom(Directory.dbDataSourcePath(Directory.paths.generated, node.entityName)));
59
- const params = tsg.identifier('params');
60
- const option = tsg.identifier('option');
61
- const statements = [
62
- tsg.variable('const', tsg.identifier('{ option }'), params),
63
- tsg.variable('const', fields, tsg
64
- .identifier('gqlResolveInfoToField')
65
- .importFrom('sasat')
66
- .call(tsg.identifier('info'))
67
- .as(node.entityName.fieldTypeRef(Directory.paths.generated))),
68
- tsg.if(option, tsg.return(ds
69
- .property('findPageable')
70
- .call(tsg.object(tsg.propertyAssign('numberOfItem', option.property('numberOfItem')), tsg.propertyAssign('offset', option.property('offset'))), fields, tsg.identifier('undefined'), tsg.identifier('context')))),
71
- tsg.return(ds.property(query.repoMethodName).call(fields, tsg.identifier('undefined'), tsg.identifier('context'))),
72
- ];
73
- return tsg.propertyAssign(query.queryName, tsg.arrowFunc(QueryGenerator.createParams(node, query), undefined, tsg.block(...statements)));
60
+ const constInfo = tsg.variable('const', fields, tsg
61
+ .identifier('gqlResolveInfoToField')
62
+ .importFrom('sasat')
63
+ .call(tsg.identifier('info'))
64
+ .as(node.entityName.fieldTypeRef(Directory.paths.generated)));
65
+ const all = () => {
66
+ return [
67
+ constInfo,
68
+ tsg.return(ds
69
+ .property(query.repoMethodName)
70
+ .call(fields, tsg.identifier('undefined'), tsg.identifier('context'))),
71
+ ];
72
+ };
73
+ const pageable = () => {
74
+ return [
75
+ constInfo,
76
+ tsg.variable('const', tsg.identifier('{ option }'), tsg.identifier('params')),
77
+ tsg.return(ds
78
+ .property('findPageable')
79
+ .call(tsg.object(tsg.propertyAssign('numberOfItem', option.property('numberOfItem')), tsg.propertyAssign('offset', option.property('offset'))), fields, tsg.identifier('undefined'), tsg.identifier('context'))),
80
+ ];
81
+ };
82
+ return tsg.propertyAssign(query.queryName, tsg.arrowFunc(QueryGenerator.createParams(node, query), undefined, tsg.block(...(query.listType === 'paging' ? pageable() : all()))));
74
83
  }
75
84
  entity(node) {
76
85
  return node.queries.map(it => (it.isList ? this.listQuery : this.query)(node, it));
@@ -9,8 +9,9 @@ import { FindMethodNode } from '../../../parser/node/findMethod.js';
9
9
  export class ResolverGenerator {
10
10
  constructor() {
11
11
  this.entityResolver = (node) => {
12
- return tsg.propertyAssign(node.entityName.name, tsg.object(...node.relations.map(relation => this.relationProperty(relation)), ...node
12
+ return tsg.propertyAssign(node.entityName.name, tsg.object(...node.relations.filter(it => it.to.gqlOption.enabled).map(relation => this.relationProperty(relation)), ...node
13
13
  .findReferencedRelations()
14
+ .filter(it => it.from.gqlOption.enabled)
14
15
  .map(relation => this.referencedByProperty(relation))));
15
16
  };
16
17
  }
@@ -23,27 +24,27 @@ export class ResolverGenerator {
23
24
  .importFrom('./relationMap')),
24
25
  ], undefined, tsg.block(tsg.if(tsg.binary(tsg.identifier(paramName).property(propertyName), '!==', tsg.identifier('undefined')), tsg.return(tsg.identifier(paramName).property(propertyName))), tsg.return(tsg
25
26
  .new(tsg
26
- .identifier(relation.toEntityName.dataSourceName())
27
- .importFrom(Directory.dbDataSourcePath(Directory.paths.generated, relation.toEntityName)))
28
- .property(FindMethodNode.paramsToName(relation.toField))
27
+ .identifier(relation.to.entityName.dataSourceName())
28
+ .importFrom(Directory.dbDataSourcePath(Directory.paths.generated, relation.to.entityName)))
29
+ .property(FindMethodNode.paramsToName(relation.to.field))
29
30
  .call(tsg
30
31
  .identifier(paramName)
31
- .property(relation.fromField)
32
+ .property(relation.from.field)
32
33
  .nonNull())))));
33
34
  }
34
35
  referencedByProperty(relation) {
35
- const paramName = relation.toEntityName.lowerCase();
36
+ const paramName = relation.to.entityName.lowerCase();
36
37
  const propertyName = relation.referencedByPropertyName();
37
38
  return tsg.propertyAssign(propertyName, tsg.arrowFunc([
38
39
  tsg.parameter(paramName, tsg
39
- .typeRef(relation.toEntityName.resultType())
40
+ .typeRef(relation.to.entityName.resultType())
40
41
  .importFrom('./relationMap')),
41
42
  ], undefined, tsg.block(tsg.if(tsg.binary(tsg.identifier(paramName).property(propertyName), '!==', tsg.identifier('undefined')), tsg.return(tsg.identifier(paramName).property(propertyName))), tsg.return(tsg
42
43
  .new(tsg
43
44
  .identifier(relation.parent.entityName.dataSourceName())
44
45
  .importFrom(Directory.dbDataSourcePath(Directory.paths.generated, relation.parent.entityName)))
45
- .property(FindMethodNode.paramsToName(relation.fromField))
46
- .call(tsg.identifier(paramName).property(relation.toField).nonNull())))));
46
+ .property(FindMethodNode.paramsToName(relation.from.field))
47
+ .call(tsg.identifier(paramName).property(relation.to.field).nonNull())))));
47
48
  }
48
49
  generate(root) {
49
50
  const hasSubscription = root.mutations().some(it => it.subscribed);
@@ -53,6 +54,6 @@ export class ResolverGenerator {
53
54
  ];
54
55
  if (hasSubscription)
55
56
  properties.push(new PropertyAssignment('Subscription', new Identifier('subscription').importFrom('./subscription')));
56
- return new TsFile(new VariableDeclaration('const', new Identifier('resolvers'), new ObjectLiteral(...properties, new SpreadAssignment(new ObjectLiteral(...root.entities().map(this.entityResolver))))).export()).disableEsLint();
57
+ return new TsFile(new VariableDeclaration('const', new Identifier('resolvers'), new ObjectLiteral(...properties, new SpreadAssignment(new ObjectLiteral(...root.entities().filter(it => it.gqlEnabled()).map(this.entityResolver))))).export()).disableEsLint();
57
58
  }
58
59
  }
@@ -4,7 +4,7 @@ import { tsg } from '../code/factory.js';
4
4
  import { MutationNode } from '../../../parser/node/gql/mutationNode.js';
5
5
  export class TypeDefGenerator {
6
6
  generate(root) {
7
- const typeDefs = root.entities().flatMap(it => it.allTypeDefs());
7
+ const typeDefs = root.entities().filter(it => it.gqlEnabled()).flatMap(it => it.allTypeDefs());
8
8
  const types = [
9
9
  ...this.createTypes(typeDefs),
10
10
  this.createQuery(root.queries()),
@@ -3,6 +3,7 @@ import { RootNode } from '../../parser/node/rootNode.js';
3
3
  export declare class RelationMapGenerator {
4
4
  generate(root: RootNode): TsFile;
5
5
  private relationMap;
6
+ private referencedRelationType;
6
7
  private entityRelationType;
7
8
  private entityRelationMap;
8
9
  private tableInfo;
@@ -4,26 +4,29 @@ import { Directory } from '../../constants/directory.js';
4
4
  import { KeywordTypeNode } from './code/node/type/typeKeyword.js';
5
5
  export class RelationMapGenerator {
6
6
  generate(root) {
7
- return new TsFile(this.relationMap(root), this.tableInfo(root), ...root.entities().flatMap(this.entityRelationType)).disableEsLint();
7
+ return new TsFile(this.relationMap(root), this.tableInfo(root), ...root.entities().flatMap(it => this.entityRelationType(it))).disableEsLint();
8
8
  }
9
9
  relationMap(root) {
10
10
  return tsg
11
11
  .variable('const', tsg.identifier('relationMap'), tsg.object(...root.entities().map(it => this.entityRelationMap(it))), tsg.typeRef('RelationMap').importFrom('sasat'))
12
12
  .export();
13
13
  }
14
+ referencedRelationType(node) {
15
+ const type = tsg.intersectionType(tsg.typeRef('Partial', [node.parent.entityName.getTypeReference(Directory.paths.generated)]), node.parent.entityName.identifiableTypeReference(Directory.paths.generated));
16
+ return tsg.propertySignature(node.referencedByPropertyName(), node.relation === 'Many' ? tsg.arrayType(type) : type);
17
+ }
14
18
  entityRelationType(node) {
15
19
  const importEntity = (entity) => Directory.entityPath(Directory.paths.generated, entity);
16
20
  const typeProperties = [
17
- ...node.relations.map(it => tsg.propertySignature(it.refPropertyName(), it
18
- .refType()
19
- .toTsType()
20
- .addImport([it.toEntityName.name], importEntity(it.toEntityName)))),
21
+ ...node.relations.map(it => tsg.propertySignature(it.refPropertyName(), tsg.intersectionType(tsg.typeRef('Partial', [
22
+ tsg.intersectionType(it
23
+ .refType()
24
+ .toTsType()
25
+ .addImport([it.to.entityName.name], importEntity(it.to.entityName)), tsg.typeRef(it.to.entityName.relationTypeName())),
26
+ ]), it.to.entityName.identifiableTypeReference(Directory.paths.generated)))),
21
27
  ...node
22
28
  .findReferencedRelations()
23
- .map(it => tsg.propertySignature(it.referencedByPropertyName(), it
24
- .referenceByType()
25
- .toTsType()
26
- .addImport([it.parent.entityName.name], importEntity(it.parent.entityName)))),
29
+ .map(it => this.referencedRelationType(it)),
27
30
  ];
28
31
  return [
29
32
  tsg
@@ -57,9 +60,9 @@ export class RelationMapGenerator {
57
60
  .call(tsg.identifier('parentTableAlias'), tsg.string(parentColumn)), qExpr
58
61
  .property('field')
59
62
  .call(tsg.identifier('childTableAlias'), tsg.string(childColumn)))));
60
- return tsg.propertyAssign(node.repository.tableName, tsg.object(...node.relations.map(rel => tsg.propertyAssign(rel.refPropertyName(), tsg.object(tsg.propertyAssign('table', tsg.string(rel.toTableName)), on(rel.fromColumnName, rel.toColumnName), tsg.propertyAssign('relation', tsg.string('One'))))), ...node
63
+ return tsg.propertyAssign(node.repository.tableName, tsg.object(...node.relations.map(rel => tsg.propertyAssign(rel.refPropertyName(), tsg.object(tsg.propertyAssign('table', tsg.string(rel.to.tableName)), on(rel.from.columnName, rel.to.columnName), tsg.propertyAssign('relation', tsg.string('One'))))), ...node
61
64
  .findReferencedRelations()
62
- .map(rel => tsg.propertyAssign(rel.referencedByPropertyName(), tsg.object(tsg.propertyAssign('table', tsg.string(rel.parent.repository.tableName)), on(rel.toColumnName, rel.fromColumnName), tsg.propertyAssign('relation', tsg.string(rel.relation)))))));
65
+ .map(rel => tsg.propertyAssign(rel.referencedByPropertyName(), tsg.object(tsg.propertyAssign('table', tsg.string(rel.parent.repository.tableName)), on(rel.to.columnName, rel.from.columnName), tsg.propertyAssign('relation', tsg.string(rel.relation)))))));
63
66
  }
64
67
  tableInfo(root) {
65
68
  const columnMap = (entity) => tsg.propertyAssign('columnMap', tsg.object(...entity.fields.map(field => tsg.propertyAssign(field.fieldName, tsg.string(field.columnName)))));
@@ -25,13 +25,14 @@ const baseDBDataSourceFile = `\
25
25
  ${new ImportDeclaration(['Fields', 'SasatDBDatasource', 'EntityType'], 'sasat').toString()}
26
26
  ${new ImportDeclaration(['relationMap', 'tableInfo'], './__generated__/relationMap').toString()}
27
27
 
28
- export abstract class BaseDBDataSource<Entity extends EntityType, Creatable, Identifiable, EntityFields extends Fields> extends SasatDBDatasource<
29
- Entity,
28
+ export abstract class BaseDBDataSource<
29
+ Entity extends EntityType,
30
30
  Creatable,
31
31
  Identifiable,
32
- EntityFields
33
- > {
34
- protected relationMap = relationMap
32
+ EntityFields extends Fields,
33
+ QueryResult extends Partial<Entity> & Identifiable,
34
+ > extends SasatDBDatasource<Entity, Creatable, Identifiable, EntityFields, QueryResult> {
35
+ protected relationMap = relationMap;
35
36
  protected tableInfo = tableInfo;
36
37
  }
37
38
  `;
@@ -9,7 +9,7 @@ export const tsValueString = (value) => {
9
9
  if (typeof value === 'boolean')
10
10
  return '' + value;
11
11
  if (typeof value === 'string')
12
- return `'${value.replace("'", "\\'")}'`;
12
+ return `'${value.replaceAll("'", "\\'")}'`;
13
13
  if (typeof value === 'bigint')
14
14
  return '' + value;
15
15
  if (typeof value === 'function')
package/lib/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export { BooleanValueExpression } from './runtime/dsl/query/query.js';
1
+ export { BooleanValueExpression, Query, LockMode, } from './runtime/dsl/query/query.js';
2
2
  export { Relation } from './migration/data/relation.js';
3
3
  export { QExpr } from './runtime/dsl/factory.js';
4
4
  export { RelationMap } from './runtime/dsl/query/createQueryResolveInfo.js';
@@ -7,7 +7,7 @@ export { gqlResolveInfoToField } from './runtime/gqlResolveInfoToField.js';
7
7
  export { ComparisonOperators } from './db/sql/expression/comparison.js';
8
8
  export { MigrationStore } from './migration/front/storeMigrator.js';
9
9
  export { SasatMigration } from './migration/front/migration.js';
10
- export { SasatDBDatasource, EntityResult, EntityType, ListQueryOption, } from './runtime/sasatDBDatasource.js';
10
+ export { SasatDBDatasource, EntityResult, EntityType, ListQueryOption, QueryOptions, } from './runtime/sasatDBDatasource.js';
11
11
  export { getCurrentDateTimeString } from './util/dateUtil.js';
12
12
  export { getDbClient } from './db/getDbClient.js';
13
13
  export { assignDeep } from './util/assignDeep.js';
@@ -2,7 +2,7 @@ import { ColumnCreator } from './columnCreator.js';
2
2
  import { ColumnBuilder } from './columnBuilder.js';
3
3
  import { Reference } from '../serialized/serializedColumn.js';
4
4
  import { TableHandler } from '../serializable/table.js';
5
- import { GqlFromContextParam, MutationOption } from '../data/gqlOption.js';
5
+ import { GqlFromContextParam, GQLOption, MutationOption } from '../data/GQLOption.js';
6
6
  import { DataStore } from '../dataStore.js';
7
7
  export interface TableBuilder {
8
8
  column(columnName: string): ColumnCreator;
@@ -16,6 +16,8 @@ export interface TableBuilder {
16
16
  setGQLUpdate(enabled: boolean, options?: Partial<MutationOption>): TableBuilder;
17
17
  setGQLDelete(enabled: boolean, options?: Partial<Omit<MutationOption, 'noReFetch'>>): TableBuilder;
18
18
  setGQLContextColumn(columns: GqlFromContextParam[]): TableBuilder;
19
+ enableGQL(): TableBuilder;
20
+ setGQLOption(option: Partial<GQLOption>): TableBuilder;
19
21
  }
20
22
  export declare class TableCreator implements TableBuilder {
21
23
  tableName: string;
@@ -31,6 +33,8 @@ export declare class TableCreator implements TableBuilder {
31
33
  createdAt(): TableBuilder;
32
34
  updatedAt(): TableBuilder;
33
35
  addIndex(...columns: string[]): TableBuilder;
36
+ enableGQL(): TableBuilder;
37
+ setGQLOption(option: Partial<GQLOption>): TableBuilder;
34
38
  setGQLCreate(enabled: boolean, options?: Partial<MutationOption>): TableBuilder;
35
39
  setGQLUpdate(enabled: boolean, options?: Partial<MutationOption>): TableBuilder;
36
40
  setGQLDelete(enabled: boolean, options?: Partial<Omit<MutationOption, 'noReFetch'>>): TableBuilder;
@@ -50,6 +50,17 @@ export class TableCreator {
50
50
  this.table.addIndex(`index_${this.tableName}__${columns.join('_')}`, ...columns);
51
51
  return this;
52
52
  }
53
+ enableGQL() {
54
+ this.table.setGQLOption({
55
+ ...this.table.gqlOption,
56
+ enabled: true,
57
+ });
58
+ return this;
59
+ }
60
+ setGQLOption(option) {
61
+ this.table.setGQLOption(option);
62
+ return this;
63
+ }
53
64
  setGQLCreate(enabled, options) {
54
65
  this.table.setGQLCreate(enabled, options);
55
66
  return this;
@@ -10,7 +10,12 @@ export declare type MutationOption = {
10
10
  subscription: boolean;
11
11
  subscriptionFilter: string[];
12
12
  };
13
- export interface GqlOption {
13
+ export interface GQLOption {
14
+ enabled: boolean;
15
+ query: {
16
+ find: boolean;
17
+ list: false | 'all' | 'paging';
18
+ };
14
19
  mutation: {
15
20
  create: MutationOption & Enabled;
16
21
  update: MutationOption & Enabled;
@@ -24,6 +29,6 @@ export declare const defaultMutationOption: {
24
29
  subscription: boolean;
25
30
  subscriptionFilter: never[];
26
31
  };
27
- export declare const getDefaultGqlOption: () => GqlOption;
28
- export declare const updateMutationOption: (option: GqlOption, mutation: Partial<GqlOption['mutation']>) => GqlOption;
32
+ export declare const getDefaultGqlOption: () => GQLOption;
33
+ export declare const updateMutationOption: (option: GQLOption, mutation: Partial<GQLOption['mutation']>) => GQLOption;
29
34
  export {};
@@ -5,6 +5,11 @@ export const defaultMutationOption = {
5
5
  subscriptionFilter: [],
6
6
  };
7
7
  export const getDefaultGqlOption = () => ({
8
+ enabled: false,
9
+ query: {
10
+ find: true,
11
+ list: 'all',
12
+ },
8
13
  mutation: {
9
14
  create: defaultMutationOption,
10
15
  update: defaultMutationOption,
@@ -1,7 +1,7 @@
1
1
  import { StoreMigrator } from './storeMigrator.js';
2
2
  import { Table, TableHandler } from '../serializable/table.js';
3
3
  import { Reference, SerializedColumn, SerializedNormalColumn } from '../serialized/serializedColumn.js';
4
- import { GqlFromContextParam, MutationOption } from '../data/gqlOption.js';
4
+ import { GqlFromContextParam, GQLOption, MutationOption } from '../data/GQLOption.js';
5
5
  import { Column } from '../serializable/column.js';
6
6
  import { SerializedTable } from '../serialized/serializedStore.js';
7
7
  import { DBType } from '../column/columnTypes.js';
@@ -18,6 +18,8 @@ export interface MigrationTable extends Table {
18
18
  setGQLUpdate(enabled: boolean, options?: Partial<MutationOption>): MigrationTable;
19
19
  setGQLDelete(enabled: boolean, options?: Partial<Omit<MutationOption, 'noReFetch'>>): MigrationTable;
20
20
  setGQLContextColumn(columns: GqlFromContextParam[]): MigrationTable;
21
+ enableGQL(): MigrationTable;
22
+ setGQLOption(option: GQLOption): MigrationTable;
21
23
  }
22
24
  export declare class TableMigrator implements MigrationTable {
23
25
  private table;
@@ -35,10 +37,13 @@ export declare class TableMigrator implements MigrationTable {
35
37
  dropColumn(columnName: string): MigrationTable;
36
38
  setGQLCreate(enabled: boolean, options?: Partial<MutationOption>): MigrationTable;
37
39
  setGQLUpdate(enabled: boolean, options?: Partial<MutationOption>): MigrationTable;
40
+ enableGQL(): MigrationTable;
41
+ setGQLOption(option: GQLOption): MigrationTable;
38
42
  setGQLDelete(enabled: boolean, options?: Partial<Omit<MutationOption, 'noReFetch'>>): MigrationTable;
39
43
  setGQLContextColumn(columns: GqlFromContextParam[]): MigrationTable;
40
44
  addForeignKey(reference: Reference): MigrationTable;
41
45
  changeColumnType(columnName: string, type: DBType): MigrationTable;
42
46
  protected tableExists(tableName: string): true;
43
47
  setDefault(columnName: string, value: string | number | null): MigrationTable;
48
+ get gqlOption(): GQLOption;
44
49
  }
@@ -56,6 +56,17 @@ export class TableMigrator {
56
56
  this.table.setGQLUpdate(enabled, options);
57
57
  return this;
58
58
  }
59
+ enableGQL() {
60
+ this.table.setGQLOption({
61
+ ...this.table.gqlOption,
62
+ enabled: true,
63
+ });
64
+ return this;
65
+ }
66
+ setGQLOption(option) {
67
+ this.table.setGQLOption(option);
68
+ return this;
69
+ }
59
70
  setGQLDelete(enabled, options) {
60
71
  this.table.setGQLDelete(enabled, options);
61
72
  return this;
@@ -99,4 +110,7 @@ export class TableMigrator {
99
110
  this.store.addQuery(`ALTER TABLE ${this.tableName} ALTER ${columnName} SET DEFAULT ${SqlString.escape(value)}`);
100
111
  return this;
101
112
  }
113
+ get gqlOption() {
114
+ return this.table.gqlOption;
115
+ }
102
116
  }
@@ -3,13 +3,14 @@ import { SerializedTable } from '../serialized/serializedStore.js';
3
3
  import { BaseColumn, Column, ReferenceColumn } from './column.js';
4
4
  import { Reference, SerializedColumn } from '../serialized/serializedColumn.js';
5
5
  import { DBIndex } from '../data/index.js';
6
- import { GqlFromContextParam, GqlOption, MutationOption } from '../data/gqlOption.js';
6
+ import { GqlFromContextParam, GQLOption, MutationOption } from '../data/GQLOption.js';
7
7
  import { EntityName } from '../../parser/node/entityName.js';
8
8
  import { DataStore } from '../dataStore.js';
9
9
  import { DBColumnTypes } from '../column/columnTypes.js';
10
10
  export interface Table extends Serializable<SerializedTable> {
11
11
  column(columnName: string): Column;
12
12
  tableName: string;
13
+ gqlOption: GQLOption;
13
14
  }
14
15
  export declare class TableHandler implements Table {
15
16
  store: DataStore;
@@ -22,7 +23,7 @@ export declare class TableHandler implements Table {
22
23
  readonly uniqueKeys: string[][];
23
24
  readonly tableName: string;
24
25
  private _gqlOption;
25
- get gqlOption(): GqlOption;
26
+ get gqlOption(): GQLOption;
26
27
  constructor(table: Partial<SerializedTable> & Pick<SerializedTable, 'tableName'>, store: DataStore);
27
28
  column(columnName: string): Column;
28
29
  addColumn(column: BaseColumn, isPrimary?: boolean, isUnique?: boolean): void;
@@ -40,6 +41,7 @@ export declare class TableHandler implements Table {
40
41
  getEntityName(): EntityName;
41
42
  setGQLCreate(enabled: boolean, options?: Partial<MutationOption>): void;
42
43
  setGQLUpdate(enabled: boolean, options?: Partial<MutationOption>): void;
44
+ setGQLOption(option: Partial<GQLOption>): void;
43
45
  setGQLDelete(enabled: boolean, options?: Partial<Omit<MutationOption, 'noReFetch'>>): void;
44
46
  setGQLContextColumn(columns: GqlFromContextParam[]): void;
45
47
  getReferenceColumns(): ReferenceColumn[];
@@ -4,7 +4,7 @@ import { SqlString } from '../../runtime/sql/sqlString.js';
4
4
  import { SasatError } from '../../error.js';
5
5
  import { referenceToSql, } from '../serialized/serializedColumn.js';
6
6
  import { DBIndex } from '../data/index.js';
7
- import { defaultMutationOption, getDefaultGqlOption, updateMutationOption, } from '../data/gqlOption.js';
7
+ import { defaultMutationOption, getDefaultGqlOption, updateMutationOption, } from '../data/GQLOption.js';
8
8
  import { assembleColumn } from '../functions/assembleColumn.js';
9
9
  import { EntityName } from '../../parser/node/entityName.js';
10
10
  export class TableHandler {
@@ -147,6 +147,9 @@ export class TableHandler {
147
147
  },
148
148
  });
149
149
  }
150
+ setGQLOption(option) {
151
+ this._gqlOption = { ...this.gqlOption, ...option };
152
+ }
150
153
  setGQLDelete(enabled, options) {
151
154
  this._gqlOption = updateMutationOption(this._gqlOption, {
152
155
  delete: {
@@ -1,6 +1,6 @@
1
1
  import { SerializedColumn } from './serializedColumn.js';
2
2
  import { Index } from '../data/index.js';
3
- import { GqlOption } from '../data/gqlOption.js';
3
+ import { GQLOption } from '../data/GQLOption.js';
4
4
  export interface SerializedStore {
5
5
  tables: SerializedTable[];
6
6
  }
@@ -10,5 +10,5 @@ export interface SerializedTable {
10
10
  uniqueKeys: string[][];
11
11
  indexes: Index[];
12
12
  tableName: string;
13
- gqlOption: GqlOption;
13
+ gqlOption: GQLOption;
14
14
  }
@@ -20,4 +20,5 @@ export declare class EntityNode {
20
20
  onCreateOptionalFields(): FieldNode[];
21
21
  hasDefaultValueFields(): FieldNode[];
22
22
  findReferencedRelations(): RelationNode[];
23
+ gqlEnabled(): boolean;
23
24
  }
@@ -8,10 +8,13 @@ export class EntityNode {
8
8
  this.fields = table.columns.map(column => FieldNode.fromColumn(column, table));
9
9
  this.relations = table
10
10
  .getReferenceColumns()
11
- .map(it => RelationNode.fromReference(this, it, table.store
12
- .table(it.data.reference.targetTable)
13
- .column(it.data.reference.targetColumn)
14
- .fieldName()));
11
+ .map(it => {
12
+ const targetTable = table.store
13
+ .table(it.data.reference.targetTable);
14
+ return RelationNode.fromReference(this, it, targetTable
15
+ .column(it.data.reference.targetColumn)
16
+ .fieldName(), targetTable.gqlOption);
17
+ });
15
18
  }
16
19
  field(fieldName) {
17
20
  return this.fields.find(it => it.fieldName === fieldName);
@@ -43,4 +46,7 @@ export class EntityNode {
43
46
  findReferencedRelations() {
44
47
  return this.repository.root.findReferencedRelations(this.entityName);
45
48
  }
49
+ gqlEnabled() {
50
+ return this.repository.gqlOption.enabled;
51
+ }
46
52
  }
@@ -1,11 +1,13 @@
1
1
  import { ParameterNode } from '../parameterNode.js';
2
2
  import { TypeNode } from '../typeNode.js';
3
+ export declare type ListQueryType = 'all' | 'paging';
3
4
  export declare class QueryNode {
4
5
  readonly queryName: string;
5
6
  readonly repoMethodName: string;
6
7
  readonly queryParams: ParameterNode[];
7
8
  readonly returnType: TypeNode;
8
9
  readonly isList: boolean;
9
- constructor(queryName: string, repoMethodName: string, queryParams: ParameterNode[], returnType: TypeNode, isList: boolean);
10
+ readonly listType?: ListQueryType | undefined;
11
+ constructor(queryName: string, repoMethodName: string, queryParams: ParameterNode[], returnType: TypeNode, isList: boolean, listType?: ListQueryType | undefined);
10
12
  toGqlString(): string;
11
13
  }
@@ -1,11 +1,12 @@
1
1
  import { ParameterNode } from '../parameterNode.js';
2
2
  export class QueryNode {
3
- constructor(queryName, repoMethodName, queryParams, returnType, isList) {
3
+ constructor(queryName, repoMethodName, queryParams, returnType, isList, listType) {
4
4
  this.queryName = queryName;
5
5
  this.repoMethodName = repoMethodName;
6
6
  this.queryParams = queryParams;
7
7
  this.returnType = returnType;
8
8
  this.isList = isList;
9
+ this.listType = listType;
9
10
  }
10
11
  toGqlString() {
11
12
  return `${this.queryName}${ParameterNode.parametersToGqlString(...this.queryParams)}: ${this.returnType.toGqlString()}`;
@@ -5,5 +5,5 @@ export declare class TypeDefNode {
5
5
  readonly params: ParameterNode[];
6
6
  static new(entity: EntityNode): TypeDefNode;
7
7
  static deletedNode(entity: EntityNode): TypeDefNode;
8
- constructor(typeName: string, params: ParameterNode[]);
8
+ private constructor();
9
9
  }
@@ -5,9 +5,10 @@ export class TypeDefNode {
5
5
  this.params = params;
6
6
  }
7
7
  static new(entity) {
8
- const reference = entity.relations.map(rel => new ParameterNode(rel.refPropertyName(), rel.refType()));
8
+ const reference = entity.relations.filter(it => it.to.gqlOption.enabled).map(rel => new ParameterNode(rel.refPropertyName(), rel.refType()));
9
9
  const referencedBy = entity
10
10
  .findReferencedRelations()
11
+ .filter(it => it.from.gqlOption.enabled)
11
12
  .map(rel => new ParameterNode(rel.referencedByPropertyName(), rel.referenceByType()));
12
13
  return new TypeDefNode(entity.entityName.name, [
13
14
  ...entity.fields.map(it => it.toParam()),
@@ -3,20 +3,30 @@ import { EntityNode } from './entityNode.js';
3
3
  import { ReferenceColumn } from '../../migration/serializable/column.js';
4
4
  import { EntityName } from './entityName.js';
5
5
  import { Relation } from '../../migration/data/relation.js';
6
+ import { GQLOption } from "../../migration/data/GQLOption.js";
7
+ declare type From = {
8
+ field: string;
9
+ columnName: string;
10
+ gqlOption: GQLOption;
11
+ };
12
+ declare type To = {
13
+ field: string;
14
+ columnName: string;
15
+ tableName: string;
16
+ entityName: EntityName;
17
+ gqlOption: GQLOption;
18
+ };
6
19
  export declare class RelationNode {
7
20
  readonly parent: EntityNode;
8
21
  readonly relationName: string | undefined;
9
- readonly fromField: string;
10
- readonly toField: string;
11
- readonly toTableName: string;
12
- readonly toEntityName: EntityName;
13
22
  readonly relation: Relation;
14
- readonly fromColumnName: string;
15
- readonly toColumnName: string;
16
- static fromReference(entity: EntityNode, ref: ReferenceColumn, targetFieldName: string): RelationNode;
23
+ readonly from: From;
24
+ readonly to: To;
25
+ static fromReference(entity: EntityNode, ref: ReferenceColumn, targetFieldName: string, targetTableGqlOption: GQLOption): RelationNode;
17
26
  private constructor();
18
27
  refPropertyName(): string;
19
28
  referencedByPropertyName(): string;
20
29
  refType(): TypeNode;
21
30
  referenceByType(): TypeNode;
22
31
  }
32
+ export {};
@@ -2,28 +2,34 @@ import { EntityTypeNode } from './typeNode.js';
2
2
  import { TableHandler } from '../../migration/serializable/table.js';
3
3
  import { EntityName } from './entityName.js';
4
4
  export class RelationNode {
5
- constructor(parent, relationName, fromField, toField, toTableName, toEntityName, relation, fromColumnName, toColumnName) {
5
+ constructor(parent, relationName, relation, from, to) {
6
6
  this.parent = parent;
7
7
  this.relationName = relationName;
8
- this.fromField = fromField;
9
- this.toField = toField;
10
- this.toTableName = toTableName;
11
- this.toEntityName = toEntityName;
12
8
  this.relation = relation;
13
- this.fromColumnName = fromColumnName;
14
- this.toColumnName = toColumnName;
9
+ this.from = from;
10
+ this.to = to;
15
11
  }
16
- static fromReference(entity, ref, targetFieldName) {
17
- return new RelationNode(entity, ref.data.reference.relationName, ref.data.fieldName, targetFieldName, ref.data.reference.targetTable, new EntityName(TableHandler.tableNameToEntityName(ref.data.reference.targetTable)), ref.data.reference.relation, ref.data.columnName, ref.data.reference.targetColumn);
12
+ static fromReference(entity, ref, targetFieldName, targetTableGqlOption) {
13
+ return new RelationNode(entity, ref.data.reference.relationName, ref.data.reference.relation, {
14
+ field: ref.data.fieldName,
15
+ columnName: ref.data.columnName,
16
+ gqlOption: ref.table.gqlOption,
17
+ }, {
18
+ field: targetFieldName,
19
+ tableName: ref.data.reference.targetTable,
20
+ entityName: new EntityName(TableHandler.tableNameToEntityName(ref.data.reference.targetTable)),
21
+ columnName: ref.data.reference.targetColumn,
22
+ gqlOption: targetTableGqlOption,
23
+ });
18
24
  }
19
25
  refPropertyName() {
20
- return this.relationName || this.fromField + this.toEntityName.name;
26
+ return this.relationName || this.from.field + this.to.entityName.name;
21
27
  }
22
28
  referencedByPropertyName() {
23
29
  return (this.relationName || '') + this.parent.entityName.name;
24
30
  }
25
31
  refType() {
26
- return new EntityTypeNode(this.toEntityName, false, false);
32
+ return new EntityTypeNode(this.to.entityName, false, false);
27
33
  }
28
34
  referenceByType() {
29
35
  if (this.relation === 'Many')
@@ -5,6 +5,7 @@ import { QueryNode } from './gql/queryNode.js';
5
5
  import { MutationNode } from './gql/mutationNode.js';
6
6
  import { TableHandler } from '../../migration/serializable/table.js';
7
7
  import { EntityName } from './entityName.js';
8
+ import { GQLOption } from "../../migration/data/GQLOption.js";
8
9
  export declare class RepositoryNode {
9
10
  readonly root: RootNode;
10
11
  readonly tableName: string;
@@ -14,6 +15,7 @@ export declare class RepositoryNode {
14
15
  readonly autoIncrementColumn?: string;
15
16
  readonly queries: QueryNode[];
16
17
  readonly mutations: MutationNode[];
18
+ readonly gqlOption: GQLOption;
17
19
  constructor(root: RootNode, table: TableHandler);
18
20
  private createEntity;
19
21
  getDefaultValueColumnNames(): string[];
@@ -15,8 +15,9 @@ export class RepositoryNode {
15
15
  this.autoIncrementColumn = table.columns
16
16
  .find(it => it.serialize().autoIncrement)
17
17
  ?.fieldName();
18
- this.queries = new QueryNodeFactory().create(table);
18
+ this.queries = new QueryNodeFactory().create(table, table.gqlOption);
19
19
  this.mutations = new MutationNodeFactory().create(table, this.entity);
20
+ this.gqlOption = table.gqlOption;
20
21
  }
21
22
  createEntity(table) {
22
23
  return new EntityNode(this, table);
@@ -37,14 +38,14 @@ export class RepositoryNode {
37
38
  };
38
39
  const refMethods = (relation) => {
39
40
  return new FindMethodNode([
40
- new ParameterNode(relation.fromField, new EntityTypeNode(relation.parent.field(relation.fromField).dbType, false, false)),
41
+ new ParameterNode(relation.from.field, new EntityTypeNode(relation.parent.field(relation.from.field).dbType, false, false)),
41
42
  ], new EntityTypeNode(EntityName.fromTableName(relation.parent.repository.tableName), relation.relation === 'Many', false), false);
42
43
  };
43
44
  const referencedByMethod = (relation) => {
44
- const to = relation.parent.repository.root.findRepository(relation.toEntityName);
45
+ const to = relation.parent.repository.root.findRepository(relation.to.entityName);
45
46
  return new FindMethodNode([
46
- new ParameterNode(relation.toField, new EntityTypeNode(to.entity.field(relation.toField).dbType, false, false)),
47
- ], new EntityTypeNode(relation.toEntityName, false, false), false);
47
+ new ParameterNode(relation.to.field, new EntityTypeNode(to.entity.field(relation.to.field).dbType, false, false)),
48
+ ], new EntityTypeNode(relation.to.entityName, false, false), false);
48
49
  };
49
50
  const methods = [
50
51
  new FindMethodNode(node.primaryKeys.map(it => {
@@ -10,7 +10,7 @@ export class RootNode {
10
10
  }
11
11
  findReferencedRelations(entity) {
12
12
  return this.entities()
13
- .map(it => it.relations.find(it => it.toEntityName.name === entity.name))
13
+ .map(it => it.relations.find(it => it.to.entityName.name === entity.name))
14
14
  .filter(it => it !== undefined);
15
15
  }
16
16
  entities() {
@@ -6,7 +6,7 @@ export declare abstract class TypeNode {
6
6
  readonly isArray: boolean;
7
7
  readonly isNullable: boolean;
8
8
  readonly isArrayNullable: boolean;
9
- constructor(typeName: DBColumnTypes | EntityName, isArray: boolean, isNullable: boolean, isArrayNullable?: boolean);
9
+ protected constructor(typeName: DBColumnTypes | EntityName, isArray: boolean, isNullable: boolean, isArrayNullable?: boolean);
10
10
  abstract toTsType(): TsType;
11
11
  toGqlString(): string;
12
12
  }
@@ -23,7 +23,7 @@ export class TypeNode {
23
23
  }
24
24
  export class ListQueryOptionTypeNode extends TypeNode {
25
25
  constructor() {
26
- super(new EntityName(TypeDefGenerator.ListQueryOptionType), false, true);
26
+ super(new EntityName(TypeDefGenerator.ListQueryOptionType), false, false);
27
27
  }
28
28
  toTsType() {
29
29
  return tsg
@@ -5,6 +5,8 @@ import { FindMethodNode } from '../node/findMethod.js';
5
5
  export class MutationNodeFactory {
6
6
  constructor() {
7
7
  this.create = (table, entity) => {
8
+ if (!table.gqlOption.enabled)
9
+ return [];
8
10
  const result = [];
9
11
  const options = table.gqlOption.mutation;
10
12
  if (options.create.enabled) {
@@ -1,7 +1,8 @@
1
1
  import { QueryNode } from '../node/gql/queryNode.js';
2
2
  import { TableHandler } from '../../migration/serializable/table.js';
3
+ import { GQLOption } from "../../migration/data/GQLOption.js";
3
4
  export declare class QueryNodeFactory {
4
- create(table: TableHandler): QueryNode[];
5
+ create(table: TableHandler, gqlOption: GQLOption): QueryNode[];
5
6
  private listQuery;
6
7
  private primaryQuery;
7
8
  }
@@ -4,11 +4,20 @@ import { EntityTypeNode, ListQueryOptionTypeNode, } from '../node/typeNode.js';
4
4
  import { ParameterNode } from '../node/parameterNode.js';
5
5
  import { FindMethodNode } from '../node/findMethod.js';
6
6
  export class QueryNodeFactory {
7
- create(table) {
8
- return [this.primaryQuery(table), this.listQuery(table)];
7
+ create(table, gqlOption) {
8
+ if (!gqlOption.enabled)
9
+ return [];
10
+ const result = [];
11
+ if (gqlOption.query.find) {
12
+ result.push(this.primaryQuery(table));
13
+ }
14
+ if (gqlOption.query.list !== false) {
15
+ result.push(this.listQuery(table, gqlOption.query.list));
16
+ }
17
+ return result;
9
18
  }
10
- listQuery(table) {
11
- return new QueryNode(lowercaseFirstLetter(plural(table.getEntityName().name)), 'find', [new ParameterNode('option', new ListQueryOptionTypeNode())], new EntityTypeNode(table.getEntityName(), true, false), true);
19
+ listQuery(table, listQueryType) {
20
+ return new QueryNode(lowercaseFirstLetter(plural(table.getEntityName().name)), 'find', listQueryType === 'paging' ? [new ParameterNode('option', new ListQueryOptionTypeNode())] : [], new EntityTypeNode(table.getEntityName(), true, false), true, listQueryType);
12
21
  }
13
22
  primaryQuery(table) {
14
23
  const primaryKeys = table.primaryKey.map(it => table.column(it).fieldName());
@@ -1,8 +1,8 @@
1
1
  import { BetweenExpression, BooleanValueExpression, ComparisonExpression, Field, Fn, InExpression, IsNullExpression, Join, JoinType, Literal, ParenthesisExpression, Query, QueryTable, Sort, SortDirection, Value } from './query/query.js';
2
2
  export declare const QExpr: {
3
3
  readonly conditions: {
4
- and: (...expr: BooleanValueExpression[]) => BooleanValueExpression;
5
- or: (...expr: BooleanValueExpression[]) => BooleanValueExpression;
4
+ and: (...expr: Array<BooleanValueExpression | undefined | null>) => BooleanValueExpression;
5
+ or: (...expr: Array<BooleanValueExpression | undefined | null>) => BooleanValueExpression;
6
6
  eq: (left: Value, right: Value) => ComparisonExpression;
7
7
  neq: (left: Value, right: Value) => ComparisonExpression;
8
8
  gt: (left: Value, right: Value) => ComparisonExpression;
@@ -1,6 +1,7 @@
1
1
  import { QueryNodeKind, } from './query/query.js';
2
+ import { nonNullable } from "../util.js";
2
3
  const compound = (expr, operator) => {
3
- return expr.reduce((acc, current) => ({
4
+ return expr.filter(nonNullable).reduce((acc, current) => ({
4
5
  kind: QueryNodeKind.CompoundExpr,
5
6
  left: acc,
6
7
  operator: operator,
@@ -14,6 +14,7 @@ export declare enum QueryNodeKind {
14
14
  Literal = 11,
15
15
  Sort = 12
16
16
  }
17
+ export declare type LockMode = 'FOR UPDATE' | 'FOR SHARE';
17
18
  export declare type Query = {
18
19
  select: Select;
19
20
  from: QueryTable;
@@ -21,6 +22,7 @@ export declare type Query = {
21
22
  sort?: Sort[];
22
23
  limit?: number;
23
24
  offset?: number;
25
+ lock?: LockMode;
24
26
  };
25
27
  declare type Select = SelectExpr[];
26
28
  export declare const NO_ALIAS: "__SASAT_NO_ALIAS";
@@ -2,6 +2,13 @@ import { Sql } from './nodeToSql.js';
2
2
  const getJoin = (from) => {
3
3
  return from.joins.flatMap(join => [join, ...getJoin(join.table)]);
4
4
  };
5
+ const getLock = (lock) => {
6
+ if (!lock)
7
+ return '';
8
+ if (lock === 'FOR UPDATE')
9
+ return ' FOR UPDATE';
10
+ return ' FOR SHARE';
11
+ };
5
12
  export const queryToSql = (query) => {
6
13
  const select = query.select.map(Sql.select).join(', ');
7
14
  const join = getJoin(query.from).map(Sql.join).join(' ');
@@ -18,5 +25,6 @@ export const queryToSql = (query) => {
18
25
  where +
19
26
  sort +
20
27
  limit +
21
- offset);
28
+ offset +
29
+ getLock(query.lock));
22
30
  };
@@ -2,7 +2,7 @@ import { CommandResponse, RelationMap } from '../index.js';
2
2
  import { Fields } from './field.js';
3
3
  import { SQLExecutor, SqlValueType } from '../db/connectors/dbClient.js';
4
4
  import { TableInfo } from './dsl/query/createQueryResolveInfo.js';
5
- import { BooleanValueExpression, Sort } from './dsl/query/query.js';
5
+ import { BooleanValueExpression, LockMode, Sort } from './dsl/query/query.js';
6
6
  export declare type EntityType = Record<string, SqlValueType>;
7
7
  export declare type EntityResult<Entity, Identifiable> = Identifiable & Partial<Entity>;
8
8
  interface Repository<Entity, Creatable, Identifiable> {
@@ -16,7 +16,14 @@ export declare type ListQueryOption = {
16
16
  order?: string;
17
17
  asc?: boolean;
18
18
  };
19
- export declare abstract class SasatDBDatasource<Entity extends EntityType, Creatable, Identifiable, EntityFields extends Fields> implements Repository<Entity, Creatable, Identifiable> {
19
+ export declare type QueryOptions = {
20
+ where?: BooleanValueExpression;
21
+ sort?: Sort[];
22
+ limit?: number;
23
+ offset?: number;
24
+ lock?: LockMode;
25
+ };
26
+ export declare abstract class SasatDBDatasource<Entity extends EntityType, Creatable, Identifiable, EntityFields extends Fields, QueryResult extends Partial<Entity> & Identifiable> implements Repository<Entity, Creatable, Identifiable> {
20
27
  protected client: SQLExecutor;
21
28
  protected abstract relationMap: RelationMap;
22
29
  protected abstract tableInfo: TableInfo;
@@ -32,27 +39,14 @@ export declare abstract class SasatDBDatasource<Entity extends EntityType, Creat
32
39
  create(entity: Creatable): Promise<Entity>;
33
40
  update(entity: Identifiable & Partial<Entity>): Promise<CommandResponse>;
34
41
  delete(entity: Identifiable): Promise<CommandResponse>;
35
- first(fields?: EntityFields, option?: {
36
- where?: BooleanValueExpression;
37
- sort?: Sort[];
38
- }, context?: any): Promise<EntityResult<Entity, Identifiable> | null>;
39
- find(fields?: EntityFields, options?: {
40
- where?: BooleanValueExpression;
41
- sort?: Sort[];
42
- limit?: number;
43
- offset?: number;
44
- }, context?: unknown): Promise<EntityResult<Entity, Identifiable>[]>;
42
+ first(fields?: EntityFields, option?: Omit<QueryOptions, 'limit' | 'offset'>, context?: any): Promise<QueryResult | null>;
43
+ find(fields?: EntityFields, options?: QueryOptions, context?: unknown): Promise<QueryResult[]>;
45
44
  findPageable(paging: {
46
45
  numberOfItem: number;
47
46
  where?: BooleanValueExpression;
48
47
  offset?: number;
49
48
  sort?: Sort[];
50
- }, fields?: EntityFields, options?: {
51
- where?: BooleanValueExpression;
52
- sort?: Sort[];
53
- limit?: number;
54
- offset?: number;
55
- }, context?: unknown): Promise<EntityResult<Entity, Identifiable>[]>;
49
+ }, fields?: EntityFields, options?: QueryOptions, context?: unknown): Promise<QueryResult[]>;
56
50
  private executeQuery;
57
51
  private createIdentifiableExpression;
58
52
  }
@@ -1,15 +1,9 @@
1
- import { BooleanValueExpression, Query, Sort } from '../dsl/query/query.js';
1
+ import { BooleanValueExpression, Query } from '../dsl/query/query.js';
2
2
  import { SQLExecutor } from '../../db/connectors/dbClient.js';
3
3
  import { RelationMap, TableInfo } from '../dsl/query/createQueryResolveInfo.js';
4
4
  import { Fields } from '../field.js';
5
5
  import { QueryResolveInfo } from '../dsl/query/sql/hydrate.js';
6
- import { ListQueryOption } from '../sasatDBDatasource.js';
7
- declare type QueryOptions = {
8
- where?: BooleanValueExpression;
9
- sort?: Sort[];
10
- limit?: number;
11
- offset?: number;
12
- };
6
+ import { ListQueryOption, QueryOptions } from '../sasatDBDatasource.js';
13
7
  export declare const createQuery: (baseTableName: string, fields: Fields, options: QueryOptions | undefined, tableInfo: TableInfo, relationMap: RelationMap, context?: any) => Query;
14
8
  declare type PagingOption = ListQueryOption & {
15
9
  where?: BooleanValueExpression;
@@ -12,8 +12,10 @@ export const createQuery = (baseTableName, fields, options, tableInfo, relationM
12
12
  table.tableAlias = tableAlias;
13
13
  tableCount++;
14
14
  const info = tableInfo[tableName];
15
- select.push(...unique([...table.fields.filter(notTypeName), ...info.identifiableKeys])
16
- .map(it => {
15
+ select.push(...unique([
16
+ ...table.fields.filter(notTypeName),
17
+ ...info.identifiableKeys,
18
+ ]).map(it => {
17
19
  const realName = info.columnMap[it] || it;
18
20
  return QExpr.field(tableAlias, realName, tableAlias + SELECT_ALIAS_SEPARATOR + it);
19
21
  }));
@@ -33,7 +35,9 @@ export const createQuery = (baseTableName, fields, options, tableInfo, relationM
33
35
  export const createPagingInnerQuery = (tableName, tableAlias, fields, option, tableInfo) => {
34
36
  const map = tableInfo[tableName].columnMap;
35
37
  return {
36
- select: fields.fields.filter(notTypeName).map(it => QExpr.field(tableAlias, map[it])),
38
+ select: fields.fields
39
+ .filter(notTypeName)
40
+ .map(it => QExpr.field(tableAlias, map[it])),
37
41
  from: QExpr.table(tableName, [], tableAlias),
38
42
  limit: option.numberOfItem,
39
43
  offset: option.offset,
@@ -2,3 +2,4 @@ export declare const pick: <T extends object>(target: T, keys: (keyof T)[]) => {
2
2
  [k: string]: T[keyof T];
3
3
  };
4
4
  export declare const unique: <T>(array: T[]) => T[];
5
+ export declare const nonNullable: <T>(value: T) => value is NonNullable<T>;
@@ -8,3 +8,4 @@ export const unique = (array) => {
8
8
  }
9
9
  return result;
10
10
  };
11
+ export const nonNullable = (value) => value != null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sasat",
3
- "version": "0.17.4",
3
+ "version": "0.18.0",
4
4
  "repository": "https://github.com/yanokunpei/sasat.git",
5
5
  "author": "yanokunpei <ninian138@gmail.com>",
6
6
  "license": "MIT",