Skip to content

Commit 882f063

Browse files
authored
Merge pull request #105 from liam-hq/enhance-postgres-parser-test
Enhance postgres parser test
2 parents a5d98eb + 35d1414 commit 882f063

File tree

3 files changed

+141
-21
lines changed

3 files changed

+141
-21
lines changed

frontend/packages/db-structure/src/parser/__snapshots__/index.test.ts.snap

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,52 @@ exports[`parse > should parse postgresql to JSON correctly 1`] = `
55
"relationships": {},
66
"tables": {
77
"users": {
8-
"columns": {},
8+
"columns": {
9+
"created_at": {
10+
"check": null,
11+
"comment": null,
12+
"default": null,
13+
"increment": false,
14+
"name": "created_at",
15+
"notNull": false,
16+
"primary": false,
17+
"type": "timestamp",
18+
"unique": false,
19+
},
20+
"email": {
21+
"check": null,
22+
"comment": null,
23+
"default": null,
24+
"increment": false,
25+
"name": "email",
26+
"notNull": true,
27+
"primary": false,
28+
"type": "varchar",
29+
"unique": true,
30+
},
31+
"id": {
32+
"check": null,
33+
"comment": null,
34+
"default": null,
35+
"increment": false,
36+
"name": "id",
37+
"notNull": true,
38+
"primary": true,
39+
"type": "serial",
40+
"unique": false,
41+
},
42+
"username": {
43+
"check": null,
44+
"comment": null,
45+
"default": null,
46+
"increment": false,
47+
"name": "username",
48+
"notNull": true,
49+
"primary": false,
50+
"type": "varchar",
51+
"unique": true,
52+
},
53+
},
954
"comment": null,
1055
"indices": [],
1156
"name": "users",

frontend/packages/db-structure/src/parser/sql/postgresql/converter.ts

Lines changed: 25 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,26 @@
1-
import type {
2-
ColumnDef,
3-
Constraint,
4-
CreateStmt,
5-
Node,
6-
String as PgString,
7-
} from '@pgsql/types'
1+
import type { Constraint, CreateStmt, Node } from '@pgsql/types'
82
import type { Columns, DBStructure, Table } from 'src/schema'
93
import type { RawStmtWrapper } from './parser'
104

115
// Transform function for AST to DBStructure
126
export const convertToDBStructure = (ast: RawStmtWrapper[]): DBStructure => {
137
const tables: Record<string, Table> = {}
148

9+
// Creating a new variable str to hold the returned string value,
10+
// as it's not a property of the String type.
11+
interface PgString {
12+
sval: string
13+
str: string
14+
}
15+
1516
function isStringNode(node: Node): node is { String: PgString } {
16-
return (node as { String: { str: string } }).String !== undefined
17+
return (
18+
'String' in node &&
19+
typeof node.String === 'object' &&
20+
node.String !== null &&
21+
'str' in node.String &&
22+
node.String.str !== 'pg_catalog'
23+
)
1724
}
1825

1926
function isConstraintNode(node: Node): node is { Constraint: Constraint } {
@@ -40,21 +47,18 @@ export const convertToDBStructure = (ast: RawStmtWrapper[]): DBStructure => {
4047

4148
const tableName = createStmt.relation.relname
4249
const columns: Columns = {}
43-
createStmt.tableElts
44-
.filter(
45-
(elt: Node): elt is { ColumnDef: ColumnDef } => 'ColumnDef' in elt,
46-
)
47-
.map((elt) => {
50+
for (const elt of createStmt.tableElts) {
51+
if ('ColumnDef' in elt) {
4852
const colDef = elt.ColumnDef
49-
return {
53+
columns[colDef.colname || ''] = {
5054
name: colDef.colname || '',
5155
type:
5256
colDef.typeName?.names
5357
?.filter(isStringNode)
54-
.map((n) => n.String.sval)
55-
.join(' ') || '',
56-
default: '', // TODO
57-
check: '', // TODO
58+
.map((n) => n.String.str)
59+
.join('') || '',
60+
default: null, // TODO
61+
check: null, // TODO
5862
primary:
5963
colDef.constraints
6064
?.filter(isConstraintNode)
@@ -77,9 +81,10 @@ export const convertToDBStructure = (ast: RawStmtWrapper[]): DBStructure => {
7781
colDef.typeName?.names
7882
?.filter(isStringNode)
7983
.some((n) => n.String.sval === 'serial') || false,
80-
comment: '', // TODO
84+
comment: null, // TODO
8185
}
82-
})
86+
}
87+
}
8388

8489
if (tableName) {
8590
tables[tableName] = {
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
import type { Table } from 'src/schema'
2+
import { aColumn, aDBStructure, aTable } from 'src/schema/factories'
3+
import { describe, expect, it } from 'vitest'
4+
import { processor } from '.'
5+
6+
describe(processor, () => {
7+
describe('should parse create_table correctry', () => {
8+
const userTable = (override?: Partial<Table>) =>
9+
aDBStructure({
10+
tables: {
11+
users: aTable({
12+
name: 'users',
13+
columns: {
14+
id: aColumn({
15+
name: 'id',
16+
type: 'serial',
17+
notNull: true,
18+
primary: true,
19+
}),
20+
...override?.columns,
21+
},
22+
}),
23+
},
24+
})
25+
26+
it('not null', () => {
27+
const result = processor(/* PostgreSQL */ `
28+
CREATE TABLE users (
29+
id SERIAL PRIMARY KEY,
30+
name VARCHAR(255) NOT NULL
31+
);
32+
`)
33+
34+
const expected = userTable({
35+
columns: {
36+
name: aColumn({
37+
name: 'name',
38+
type: 'varchar',
39+
notNull: true,
40+
}),
41+
},
42+
})
43+
44+
expect(result).toEqual(expected)
45+
})
46+
47+
it('nullable', () => {
48+
const result = processor(/* PostgreSQL */ `
49+
CREATE TABLE users (
50+
id SERIAL PRIMARY KEY,
51+
name VARCHAR(255)
52+
);
53+
`)
54+
55+
const expected = userTable({
56+
columns: {
57+
name: aColumn({
58+
name: 'name',
59+
type: 'varchar',
60+
notNull: false,
61+
}),
62+
},
63+
})
64+
65+
expect(result).toEqual(expected)
66+
})
67+
68+
// TODO: Implement default value
69+
})
70+
})

0 commit comments

Comments
 (0)