chore: import upstream snapshot with attribution
CI / Migrate Dev DB (push) Has been skipped
CI / Detect Version (push) Has been cancelled
CI / Migrate DB (push) Has been cancelled
CI / Build Dev ECR (./docker/app.Dockerfile, ECR_APP) (push) Has been cancelled
CI / Build Dev ECR (./docker/db.Dockerfile, ECR_MIGRATIONS) (push) Has been cancelled
CI / Build Dev ECR (./docker/pii.Dockerfile, ECR_PII) (push) Has been cancelled
CI / Build Dev ECR (./docker/realtime.Dockerfile, ECR_REALTIME) (push) Has been cancelled
CI / Deploy Trigger.dev (Dev) (push) Has been cancelled
CI / Build AMD64 (./docker/app.Dockerfile, ECR_APP, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build AMD64 (./docker/db.Dockerfile, ECR_MIGRATIONS, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build AMD64 (./docker/pii.Dockerfile, ECR_PII, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build AMD64 (./docker/realtime.Dockerfile, ECR_REALTIME, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/app.Dockerfile, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/db.Dockerfile, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/pii.Dockerfile, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/realtime.Dockerfile, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Check Docs Changes (push) Has been cancelled
CI / Process Docs (push) Has been cancelled
CI / Create GitHub Release (push) Has been cancelled
CI / Test and Build (push) Has been cancelled
Publish CLI Package / publish-npm (push) Has been cancelled
Publish Python SDK / publish-pypi (push) Has been cancelled
Publish TypeScript SDK / publish-npm (push) Has been cancelled

This commit is contained in:
wehub-resource-sync
2026-07-13 13:20:55 +08:00
commit d25d482dc2
13754 changed files with 4996608 additions and 0 deletions
@@ -0,0 +1,405 @@
/**
* @vitest-environment node
*/
import { dbChainMock, dbChainMockFns, resetDbChainMock } from '@sim/testing'
import { beforeEach, describe, expect, it, vi } from 'vitest'
import { deleteColumn, renameColumn } from '@/lib/table/columns/service'
import {
batchInsertRows,
insertRow,
replaceTableRows,
updateRow,
upsertRow,
} from '@/lib/table/rows/service'
import type { TableDefinition } from '@/lib/table/types'
import { getUniqueColumns } from '@/lib/table/validation'
vi.mock('@sim/db', () => dbChainMock)
// Capacity is exercised in billing.test.ts; here it's a no-op so the timeout-scaling
// suites can use large synthetic row counts without tripping the plan limit.
vi.mock('@/lib/table/billing', () => ({
assertRowCapacity: vi.fn().mockResolvedValue(1_000_000),
notifyTableRowUsage: vi.fn(),
getMaxRowsPerTable: vi.fn().mockResolvedValue(1_000_000),
wouldExceedRowLimit: () => false,
TableRowLimitError: class TableRowLimitError extends Error {},
}))
vi.mock('@/lib/table/validation', () => ({
validateRowSize: vi.fn(() => ({ valid: true, errors: [] })),
validateRowAgainstSchema: vi.fn(() => ({ valid: true, errors: [] })),
coerceRowToSchema: vi.fn(() => ({ valid: true, errors: [] })),
coerceRowValues: vi.fn(),
validateTableName: vi.fn(() => ({ valid: true, errors: [] })),
validateTableSchema: vi.fn(() => ({ valid: true, errors: [] })),
getUniqueColumns: vi.fn(() => []),
checkUniqueConstraintsDb: vi.fn(async () => ({ valid: true, errors: [] })),
checkBatchUniqueConstraintsDb: vi.fn(async () => ({ valid: true, errors: [] })),
}))
/**
* Inspects the queued `trx.execute(...)` calls for SQL containing `substring`.
* Works with both `sql\`...\`` (produces `{ strings, values }`) and `sql.raw(...)`
* (produces `{ rawSql }`) from the global drizzle mock.
*/
function findExecutedSqlContaining(substring: string): boolean {
return dbChainMockFns.execute.mock.calls.some(([arg]) => {
if (!arg || typeof arg !== 'object') return false
const a = arg as Record<string, unknown>
if (Array.isArray(a.strings)) {
return (a.strings as string[]).some((s) => typeof s === 'string' && s.includes(substring))
}
if (typeof a.rawSql === 'string') {
return (a.rawSql as string).includes(substring)
}
return false
})
}
function findExecutedRawSql(substring: string): string | undefined {
for (const [arg] of dbChainMockFns.execute.mock.calls) {
if (!arg || typeof arg !== 'object') continue
const raw = (arg as { rawSql?: unknown }).rawSql
if (typeof raw === 'string' && raw.includes(substring)) return raw
}
return undefined
}
const EXISTING_ROW = {
id: 'row-1',
tableId: 'tbl-1',
workspaceId: 'ws-1',
data: { name: 'Alice', age: 30 },
position: 1,
createdAt: new Date('2024-01-01'),
updatedAt: new Date('2024-01-01'),
}
const TABLE: TableDefinition = {
id: 'tbl-1',
name: 'People',
description: null,
schema: {
columns: [
{ name: 'name', type: 'string' },
{ name: 'age', type: 'number' },
],
},
metadata: null,
rowCount: 0,
maxRows: 1000,
workspaceId: 'ws-1',
createdBy: 'user-1',
archivedAt: null,
createdAt: new Date('2024-01-01'),
updatedAt: new Date('2024-01-01'),
}
describe('updateRow — partial merge', () => {
beforeEach(() => {
vi.clearAllMocks()
resetDbChainMock()
dbChainMockFns.limit.mockResolvedValue([EXISTING_ROW])
})
it('preserves columns not included in the partial update', async () => {
const result = await updateRow(
{ tableId: 'tbl-1', rowId: 'row-1', data: { age: 31 }, workspaceId: 'ws-1' },
TABLE,
'req-1'
)
expect(result.data).toEqual({ name: 'Alice', age: 31 })
expect(dbChainMockFns.set).toHaveBeenCalledWith(
expect.objectContaining({ data: { name: 'Alice', age: 31 } })
)
})
it('allows updating a single column without affecting others', async () => {
const result = await updateRow(
{ tableId: 'tbl-1', rowId: 'row-1', data: { name: 'Bob' }, workspaceId: 'ws-1' },
TABLE,
'req-1'
)
expect(result.data).toEqual({ name: 'Bob', age: 30 })
expect(dbChainMockFns.set).toHaveBeenCalledWith(
expect.objectContaining({ data: { name: 'Bob', age: 30 } })
)
})
it('allows explicitly nulling a field while preserving others', async () => {
const result = await updateRow(
{ tableId: 'tbl-1', rowId: 'row-1', data: { age: null }, workspaceId: 'ws-1' },
TABLE,
'req-1'
)
expect(result.data).toEqual({ name: 'Alice', age: null })
expect(dbChainMockFns.set).toHaveBeenCalledWith(
expect.objectContaining({ data: { name: 'Alice', age: null } })
)
})
it('handles a full-row update correctly (idempotent merge)', async () => {
const result = await updateRow(
{ tableId: 'tbl-1', rowId: 'row-1', data: { name: 'Bob', age: 25 }, workspaceId: 'ws-1' },
TABLE,
'req-1'
)
expect(result.data).toEqual({ name: 'Bob', age: 25 })
})
it('throws when the row does not exist', async () => {
dbChainMockFns.limit.mockResolvedValueOnce([])
await expect(
updateRow(
{ tableId: 'tbl-1', rowId: 'row-missing', data: { age: 31 }, workspaceId: 'ws-1' },
TABLE,
'req-1'
)
).rejects.toThrow('Row not found')
})
})
describe('insertRow — position race safety (migration 0198 + advisory lock)', () => {
beforeEach(() => {
vi.resetAllMocks()
resetDbChainMock()
vi.mocked(getUniqueColumns).mockReturnValue([])
})
it('auto-position inserts acquire the per-table advisory lock before reading max(position)', async () => {
await expect(
insertRow({ tableId: 'tbl-1', data: { name: 'a' }, workspaceId: 'ws-1' }, TABLE, 'req-1')
).rejects.toBeDefined()
expect(findExecutedSqlContaining('pg_advisory_xact_lock')).toBe(true)
expect(findExecutedSqlContaining('hashtextextended')).toBe(true)
})
it('explicit-position inserts also acquire the advisory lock to serialize order-key minting', async () => {
await expect(
insertRow(
{ tableId: 'tbl-1', data: { name: 'a' }, workspaceId: 'ws-1', position: 5 },
TABLE,
'req-1'
)
).rejects.toBeDefined()
// A position-based insert resolves its order_key from the neighbor at that
// rank; the lock serializes concurrent minting at the same slot.
expect(findExecutedSqlContaining('pg_advisory_xact_lock')).toBe(true)
})
it('batchInsertRows acquires the advisory lock (always auto-positioned)', async () => {
await expect(
batchInsertRows(
{ tableId: 'tbl-1', rows: [{ name: 'a' }, { name: 'b' }], workspaceId: 'ws-1' },
TABLE,
'req-1'
)
).rejects.toBeDefined()
expect(findExecutedSqlContaining('pg_advisory_xact_lock')).toBe(true)
})
it('upsertRow skips the advisory lock on the update path (match found)', async () => {
vi.mocked(getUniqueColumns).mockReturnValue([{ name: 'name', type: 'string', unique: true }])
dbChainMockFns.limit.mockResolvedValueOnce([
{
id: 'row-1',
tableId: 'tbl-1',
workspaceId: 'ws-1',
data: { name: 'Alice', age: 30 },
position: 0,
createdAt: new Date(),
updatedAt: new Date(),
},
])
dbChainMockFns.returning.mockResolvedValueOnce([
{
id: 'row-1',
tableId: 'tbl-1',
workspaceId: 'ws-1',
data: { name: 'Alice', age: 31 },
position: 0,
createdAt: new Date(),
updatedAt: new Date(),
},
])
await upsertRow(
{
tableId: 'tbl-1',
workspaceId: 'ws-1',
data: { name: 'Alice', age: 31 },
conflictTarget: 'name',
},
TABLE,
'req-1'
)
expect(findExecutedSqlContaining('pg_advisory_xact_lock')).toBe(false)
})
it('upsertRow acquires the advisory lock on the insert path (no match)', async () => {
vi.mocked(getUniqueColumns).mockReturnValue([{ name: 'name', type: 'string', unique: true }])
// Initial existing-row check + post-lock re-check both find no match.
dbChainMockFns.limit.mockResolvedValueOnce([])
dbChainMockFns.limit.mockResolvedValueOnce([])
await expect(
upsertRow(
{
tableId: 'tbl-1',
workspaceId: 'ws-1',
data: { name: 'Bob', age: 25 },
conflictTarget: 'name',
},
TABLE,
'req-1'
)
).rejects.toBeDefined()
expect(findExecutedSqlContaining('pg_advisory_xact_lock')).toBe(true)
})
it('upsertRow re-checks after acquiring the lock and switches to UPDATE when a racing tx inserted the row', async () => {
vi.mocked(getUniqueColumns).mockReturnValue([{ name: 'name', type: 'string', unique: true }])
// Initial existing-row check: no match (another tx has not committed yet).
dbChainMockFns.limit.mockResolvedValueOnce([])
// Post-lock re-check: a racing tx just inserted the row.
const racedRow = {
id: 'row-raced',
tableId: 'tbl-1',
workspaceId: 'ws-1',
data: { name: 'Bob', age: 25 },
position: 0,
createdAt: new Date(),
updatedAt: new Date(),
}
dbChainMockFns.limit.mockResolvedValueOnce([racedRow])
// UPDATE returning the patched row.
dbChainMockFns.returning.mockResolvedValueOnce([
{ ...racedRow, data: { name: 'Bob', age: 26 } },
])
const result = await upsertRow(
{
tableId: 'tbl-1',
workspaceId: 'ws-1',
data: { name: 'Bob', age: 26 },
conflictTarget: 'name',
},
TABLE,
'req-1'
)
expect(findExecutedSqlContaining('pg_advisory_xact_lock')).toBe(true)
expect(result.operation).toBe('update')
expect(result.row.id).toBe('row-raced')
expect(dbChainMockFns.update).toHaveBeenCalled()
expect(dbChainMockFns.insert).not.toHaveBeenCalled()
})
})
describe('mutation paths — SET LOCAL timeouts', () => {
beforeEach(() => {
vi.clearAllMocks()
resetDbChainMock()
})
it('insertRow sets the default 10s/3s/5s timeouts', async () => {
await expect(
insertRow({ tableId: 'tbl-1', data: { name: 'a' }, workspaceId: 'ws-1' }, TABLE, 'req-1')
).rejects.toBeDefined()
expect(findExecutedRawSql("SET LOCAL statement_timeout = '10000ms'")).toBeDefined()
expect(findExecutedRawSql("SET LOCAL lock_timeout = '3000ms'")).toBeDefined()
expect(
findExecutedRawSql("SET LOCAL idle_in_transaction_session_timeout = '5000ms'")
).toBeDefined()
})
it('batchInsertRows raises statement_timeout to 60s', async () => {
await expect(
batchInsertRows(
{ tableId: 'tbl-1', rows: [{ name: 'a' }], workspaceId: 'ws-1' },
TABLE,
'req-1'
)
).rejects.toBeDefined()
expect(findExecutedRawSql("SET LOCAL statement_timeout = '60000ms'")).toBeDefined()
})
it('replaceTableRows scales statement_timeout with (existing + new) row count', async () => {
const bigTable: TableDefinition = { ...TABLE, rowCount: 100_000, maxRows: 1_000_000 }
const payload = Array.from({ length: 50_000 }, (_, i) => ({ name: `row-${i}` }))
await replaceTableRows(
{ tableId: 'tbl-1', workspaceId: 'ws-1', rows: payload },
bigTable,
'req-1'
)
// (100_000 + 50_000) × 3ms/row = 450_000ms; above 120_000 floor, below 600_000 cap
expect(findExecutedRawSql("SET LOCAL statement_timeout = '450000ms'")).toBeDefined()
})
it('replaceTableRows caps scaled timeout at 10 minutes for very large tables', async () => {
const hugeTable: TableDefinition = { ...TABLE, rowCount: 10_000_000, maxRows: 20_000_000 }
await replaceTableRows({ tableId: 'tbl-1', workspaceId: 'ws-1', rows: [] }, hugeTable, 'req-1')
// 10M × 3ms = 30M ms, capped at 600_000ms (10 min)
expect(findExecutedRawSql("SET LOCAL statement_timeout = '600000ms'")).toBeDefined()
})
it('replaceTableRows uses the 120s floor on small tables', async () => {
const smallTable: TableDefinition = { ...TABLE, rowCount: 10 }
await replaceTableRows(
{ tableId: 'tbl-1', workspaceId: 'ws-1', rows: [{ name: 'a' }, { name: 'b' }] },
smallTable,
'req-1'
)
// 12 × 3ms = 36ms → floored at 120_000ms
expect(findExecutedRawSql("SET LOCAL statement_timeout = '120000ms'")).toBeDefined()
})
it('renameColumn is metadata-only — no per-row JSONB rewrite regardless of row count', async () => {
dbChainMockFns.limit.mockResolvedValueOnce([{ ...TABLE, rowCount: 500_000 }])
await renameColumn({ tableId: 'tbl-1', oldName: 'name', newName: 'full_name' }, 'req-1')
// Row data is keyed by the column's stable id (unchanged by a rename), so no
// `user_table_rows` key rewrite is executed — and thus no scaled timeout.
expect(findExecutedSqlContaining('jsonb_build_object')).toBe(false)
})
it('deleteColumn uses the 60s floor on small tables', async () => {
dbChainMockFns.limit.mockResolvedValueOnce([{ ...TABLE, rowCount: 100 }])
await deleteColumn({ tableId: 'tbl-1', columnName: 'age' }, 'req-1')
// 100 × 2ms = 200ms → floored at 60_000ms
expect(findExecutedRawSql("SET LOCAL statement_timeout = '60000ms'")).toBeDefined()
})
it('replaceTableRows acquires the per-table advisory lock to serialize concurrent replaces', async () => {
await replaceTableRows(
{ tableId: 'tbl-1', workspaceId: 'ws-1', rows: [{ name: 'a' }] },
{ ...TABLE, rowCount: 5 },
'req-1'
)
expect(findExecutedSqlContaining('pg_advisory_xact_lock')).toBe(true)
expect(findExecutedSqlContaining('hashtextextended')).toBe(true)
})
})