diff --git a/.changeset/nice-starfishes-collect.md b/.changeset/nice-starfishes-collect.md
new file mode 100644
index 000000000..b3175163d
--- /dev/null
+++ b/.changeset/nice-starfishes-collect.md
@@ -0,0 +1,6 @@
+---
+"@liam-hq/db-structure": patch
+"@liam-hq/cli": patch
+---
+
+♻️ Add createParserTestCases function and update parser tests
diff --git a/frontend/packages/db-structure/src/parser/__tests__/testcase.ts b/frontend/packages/db-structure/src/parser/__tests__/testcase.ts
index 74336a18f..d636be6f5 100644
--- a/frontend/packages/db-structure/src/parser/__tests__/testcase.ts
+++ b/frontend/packages/db-structure/src/parser/__tests__/testcase.ts
@@ -1,35 +1,13 @@
import {
type Table,
aColumn,
- aDBStructure,
- aTable,
+ type aDBStructure,
anIndex,
} from '../../schema/index.js'
-const userTable = (override?: Partial
) =>
- aDBStructure({
- tables: {
- users: aTable({
- name: 'users',
- columns: {
- id: aColumn({
- name: 'id',
- type: 'bigserial',
- notNull: true,
- primary: true,
- unique: true,
- }),
- ...override?.columns,
- },
- indices: {
- ...override?.indices,
- },
- comment: override?.comment ?? null,
- }),
- },
- })
-
-export const parserTestCases = {
+export const createParserTestCases = (
+ userTable: (override?: Partial) => ReturnType,
+) => ({
'table comment': userTable({
comment: 'store our users.',
}),
@@ -96,20 +74,21 @@ export const parserTestCases = {
}),
},
}),
- 'index (unique: false)': userTable({
- columns: {
- email: aColumn({
- name: 'email',
- }),
- },
- indices: {
- index_users_on_id_and_email: anIndex({
- name: 'index_users_on_id_and_email',
- unique: false,
- columns: ['id', 'email'],
- }),
- },
- }),
+ 'index (unique: false)': (indexName: string) =>
+ userTable({
+ columns: {
+ email: aColumn({
+ name: 'email',
+ }),
+ },
+ indices: {
+ [indexName]: anIndex({
+ name: indexName,
+ unique: false,
+ columns: ['id', 'email'],
+ }),
+ },
+ }),
'index (unique: true)': userTable({
columns: {
email: aColumn({
@@ -136,9 +115,9 @@ export const parserTestCases = {
deleteConstraint: 'NO_ACTION',
},
}),
- 'foreign key (one-to-one)': {
- users_id_to_posts_user_id: {
- name: 'users_id_to_posts_user_id',
+ 'foreign key (one-to-one)': (name: string) => ({
+ [name]: {
+ name,
primaryTableName: 'users',
primaryColumnName: 'id',
foreignTableName: 'posts',
@@ -147,7 +126,7 @@ export const parserTestCases = {
updateConstraint: 'NO_ACTION',
deleteConstraint: 'NO_ACTION',
},
- },
+ }),
'foreign key with action': {
fk_posts_user_id: {
name: 'fk_posts_user_id',
@@ -160,4 +139,4 @@ export const parserTestCases = {
deleteConstraint: 'CASCADE',
},
},
-}
+})
diff --git a/frontend/packages/db-structure/src/parser/prisma/index.test.ts b/frontend/packages/db-structure/src/parser/prisma/index.test.ts
index 8198e5ba1..93f419b5a 100644
--- a/frontend/packages/db-structure/src/parser/prisma/index.test.ts
+++ b/frontend/packages/db-structure/src/parser/prisma/index.test.ts
@@ -1,6 +1,7 @@
import { describe, expect, it } from 'vitest'
import type { Table } from '../../schema/index.js'
import { aColumn, aDBStructure, aTable, anIndex } from '../../schema/index.js'
+import { createParserTestCases } from '../__tests__/index.js'
import { processor as _processor } from './index.js'
describe(_processor, () => {
@@ -12,11 +13,11 @@ describe(_processor, () => {
columns: {
id: aColumn({
name: 'id',
- type: 'serial',
+ type: 'bigserial',
default: 'autoincrement()',
notNull: true,
primary: true,
- unique: false,
+ unique: true,
}),
...override?.columns,
},
@@ -46,11 +47,13 @@ describe(_processor, () => {
const processor = async (schema: string) =>
_processor(`${prismaSchemaHeader}\n\n${schema}`)
+ const parserTestCases = createParserTestCases(userTable)
+
describe('should parse prisma schema correctly', () => {
it('not null', async () => {
const { value } = await processor(`
model users {
- id Int @id @default(autoincrement())
+ id BigInt @id @default(autoincrement())
name String
}
`)
@@ -71,50 +74,29 @@ describe(_processor, () => {
it('nullable', async () => {
const { value } = await processor(`
model users {
- id Int @id @default(autoincrement())
+ id BigInt @id @default(autoincrement())
description String?
}
`)
- const expected = userTable({
- columns: {
- description: aColumn({
- name: 'description',
- type: 'text',
- notNull: false,
- }),
- },
- })
-
- expect(value).toEqual(expected)
+ expect(value).toEqual(parserTestCases.nullable)
})
it('default value as string', async () => {
const { value } = await processor(`
model users {
- id Int @id @default(autoincrement())
- description String @default("user's description")
+ id BigInt @id @default(autoincrement())
+ description String? @default("user's description")
}
`)
- const expected = userTable({
- columns: {
- description: aColumn({
- name: 'description',
- type: 'text',
- default: "user's description",
- notNull: true,
- }),
- },
- })
-
- expect(value).toEqual(expected)
+ expect(value).toEqual(parserTestCases['default value as string'])
})
it('default value as integer', async () => {
const { value } = await processor(`
model users {
- id Int @id @default(autoincrement())
+ id BigInt @id @default(autoincrement())
age Int @default(30)
}
`)
@@ -136,7 +118,7 @@ describe(_processor, () => {
it('default value as boolean', async () => {
const { value } = await processor(`
model users {
- id Int @id @default(autoincrement())
+ id BigInt @id @default(autoincrement())
active Boolean @default(true)
}
`)
@@ -158,84 +140,54 @@ describe(_processor, () => {
it('column comment', async () => {
const { value } = await processor(`
model users {
- id Int @id @default(autoincrement())
+ id BigInt @id @default(autoincrement())
/// this is description
description String?
}
`)
- const expected = userTable({
- columns: {
- description: aColumn({
- name: 'description',
- type: 'text',
- comment: 'this is description',
- }),
- },
- })
-
- expect(value).toEqual(expected)
+ expect(value).toEqual(parserTestCases['column comment'])
})
it('table comment', async () => {
const { value } = await processor(`
/// store our users.
model users {
- id Int @id @default(autoincrement())
+ id BigInt @id @default(autoincrement())
}
`)
- const expected = userTable({
- comment: 'store our users.',
- })
-
- expect(value).toEqual(expected)
+ expect(value).toEqual(parserTestCases['table comment'])
})
it('index (unique: false)', async () => {
+ const indexName = 'users_id_email_idx'
const { value } = await processor(`
model users {
- id Int @id @default(autoincrement())
- email String
+ id BigInt @id @default(autoincrement())
+ email String? @db.VarChar
@@index([id, email])
}
`)
-
- const expected = userTable({
- columns: {
- email: aColumn({
- name: 'email',
- type: 'text',
- notNull: true,
- }),
- },
- indices: {
- users_id_email_idx: anIndex({
- name: 'users_id_email_idx',
- unique: false,
- columns: ['id', 'email'],
- }),
- },
- })
-
- expect(value).toEqual(expected)
+ expect(value).toEqual(parserTestCases['index (unique: false)'](indexName))
})
it('index (unique: true)', async () => {
const { value } = await processor(`
model users {
- id Int @id @default(autoincrement())
- email String
- @@unique([id, email])
+ id BigInt @id @default(autoincrement())
+ mention String? @unique
+ @@unique([id, mention])
}
`)
const expected = userTable({
columns: {
- email: aColumn({
- name: 'email',
+ mention: aColumn({
+ name: 'mention',
type: 'text',
- notNull: true,
+ notNull: false,
+ unique: true,
}),
},
indices: {
@@ -244,10 +196,15 @@ describe(_processor, () => {
unique: true,
columns: ['id'],
}),
- users_id_email_key: anIndex({
- name: 'users_id_email_key',
+ users_id_mention_key: anIndex({
+ name: 'users_id_mention_key',
+ unique: true,
+ columns: ['id', 'mention'],
+ }),
+ users_mention_key: anIndex({
+ name: 'users_mention_key',
unique: true,
- columns: ['id', 'email'],
+ columns: ['mention'],
}),
},
})
@@ -256,63 +213,43 @@ describe(_processor, () => {
})
it('relationship (one-to-many)', async () => {
+ const keyName = 'postsTousers'
const { value } = await processor(`
model users {
- id Int @id @default(autoincrement())
+ id BigInt @id @default(autoincrement())
posts posts[]
}
model posts {
- id Int @id @default(autoincrement())
+ id BigInt @id @default(autoincrement())
user users @relation(fields: [user_id], references: [id])
- user_id Int
+ user_id BigInt
}
`)
- const expected = {
- postsTousers: {
- name: 'postsTousers',
- primaryTableName: 'users',
- primaryColumnName: 'id',
- foreignTableName: 'posts',
- foreignColumnName: 'user_id',
- cardinality: 'ONE_TO_MANY',
- updateConstraint: 'NO_ACTION',
- deleteConstraint: 'NO_ACTION',
- },
- }
-
- expect(value.relationships).toEqual(expected)
+ expect(value.relationships).toEqual(
+ parserTestCases['foreign key (one-to-many)'](keyName),
+ )
})
it('relationship (one-to-one)', async () => {
+ const keyName = 'postsTousers'
const { value } = await processor(`
model users {
- id Int @id @default(autoincrement())
+ id BigInt @id @default(autoincrement())
post posts?
}
model posts {
- id Int @id @default(autoincrement())
+ id BigInt @id @default(autoincrement())
user users @relation(fields: [user_id], references: [id])
- user_id Int @unique
+ user_id BigInt @unique
}
`)
- const expected = {
- postsTousers: {
- name: 'postsTousers',
- primaryTableName: 'users',
- primaryColumnName: 'id',
- foreignTableName: 'posts',
- foreignColumnName: 'user_id',
- cardinality: 'ONE_TO_ONE',
- updateConstraint: 'NO_ACTION',
- deleteConstraint: 'NO_ACTION',
- },
- }
-
- expect(value.relationships).toEqual(expected)
+ expect(value.relationships).toEqual(
+ parserTestCases['foreign key (one-to-one)'](keyName),
+ )
})
describe('foreign key constraints (on delete)', () => {
@@ -329,14 +266,14 @@ describe(_processor, () => {
async (prismaAction: string, expectedAction: string) => {
const { value } = await processor(`
model users {
- id Int @id @default(autoincrement())
+ id BigInt @id @default(autoincrement())
posts posts[]
}
model posts {
- id Int @id @default(autoincrement())
+ id BigInt @id @default(autoincrement())
user users @relation(fields: [user_id], references: [id], onDelete: ${prismaAction})
- user_id Int
+ user_id BigInt
}
`)
@@ -361,14 +298,14 @@ describe(_processor, () => {
it('columns do not include model type', async () => {
const { value } = await processor(`
model users {
- id Int @id @default(autoincrement())
+ id BigInt @id @default(autoincrement())
posts posts[]
}
model posts {
- id Int @id @default(autoincrement())
+ id BigInt @id @default(autoincrement())
user users @relation(fields: [user_id], references: [id])
- user_id Int
+ user_id BigInt
}
`)
@@ -396,7 +333,7 @@ describe(_processor, () => {
it('unique', async () => {
const { value } = await processor(`
model users {
- id Int @id @default(autoincrement())
+ id BigInt @id @default(autoincrement())
email String @unique
}
`)
@@ -425,7 +362,7 @@ describe(_processor, () => {
it('not unique', async () => {
const { value } = await processor(`
model users {
- id Int @id @default(autoincrement())
+ id BigInt @id @default(autoincrement())
email String
}
`)
diff --git a/frontend/packages/db-structure/src/parser/prisma/parser.ts b/frontend/packages/db-structure/src/parser/prisma/parser.ts
index 69136ba77..dddf17577 100644
--- a/frontend/packages/db-structure/src/parser/prisma/parser.ts
+++ b/frontend/packages/db-structure/src/parser/prisma/parser.ts
@@ -34,7 +34,7 @@ async function parsePrismaSchema(schemaString: string): Promise {
),
default: defaultValue,
notNull: field.isRequired,
- unique: field.isUnique,
+ unique: field.isId || field.isUnique,
primary: field.isId,
comment: field.documentation ?? null,
check: null,
diff --git a/frontend/packages/db-structure/src/parser/schemarb/index.test.ts b/frontend/packages/db-structure/src/parser/schemarb/index.test.ts
index 9f3465f63..2b555a5d6 100644
--- a/frontend/packages/db-structure/src/parser/schemarb/index.test.ts
+++ b/frontend/packages/db-structure/src/parser/schemarb/index.test.ts
@@ -3,7 +3,7 @@ import type { Table } from '../../schema/index.js'
import { aColumn, aDBStructure, aTable } from '../../schema/index.js'
import { UnsupportedTokenError, processor } from './index.js'
-import { parserTestCases } from '../__tests__/index.js'
+import { createParserTestCases } from '../__tests__/index.js'
describe(processor, () => {
const userTable = (override?: Partial) =>
@@ -28,6 +28,7 @@ describe(processor, () => {
}),
},
})
+ const parserTestCases = createParserTestCases(userTable)
describe('should parse create_table correctly', () => {
it('table comment', async () => {
@@ -188,6 +189,7 @@ describe(processor, () => {
})
it('index (unique: false)', async () => {
+ const indexName = 'index_users_on_id_and_email'
const { value } = await processor(/* Ruby */ `
create_table "users" do |t|
t.string "email"
@@ -195,7 +197,7 @@ describe(processor, () => {
end
`)
- expect(value).toEqual(parserTestCases['index (unique: false)'])
+ expect(value).toEqual(parserTestCases['index (unique: false)'](indexName))
})
it('index (unique: true)', async () => {
@@ -244,6 +246,7 @@ describe(processor, () => {
})
it('foreign key (one-to-one)', async () => {
+ const keyName = 'users_id_to_posts_user_id'
const { value } = await processor(/* Ruby */ `
create_table "posts" do |t|
t.bigint "user_id", unique: true
@@ -253,7 +256,7 @@ describe(processor, () => {
`)
expect(value.relationships).toEqual(
- parserTestCases['foreign key (one-to-one)'],
+ parserTestCases['foreign key (one-to-one)'](keyName),
)
})
diff --git a/frontend/packages/db-structure/src/parser/sql/postgresql/index.test.ts b/frontend/packages/db-structure/src/parser/sql/postgresql/index.test.ts
index 4e06836b5..b92785e95 100644
--- a/frontend/packages/db-structure/src/parser/sql/postgresql/index.test.ts
+++ b/frontend/packages/db-structure/src/parser/sql/postgresql/index.test.ts
@@ -1,9 +1,35 @@
import { describe, expect, it } from 'vitest'
-import { parserTestCases } from '../../__tests__/index.js'
+import type { Table } from '../../../schema/index.js'
+import { aColumn, aDBStructure, aTable } from '../../../schema/index.js'
+import { createParserTestCases } from '../../__tests__/index.js'
import { UnexpectedTokenWarningError } from '../../errors.js'
import { processor } from './index.js'
describe(processor, () => {
+ const userTable = (override?: Partial) =>
+ aDBStructure({
+ tables: {
+ users: aTable({
+ name: 'users',
+ columns: {
+ id: aColumn({
+ name: 'id',
+ type: 'bigserial',
+ notNull: true,
+ primary: true,
+ unique: true,
+ }),
+ ...override?.columns,
+ },
+ indices: {
+ ...override?.indices,
+ },
+ comment: override?.comment ?? null,
+ }),
+ },
+ })
+ const parserTestCases = createParserTestCases(userTable)
+
describe('should parse CREATE TABLE statement correctly', () => {
it('table comment', async () => {
const { value } = await processor(/* sql */ `
@@ -95,6 +121,7 @@ describe(processor, () => {
})
it('index (unique: false)', async () => {
+ const indexName = 'index_users_on_id_and_email'
const { value } = await processor(/* sql */ `
CREATE TABLE users (
id BIGSERIAL PRIMARY KEY,
@@ -104,7 +131,7 @@ describe(processor, () => {
CREATE INDEX index_users_on_id_and_email ON public.users USING btree (id, email);
`)
- expect(value).toEqual(parserTestCases['index (unique: false)'])
+ expect(value).toEqual(parserTestCases['index (unique: false)'](indexName))
})
it('index (unique: true)', async () => {
@@ -152,6 +179,7 @@ describe(processor, () => {
})
it('foreign key (one-to-one)', async () => {
+ const keyName = 'users_id_to_posts_user_id'
const { value } = await processor(/* sql */ `
CREATE TABLE posts (
id BIGSERIAL PRIMARY KEY,
@@ -160,7 +188,7 @@ describe(processor, () => {
`)
expect(value.relationships).toEqual(
- parserTestCases['foreign key (one-to-one)'],
+ parserTestCases['foreign key (one-to-one)'](keyName),
)
})
})
@@ -179,6 +207,7 @@ describe(processor, () => {
})
it('foreign key (one-to-one)', async () => {
+ const keyName = 'users_id_to_posts_user_id'
const { value } = await processor(/* sql */ `
CREATE TABLE posts (
id SERIAL PRIMARY KEY,
@@ -190,7 +219,7 @@ describe(processor, () => {
`)
expect(value.relationships).toEqual(
- parserTestCases['foreign key (one-to-one)'],
+ parserTestCases['foreign key (one-to-one)'](keyName),
)
})