diff --git a/src/graphql/controller.ts b/src/graphql/controller.ts index 450c8cd..278f9b4 100644 --- a/src/graphql/controller.ts +++ b/src/graphql/controller.ts @@ -199,7 +199,6 @@ export class GqlEntityController { * INDEX name (name) * ); * ``` - * */ public async createEntityStores(knex: Knex): Promise<{ builder: Knex.SchemaBuilder }> { let builder = knex.schema; @@ -212,31 +211,40 @@ export class GqlEntityController { const tableName = pluralize(type.name.toLowerCase()); builder = builder.dropTableIfExists(tableName).createTable(tableName, t => { - t.primary(['id']); + let tableHasAutoIncrement = false; this.getTypeFields(type).forEach(field => { const fieldType = field.type instanceof GraphQLNonNull ? field.type.ofType : field.type; if (isListType(fieldType) && fieldType.ofType instanceof GraphQLObjectType) return; - const sqlType = this.getSqlType(field.type); - - let column = - 'options' in sqlType - ? t[sqlType.name](field.name, ...sqlType.options) - : t[sqlType.name](field.name); - if (field.type instanceof GraphQLNonNull) { - column = column.notNullable(); - } + const directives = field.astNode?.directives ?? []; + const autoIncrementDirective = directives.find(dir => dir.name.value === 'autoIncrement'); + + if (autoIncrementDirective) { + t.increments(field.name, { primaryKey: true }); + tableHasAutoIncrement = true; + } else { + const sqlType = this.getSqlType(field.type); + let column = + 'options' in sqlType + ? t[sqlType.name](field.name, ...sqlType.options) + : t[sqlType.name](field.name); + + if (field.type instanceof GraphQLNonNull) { + column = column.notNullable(); + } - if (!['text', 'json'].includes(sqlType.name)) { - column.index(); + if (!['text', 'json'].includes(sqlType.name)) { + column.index(); + } } }); + + if (!tableHasAutoIncrement) t.primary(['id']); }); }); await builder; - return { builder }; } diff --git a/src/utils/graphql.ts b/src/utils/graphql.ts index f42d5ef..a48f109 100644 --- a/src/utils/graphql.ts +++ b/src/utils/graphql.ts @@ -10,8 +10,9 @@ import { jsonToGraphQLQuery } from 'json-to-graphql-query'; import pluralize from 'pluralize'; export const extendSchema = (schema: string): string => { - return `directive @derivedFrom(field: String!) on FIELD_DEFINITION -${schema}`; + return `directive @derivedFrom(field: String!) on FIELD_DEFINITION + directive @autoIncrement on FIELD_DEFINITION + ${schema}`; }; /** diff --git a/test/unit/graphql/__snapshots__/controller.test.ts.snap b/test/unit/graphql/__snapshots__/controller.test.ts.snap index d3e1442..5c652aa 100644 --- a/test/unit/graphql/__snapshots__/controller.test.ts.snap +++ b/test/unit/graphql/__snapshots__/controller.test.ts.snap @@ -8,12 +8,15 @@ exports[` 3`] = `"'id' field for type Participant is not a scalar type."`; exports[`GqlEntityController createEntityStores should work 1`] = ` "drop table if exists \`votes\`; -create table \`votes\` (\`id\` integer not null, \`name\` varchar(256), \`authenticators\` json, \`big_number\` bigint, \`decimal\` float, \`big_decimal\` float, primary key (\`id\`)); -create index \`votes_id_index\` on \`votes\` (\`id\`); +create table \`votes\` (\`id\` integer not null primary key autoincrement, \`name\` varchar(256), \`authenticators\` json, \`big_number\` bigint, \`decimal\` float, \`big_decimal\` float, \`poster\` varchar(256)); create index \`votes_name_index\` on \`votes\` (\`name\`); create index \`votes_big_number_index\` on \`votes\` (\`big_number\`); create index \`votes_decimal_index\` on \`votes\` (\`decimal\`); -create index \`votes_big_decimal_index\` on \`votes\` (\`big_decimal\`)" +create index \`votes_big_decimal_index\` on \`votes\` (\`big_decimal\`); +create index \`votes_poster_index\` on \`votes\` (\`poster\`); +drop table if exists \`posters\`; +create table \`posters\` (\`id\` integer not null primary key autoincrement, \`name\` varchar(256) not null); +create index \`posters_name_index\` on \`posters\` (\`name\`)" `; exports[`GqlEntityController generateQueryFields should work 1`] = ` diff --git a/test/unit/graphql/controller.test.ts b/test/unit/graphql/controller.test.ts index ac91b10..b962d78 100644 --- a/test/unit/graphql/controller.test.ts +++ b/test/unit/graphql/controller.test.ts @@ -1,6 +1,7 @@ import { GraphQLObjectType, GraphQLSchema, printSchema } from 'graphql'; import knex from 'knex'; import { GqlEntityController } from '../../../src/graphql/controller'; +import { extendSchema } from '../../../src/utils/graphql'; describe('GqlEntityController', () => { describe('generateQueryFields', () => { @@ -17,7 +18,6 @@ type Vote { name: 'Query', fields: queryFields }); - const schema = printSchema(new GraphQLSchema({ query: querySchema })); expect(schema).toMatchSnapshot(); }); @@ -56,23 +56,33 @@ type Vote { }); it('should work', async () => { - const controller = new GqlEntityController(` + let schema = ` scalar BigInt scalar Decimal scalar BigDecimal type Vote { - id: Int! + id: Int! @autoIncrement name: String authenticators: [String] big_number: BigInt decimal: Decimal big_decimal: BigDecimal + poster : Poster +} + +type Poster { + id: ID! @autoIncrement + name: String! } - `); - const { builder } = await controller.createEntityStores(mockKnex); - expect(builder.toString()).toMatchSnapshot(); + `; + + schema = extendSchema(schema); + const controller = new GqlEntityController(schema); + const { builder } = await controller.createEntityStores(mockKnex); + const createQuery = builder.toString(); + expect(createQuery).toMatchSnapshot(); }); });