Skip to content

✨ enhance the schema.rb parser to support Constraints #1408

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 13 commits into
base: main
Choose a base branch
from
Open
85 changes: 76 additions & 9 deletions frontend/packages/db-structure/src/parser/__tests__/testcase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,44 @@ export const createParserTestCases = (
columns: ['email'],
}),
},
constraints: {
UNIQUE_email: {
type: 'UNIQUE',
name: 'UNIQUE_email',
columnName: 'email',
},
},
}),
'foreign key': (name: string) => ({
relationships: {
[name]: {
name,
primaryTableName: 'users',
primaryColumnName: 'id',
foreignTableName: 'posts',
foreignColumnName: 'user_id',
cardinality: 'ONE_TO_MANY',
updateConstraint: 'NO_ACTION',
deleteConstraint: 'NO_ACTION',
},
},
constraints: {
PRIMARY_id: {
type: 'PRIMARY KEY',
name: 'PRIMARY_id',
columnName: 'id',
},
[name]: {
type: 'FOREIGN KEY',
name,
columnName: 'user_id',
targetTableName: 'users',
targetColumnName: 'id',
updateConstraint: 'NO_ACTION',
deleteConstraint: 'NO_ACTION',
},
},
}),
'foreign key (one-to-many)': (name: string) => ({
[name]: {
name,
Expand All @@ -140,15 +177,45 @@ export const createParserTestCases = (
},
}),
'foreign key with action': {
fk_posts_user_id: {
name: 'fk_posts_user_id',
primaryTableName: 'users',
primaryColumnName: 'id',
foreignTableName: 'posts',
foreignColumnName: 'user_id',
cardinality: 'ONE_TO_MANY',
updateConstraint: 'RESTRICT',
deleteConstraint: 'CASCADE',
relationships: {
fk_posts_user_id: {
name: 'fk_posts_user_id',
primaryTableName: 'users',
primaryColumnName: 'id',
foreignTableName: 'posts',
foreignColumnName: 'user_id',
cardinality: 'ONE_TO_MANY',
updateConstraint: 'RESTRICT',
deleteConstraint: 'CASCADE',
},
},
constraints: {
PRIMARY_id: {
type: 'PRIMARY KEY',
name: 'PRIMARY_id',
columnName: 'id',
},
fk_posts_user_id: {
type: 'FOREIGN KEY',
name: 'fk_posts_user_id',
columnName: 'user_id',
targetTableName: 'users',
targetColumnName: 'id',
updateConstraint: 'RESTRICT',
deleteConstraint: 'CASCADE',
},
},
},
'check constraint': {
PRIMARY_id: {
type: 'PRIMARY KEY',
name: 'PRIMARY_id',
columnName: 'id',
},
age_range_check: {
type: 'CHECK',
name: 'age_range_check',
detail: 'age >= 20 and age < 20',
},
},
})
97 changes: 73 additions & 24 deletions frontend/packages/db-structure/src/parser/schemarb/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,14 @@ describe(processor, () => {
...override?.indexes,
},
comment: override?.comment ?? null,
constraints: {
PRIMARY_id: {
type: 'PRIMARY KEY',
name: 'PRIMARY_id',
columnName: 'id',
},
...override?.constraints,
},
}),
},
})
Expand Down Expand Up @@ -213,62 +221,103 @@ describe(processor, () => {
expect(value).toEqual(parserTestCases['index (unique: true)'](''))
})

it('foreign key (one-to-many)', async () => {
it('foreign key', async () => {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I created a test of "foreign key" to test the behaviour with add_foreign_key by checking both relationships and constraints.
Since the existing cases like "foreign key (one-to-many)" were intended to test relationship cardinalities, I grouped them under a describe block named "foreign key cardinality". (I think using "Hide whitespace" to will make the diff easier to read)

const keyName = 'fk_posts_user_id'
const { value } = await processor(/* Ruby */ `
create_table "posts" do |t|
t.bigint "user_id"
end

add_foreign_key "posts", "users", column: "user_id", name: "${keyName}"
`)

expect(value.relationships).toEqual(
parserTestCases['foreign key (one-to-many)'](keyName),
parserTestCases['foreign key'](keyName).relationships,
)
expect(value.tables['posts']?.constraints).toEqual(
parserTestCases['foreign key'](keyName).constraints,
)
})

it('foreign key with omit column name', async () => {
const keyName = 'fk_posts_user_id'
const { value } = await processor(/* Ruby */ `
describe('foreign key cardinality', () => {
it('foreign key (one-to-many)', async () => {
const keyName = 'fk_posts_user_id'
const { value } = await processor(/* Ruby */ `
add_foreign_key "posts", "users", column: "user_id", name: "${keyName}"
`)

expect(value.relationships).toEqual(
parserTestCases['foreign key (one-to-many)'](keyName),
)
})

it('foreign key with omit column name', async () => {
const keyName = 'fk_posts_user_id'
const { value } = await processor(/* Ruby */ `
add_foreign_key "posts", "users", name: "${keyName}"
`)

expect(value.relationships).toEqual(
parserTestCases['foreign key (one-to-many)'](keyName),
)
})
expect(value.relationships).toEqual(
parserTestCases['foreign key (one-to-many)'](keyName),
)
})

it('foreign key with omit key name', async () => {
const { value } = await processor(/* Ruby */ `
it('foreign key with omit key name', async () => {
const { value } = await processor(/* Ruby */ `
add_foreign_key "posts", "users", column: "user_id"
`)

expect(value.relationships).toEqual(
parserTestCases['foreign key (one-to-many)'](
'users_id_to_posts_user_id',
),
)
})
expect(value.relationships).toEqual(
parserTestCases['foreign key (one-to-many)'](
'users_id_to_posts_user_id',
),
)
})

it('foreign key (one-to-one)', async () => {
const keyName = 'users_id_to_posts_user_id'
const { value } = await processor(/* Ruby */ `
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
end

add_foreign_key "posts", "users", column: "user_id"
`)

expect(value.relationships).toEqual(
parserTestCases['foreign key (one-to-one)'](keyName),
)
expect(value.relationships).toEqual(
parserTestCases['foreign key (one-to-one)'](keyName),
)
})
})

it('foreign keys with action', async () => {
const { value } = await processor(/* Ruby */ `
create_table "posts" do |t|
t.bigint "user_id"
end

add_foreign_key "posts", "users", column: "user_id", name: "fk_posts_user_id", on_update: :restrict, on_delete: :cascade
`)

expect(value.relationships).toEqual(
parserTestCases['foreign key with action'],
parserTestCases['foreign key with action'].relationships,
)
expect(value.tables['posts']?.constraints).toEqual(
parserTestCases['foreign key with action'].constraints,
)
})

it('check constraint', async () => {
const { value } = await processor(/* Ruby */ `
create_table "users" do |t|
t.integer "age"
end

add_check_constraint "users", "age >= 20 and age < 20", name: "age_range_check"
`)

expect(value.tables['users']?.constraints).toEqual(
parserTestCases['check constraint'],
)
})
})
Expand Down
Loading
Loading