sasat 0.16.3 → 0.17.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 (30) hide show
  1. package/lib/generator/controller.js +1 -1
  2. package/lib/generator/generator.d.ts +1 -1
  3. package/lib/generator/ts/db/generatedRepositoryGenerator.js +2 -1
  4. package/lib/generator/ts/generator.d.ts +1 -1
  5. package/lib/generator/ts/generator.js +1 -1
  6. package/lib/generator/ts/gql/contextGenerator.js +1 -1
  7. package/lib/generator/ts/gql/mutationGenerator.js +1 -1
  8. package/lib/generator/ts/gql/queryGenerator.js +10 -8
  9. package/lib/generator/ts/relationMapGenerator.js +5 -7
  10. package/lib/generator/ts/staticFiles.js +7 -6
  11. package/lib/index.d.ts +1 -2
  12. package/lib/index.js +1 -1
  13. package/lib/migration/creators/tableCreator.d.ts +8 -8
  14. package/lib/migration/creators/tableCreator.js +8 -8
  15. package/lib/migration/front/tableMigrator.d.ts +8 -8
  16. package/lib/migration/front/tableMigrator.js +8 -8
  17. package/lib/migration/serializable/table.d.ts +4 -4
  18. package/lib/migration/serializable/table.js +4 -4
  19. package/lib/parser/node/relationNode.d.ts +2 -0
  20. package/lib/parser/node/relationNode.js +4 -2
  21. package/lib/runtime/dsl/query/createQueryResolveInfo.d.ts +1 -5
  22. package/lib/runtime/dsl/query/fieldToQuery.d.ts +1 -1
  23. package/lib/runtime/dsl/query/sql/queryToSql.js +6 -4
  24. package/lib/runtime/{sasatRepository.d.ts → sasatDBDatasource.d.ts} +8 -6
  25. package/lib/runtime/{sasatRepository.js → sasatDBDatasource.js} +22 -34
  26. package/lib/runtime/sql/runQuery.d.ts +40 -0
  27. package/lib/runtime/sql/runQuery.js +67 -0
  28. package/lib/runtime/util.d.ts +1 -0
  29. package/lib/runtime/util.js +9 -0
  30. package/package.json +2 -2
@@ -52,7 +52,7 @@ export class CodeGenerateController {
52
52
  writeFile(this.getFullPath(this.generateDir, 'query'), this.codeGen.generateGqlQuery(rootNode)),
53
53
  writeFile(this.getFullPath(this.generateDir, 'mutation'), this.codeGen.generateGqlMutation(rootNode)),
54
54
  writeFile(this.getFullPath(this.generateDir, 'subscription'), this.codeGen.generateGqlSubscription(rootNode)),
55
- writeFile(this.getFullPath(this.generateDir, 'context'), this.codeGen.generateGqlContext(rootNode)),
55
+ writeFile(this.getFullPath(this.generateDir, 'context'), this.codeGen.generateGQLContext(rootNode)),
56
56
  ];
57
57
  }
58
58
  generateFiles(rootNode) {
@@ -15,7 +15,7 @@ export interface CodeGenerator {
15
15
  generateGqlQuery(root: RootNode): string;
16
16
  generateGqlMutation(root: RootNode): string;
17
17
  generateGqlSubscription(root: RootNode): string;
18
- generateGqlContext(root: RootNode): string;
18
+ generateGQLContext(root: RootNode): string;
19
19
  generateFiles(RootNode: RootNode): FileData;
20
20
  generateOnceFiles(RootNode: RootNode): FileData;
21
21
  }
@@ -104,7 +104,7 @@ export class GeneratedRepositoryGenerator {
104
104
  : qExpr
105
105
  .property('conditions')
106
106
  .property('and')
107
- .call(...exps))))),
107
+ .call(...exps))), tsg.identifier('context'))),
108
108
  ];
109
109
  const returnType = tsg
110
110
  .typeRef('EntityResult', [
@@ -117,6 +117,7 @@ export class GeneratedRepositoryGenerator {
117
117
  new Parameter(`fields?`, tsg
118
118
  .typeRef(`${node.entityName}Fields`)
119
119
  .importFrom(Directory.generatedPath(Directory.paths.generatedDataSource.db, 'fields'))),
120
+ tsg.parameter('context?', tsg.typeRef('GQLContext').importFrom(Directory.basePath(Directory.paths.generatedDataSource.db, 'context'))),
120
121
  ], new TypeReference('Promise', [
121
122
  it.returnType.isArray
122
123
  ? tsg.arrayType(returnType)
@@ -12,7 +12,7 @@ export declare class TsCodeGenerator implements CodeGenerator {
12
12
  generateGqlResolver(root: RootNode): string;
13
13
  generateGqlMutation(root: RootNode): string;
14
14
  generateGqlSubscription(root: RootNode): string;
15
- generateGqlContext(root: RootNode): string;
15
+ generateGQLContext(root: RootNode): string;
16
16
  generateFiles(root: RootNode): FileData;
17
17
  generateOnceFiles(): FileData;
18
18
  }
@@ -38,7 +38,7 @@ export class TsCodeGenerator {
38
38
  generateGqlSubscription(root) {
39
39
  return new SubscriptionGenerator().generate(root.mutations()).toString();
40
40
  }
41
- generateGqlContext(root) {
41
+ generateGQLContext(root) {
42
42
  return new ContextGenerator().generate(root.contexts).toString();
43
43
  }
44
44
  generateFiles(root) {
@@ -3,7 +3,7 @@ import { TsInterface } from '../code/node/interface.js';
3
3
  import { PropertySignature } from '../code/node/propertySignature.js';
4
4
  export class ContextGenerator {
5
5
  generate(contexts) {
6
- return new TsFile(new TsInterface('BaseGqlContext')
6
+ return new TsFile(new TsInterface('BaseGQLContext')
7
7
  .addProperties(contexts.map(it => new PropertySignature(it.name, it.type.toTsType())))
8
8
  .export()).disableEsLint();
9
9
  }
@@ -29,7 +29,7 @@ export class MutationGenerator {
29
29
  return [
30
30
  tsg.parameter('_', tsg.typeRef('unknown')),
31
31
  tsg.parameter('params', paramType),
32
- tsg.parameter(useContext || reFetch ? 'context' : '_1', tsg.typeRef('GqlContext').importFrom('../context')),
32
+ tsg.parameter(useContext || reFetch ? 'context' : '_1', tsg.typeRef('GQLContext').importFrom('../context')),
33
33
  tsg.parameter(reFetch ? 'info' : '_2', tsg.typeRef('GraphQLResolveInfo').importFrom('graphql')),
34
34
  ];
35
35
  }
@@ -8,12 +8,14 @@ export class QueryGenerator {
8
8
  .export()).addImport(['GraphQLResolveInfo'], 'graphql').disableEsLint();
9
9
  }
10
10
  static createParams(node, query) {
11
+ const context = tsg.parameter('context', tsg.typeRef('GQLContext').importFrom('../context'));
12
+ const resolveInfo = tsg.parameter('info', tsg.typeRef('GraphQLResolveInfo'));
11
13
  if (query.queryParams.length === 0)
12
14
  return [
13
15
  tsg.parameter('_1', tsg.typeRef('unknown')),
14
16
  tsg.parameter('_2', tsg.typeRef('unknown')),
15
- tsg.parameter('_3', tsg.typeRef('unknown')),
16
- tsg.parameter('info', tsg.typeRef('GraphQLResolveInfo')),
17
+ context,
18
+ resolveInfo,
17
19
  ];
18
20
  if (query.isList) {
19
21
  return [
@@ -21,8 +23,8 @@ export class QueryGenerator {
21
23
  tsg.parameter('params', tsg.typeLiteral([
22
24
  tsg.propertySignature('option', query.queryParams[0].type.toTsType(), true, false),
23
25
  ])),
24
- tsg.parameter('_2', tsg.typeRef('unknown')),
25
- tsg.parameter('info', tsg.typeRef('GraphQLResolveInfo')),
26
+ context,
27
+ resolveInfo,
26
28
  ];
27
29
  }
28
30
  const paramNames = query.queryParams.map(it => it.name);
@@ -31,8 +33,8 @@ export class QueryGenerator {
31
33
  tsg.parameter(`{ ${paramNames.join(',')} }`, node.entityName
32
34
  .getTypeReference(Directory.paths.generated)
33
35
  .pick(...paramNames)),
34
- tsg.parameter('_2', tsg.typeRef('unknown')),
35
- tsg.parameter('info', tsg.typeRef('GraphQLResolveInfo')),
36
+ context,
37
+ resolveInfo,
36
38
  ];
37
39
  }
38
40
  query(node, query) {
@@ -45,7 +47,7 @@ export class QueryGenerator {
45
47
  .identifier('gqlResolveInfoToField')
46
48
  .importFrom('sasat')
47
49
  .call(tsg.identifier('info'))
48
- .as(node.entityName.fieldTypeRef(Directory.paths.generated)))));
50
+ .as(node.entityName.fieldTypeRef(Directory.paths.generated)), tsg.identifier('context'))));
49
51
  }
50
52
  listQuery(node, query) {
51
53
  const fields = tsg.identifier('fields');
@@ -63,7 +65,7 @@ export class QueryGenerator {
63
65
  .as(node.entityName.fieldTypeRef(Directory.paths.generated))),
64
66
  tsg.if(option, tsg.return(ds
65
67
  .property('findPageable')
66
- .call(tsg.object(tsg.propertyAssign('numberOfItem', option.property('numberOfItem')), tsg.propertyAssign('offset', option.property('offset'))), fields))),
68
+ .call(tsg.object(tsg.propertyAssign('numberOfItem', option.property('numberOfItem')), tsg.propertyAssign('offset', option.property('offset'))), fields, tsg.identifier('undefined'), tsg.identifier('context')))),
67
69
  tsg.return(ds.property(query.repoMethodName).call(fields)),
68
70
  ];
69
71
  return tsg.propertyAssign(query.queryName, tsg.arrowFunc(QueryGenerator.createParams(node, query), undefined, tsg.block(...statements)));
@@ -4,12 +4,10 @@ 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), tsg
8
- .variable('const', 'dataStoreInfo', tsg.object(tsg.propertyAssign('tableInfo'), tsg.propertyAssign('relationMap')), tsg.typeRef('DataStoreInfo').importFrom('sasat'))
9
- .export(), ...root.entities().flatMap(this.entityRelationType)).disableEsLint();
7
+ return new TsFile(this.relationMap(root), this.tableInfo(root), ...root.entities().flatMap(this.entityRelationType)).disableEsLint();
10
8
  }
11
9
  relationMap(root) {
12
- return tsg.variable('const', tsg.identifier('relationMap'), tsg.object(...root.entities().map(it => this.entityRelationMap(it))), tsg.typeRef('RelationMap').importFrom('sasat'));
10
+ return tsg.variable('const', tsg.identifier('relationMap'), tsg.object(...root.entities().map(it => this.entityRelationMap(it))), tsg.typeRef('RelationMap').importFrom('sasat')).export();
13
11
  }
14
12
  entityRelationType(node) {
15
13
  const importEntity = (entity) => Directory.entityPath(Directory.paths.generated, entity);
@@ -57,12 +55,12 @@ export class RelationMapGenerator {
57
55
  .call(tsg.identifier('parentTableAlias'), tsg.string(parentColumn)), qExpr
58
56
  .property('field')
59
57
  .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.fromField, rel.toField), tsg.propertyAssign('relation', tsg.string('One'))))), ...node
58
+ 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
61
59
  .findReferencedRelations()
62
- .map(rel => tsg.propertyAssign(rel.referencedByPropertyName(), tsg.object(tsg.propertyAssign('table', tsg.string(rel.parent.repository.tableName)), on(rel.toField, rel.fromField), tsg.propertyAssign('relation', tsg.string(rel.relation)))))));
60
+ .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)))))));
63
61
  }
64
62
  tableInfo(root) {
65
63
  const columnMap = (entity) => tsg.propertyAssign('columnMap', tsg.object(...entity.fields.map(field => tsg.propertyAssign(field.fieldName, tsg.string(field.columnName)))));
66
- return tsg.variable('const', 'tableInfo', tsg.object(...root.repositories.map(repo => tsg.propertyAssign(repo.tableName, tsg.object(tsg.propertyAssign('identifiableKeys', tsg.array(repo.primaryKeys.map(tsg.string))), columnMap(repo.entity))))));
64
+ return tsg.variable('const', 'tableInfo', tsg.object(...root.repositories.map(repo => tsg.propertyAssign(repo.tableName, tsg.object(tsg.propertyAssign('identifiableKeys', tsg.array(repo.primaryKeys.map(tsg.string))), columnMap(repo.entity)))))).export();
67
65
  }
68
66
  }
@@ -1,7 +1,7 @@
1
1
  import { ImportDeclaration } from './code/importDeclaration.js';
2
2
  const contextFile = `\
3
- ${new ImportDeclaration(['BaseGqlContext'], './__generated__/context').toString()}
4
- export interface GqlContext extends BaseGqlContext {}
3
+ ${new ImportDeclaration(['BaseGQLContext'], './__generated__/context').toString()}
4
+ export type GQLContext = BaseGQLContext & Record<string, never>;
5
5
  `;
6
6
  const pubsubFile = `\
7
7
  ${new ImportDeclaration(['PubSub', 'PubSubEngine'], 'graphql-subscriptions').toString()}
@@ -22,16 +22,17 @@ export const schema = {
22
22
  };
23
23
  `;
24
24
  const baseDBDataSourceFile = `\
25
- ${new ImportDeclaration(['Fields', 'SasatRepository', 'EntityType'], 'sasat').toString()}
26
- ${new ImportDeclaration(['dataStoreInfo'], './__generated__/relationMap').toString()}
25
+ ${new ImportDeclaration(['Fields', 'SasatDBDatasource', 'EntityType'], 'sasat').toString()}
26
+ ${new ImportDeclaration(['relationMap', 'tableInfo'], './__generated__/relationMap').toString()}
27
27
 
28
- export abstract class BaseDBDataSource<Entity extends EntityType, Creatable, Identifiable, EntityFields extends Fields> extends SasatRepository<
28
+ export abstract class BaseDBDataSource<Entity extends EntityType, Creatable, Identifiable, EntityFields extends Fields> extends SasatDBDatasource<
29
29
  Entity,
30
30
  Creatable,
31
31
  Identifiable,
32
32
  EntityFields
33
33
  > {
34
- protected maps = dataStoreInfo;
34
+ protected relationMap = relationMap
35
+ protected tableInfo = tableInfo;
35
36
  }
36
37
  `;
37
38
  export const staticFiles = [
package/lib/index.d.ts CHANGED
@@ -1,4 +1,3 @@
1
- export { DataStoreInfo } from './runtime/dsl/query/createQueryResolveInfo.js';
2
1
  export { BooleanValueExpression } from './runtime/dsl/query/query.js';
3
2
  export { Relation } from './migration/data/relation.js';
4
3
  export { QExpr } from './runtime/dsl/factory.js';
@@ -8,7 +7,7 @@ export { gqlResolveInfoToField } from './runtime/gqlResolveInfoToField.js';
8
7
  export { ComparisonOperators } from './db/sql/expression/comparison.js';
9
8
  export { MigrationStore } from './migration/front/storeMigrator.js';
10
9
  export { SasatMigration } from './migration/front/migration.js';
11
- export { SasatRepository, EntityResult, EntityType, ListQueryOption, } from './runtime/sasatRepository.js';
10
+ export { SasatDBDatasource, EntityResult, EntityType, ListQueryOption, } from './runtime/sasatDBDatasource.js';
12
11
  export { getCurrentDateTimeString } from './util/dateUtil.js';
13
12
  export { getDbClient } from './db/getDbClient.js';
14
13
  export { assignDeep } from './util/assignDeep.js';
package/lib/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  export { QExpr } from './runtime/dsl/factory.js';
2
2
  export { gqlResolveInfoToField } from './runtime/gqlResolveInfoToField.js';
3
- export { SasatRepository, } from './runtime/sasatRepository.js';
3
+ export { SasatDBDatasource, } from './runtime/sasatDBDatasource.js';
4
4
  export { getCurrentDateTimeString } from './util/dateUtil.js';
5
5
  export { getDbClient } from './db/getDbClient.js';
6
6
  export { assignDeep } from './util/assignDeep.js';
@@ -12,10 +12,10 @@ export interface TableBuilder {
12
12
  createdAt(): TableBuilder;
13
13
  updatedAt(): TableBuilder;
14
14
  addIndex(...columns: string[]): TableBuilder;
15
- setGqlCreate(enabled: boolean, options?: Partial<MutationOption>): TableBuilder;
16
- setGqlUpdate(enabled: boolean, options?: Partial<MutationOption>): TableBuilder;
17
- setGqlDelete(enabled: boolean, options?: Partial<Omit<MutationOption, 'noReFetch'>>): TableBuilder;
18
- setGqlContextColumn(columns: GqlFromContextParam[]): TableBuilder;
15
+ setGQLCreate(enabled: boolean, options?: Partial<MutationOption>): TableBuilder;
16
+ setGQLUpdate(enabled: boolean, options?: Partial<MutationOption>): TableBuilder;
17
+ setGQLDelete(enabled: boolean, options?: Partial<Omit<MutationOption, 'noReFetch'>>): TableBuilder;
18
+ setGQLContextColumn(columns: GqlFromContextParam[]): TableBuilder;
19
19
  }
20
20
  export declare class TableCreator implements TableBuilder {
21
21
  tableName: string;
@@ -31,8 +31,8 @@ export declare class TableCreator implements TableBuilder {
31
31
  createdAt(): TableBuilder;
32
32
  updatedAt(): TableBuilder;
33
33
  addIndex(...columns: string[]): TableBuilder;
34
- setGqlCreate(enabled: boolean, options?: Partial<MutationOption>): TableBuilder;
35
- setGqlUpdate(enabled: boolean, options?: Partial<MutationOption>): TableBuilder;
36
- setGqlDelete(enabled: boolean, options?: Partial<Omit<MutationOption, 'noReFetch'>>): TableBuilder;
37
- setGqlContextColumn(columns: GqlFromContextParam[]): TableBuilder;
34
+ setGQLCreate(enabled: boolean, options?: Partial<MutationOption>): TableBuilder;
35
+ setGQLUpdate(enabled: boolean, options?: Partial<MutationOption>): TableBuilder;
36
+ setGQLDelete(enabled: boolean, options?: Partial<Omit<MutationOption, 'noReFetch'>>): TableBuilder;
37
+ setGQLContextColumn(columns: GqlFromContextParam[]): TableBuilder;
38
38
  }
@@ -50,20 +50,20 @@ export class TableCreator {
50
50
  this.table.addIndex(`index_${this.tableName}__${columns.join('_')}`, ...columns);
51
51
  return this;
52
52
  }
53
- setGqlCreate(enabled, options) {
54
- this.table.setGqlCreate(enabled, options);
53
+ setGQLCreate(enabled, options) {
54
+ this.table.setGQLCreate(enabled, options);
55
55
  return this;
56
56
  }
57
- setGqlUpdate(enabled, options) {
58
- this.table.setGqlUpdate(enabled, options);
57
+ setGQLUpdate(enabled, options) {
58
+ this.table.setGQLUpdate(enabled, options);
59
59
  return this;
60
60
  }
61
- setGqlDelete(enabled, options) {
62
- this.table.setGqlDelete(enabled, options);
61
+ setGQLDelete(enabled, options) {
62
+ this.table.setGQLDelete(enabled, options);
63
63
  return this;
64
64
  }
65
- setGqlContextColumn(columns) {
66
- this.table.setGqlContextColumn(columns);
65
+ setGQLContextColumn(columns) {
66
+ this.table.setGQLContextColumn(columns);
67
67
  return this;
68
68
  }
69
69
  }
@@ -14,10 +14,10 @@ export interface MigrationTable extends Table {
14
14
  addForeignKey(reference: Reference): MigrationTable;
15
15
  changeColumnType(columnName: string, type: DBType): MigrationTable;
16
16
  setDefault(columnName: string, value: string | number | null): MigrationTable;
17
- setGqlCreate(enabled: boolean, options?: Partial<MutationOption>): MigrationTable;
18
- setGqlUpdate(enabled: boolean, options?: Partial<MutationOption>): MigrationTable;
19
- setGqlDelete(enabled: boolean, options?: Partial<Omit<MutationOption, 'noReFetch'>>): MigrationTable;
20
- setGqlContextColumn(columns: GqlFromContextParam[]): MigrationTable;
17
+ setGQLCreate(enabled: boolean, options?: Partial<MutationOption>): MigrationTable;
18
+ setGQLUpdate(enabled: boolean, options?: Partial<MutationOption>): MigrationTable;
19
+ setGQLDelete(enabled: boolean, options?: Partial<Omit<MutationOption, 'noReFetch'>>): MigrationTable;
20
+ setGQLContextColumn(columns: GqlFromContextParam[]): MigrationTable;
21
21
  }
22
22
  export declare class TableMigrator implements MigrationTable {
23
23
  private table;
@@ -33,10 +33,10 @@ export declare class TableMigrator implements MigrationTable {
33
33
  removeIndex(...columns: string[]): MigrationTable;
34
34
  addColumn(column: SerializedNormalColumn): MigrationTable;
35
35
  dropColumn(columnName: string): MigrationTable;
36
- setGqlCreate(enabled: boolean, options?: Partial<MutationOption>): MigrationTable;
37
- setGqlUpdate(enabled: boolean, options?: Partial<MutationOption>): MigrationTable;
38
- setGqlDelete(enabled: boolean, options?: Partial<Omit<MutationOption, 'noReFetch'>>): MigrationTable;
39
- setGqlContextColumn(columns: GqlFromContextParam[]): MigrationTable;
36
+ setGQLCreate(enabled: boolean, options?: Partial<MutationOption>): MigrationTable;
37
+ setGQLUpdate(enabled: boolean, options?: Partial<MutationOption>): MigrationTable;
38
+ setGQLDelete(enabled: boolean, options?: Partial<Omit<MutationOption, 'noReFetch'>>): MigrationTable;
39
+ setGQLContextColumn(columns: GqlFromContextParam[]): MigrationTable;
40
40
  addForeignKey(reference: Reference): MigrationTable;
41
41
  changeColumnType(columnName: string, type: DBType): MigrationTable;
42
42
  protected tableExists(tableName: string): true;
@@ -48,20 +48,20 @@ export class TableMigrator {
48
48
  this.store.addQuery(SqlCreator.dropColumn(this.tableName, columnName));
49
49
  return this;
50
50
  }
51
- setGqlCreate(enabled, options) {
52
- this.table.setGqlCreate(enabled, options);
51
+ setGQLCreate(enabled, options) {
52
+ this.table.setGQLCreate(enabled, options);
53
53
  return this;
54
54
  }
55
- setGqlUpdate(enabled, options) {
56
- this.table.setGqlUpdate(enabled, options);
55
+ setGQLUpdate(enabled, options) {
56
+ this.table.setGQLUpdate(enabled, options);
57
57
  return this;
58
58
  }
59
- setGqlDelete(enabled, options) {
60
- this.table.setGqlDelete(enabled, options);
59
+ setGQLDelete(enabled, options) {
60
+ this.table.setGQLDelete(enabled, options);
61
61
  return this;
62
62
  }
63
- setGqlContextColumn(columns) {
64
- this.table.setGqlContextColumn(columns);
63
+ setGQLContextColumn(columns) {
64
+ this.table.setGQLContextColumn(columns);
65
65
  return this;
66
66
  }
67
67
  addForeignKey(reference) {
@@ -38,10 +38,10 @@ export declare class TableHandler implements Table {
38
38
  hasColumn(columnName: string): boolean;
39
39
  isColumnPrimary(columnName: string): boolean;
40
40
  getEntityName(): EntityName;
41
- setGqlCreate(enabled: boolean, options?: Partial<MutationOption>): void;
42
- setGqlUpdate(enabled: boolean, options?: Partial<MutationOption>): void;
43
- setGqlDelete(enabled: boolean, options?: Partial<Omit<MutationOption, 'noReFetch'>>): void;
44
- setGqlContextColumn(columns: GqlFromContextParam[]): void;
41
+ setGQLCreate(enabled: boolean, options?: Partial<MutationOption>): void;
42
+ setGQLUpdate(enabled: boolean, options?: Partial<MutationOption>): void;
43
+ setGQLDelete(enabled: boolean, options?: Partial<Omit<MutationOption, 'noReFetch'>>): void;
44
+ setGQLContextColumn(columns: GqlFromContextParam[]): void;
45
45
  getReferenceColumns(): ReferenceColumn[];
46
46
  addForeignKey(reference: Reference): void;
47
47
  changeType(columnName: string, type: DBColumnTypes): void;
@@ -129,7 +129,7 @@ export class TableHandler {
129
129
  getEntityName() {
130
130
  return new EntityName(TableHandler.tableNameToEntityName(this.tableName));
131
131
  }
132
- setGqlCreate(enabled, options) {
132
+ setGQLCreate(enabled, options) {
133
133
  this._gqlOption = updateMutationOption(this._gqlOption, {
134
134
  create: {
135
135
  ...defaultMutationOption,
@@ -138,7 +138,7 @@ export class TableHandler {
138
138
  },
139
139
  });
140
140
  }
141
- setGqlUpdate(enabled, options) {
141
+ setGQLUpdate(enabled, options) {
142
142
  this._gqlOption = updateMutationOption(this._gqlOption, {
143
143
  update: {
144
144
  ...defaultMutationOption,
@@ -147,7 +147,7 @@ export class TableHandler {
147
147
  },
148
148
  });
149
149
  }
150
- setGqlDelete(enabled, options) {
150
+ setGQLDelete(enabled, options) {
151
151
  this._gqlOption = updateMutationOption(this._gqlOption, {
152
152
  delete: {
153
153
  ...defaultMutationOption,
@@ -156,7 +156,7 @@ export class TableHandler {
156
156
  },
157
157
  });
158
158
  }
159
- setGqlContextColumn(columns) {
159
+ setGQLContextColumn(columns) {
160
160
  this._gqlOption = updateMutationOption(this._gqlOption, {
161
161
  fromContextColumns: columns,
162
162
  });
@@ -11,6 +11,8 @@ export declare class RelationNode {
11
11
  readonly toTableName: string;
12
12
  readonly toEntityName: EntityName;
13
13
  readonly relation: Relation;
14
+ readonly fromColumnName: string;
15
+ readonly toColumnName: string;
14
16
  static fromReference(entity: EntityNode, ref: ReferenceColumn, targetFieldName: string): RelationNode;
15
17
  private constructor();
16
18
  refPropertyName(): string;
@@ -2,7 +2,7 @@ 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) {
5
+ constructor(parent, relationName, fromField, toField, toTableName, toEntityName, relation, fromColumnName, toColumnName) {
6
6
  this.parent = parent;
7
7
  this.relationName = relationName;
8
8
  this.fromField = fromField;
@@ -10,9 +10,11 @@ export class RelationNode {
10
10
  this.toTableName = toTableName;
11
11
  this.toEntityName = toEntityName;
12
12
  this.relation = relation;
13
+ this.fromColumnName = fromColumnName;
14
+ this.toColumnName = toColumnName;
13
15
  }
14
16
  static fromReference(entity, ref, targetFieldName) {
15
- 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);
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);
16
18
  }
17
19
  refPropertyName() {
18
20
  return this.relationName || this.fromField + this.toEntityName.name;
@@ -3,7 +3,7 @@ import { QueryResolveInfo } from './sql/hydrate.js';
3
3
  import { Fields } from '../../field.js';
4
4
  export declare type RelationInfo = {
5
5
  table: string;
6
- on: (parentTableAlias: string, childTableAlias: string) => BooleanValueExpression;
6
+ on: (parentTableAlias: string, childTableAlias: string, context?: any) => BooleanValueExpression;
7
7
  relation: 'One' | 'OneOrZero' | 'Many';
8
8
  };
9
9
  export declare type RelationMap = {
@@ -19,8 +19,4 @@ export declare type TableInfo = {
19
19
  };
20
20
  };
21
21
  };
22
- export declare type DataStoreInfo = {
23
- tableInfo: TableInfo;
24
- relationMap: RelationMap;
25
- };
26
22
  export declare const createQueryResolveInfo: (tableName: string, fields: Fields, map: RelationMap, tableInfo: TableInfo) => QueryResolveInfo;
@@ -1,5 +1,5 @@
1
1
  import { Query } from './query.js';
2
2
  import { RelationMap } from './createQueryResolveInfo.js';
3
3
  import { Fields } from '../../field.js';
4
- export declare const fieldToQuery: (tableName: string, fields: Fields, map: RelationMap) => Query;
4
+ export declare const fieldToQuery: (tableName: string, fields: Fields, map: RelationMap) => Pick<Query, 'select' | 'from'>;
5
5
  export declare const createPagingInnerQuery: (tableName: string, fields: Fields, len: number, offset: number) => Query;
@@ -5,16 +5,18 @@ const getJoin = (from) => {
5
5
  export const queryToSql = (query) => {
6
6
  const select = query.select.map(Sql.select).join(', ');
7
7
  const join = getJoin(query.from).map(Sql.join).join(' ');
8
- const where = query.where ? 'WHERE ' + Sql.booleanValue(query.where) : '';
8
+ const where = query.where ? ' WHERE ' + Sql.booleanValue(query.where) : '';
9
9
  const sort = query.sort && query.sort.length !== 0
10
10
  ? ' ORDER BY ' + Sql.sorts(query.sort)
11
11
  : '';
12
- const offset = query.offset ? 'OFFSET ' + query.offset : '';
13
12
  const limit = query.limit ? ' LIMIT ' + query.limit : '';
13
+ const offset = query.offset ? ' OFFSET ' + query.offset : '';
14
+ if (offset && !limit)
15
+ throw new Error('LIMIT is required to use OFFSET.');
14
16
  return (`SELECT ${select} FROM ${Sql.table(query.from)}` +
15
17
  join +
16
18
  where +
17
19
  sort +
18
- offset +
19
- limit);
20
+ limit +
21
+ offset);
20
22
  };
@@ -1,7 +1,8 @@
1
- import { CommandResponse, DataStoreInfo } from '../index.js';
1
+ import { CommandResponse, RelationMap } from '../index.js';
2
2
  import { Fields } from './field.js';
3
3
  import { ResultRow } from './dsl/query/sql/hydrate.js';
4
4
  import { SQLExecutor, SqlValueType } from '../db/connectors/dbClient.js';
5
+ import { TableInfo } from './dsl/query/createQueryResolveInfo.js';
5
6
  import { BooleanValueExpression, Query, Sort } from './dsl/query/query.js';
6
7
  export declare type EntityType = Record<string, SqlValueType>;
7
8
  export declare type EntityResult<Entity, Identifiable> = Identifiable & Partial<Entity>;
@@ -16,9 +17,10 @@ export declare type ListQueryOption = {
16
17
  order?: string;
17
18
  asc?: boolean;
18
19
  };
19
- export declare abstract class SasatRepository<Entity extends EntityType, Creatable, Identifiable, EntityFields extends Fields> implements Repository<Entity, Creatable, Identifiable> {
20
+ export declare abstract class SasatDBDatasource<Entity extends EntityType, Creatable, Identifiable, EntityFields extends Fields> implements Repository<Entity, Creatable, Identifiable> {
20
21
  protected client: SQLExecutor;
21
- protected abstract maps: DataStoreInfo;
22
+ protected abstract relationMap: RelationMap;
23
+ protected abstract tableInfo: TableInfo;
22
24
  abstract readonly tableName: string;
23
25
  abstract readonly fields: string[];
24
26
  protected abstract readonly primaryKeys: string[];
@@ -34,13 +36,13 @@ export declare abstract class SasatRepository<Entity extends EntityType, Creatab
34
36
  first(fields?: EntityFields, option?: {
35
37
  where?: BooleanValueExpression;
36
38
  sort?: Sort[];
37
- }): Promise<EntityResult<Entity, Identifiable> | null>;
39
+ }, context?: any): Promise<EntityResult<Entity, Identifiable> | null>;
38
40
  find(fields?: EntityFields, options?: {
39
41
  where?: BooleanValueExpression;
40
42
  sort?: Sort[];
41
43
  limit?: number;
42
44
  offset?: number;
43
- }): Promise<EntityResult<Entity, Identifiable>[]>;
45
+ }, context?: unknown): Promise<EntityResult<Entity, Identifiable>[]>;
44
46
  findPageable(paging: {
45
47
  numberOfItem: number;
46
48
  where?: BooleanValueExpression;
@@ -51,7 +53,7 @@ export declare abstract class SasatRepository<Entity extends EntityType, Creatab
51
53
  sort?: Sort[];
52
54
  limit?: number;
53
55
  offset?: number;
54
- }): Promise<EntityResult<Entity, Identifiable>[]>;
56
+ }, context?: unknown): Promise<EntityResult<Entity, Identifiable>[]>;
55
57
  private executeQuery;
56
58
  private createIdentifiableExpression;
57
59
  }
@@ -1,16 +1,15 @@
1
1
  import { getDbClient, QExpr, } from '../index.js';
2
- import { appendKeysToQuery, hydrate, } from './dsl/query/sql/hydrate.js';
3
2
  import { createQueryResolveInfo } from './dsl/query/createQueryResolveInfo.js';
4
3
  import { queryToSql } from './dsl/query/sql/queryToSql.js';
5
- import { createPagingInnerQuery, fieldToQuery, } from './dsl/query/fieldToQuery.js';
6
4
  import { replaceAliases } from './dsl/replaceAliases.js';
7
5
  import { createToSql, deleteToSql, updateToSql, } from './dsl/mutation/mutation.js';
8
- export class SasatRepository {
6
+ import { createPagingFieldQuery, createQuery, runQuery } from "./sql/runQuery";
7
+ export class SasatDBDatasource {
9
8
  constructor(client = getDbClient()) {
10
9
  this.client = client;
11
10
  }
12
11
  async query(query) {
13
- const sql = queryToSql(replaceAliases(query, this.maps.tableInfo));
12
+ const sql = queryToSql(replaceAliases(query, this.tableInfo));
14
13
  return this.client.rawQuery(sql);
15
14
  }
16
15
  async create(entity) {
@@ -25,7 +24,7 @@ export class SasatRepository {
25
24
  value,
26
25
  })),
27
26
  };
28
- const response = await this.client.rawCommand(createToSql(dsl, this.maps.tableInfo));
27
+ const response = await this.client.rawCommand(createToSql(dsl, this.tableInfo));
29
28
  if (!this.autoIncrementColumn)
30
29
  return obj;
31
30
  return {
@@ -42,51 +41,40 @@ export class SasatRepository {
42
41
  })),
43
42
  where: this.createIdentifiableExpression(entity),
44
43
  };
45
- return this.client.rawCommand(updateToSql(dsl, this.maps.tableInfo));
44
+ return this.client.rawCommand(updateToSql(dsl, this.tableInfo));
46
45
  }
47
46
  async delete(entity) {
48
47
  const dsl = {
49
48
  table: this.tableName,
50
49
  where: this.createIdentifiableExpression(entity),
51
50
  };
52
- return this.client.rawCommand(deleteToSql(dsl, this.maps.tableInfo));
51
+ return this.client.rawCommand(deleteToSql(dsl, this.tableInfo));
53
52
  }
54
- async first(fields, option) {
55
- const result = await this.find(fields, option);
53
+ async first(fields, option, context) {
54
+ const result = await this.find(fields, option, context);
56
55
  if (result.length !== 0)
57
56
  return result[0];
58
57
  return null;
59
58
  }
60
- async find(fields = { fields: this.fields }, options) {
61
- const query = {
62
- ...fieldToQuery(this.tableName, fields, this.maps.relationMap),
63
- where: options?.where,
64
- sort: options?.sort,
65
- limit: options?.limit,
66
- offset: options?.offset,
67
- };
59
+ async find(fields = { fields: this.fields }, options, context) {
60
+ const query = createQuery(this.tableName, fields, options, this.tableInfo, this.relationMap, context);
68
61
  return this.executeQuery(query, fields);
69
62
  }
70
- async findPageable(paging, fields = { fields: this.fields }, options) {
71
- const partial = fieldToQuery(this.tableName, fields, this.maps.relationMap);
72
- const innerQuery = createPagingInnerQuery(this.tableName, fields, paging.numberOfItem, paging.offset || 0);
73
- const query = {
74
- select: partial.select,
75
- from: {
76
- ...partial.from,
77
- nameOrQuery: innerQuery,
78
- },
79
- where: options?.where,
80
- sort: options?.sort,
81
- limit: options?.limit,
82
- offset: options?.offset,
83
- };
63
+ async findPageable(paging, fields = { fields: this.fields }, options, context) {
64
+ const query = createPagingFieldQuery({
65
+ baseTableName: this.tableName,
66
+ fields,
67
+ tableInfo: this.tableInfo,
68
+ relationMap: this.relationMap,
69
+ pagingOption: paging,
70
+ queryOption: options,
71
+ context,
72
+ });
84
73
  return this.executeQuery(query, fields);
85
74
  }
86
75
  async executeQuery(query, fields) {
87
- const info = createQueryResolveInfo(this.tableName, fields, this.maps.relationMap, this.maps.tableInfo);
88
- const result = await this.query(appendKeysToQuery(query, this.maps.tableInfo));
89
- return hydrate(result, info);
76
+ const info = createQueryResolveInfo(this.tableName, fields, this.relationMap, this.tableInfo);
77
+ return await runQuery(this.client, query, info);
90
78
  }
91
79
  createIdentifiableExpression(entity) {
92
80
  const expr = this.primaryKeys.map(it => {
@@ -0,0 +1,40 @@
1
+ import { BooleanValueExpression, Query, Sort } from "../dsl/query/query.js";
2
+ import { SQLExecutor } from "../../db/connectors/dbClient.js";
3
+ import { RelationMap, TableInfo } from "../dsl/query/createQueryResolveInfo.js";
4
+ import { Fields } from "../field.js";
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
+ };
13
+ export declare const createQuery: (baseTableName: string, fields: Fields, options: QueryOptions | undefined, tableInfo: TableInfo, relationMap: RelationMap, context?: any) => Query;
14
+ declare type PagingOption = ListQueryOption & {
15
+ where?: BooleanValueExpression;
16
+ };
17
+ export declare const createPagingInnerQuery: (tableName: string, tableAlias: string, fields: Fields, option: PagingOption, tableInfo: TableInfo) => Query;
18
+ export declare const runQuery: (client: SQLExecutor, query: Query, resolveInfo: QueryResolveInfo) => Promise<unknown[]>;
19
+ declare type RunFieldQueryArg = {
20
+ client: SQLExecutor;
21
+ queryOptions: QueryOptions;
22
+ tableInfo: TableInfo;
23
+ relationMap: RelationMap;
24
+ baseTableName: string;
25
+ fields: Fields;
26
+ };
27
+ export declare const runFieldQuery: ({ client, tableInfo, baseTableName, fields, relationMap, queryOptions }: RunFieldQueryArg) => Promise<unknown[]>;
28
+ declare type CreatePagingFieldQueryArg = {
29
+ baseTableName: string;
30
+ fields: Fields;
31
+ tableInfo: TableInfo;
32
+ relationMap: RelationMap;
33
+ queryOption?: QueryOptions;
34
+ pagingOption: ListQueryOption & {
35
+ where?: BooleanValueExpression;
36
+ };
37
+ context?: any;
38
+ };
39
+ export declare const createPagingFieldQuery: ({ baseTableName, fields, queryOption, pagingOption, tableInfo, relationMap, context, }: CreatePagingFieldQueryArg) => Query;
40
+ export {};
@@ -0,0 +1,67 @@
1
+ import { createQueryResolveInfo } from "../dsl/query/createQueryResolveInfo.js";
2
+ import { QExpr } from "../dsl/factory.js";
3
+ import { unique } from "../util.js";
4
+ import { queryToSql } from "../dsl/query/sql/queryToSql.js";
5
+ import { hydrate } from "../dsl/query/sql/hydrate.js";
6
+ import { SELECT_ALIAS_SEPARATOR } from "../dsl/query/sql/nodeToSql.js";
7
+ export const createQuery = (baseTableName, fields, options, tableInfo, relationMap, context) => {
8
+ let tableCount = 0;
9
+ const select = [];
10
+ const resolveFields = (tableName, table) => {
11
+ const tableAlias = table.tableAlias || 't' + tableCount;
12
+ table.tableAlias = tableAlias;
13
+ tableCount++;
14
+ const info = tableInfo[tableName];
15
+ select.push(...unique([...table.fields, ...info.identifiableKeys])
16
+ .map(it => {
17
+ const realName = info.columnMap[it];
18
+ return QExpr.field(tableAlias, realName, tableAlias + SELECT_ALIAS_SEPARATOR + it);
19
+ }));
20
+ return QExpr.table(tableName, Object.entries(table.relations || {})
21
+ .map(([relationName, table]) => {
22
+ const current = tableCount;
23
+ const rel = relationMap[tableName][relationName];
24
+ return QExpr.join(resolveFields(rel.table, table), rel.on(tableAlias, table.tableAlias || 't' + current, context), "LEFT");
25
+ }), tableAlias);
26
+ };
27
+ const from = resolveFields(baseTableName, fields);
28
+ return {
29
+ select,
30
+ from,
31
+ ...options,
32
+ };
33
+ };
34
+ export const createPagingInnerQuery = (tableName, tableAlias, fields, option, tableInfo) => {
35
+ const map = tableInfo[tableName].columnMap;
36
+ return {
37
+ select: fields.fields.map(it => QExpr.field(tableAlias, map[it])),
38
+ from: QExpr.table(tableName, [], tableAlias),
39
+ limit: option.numberOfItem,
40
+ offset: option.offset,
41
+ where: option.where,
42
+ sort: option.order ? [
43
+ QExpr.sort(QExpr.field(tableAlias, map[option.order]), option.asc ? "ASC" : 'DESC')
44
+ ] : undefined,
45
+ };
46
+ };
47
+ export const runQuery = async (client, query, resolveInfo) => {
48
+ const resultRows = await client.rawQuery(queryToSql(query));
49
+ return hydrate(resultRows, resolveInfo);
50
+ };
51
+ export const runFieldQuery = async ({ client, tableInfo, baseTableName, fields, relationMap, queryOptions }) => {
52
+ const query = createQuery(baseTableName, fields, queryOptions, tableInfo, relationMap);
53
+ const resolveInfo = createQueryResolveInfo(baseTableName, fields, relationMap, tableInfo);
54
+ return runQuery(client, query, resolveInfo);
55
+ };
56
+ export const createPagingFieldQuery = ({ baseTableName, fields, queryOption, pagingOption, tableInfo, relationMap, context, }) => {
57
+ const tableAlias = fields.tableAlias || 't0';
58
+ const innerQuery = createPagingInnerQuery(baseTableName, tableAlias, fields, pagingOption, tableInfo);
59
+ const main = createQuery(baseTableName, fields, queryOption, tableInfo, relationMap, context);
60
+ return {
61
+ select: main.select,
62
+ from: {
63
+ ...main.from,
64
+ nameOrQuery: innerQuery,
65
+ },
66
+ };
67
+ };
@@ -1,3 +1,4 @@
1
1
  export declare const pick: <T extends object>(target: T, keys: (keyof T)[]) => {
2
2
  [k: string]: T[keyof T];
3
3
  };
4
+ export declare const unique: <T>(array: T[]) => T[];
@@ -1 +1,10 @@
1
1
  export const pick = (target, keys) => Object.fromEntries(keys.map(key => [key, target[key]]));
2
+ export const unique = (array) => {
3
+ const result = [];
4
+ for (let i = 0, l = array.length; i < l; i += 1) {
5
+ if (!result.includes(array[i])) {
6
+ result.push(array[i]);
7
+ }
8
+ }
9
+ return result;
10
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sasat",
3
- "version": "0.16.3",
3
+ "version": "0.17.0",
4
4
  "repository": "https://github.com/yanokunpei/sasat.git",
5
5
  "author": "yanokunpei <ninian138@gmail.com>",
6
6
  "license": "MIT",
@@ -65,7 +65,7 @@
65
65
  "tsconfig-paths": "4.1.0"
66
66
  },
67
67
  "peerDependencies": {
68
- "apollo-server": "^2.0.0 || ^3.0.0",
68
+ "@apollo/server": "^4.0.0",
69
69
  "typescript": "^3.7.4 || ^4.0.0"
70
70
  },
71
71
  "lint-staged": {