146 lines
4.4 KiB
TypeScript
146 lines
4.4 KiB
TypeScript
/**
|
|
* Unit tests for PostgreSqlDialect
|
|
*/
|
|
|
|
import { describe, it, expect } from 'vitest'
|
|
import { PostgreSqlDialect } from '@services/database/dialects/postgresql-dialect'
|
|
|
|
describe('PostgreSqlDialect', () => {
|
|
const dialect = new PostgreSqlDialect()
|
|
|
|
describe('dbType', () => {
|
|
it('should return postgresql', () => {
|
|
expect(dialect.dbType).toBe('postgresql')
|
|
})
|
|
})
|
|
|
|
describe('quoteTableName', () => {
|
|
it('should wrap schema and table in double quotes', () => {
|
|
expect(dialect.quoteTableName('dbo', 'Table')).toBe('"dbo"."Table"')
|
|
})
|
|
|
|
it('should handle arbitrary names', () => {
|
|
expect(dialect.quoteTableName('my_schema', 'my_table')).toBe('"my_schema"."my_table"')
|
|
})
|
|
})
|
|
|
|
describe('param', () => {
|
|
it('should return $N with 1-based index ($1 for param(0))', () => {
|
|
expect(dialect.param(0)).toBe('$1')
|
|
expect(dialect.param(1)).toBe('$2')
|
|
expect(dialect.param(3)).toBe('$4')
|
|
expect(dialect.param(10)).toBe('$11')
|
|
})
|
|
})
|
|
|
|
describe('params', () => {
|
|
it('should return comma-separated $N placeholders (1-based)', () => {
|
|
expect(dialect.params(1)).toBe('$1')
|
|
expect(dialect.params(3)).toBe('$1,$2,$3')
|
|
expect(dialect.params(5)).toBe('$1,$2,$3,$4,$5')
|
|
})
|
|
|
|
it('should return empty string for count 0', () => {
|
|
expect(dialect.params(0)).toBe('')
|
|
})
|
|
})
|
|
|
|
describe('currentTimestamp', () => {
|
|
it('should return CURRENT_TIMESTAMP', () => {
|
|
expect(dialect.currentTimestamp()).toBe('CURRENT_TIMESTAMP')
|
|
})
|
|
})
|
|
|
|
describe('upsert', () => {
|
|
it('should generate ON CONFLICT DO UPDATE SQL', () => {
|
|
const result = dialect.upsert({
|
|
table: '"dbo"."Table"',
|
|
keyColumns: ['id'],
|
|
allColumns: ['id', 'name', 'value'],
|
|
startParamIndex: 0
|
|
})
|
|
|
|
expect(result.sql).toContain('INSERT INTO "dbo"."Table" (id, name, value)')
|
|
expect(result.sql).toContain('VALUES ($1, $2, $3)')
|
|
expect(result.sql).toContain('ON CONFLICT ("id")')
|
|
expect(result.sql).toContain('DO UPDATE SET')
|
|
expect(result.sql).toContain('"name" = EXCLUDED."name"')
|
|
expect(result.sql).toContain('"value" = EXCLUDED."value"')
|
|
// key column should NOT appear in DO UPDATE SET
|
|
expect(result.sql).not.toContain('"id" = EXCLUDED."id"')
|
|
expect(result.nextParamIndex).toBe(3)
|
|
})
|
|
|
|
it('should handle composite key columns with all double-quoted', () => {
|
|
const result = dialect.upsert({
|
|
table: '"dbo"."Table"',
|
|
keyColumns: ['id', 'code'],
|
|
allColumns: ['id', 'code', 'name'],
|
|
startParamIndex: 0
|
|
})
|
|
|
|
expect(result.sql).toContain('ON CONFLICT ("id", "code")')
|
|
expect(result.sql).toContain('"name" = EXCLUDED."name"')
|
|
expect(result.nextParamIndex).toBe(3)
|
|
})
|
|
|
|
it('should use startParamIndex for parameter numbering', () => {
|
|
const result = dialect.upsert({
|
|
table: '"dbo"."Table"',
|
|
keyColumns: ['id'],
|
|
allColumns: ['id', 'name'],
|
|
startParamIndex: 5
|
|
})
|
|
|
|
// startParamIndex=5 means $6, $7 (1-based: index+1)
|
|
expect(result.sql).toContain('$6')
|
|
expect(result.sql).toContain('$7')
|
|
expect(result.nextParamIndex).toBe(7)
|
|
})
|
|
})
|
|
|
|
describe('paginate', () => {
|
|
it('should append LIMIT and OFFSET with literal values', () => {
|
|
const result = dialect.paginate({
|
|
sql: 'SELECT * FROM "dbo"."Table"',
|
|
limit: 10,
|
|
offset: 20,
|
|
paramIndex: 0
|
|
})
|
|
|
|
expect(result.sql).toBe('SELECT * FROM "dbo"."Table" LIMIT 10 OFFSET 20')
|
|
expect(result.nextParamIndex).toBe(0)
|
|
})
|
|
|
|
it('should use 0 as default offset', () => {
|
|
const result = dialect.paginate({
|
|
sql: 'SELECT * FROM "dbo"."Table"',
|
|
limit: 50,
|
|
paramIndex: 3
|
|
})
|
|
|
|
expect(result.sql).toBe('SELECT * FROM "dbo"."Table" LIMIT 50 OFFSET 0')
|
|
expect(result.nextParamIndex).toBe(3)
|
|
})
|
|
|
|
it('should not change nextParamIndex (no params added)', () => {
|
|
const result = dialect.paginate({
|
|
sql: 'SELECT * FROM "dbo"."Table"',
|
|
limit: 100,
|
|
offset: 50,
|
|
paramIndex: 10
|
|
})
|
|
|
|
expect(result.nextParamIndex).toBe(10)
|
|
})
|
|
})
|
|
|
|
describe('maxBatchRows', () => {
|
|
it('should return 1000 regardless of columns', () => {
|
|
expect(dialect.maxBatchRows(1)).toBe(1000)
|
|
expect(dialect.maxBatchRows(10)).toBe(1000)
|
|
expect(dialect.maxBatchRows(100)).toBe(1000)
|
|
})
|
|
})
|
|
})
|