Skip to content

Commit

Permalink
cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
koskimas committed Jul 21, 2022
1 parent 3cfa747 commit e22e03b
Show file tree
Hide file tree
Showing 11 changed files with 183 additions and 33 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "kysely",
"version": "0.19.11",
"version": "0.19.12",
"description": "Type safe SQL query builder",
"repository": {
"type": "git",
Expand Down
5 changes: 4 additions & 1 deletion src/operation-node/create-table-node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,11 @@ import { OperationNode } from './operation-node.js'
import { TableNode } from './table-node.js'
import { ConstraintNode } from './constraint-node.js'
import { ColumnDefinitionNode } from './column-definition-node.js'
import { ArrayItemType } from '../util/type-utils.js'

export const ON_COMMIT_ACTIONS = ['preserve rows', 'delete rows', 'drop']
export type OnCommitAction = ArrayItemType<typeof ON_COMMIT_ACTIONS>

export type OnCommitAction = 'preserve rows' | 'delete rows' | 'drop'
export type CreateTableNodeParams = Omit<
CreateTableNode,
'kind' | 'table' | 'columns' | 'constraints'
Expand Down
18 changes: 12 additions & 6 deletions src/operation-node/references-node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,19 @@ import { OperationNode } from './operation-node.js'
import { ColumnNode } from './column-node.js'
import { TableNode } from './table-node.js'
import { freeze } from '../util/object-utils.js'
import { ArrayItemType } from '../util/type-utils.js'

export type OnModifyForeignAction =
| 'no action'
| 'restrict'
| 'cascade'
| 'set null'
| 'set default'
export const ON_MODIFY_FOREIGN_ACTIONS = [
'no action',
'restrict',
'cascade',
'set null',
'set default',
] as const

export type OnModifyForeignAction = ArrayItemType<
typeof ON_MODIFY_FOREIGN_ACTIONS
>

export interface ReferencesNode extends OperationNode {
readonly kind: 'ReferencesNode'
Expand Down
12 changes: 12 additions & 0 deletions src/parser/on-commit-action-parse.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import {
OnCommitAction,
ON_COMMIT_ACTIONS,
} from '../operation-node/create-table-node.js'

export function parseOnCommitAction(action: OnCommitAction): OnCommitAction {
if (ON_COMMIT_ACTIONS.includes(action)) {
return action
}

throw new Error(`invalid OnCommitAction ${action}`)
}
14 changes: 14 additions & 0 deletions src/parser/on-modify-action-parser.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import {
OnModifyForeignAction,
ON_MODIFY_FOREIGN_ACTIONS,
} from '../operation-node/references-node.js'

export function parseOnModifyForeignAction(
action: OnModifyForeignAction
): OnModifyForeignAction {
if (ON_MODIFY_FOREIGN_ACTIONS.includes(action)) {
return action
}

throw new Error(`invalid OnModifyForeignAction ${action}`)
}
44 changes: 24 additions & 20 deletions src/query-compiler/default-query-compiler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -376,26 +376,6 @@ export class DefaultQueryCompiler
this.append(this.sanitizeIdentifier(node.identifier))
}

protected sanitizeIdentifier = (identifier: string): string => {
const leftWrapper = this.getLeftIdentifierWrapper()
const rightWrapper = this.getRightIdentifierWrapper()

let sanitizedIdentifier = identifier
.split('')
.map((char) => {
if (char === leftWrapper) {
return `${leftWrapper}${leftWrapper}`
} else if (char === rightWrapper) {
return `${rightWrapper}${rightWrapper}`
}

return char
})
.join('')

return sanitizedIdentifier
}

protected override visitFilter(node: FilterNode): void {
if (node.left) {
this.visitNode(node.left)
Expand Down Expand Up @@ -1161,6 +1141,30 @@ export class DefaultQueryCompiler
return '$' + this.numParameters
}

protected sanitizeIdentifier(identifier: string): string {
if (!isString(identifier)) {
throw new Error(
'a non-string identifier was passed to sanitizeIdentifier.'
)
}

const leftWrap = this.getLeftIdentifierWrapper()
const rightWrap = this.getRightIdentifierWrapper()

let sanitized = ''
for (const c of identifier) {
sanitized += c

if (c === leftWrap) {
sanitized += leftWrap
} else if (c === rightWrap) {
sanitized += rightWrap
}
}

return sanitized
}

protected addParameter(parameter: unknown): void {
this.#parameters.push(parameter)
}
Expand Down
5 changes: 3 additions & 2 deletions src/schema/column-definition-builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
} from '../parser/default-value-parser.js'
import { GeneratedNode } from '../operation-node/generated-node.js'
import { DefaultValueNode } from '../operation-node/default-value-node.js'
import { parseOnModifyForeignAction } from '../parser/on-modify-action-parser.js'

export interface ColumnDefinitionBuilderInterface {
/**
Expand Down Expand Up @@ -236,7 +237,7 @@ export class ColumnDefinitionBuilder
ColumnDefinitionNode.cloneWith(this.#node, {
references: ReferencesNode.cloneWithOnDelete(
this.#node.references,
onDelete
parseOnModifyForeignAction(onDelete)
),
})
)
Expand All @@ -251,7 +252,7 @@ export class ColumnDefinitionBuilder
ColumnDefinitionNode.cloneWith(this.#node, {
references: ReferencesNode.cloneWithOnUpdate(
this.#node.references,
onUpdate
parseOnModifyForeignAction(onUpdate)
),
})
)
Expand Down
3 changes: 2 additions & 1 deletion src/schema/create-table-builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import { UniqueConstraintNode } from '../operation-node/unique-constraint-node.j
import { CheckConstraintNode } from '../operation-node/check-constraint-node.js'
import { AnyRawBuilder } from '../util/type-utils.js'
import { parseTable } from '../parser/table-parser.js'
import { parseOnCommitAction } from '../parser/on-commit-action-parse.js'

/**
* This builder can be used to create a `create table` query.
Expand Down Expand Up @@ -60,7 +61,7 @@ export class CreateTableBuilder<TB extends string, C extends string = never>
return new CreateTableBuilder({
...this.#props,
createTableNode: CreateTableNode.cloneWith(this.#props.createTableNode, {
onCommit,
onCommit: parseOnCommitAction(onCommit),
}),
})
}
Expand Down
5 changes: 3 additions & 2 deletions src/schema/foreign-key-constraint-builder.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { ForeignKeyConstraintNode } from '../operation-node/foreign-key-constraint-node.js'
import { OperationNodeSource } from '../operation-node/operation-node-source.js'
import { OnModifyForeignAction } from '../operation-node/references-node.js'
import { parseOnModifyForeignAction } from '../parser/on-modify-action-parser.js'
import { preventAwait } from '../util/prevent-await.js'

export interface ForeignKeyConstraintBuilderInterface<R> {
Expand All @@ -22,15 +23,15 @@ export class ForeignKeyConstraintBuilder
onDelete(onDelete: OnModifyForeignAction): ForeignKeyConstraintBuilder {
return new ForeignKeyConstraintBuilder(
ForeignKeyConstraintNode.cloneWith(this.#node, {
onDelete,
onDelete: parseOnModifyForeignAction(onDelete),
})
)
}

onUpdate(onUpdate: OnModifyForeignAction): ForeignKeyConstraintBuilder {
return new ForeignKeyConstraintBuilder(
ForeignKeyConstraintNode.cloneWith(this.#node, {
onUpdate,
onUpdate: parseOnModifyForeignAction(onUpdate),
})
)
}
Expand Down
74 changes: 74 additions & 0 deletions test/node/src/sanitize-identifiers.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import { Updateable } from '../../../dist/cjs'

import {
BUILT_IN_DIALECTS,
destroyTest,
initTest,
TestContext,
Person,
testSql,
} from './test-setup.js'

for (const dialect of BUILT_IN_DIALECTS) {
describe(`${dialect}: sanitize identifiers`, () => {
let ctx: TestContext

before(async function () {
ctx = await initTest(this, dialect)
})

after(async () => {
await destroyTest(ctx)
})

it('should escape identifier quotes', async () => {
const obj: Record<string, unknown> = {
first_name: 'foo',
'last_name"`': 'bar',
}

const person = obj as unknown as Updateable<Person>
const query = ctx.db.updateTable('person').set(person)

testSql(query, dialect, {
postgres: {
sql: 'update "person" set "first_name" = $1, "last_name""`" = $2',
parameters: ['foo', 'bar'],
},
mysql: {
sql: 'update `person` set `first_name` = ?, `last_name"``` = ?',
parameters: ['foo', 'bar'],
},
sqlite: {
sql: 'update "person" set "first_name" = ?, "last_name""`" = ?',
parameters: ['foo', 'bar'],
},
})
})

it('should escape multiple identifier quotes', async () => {
const obj: Record<string, unknown> = {
first_name: 'foo',
'last_name""``': 'bar',
}

const person = obj as unknown as Updateable<Person>
const query = ctx.db.updateTable('person').set(person)

testSql(query, dialect, {
postgres: {
sql: 'update "person" set "first_name" = $1, "last_name""""``" = $2',
parameters: ['foo', 'bar'],
},
mysql: {
sql: 'update `person` set `first_name` = ?, `last_name""````` = ?',
parameters: ['foo', 'bar'],
},
sqlite: {
sql: 'update "person" set "first_name" = ?, "last_name""""``" = ?',
parameters: ['foo', 'bar'],
},
})
})
})
}
34 changes: 34 additions & 0 deletions test/node/src/select.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -640,5 +640,39 @@ for (const dialect of BUILT_IN_DIALECTS) {
})
}
}

it.skip('perf', async () => {
const ids = Array.from({ length: 100 }).map(() =>
Math.round(Math.random() * 1000)
)

function test() {
return ctx.db
.updateTable('person')
.set({
first_name: 'foo',
last_name: 'bar',
id: 100,
gender: 'other',
})
.where('id', 'in', ids)
.compile()
}

// Warmup
for (let i = 0; i < 1000; ++i) {
test()
}

const time = Date.now()
const N = 100000

for (let i = 0; i < N; ++i) {
test()
}

const endTime = Date.now()
console.log((endTime - time) / N)
})
})
}

0 comments on commit e22e03b

Please sign in to comment.