Skip to content

Commit 78176f2

Browse files
committed
implement generated
1 parent 722faec commit 78176f2

File tree

7 files changed

+1732
-1730
lines changed

7 files changed

+1732
-1730
lines changed

README.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,9 @@ ON FIELD_DEFINITION:
139139
* If any column is marked with "unicode", then the table will have `CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci`.
140140
* unique
141141
* Marks a column with the UNIQUE keyword.
142+
* generated
143+
* Marks a generated column.
144+
* Example: `@sql(generated: "(data->>'$.test')")`. See [main-test.ts](__tests__/main-test.ts#L137) for more examples.
142145

143146
## SQL Features Supported<sup>1</sup>:
144147
- [x] Auto Increment
@@ -151,6 +154,6 @@ ON FIELD_DEFINITION:
151154
- [ ] Check
152155
- [X] Constraints
153156
- [X] Foreign Key (via @constraints)
154-
- [ ] Generated Columns
157+
- [x] Generated Columns
155158

156159
<sup>1</sup>Only MySQL is supported at the moment.

__tests__/main-test.ts

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ test('main test', () => {
1818
primary: Boolean
1919
type: String
2020
unique: Boolean
21+
generated: String
2122
) on OBJECT | FIELD_DEFINITION
2223
2324
# See graphql-directive-private
@@ -117,8 +118,8 @@ test('error multiple primary index', () => {
117118
${sqlDirectiveDeclaration}
118119
119120
type User @sql(unicode: true) {
120-
userId: String @sql(primary: true)
121-
postId: String @sql(primary: true)
121+
userId: String @sql(type: "BINARY(16)", primary: true)
122+
postId: String @sql(type: "BINARY(16)", primary: true)
122123
}
123124
`
124125

@@ -132,3 +133,49 @@ test('error multiple primary index', () => {
132133
})
133134
}).toThrow()
134135
})
136+
137+
test('generated', () => {
138+
const typeDefs = gql`
139+
${sqlDirectiveDeclaration}
140+
141+
scalar JSON
142+
143+
type GeneratedTest {
144+
userId: String @sql(type: "BINARY(16)", primary: true)
145+
data: JSON @sql
146+
test1: String
147+
@sql(
148+
type: "VARCHAR(30)"
149+
generated: "GENERATED ALWAYS AS (data->>'$.test') VIRTUAL"
150+
)
151+
test2: String
152+
@sql(type: "VARCHAR(30)", generated: "ALWAYS AS (data->>'$.test')")
153+
test3: String @sql(type: "VARCHAR(30)", generated: "AS (data->>'$.test')")
154+
test4: String
155+
@sql(type: "VARCHAR(30)", generated: "(data->>'$.test')", index: true)
156+
}
157+
`
158+
159+
const outputFilepath = '__tests__/testOutput.sql'
160+
const directives = getSchemaDirectives()
161+
makeSqlSchema({
162+
typeDefs,
163+
schemaDirectives: directives,
164+
outputFilepath,
165+
databaseName: 'dbname',
166+
tablePrefix: 'test_',
167+
})
168+
169+
const testOutput = fs.readFileSync(outputFilepath, { encoding: 'utf8' })
170+
console.log('testOutput', testOutput)
171+
expect(testOutput).toEqual(`CREATE TABLE \`dbname\`.\`test_GeneratedTest\` (
172+
\`userId\` BINARY(16) NOT NULL,
173+
\`data\` JSON NOT NULL,
174+
\`test1\` VARCHAR(30) GENERATED ALWAYS AS (data->>'$.test') VIRTUAL NOT NULL,
175+
\`test2\` VARCHAR(30) GENERATED ALWAYS AS (data->>'$.test') NOT NULL,
176+
\`test3\` VARCHAR(30) AS (data->>'$.test') NOT NULL,
177+
\`test4\` VARCHAR(30) AS (data->>'$.test') NOT NULL,
178+
PRIMARY KEY (\`userId\`),
179+
INDEX \`TEST4INDEX\` (\`test4\` ASC)
180+
);`)
181+
})

__tests__/testOutput.sql

Lines changed: 8 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,10 @@
1-
CREATE TABLE `dbname`.`test_User` (
1+
CREATE TABLE `dbname`.`test_GeneratedTest` (
22
`userId` BINARY(16) NOT NULL,
3-
`uniqueColumn` INT NOT NULL UNIQUE,
4-
`databaseOnlyField` INT NOT NULL,
5-
PRIMARY KEY (`userId`)
6-
) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
7-
8-
CREATE TABLE `dbname`.`test_Post` (
9-
`postId` INT NOT NULL AUTO_INCREMENT,
10-
`userId` BINARY(16) NOT NULL,
11-
`content` VARCHAR(300) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL,
12-
`likes` INT NOT NULL,
13-
`dateCreated` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
14-
PRIMARY KEY (`postId`),
15-
INDEX `USERIDINDEX` (`userId` ASC)
16-
) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
17-
18-
CREATE TABLE `dbname`.`test_UserPair` (
19-
`userPairId` BINARY(16) NOT NULL,
20-
`parentUserId` BINARY(16) NOT NULL,
21-
`childUserId` BINARY(16) NOT NULL,
22-
PRIMARY KEY (`userPairId`),
23-
INDEX `PARENTUSERIDINDEX` (`parentUserId` ASC),
24-
INDEX `CHILDUSERIDINDEX` (`childUserId` ASC),
25-
UNIQUE(parentUserId, childUserId),
26-
FOREIGN KEY (parentUserId) REFERENCES User(userId)
3+
`data` JSON NOT NULL,
4+
`test1` VARCHAR(30) GENERATED ALWAYS AS (data->>'$.test') VIRTUAL NOT NULL,
5+
`test2` VARCHAR(30) GENERATED ALWAYS AS (data->>'$.test') NOT NULL,
6+
`test3` VARCHAR(30) AS (data->>'$.test') NOT NULL,
7+
`test4` VARCHAR(30) AS (data->>'$.test') NOT NULL,
8+
PRIMARY KEY (`userId`),
9+
INDEX `TEST4INDEX` (`test4` ASC)
2710
);

package.json

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,13 @@
3333
"graphql-tag": "^2.10.1",
3434
"graphql-tools": "^4.0.0",
3535
"husky": "^1.1.1",
36-
"jest": "^23.6.0",
36+
"jest": "^25.1.0",
3737
"lint-staged": "^7.3.0",
3838
"prettier": "^1.14.3",
39-
"ts-jest": "^23.10.4",
40-
"tslint": "^5.11.0",
41-
"tslint-config-prettier": "^1.15.0",
42-
"typescript": "^3.1.1"
39+
"ts-jest": "^25.2.0",
40+
"tslint": "^6.0.0",
41+
"tslint-config-prettier": "^1.18.0",
42+
"typescript": "^3.7.5"
4343
},
4444
"keywords": [
4545
"graphql",

src/getSchemaDirectives.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,9 @@ export function getSchemaDirectives({
6363
unique: {
6464
type: GraphQLBoolean,
6565
},
66+
generated: {
67+
type: GraphQLString,
68+
},
6669
},
6770
})
6871
}
@@ -113,6 +116,7 @@ export function customDirectiveDeclaration(
113116
primary: Boolean
114117
type: String
115118
unique: Boolean
119+
generated: String
116120
) on OBJECT | FIELD_DEFINITION`
117121
}
118122
export const sqlDirectiveDeclaration = customDirectiveDeclaration('sql')

src/makeSqlSchema.ts

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ export interface IColumn {
4545
graphQLType: string
4646
unicode?: boolean
4747
unique?: boolean
48+
generated?: string
4849
}
4950

5051
export interface ISQLAST {
@@ -110,9 +111,7 @@ function setDefaults() {
110111
emitError(
111112
table.name,
112113
column.name,
113-
`A default SQL type cannot be generated for GraphQL type ${
114-
column.graphQLType
115-
}`
114+
`A default SQL type cannot be generated for GraphQL type ${column.graphQLType}`
116115
)
117116
}
118117
}
@@ -142,6 +141,13 @@ function setDefaults() {
142141
'"unicode" is not allowed with "auto".'
143142
)
144143
}
144+
if (column.generated) {
145+
emitError(
146+
table.name,
147+
column.name,
148+
'"generated" is not allowed with "auto".'
149+
)
150+
}
145151
}
146152

147153
if (column.unicode) {
@@ -157,6 +163,26 @@ function setDefaults() {
157163
table.unicode = true
158164
}
159165
}
166+
167+
if (column.generated && column.default) {
168+
emitError(
169+
table.name,
170+
column.name,
171+
'"default" is not allowed with "generated".'
172+
)
173+
}
174+
175+
if (column.generated && column.generated.startsWith('ALWAYS AS')) {
176+
column.generated = `GENERATED ${column.generated}`
177+
}
178+
179+
if (
180+
column.generated &&
181+
!column.generated.startsWith('GENERATED') &&
182+
!column.generated.startsWith('AS')
183+
) {
184+
column.generated = `AS ${column.generated}`
185+
}
160186
})
161187
})
162188
}
@@ -200,17 +226,17 @@ function renderCreateSchemaScript(
200226
forEachTableDo(table => {
201227
const columnDefinitions: string[] = []
202228
forEachColumnDo(table, column => {
203-
const nullClause = !!column.nullable ? 'NULL ' : 'NOT NULL '
204229
const unicodeClause = !!column.unicode
205230
? 'CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci '
206231
: ''
232+
const generatedClause = !!column.generated ? `${column.generated} ` : ''
233+
const nullClause = !!column.nullable ? 'NULL ' : 'NOT NULL '
207234
const defaultClause = !!column.default ? `DEFAULT ${column.default} ` : ''
208-
const autoClause = !!column.auto ? 'AUTO_INCREMENT ' : ''
235+
const autoClause =
236+
!!column.auto && column.type !== 'SERIAL' ? 'AUTO_INCREMENT ' : ''
209237
const uniqueClause = !!column.unique ? `UNIQUE ` : ''
210238
columnDefinitions.push(
211-
`\`${column.name}\` ${
212-
column.type
213-
} ${unicodeClause}${nullClause}${defaultClause}${autoClause}${uniqueClause}`.trim()
239+
`\`${column.name}\` ${column.type} ${unicodeClause}${generatedClause}${nullClause}${defaultClause}${autoClause}${uniqueClause}`.trim()
214240
)
215241
})
216242

0 commit comments

Comments
 (0)