orez 0.2.27 → 0.2.30
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cf-do/worker.d.ts +3 -0
- package/dist/cf-do/worker.d.ts.map +1 -1
- package/dist/cf-do/worker.js +37 -15
- package/dist/cf-do/worker.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -1
- package/package.json +3 -4
- package/src/admin/admin-data.test.ts +0 -348
- package/src/admin/http-proxy.ts +0 -252
- package/src/admin/log-store.ts +0 -192
- package/src/admin/server.ts +0 -471
- package/src/admin/ui.ts +0 -1322
- package/src/bench/proxy-throughput.bench.ts +0 -343
- package/src/bench/serial-mutations.bench.ts +0 -270
- package/src/browser.ts +0 -203
- package/src/cf-do/.wrangler/cache/cf.json +0 -1
- package/src/cf-do/.wrangler/state/v3/cache/miniflare-CacheObject/metadata.sqlite +0 -0
- package/src/cf-do/.wrangler/state/v3/cache/miniflare-CacheObject/metadata.sqlite-shm +0 -0
- package/src/cf-do/.wrangler/state/v3/cache/miniflare-CacheObject/metadata.sqlite-wal +0 -0
- package/src/cf-do/.wrangler/state/v3/do/zero-do-ZeroDO/0ffaabee41a60e04dd0eb7db3073f0a40139e6a97ccd26823967acb652b89a7b.sqlite +0 -0
- package/src/cf-do/.wrangler/state/v3/do/zero-do-ZeroDO/metadata.sqlite +0 -0
- package/src/cf-do/.wrangler/state/v3/do/zero-do-ZeroDO/metadata.sqlite-shm +0 -0
- package/src/cf-do/.wrangler/state/v3/do/zero-do-ZeroDO/metadata.sqlite-wal +0 -0
- package/src/cf-do/.wrangler/tmp/bundle-0z4CpE/middleware-insertion-facade.js +0 -11
- package/src/cf-do/.wrangler/tmp/bundle-0z4CpE/middleware-loader.entry.ts +0 -134
- package/src/cf-do/.wrangler/tmp/bundle-vYmw0E/middleware-insertion-facade.js +0 -11
- package/src/cf-do/.wrangler/tmp/bundle-vYmw0E/middleware-loader.entry.ts +0 -134
- package/src/cf-do/.wrangler/tmp/dev-cbILNo/worker.js +0 -1059
- package/src/cf-do/.wrangler/tmp/dev-cbILNo/worker.js.map +0 -8
- package/src/cf-do/.wrangler/tmp/dev-qbho19/worker.js +0 -1059
- package/src/cf-do/.wrangler/tmp/dev-qbho19/worker.js.map +0 -8
- package/src/cf-do/ARCHITECTURE.md +0 -93
- package/src/cf-do/CHAT_E2E.md +0 -213
- package/src/cf-do/watermark.test.ts +0 -103
- package/src/cf-do/watermark.ts +0 -118
- package/src/cf-do/worker.ts +0 -1041
- package/src/cf-do/wrangler.toml +0 -11
- package/src/cf-pglite/README.md +0 -19
- package/src/change-tracking.ts +0 -25
- package/src/child-process.test.ts +0 -147
- package/src/child-process.ts +0 -90
- package/src/cli-entry.ts +0 -72
- package/src/cli.test.ts +0 -40
- package/src/cli.ts +0 -1214
- package/src/config.ts +0 -150
- package/src/do-sql-tracking.test.ts +0 -19
- package/src/do-sql-tracking.ts +0 -19
- package/src/index.ts +0 -1215
- package/src/integration/integration.test.ts +0 -517
- package/src/integration/native-binary.guard.test.ts +0 -13
- package/src/integration/native-startup.test.ts +0 -44
- package/src/integration/replication-latency.test.ts +0 -428
- package/src/integration/restore-live-stress.test.ts +0 -433
- package/src/integration/restore-reset.test.ts +0 -400
- package/src/integration/restore.test.ts +0 -274
- package/src/integration/test-permissions.ts +0 -147
- package/src/load-config.ts +0 -46
- package/src/log.ts +0 -96
- package/src/mutex.ts +0 -47
- package/src/pg-proxy-browser.singledb.test.ts +0 -233
- package/src/pg-proxy-browser.ts +0 -2022
- package/src/pg-proxy-do-backend.test.ts +0 -3890
- package/src/pg-proxy-do-backend.ts +0 -7191
- package/src/pg-proxy.ts +0 -1087
- package/src/pg-sqlite-compiler/README.md +0 -53
- package/src/pg-sqlite-compiler/catalog/seed.ts +0 -524
- package/src/pg-sqlite-compiler/fixtures/pgsqlite/arithmetic.json +0 -307
- package/src/pg-sqlite-compiler/fixtures/pgsqlite/array.json +0 -377
- package/src/pg-sqlite-compiler/fixtures/pgsqlite/cast.json +0 -12
- package/src/pg-sqlite-compiler/fixtures/pgsqlite/catalog.json +0 -447
- package/src/pg-sqlite-compiler/fixtures/pgsqlite/create-table.json +0 -32
- package/src/pg-sqlite-compiler/fixtures/pgsqlite/datetime.json +0 -397
- package/src/pg-sqlite-compiler/fixtures/pgsqlite/enum.json +0 -337
- package/src/pg-sqlite-compiler/fixtures/pgsqlite/insert.json +0 -337
- package/src/pg-sqlite-compiler/fixtures/pgsqlite/json.json +0 -537
- package/src/pg-sqlite-compiler/fixtures/pgsqlite/misc.json +0 -1837
- package/src/pg-sqlite-compiler/index.ts +0 -73
- package/src/pg-sqlite-compiler/integration.test.ts +0 -136
- package/src/pg-sqlite-compiler/passes/ast-utils.ts +0 -113
- package/src/pg-sqlite-compiler/passes/catalog.ts +0 -65
- package/src/pg-sqlite-compiler/passes/datetime.ts +0 -74
- package/src/pg-sqlite-compiler/passes/index.ts +0 -49
- package/src/pg-sqlite-compiler/passes/types.ts +0 -156
- package/src/pg-sqlite-compiler/smoke.test.ts +0 -69
- package/src/pg-sqlite-compiler/test/catalog.test.ts +0 -171
- package/src/pg-sqlite-compiler/test/corpus.test.ts +0 -161
- package/src/pg-sqlite-compiler/test/datetime.oracle.test.ts +0 -102
- package/src/pg-sqlite-compiler/test/oracle.ts +0 -237
- package/src/pg-sqlite-compiler/test/types.test.ts +0 -109
- package/src/pg-sqlite-compiler/types.ts +0 -63
- package/src/pglite-ipc.test.ts +0 -116
- package/src/pglite-ipc.ts +0 -266
- package/src/pglite-manager.ts +0 -557
- package/src/pglite-web-proxy.test.ts +0 -57
- package/src/pglite-web-proxy.ts +0 -221
- package/src/pglite-web-worker.ts +0 -152
- package/src/pglite-worker-thread.ts +0 -253
- package/src/port.ts +0 -25
- package/src/process-title.ts +0 -9
- package/src/recovery.ts +0 -155
- package/src/replication/change-tracker.test.ts +0 -357
- package/src/replication/change-tracker.ts +0 -279
- package/src/replication/handler.test.ts +0 -511
- package/src/replication/handler.ts +0 -1190
- package/src/replication/pgoutput-encoder.test.ts +0 -697
- package/src/replication/pgoutput-encoder.ts +0 -373
- package/src/replication/tcp-replication.test.ts +0 -876
- package/src/replication/zero-compat.test.ts +0 -1150
- package/src/restore-stress.test.ts +0 -188
- package/src/s3-local.ts +0 -203
- package/src/shim/hooks.mjs +0 -120
- package/src/shim/register.mjs +0 -4
- package/src/sqlite-mode/apply-mode.ts +0 -224
- package/src/sqlite-mode/index.ts +0 -15
- package/src/sqlite-mode/native-binary.ts +0 -89
- package/src/sqlite-mode/package-resolve.ts +0 -17
- package/src/sqlite-mode/resolve-mode.ts +0 -80
- package/src/sqlite-mode/shim-template.ts +0 -159
- package/src/sqlite-mode/sqlite-mode.test.ts +0 -427
- package/src/sqlite-mode/types.ts +0 -30
- package/src/vite-plugin.ts +0 -67
- package/src/wasm-sqlite.test.ts +0 -537
- package/src/worker/browser-admin.ts +0 -52
- package/src/worker/browser-build-config.test.ts +0 -71
- package/src/worker/browser-build-config.ts +0 -109
- package/src/worker/browser-embed-admin.test.ts +0 -75
- package/src/worker/browser-embed.ts +0 -345
- package/src/worker/cf-patches.ts +0 -384
- package/src/worker/embed-integration.test.ts +0 -321
- package/src/worker/index.ts +0 -138
- package/src/worker/shims/fastify.test.ts +0 -255
- package/src/worker/shims/fastify.ts +0 -306
- package/src/worker/shims/http-service.test.ts +0 -355
- package/src/worker/shims/http-service.ts +0 -293
- package/src/worker/shims/node-stub.ts +0 -290
- package/src/worker/shims/oxfmt.ts +0 -3
- package/src/worker/shims/postgres-browser.ts +0 -59
- package/src/worker/shims/postgres-socket.test.ts +0 -576
- package/src/worker/shims/postgres-socket.ts +0 -310
- package/src/worker/shims/postgres.test.ts +0 -364
- package/src/worker/shims/postgres.ts +0 -1454
- package/src/worker/shims/sqlite-browser.test.ts +0 -233
- package/src/worker/shims/sqlite-browser.ts +0 -175
- package/src/worker/shims/sqlite.test.ts +0 -786
- package/src/worker/shims/sqlite.ts +0 -978
- package/src/worker/shims/stream-browser.ts +0 -15
- package/src/worker/shims/ws-browser.test.ts +0 -205
- package/src/worker/shims/ws-browser.ts +0 -248
- package/src/worker/shims/ws.test.ts +0 -288
- package/src/worker/shims/ws.ts +0 -467
- package/src/worker/shims/zero-process-env.ts +0 -11
- package/src/worker/types.ts +0 -75
- package/src/worker/worker-integration.test.ts +0 -223
- package/src/worker/worker.test.ts +0 -136
- package/src/worker/zero-cache-embed-cf.ts +0 -463
- package/src/worker/zero-cache-embed.ts +0 -277
|
@@ -1,237 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* pgsqlite-backed oracle for compiler quality.
|
|
3
|
-
*
|
|
4
|
-
* Spawns a real pgsqlite server, sends PG SQL via the PG wire protocol,
|
|
5
|
-
* captures the result set. Compares against running the same query through
|
|
6
|
-
* our compiler + bun:sqlite. Equivalence at the result-set level is what we
|
|
7
|
-
* actually care about — pgsqlite is the oracle, not the spec.
|
|
8
|
-
*
|
|
9
|
-
* The pgsqlite binary path comes from `vendor/pgsqlite/.resolved-path`,
|
|
10
|
-
* populated by `scripts/pgsqlite/ensure.ts`. If empty, oracle tests should
|
|
11
|
-
* be marked `it.skip` so the suite still runs without pgsqlite installed.
|
|
12
|
-
*/
|
|
13
|
-
import { spawn, type ChildProcess } from 'node:child_process'
|
|
14
|
-
import { existsSync, mkdtempSync, readFileSync, rmSync } from 'node:fs'
|
|
15
|
-
import { createConnection, createServer } from 'node:net'
|
|
16
|
-
import { tmpdir } from 'node:os'
|
|
17
|
-
import { resolve } from 'node:path'
|
|
18
|
-
|
|
19
|
-
import Database from '@rocicorp/zero-sqlite3'
|
|
20
|
-
|
|
21
|
-
const VENDOR_PATH_FILE = resolve(
|
|
22
|
-
import.meta.dirname,
|
|
23
|
-
'..',
|
|
24
|
-
'..',
|
|
25
|
-
'..',
|
|
26
|
-
'vendor',
|
|
27
|
-
'pgsqlite',
|
|
28
|
-
'.resolved-path'
|
|
29
|
-
)
|
|
30
|
-
|
|
31
|
-
export function pgsqliteBinPath(): string | null {
|
|
32
|
-
if (!existsSync(VENDOR_PATH_FILE)) return null
|
|
33
|
-
const path = readFileSync(VENDOR_PATH_FILE, 'utf-8').trim()
|
|
34
|
-
return path && existsSync(path) ? path : null
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
export const ORACLE_AVAILABLE = pgsqliteBinPath() !== null
|
|
38
|
-
|
|
39
|
-
export interface OracleServer {
|
|
40
|
-
port: number
|
|
41
|
-
dbPath: string
|
|
42
|
-
stop(): Promise<void>
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* Pick a free TCP port by binding ephemeral and reading what we got.
|
|
47
|
-
* Then close immediately and hand the port to pgsqlite. There's a tiny TOCTOU
|
|
48
|
-
* window where another process could grab it before pgsqlite binds, but
|
|
49
|
-
* vitest's parallel test files all go through this helper, so the only races
|
|
50
|
-
* are against unrelated processes on the host — vanishingly unlikely in CI.
|
|
51
|
-
*/
|
|
52
|
-
async function getFreePort(): Promise<number> {
|
|
53
|
-
return new Promise((resolveFn, reject) => {
|
|
54
|
-
const server = createServer()
|
|
55
|
-
server.unref()
|
|
56
|
-
server.on('error', reject)
|
|
57
|
-
server.listen(0, '127.0.0.1', () => {
|
|
58
|
-
const addr = server.address()
|
|
59
|
-
if (!addr || typeof addr === 'string') {
|
|
60
|
-
server.close()
|
|
61
|
-
reject(new Error('failed to get free port'))
|
|
62
|
-
return
|
|
63
|
-
}
|
|
64
|
-
const port = addr.port
|
|
65
|
-
server.close(() => resolveFn(port))
|
|
66
|
-
})
|
|
67
|
-
})
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
async function probePort(port: number, timeoutMs: number): Promise<boolean> {
|
|
71
|
-
return new Promise((resolveFn) => {
|
|
72
|
-
const sock = createConnection({ host: '127.0.0.1', port })
|
|
73
|
-
const cleanup = (val: boolean) => {
|
|
74
|
-
try {
|
|
75
|
-
sock.destroy()
|
|
76
|
-
} catch {}
|
|
77
|
-
resolveFn(val)
|
|
78
|
-
}
|
|
79
|
-
const timer = setTimeout(() => cleanup(false), timeoutMs)
|
|
80
|
-
sock.once('connect', () => {
|
|
81
|
-
clearTimeout(timer)
|
|
82
|
-
cleanup(true)
|
|
83
|
-
})
|
|
84
|
-
sock.once('error', () => {
|
|
85
|
-
clearTimeout(timer)
|
|
86
|
-
cleanup(false)
|
|
87
|
-
})
|
|
88
|
-
})
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
/**
|
|
92
|
-
* Start a pgsqlite server on an OS-assigned ephemeral port with an ephemeral
|
|
93
|
-
* database. Throws on probe timeout. Caller is responsible for calling
|
|
94
|
-
* `stop()` in a `finally` / `afterAll` hook — `stop()` awaits child exit
|
|
95
|
-
* and cleans up the tempdir.
|
|
96
|
-
*/
|
|
97
|
-
export async function startPgsqliteServer(): Promise<OracleServer> {
|
|
98
|
-
const bin = pgsqliteBinPath()
|
|
99
|
-
if (!bin) throw new Error('pgsqlite binary not available')
|
|
100
|
-
|
|
101
|
-
const port = await getFreePort()
|
|
102
|
-
const tmpDir = mkdtempSync(resolve(tmpdir(), 'orez-oracle-'))
|
|
103
|
-
const dbPath = resolve(tmpDir, 'pg.db')
|
|
104
|
-
|
|
105
|
-
const proc: ChildProcess = spawn(
|
|
106
|
-
bin,
|
|
107
|
-
['--port', String(port), '--database', dbPath, '--log-level', 'error'],
|
|
108
|
-
{ stdio: ['ignore', 'pipe', 'pipe'] }
|
|
109
|
-
)
|
|
110
|
-
|
|
111
|
-
const exited: Promise<void> = new Promise((res) => proc.once('exit', () => res()))
|
|
112
|
-
|
|
113
|
-
// wait for "ready" — poll until the server accepts a connection or we time out
|
|
114
|
-
let ready = false
|
|
115
|
-
const start = Date.now()
|
|
116
|
-
while (Date.now() - start < 10_000) {
|
|
117
|
-
if (await probePort(port, 250)) {
|
|
118
|
-
ready = true
|
|
119
|
-
break
|
|
120
|
-
}
|
|
121
|
-
if (proc.exitCode !== null) {
|
|
122
|
-
throw new Error(`pgsqlite exited before becoming ready (code=${proc.exitCode})`)
|
|
123
|
-
}
|
|
124
|
-
await new Promise((r) => setTimeout(r, 50))
|
|
125
|
-
}
|
|
126
|
-
if (!ready) {
|
|
127
|
-
try {
|
|
128
|
-
proc.kill('SIGKILL')
|
|
129
|
-
} catch {}
|
|
130
|
-
try {
|
|
131
|
-
rmSync(tmpDir, { recursive: true, force: true })
|
|
132
|
-
} catch {}
|
|
133
|
-
throw new Error(`pgsqlite did not become ready on port ${port} within 10s`)
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
return {
|
|
137
|
-
port,
|
|
138
|
-
dbPath,
|
|
139
|
-
async stop() {
|
|
140
|
-
try {
|
|
141
|
-
proc.kill('SIGTERM')
|
|
142
|
-
} catch {}
|
|
143
|
-
// wait up to 2s for graceful exit, then SIGKILL
|
|
144
|
-
const killTimer = setTimeout(() => {
|
|
145
|
-
try {
|
|
146
|
-
proc.kill('SIGKILL')
|
|
147
|
-
} catch {}
|
|
148
|
-
}, 2_000)
|
|
149
|
-
try {
|
|
150
|
-
await exited
|
|
151
|
-
} finally {
|
|
152
|
-
clearTimeout(killTimer)
|
|
153
|
-
}
|
|
154
|
-
try {
|
|
155
|
-
rmSync(tmpDir, { recursive: true, force: true })
|
|
156
|
-
} catch {}
|
|
157
|
-
},
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
/**
|
|
162
|
-
* Helper: open a postgres.js client to a running pgsqlite server.
|
|
163
|
-
* Requires `postgres` to be available (we already ship it via @rocicorp/zero).
|
|
164
|
-
*/
|
|
165
|
-
export async function connectOracle(server: OracleServer): Promise<{
|
|
166
|
-
exec: (sql: string, params?: any[]) => Promise<any[]>
|
|
167
|
-
end: () => Promise<void>
|
|
168
|
-
}> {
|
|
169
|
-
const { default: postgres } = await import('postgres')
|
|
170
|
-
const sql = postgres({
|
|
171
|
-
host: '127.0.0.1',
|
|
172
|
-
port: server.port,
|
|
173
|
-
user: 'oracle',
|
|
174
|
-
password: '',
|
|
175
|
-
database: 'main',
|
|
176
|
-
ssl: false,
|
|
177
|
-
max: 1,
|
|
178
|
-
idle_timeout: 5,
|
|
179
|
-
connect_timeout: 5,
|
|
180
|
-
fetch_types: false,
|
|
181
|
-
prepare: false,
|
|
182
|
-
})
|
|
183
|
-
return {
|
|
184
|
-
exec: async (s: string, params: any[] = []) => {
|
|
185
|
-
const rows = await sql.unsafe(s, params as any[])
|
|
186
|
-
return rows as any[]
|
|
187
|
-
},
|
|
188
|
-
end: () => sql.end({ timeout: 2 }).then(() => undefined),
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
/**
|
|
193
|
-
* Run the same query against pgsqlite (oracle) and our compiler+SQLite (under
|
|
194
|
-
* test). Return both result sets so the test can diff them however it wants.
|
|
195
|
-
*
|
|
196
|
-
* Uses freshly-spawned servers/dbs for each call — slow but isolated. For
|
|
197
|
-
* batches use the lower-level helpers above.
|
|
198
|
-
*/
|
|
199
|
-
export async function runOracleAndCompiler(
|
|
200
|
-
setupSql: string[],
|
|
201
|
-
pgSql: string,
|
|
202
|
-
params: any[] = []
|
|
203
|
-
): Promise<{
|
|
204
|
-
oracle: any[]
|
|
205
|
-
ours: any[]
|
|
206
|
-
}> {
|
|
207
|
-
const server = await startPgsqliteServer()
|
|
208
|
-
try {
|
|
209
|
-
const conn = await connectOracle(server)
|
|
210
|
-
try {
|
|
211
|
-
for (const s of setupSql) await conn.exec(s)
|
|
212
|
-
const oracle = await conn.exec(pgSql, params)
|
|
213
|
-
|
|
214
|
-
// ours: setup + query against fresh in-memory sqlite (after compile())
|
|
215
|
-
const { compile } = await import('../index.js')
|
|
216
|
-
const db = new Database(':memory:')
|
|
217
|
-
for (const s of setupSql) {
|
|
218
|
-
const { sql: translated } = compile(s)
|
|
219
|
-
db.exec(translated)
|
|
220
|
-
}
|
|
221
|
-
const { sql: translatedQuery } = compile(pgSql)
|
|
222
|
-
// postgres.js uses $1 params; sqlite uses ?
|
|
223
|
-
const sqliteSql = translatedQuery.replace(/\$(\d+)/g, '?')
|
|
224
|
-
const stmt = db.prepare(sqliteSql)
|
|
225
|
-
const ours = (
|
|
226
|
-
params.length > 0 ? stmt.all(...(params as any[])) : stmt.all()
|
|
227
|
-
) as any[]
|
|
228
|
-
db.close()
|
|
229
|
-
|
|
230
|
-
return { oracle, ours }
|
|
231
|
-
} finally {
|
|
232
|
-
await conn.end()
|
|
233
|
-
}
|
|
234
|
-
} finally {
|
|
235
|
-
await server.stop()
|
|
236
|
-
}
|
|
237
|
-
}
|
|
@@ -1,109 +0,0 @@
|
|
|
1
|
-
import Database from '@rocicorp/zero-sqlite3'
|
|
2
|
-
/**
|
|
3
|
-
* Snapshot tests for the types pass. Each case asserts that the emitted
|
|
4
|
-
* SQLite SQL has the expected normalized type name AND that the result
|
|
5
|
-
* actually executes against a fresh @rocicorp/zero-sqlite3 in-memory db.
|
|
6
|
-
*/
|
|
7
|
-
import { describe, expect, it } from 'vitest'
|
|
8
|
-
|
|
9
|
-
import { compile } from '../index.js'
|
|
10
|
-
|
|
11
|
-
function compilesAndRuns(pgSql: string): { sql: string } {
|
|
12
|
-
const { sql, warnings } = compile(pgSql)
|
|
13
|
-
expect(warnings).toEqual([])
|
|
14
|
-
const db = new Database(':memory:')
|
|
15
|
-
db.exec(sql)
|
|
16
|
-
db.close()
|
|
17
|
-
return { sql }
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
describe('types pass', () => {
|
|
21
|
-
it('BIGSERIAL → INTEGER (rowid alias on PRIMARY KEY)', () => {
|
|
22
|
-
const { sql } = compilesAndRuns('CREATE TABLE t (id BIGSERIAL PRIMARY KEY)')
|
|
23
|
-
expect(sql).toMatch(/INTEGER PRIMARY KEY/i)
|
|
24
|
-
expect(sql).not.toMatch(/bigserial/i)
|
|
25
|
-
})
|
|
26
|
-
|
|
27
|
-
it('jsonb → TEXT', () => {
|
|
28
|
-
const { sql } = compilesAndRuns(
|
|
29
|
-
'CREATE TABLE t (id text PRIMARY KEY, p jsonb NOT NULL)'
|
|
30
|
-
)
|
|
31
|
-
expect(sql).toMatch(/p TEXT NOT NULL/i)
|
|
32
|
-
expect(sql).not.toMatch(/jsonb/i)
|
|
33
|
-
})
|
|
34
|
-
|
|
35
|
-
it('text[] → TEXT (arrays as JSON text)', () => {
|
|
36
|
-
const { sql } = compilesAndRuns(
|
|
37
|
-
'CREATE TABLE t (id text PRIMARY KEY, tags text[] NOT NULL)'
|
|
38
|
-
)
|
|
39
|
-
expect(sql).toMatch(/tags TEXT NOT NULL/i)
|
|
40
|
-
expect(sql).not.toMatch(/\[/)
|
|
41
|
-
})
|
|
42
|
-
|
|
43
|
-
it('timestamp with time zone → TEXT', () => {
|
|
44
|
-
const { sql } = compilesAndRuns(
|
|
45
|
-
'CREATE TABLE t (id text PRIMARY KEY, ts timestamp with time zone NOT NULL)'
|
|
46
|
-
)
|
|
47
|
-
expect(sql).toMatch(/ts TEXT NOT NULL/i)
|
|
48
|
-
expect(sql).not.toMatch(/timestamp/i)
|
|
49
|
-
expect(sql).not.toMatch(/with time zone/i)
|
|
50
|
-
})
|
|
51
|
-
|
|
52
|
-
it('varchar(N) → TEXT (drop length typmod)', () => {
|
|
53
|
-
const { sql } = compilesAndRuns(
|
|
54
|
-
'CREATE TABLE t (id text PRIMARY KEY, val varchar(64))'
|
|
55
|
-
)
|
|
56
|
-
expect(sql).toMatch(/val TEXT/i)
|
|
57
|
-
expect(sql).not.toMatch(/varchar/i)
|
|
58
|
-
expect(sql).not.toMatch(/\(64\)/)
|
|
59
|
-
})
|
|
60
|
-
|
|
61
|
-
it('boolean → INTEGER', () => {
|
|
62
|
-
const { sql } = compilesAndRuns(
|
|
63
|
-
'CREATE TABLE t (id text PRIMARY KEY, enabled boolean NOT NULL DEFAULT false)'
|
|
64
|
-
)
|
|
65
|
-
expect(sql).toMatch(/enabled INTEGER NOT NULL/i)
|
|
66
|
-
expect(sql).not.toMatch(/boolean/i)
|
|
67
|
-
})
|
|
68
|
-
|
|
69
|
-
it('uuid → TEXT', () => {
|
|
70
|
-
const { sql } = compilesAndRuns('CREATE TABLE t (id uuid PRIMARY KEY)')
|
|
71
|
-
expect(sql).toMatch(/id TEXT PRIMARY KEY/i)
|
|
72
|
-
expect(sql).not.toMatch(/uuid/i)
|
|
73
|
-
})
|
|
74
|
-
|
|
75
|
-
it('bytea → BLOB', () => {
|
|
76
|
-
const { sql } = compilesAndRuns('CREATE TABLE t (id text PRIMARY KEY, body bytea)')
|
|
77
|
-
expect(sql).toMatch(/body BLOB/i)
|
|
78
|
-
expect(sql).not.toMatch(/bytea/i)
|
|
79
|
-
})
|
|
80
|
-
|
|
81
|
-
it('numeric(10,2) → NUMERIC (drops precision)', () => {
|
|
82
|
-
const { sql } = compilesAndRuns(
|
|
83
|
-
'CREATE TABLE t (id text PRIMARY KEY, amount numeric(10,2))'
|
|
84
|
-
)
|
|
85
|
-
expect(sql).toMatch(/amount NUMERIC/i)
|
|
86
|
-
expect(sql).not.toMatch(/\(10/)
|
|
87
|
-
})
|
|
88
|
-
|
|
89
|
-
it('composite: all common chat-app types in one table', () => {
|
|
90
|
-
const { sql } = compilesAndRuns(
|
|
91
|
-
'CREATE TABLE event (' +
|
|
92
|
-
'id BIGSERIAL PRIMARY KEY, ' +
|
|
93
|
-
'user_id uuid NOT NULL, ' +
|
|
94
|
-
'"createdAt" timestamp with time zone DEFAULT NOW() NOT NULL, ' +
|
|
95
|
-
"payload jsonb NOT NULL DEFAULT '{}', " +
|
|
96
|
-
"tags text[] NOT NULL DEFAULT '{}', " +
|
|
97
|
-
'amount numeric(10,2), ' +
|
|
98
|
-
'enabled boolean NOT NULL DEFAULT true' +
|
|
99
|
-
')'
|
|
100
|
-
)
|
|
101
|
-
expect(sql).toMatch(/INTEGER PRIMARY KEY/i)
|
|
102
|
-
expect(sql).toMatch(/user_id TEXT NOT NULL/i)
|
|
103
|
-
expect(sql).toMatch(/"createdAt" TEXT DEFAULT CURRENT_TIMESTAMP NOT NULL/i)
|
|
104
|
-
expect(sql).toMatch(/payload TEXT NOT NULL/i)
|
|
105
|
-
expect(sql).toMatch(/tags TEXT NOT NULL/i)
|
|
106
|
-
expect(sql).toMatch(/amount NUMERIC/i)
|
|
107
|
-
expect(sql).toMatch(/enabled INTEGER NOT NULL/i)
|
|
108
|
-
})
|
|
109
|
-
})
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Schema metadata available to passes for type-aware translation.
|
|
3
|
-
*
|
|
4
|
-
* Implementations are caller-provided. The default NOOP_SCHEMA returns nothing
|
|
5
|
-
* and passes degrade gracefully (regex/AST-shape fallbacks).
|
|
6
|
-
*
|
|
7
|
-
* For orez, the eventual implementation will read from `ctx.storage.sql`
|
|
8
|
-
* PRAGMA + the `_orez_pg_metadata` catalog table.
|
|
9
|
-
*/
|
|
10
|
-
export interface SchemaInfo {
|
|
11
|
-
/** PG type name (e.g. "jsonb", "text[]") for a column, or undefined. */
|
|
12
|
-
getColumnType(schema: string, table: string, column: string): string | undefined
|
|
13
|
-
|
|
14
|
-
/** ENUM definition lookup by PG type name. */
|
|
15
|
-
getEnum(typeName: string): EnumInfo | undefined
|
|
16
|
-
|
|
17
|
-
/** Validate an ENUM literal value. */
|
|
18
|
-
isEnumValue(typeOid: number, label: string): boolean
|
|
19
|
-
|
|
20
|
-
/** Column list for a table (for SELECT * expansion, RETURNING * etc.). */
|
|
21
|
-
getTableColumns(schema: string, table: string): readonly string[] | undefined
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export interface EnumInfo {
|
|
25
|
-
typeOid: number
|
|
26
|
-
values: readonly string[]
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
export interface CompileWarning {
|
|
30
|
-
kind: string
|
|
31
|
-
message: string
|
|
32
|
-
/** PG AST node tag where the warning was raised. */
|
|
33
|
-
near?: string
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export interface CompileResult {
|
|
37
|
-
sql: string
|
|
38
|
-
warnings: CompileWarning[]
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
export interface CompileOptions {
|
|
42
|
-
schema?: SchemaInfo
|
|
43
|
-
pgVersion?: number
|
|
44
|
-
/** Override pass list (mainly for testing individual passes). */
|
|
45
|
-
passes?: Pass[]
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
/** Context passed to every pass. */
|
|
49
|
-
export interface PassContext {
|
|
50
|
-
schema: SchemaInfo
|
|
51
|
-
warnings: CompileWarning[]
|
|
52
|
-
/**
|
|
53
|
-
* Optional pass list — if set, runPasses uses these instead of the default
|
|
54
|
-
* pipeline. Otherwise the full default pipeline runs.
|
|
55
|
-
*/
|
|
56
|
-
passes?: Pass[]
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
/** A pass is a function that mutates a RawStmt in place. */
|
|
60
|
-
export interface Pass {
|
|
61
|
-
name: string
|
|
62
|
-
run(rawStmt: any, ctx: PassContext): void
|
|
63
|
-
}
|
package/src/pglite-ipc.test.ts
DELETED
|
@@ -1,116 +0,0 @@
|
|
|
1
|
-
import { describe, test, expect, beforeAll, afterAll } from 'vitest'
|
|
2
|
-
|
|
3
|
-
import { PGliteWorkerProxy } from './pglite-ipc.js'
|
|
4
|
-
|
|
5
|
-
describe('PGliteWorkerProxy', () => {
|
|
6
|
-
let proxy: PGliteWorkerProxy
|
|
7
|
-
|
|
8
|
-
beforeAll(async () => {
|
|
9
|
-
proxy = new PGliteWorkerProxy({
|
|
10
|
-
dataDir: 'memory://',
|
|
11
|
-
name: 'test',
|
|
12
|
-
withExtensions: false,
|
|
13
|
-
debug: 0,
|
|
14
|
-
pgliteOptions: {},
|
|
15
|
-
})
|
|
16
|
-
await proxy.waitReady
|
|
17
|
-
}, 30_000)
|
|
18
|
-
|
|
19
|
-
afterAll(async () => {
|
|
20
|
-
await proxy.close()
|
|
21
|
-
})
|
|
22
|
-
|
|
23
|
-
test('exec creates table', async () => {
|
|
24
|
-
await proxy.exec(`
|
|
25
|
-
CREATE TABLE test_items (
|
|
26
|
-
id SERIAL PRIMARY KEY,
|
|
27
|
-
name TEXT NOT NULL
|
|
28
|
-
)
|
|
29
|
-
`)
|
|
30
|
-
})
|
|
31
|
-
|
|
32
|
-
test('query returns rows', async () => {
|
|
33
|
-
await proxy.exec(`INSERT INTO test_items (name) VALUES ('hello')`)
|
|
34
|
-
await proxy.exec(`INSERT INTO test_items (name) VALUES ('world')`)
|
|
35
|
-
|
|
36
|
-
const result = await proxy.query<{ id: number; name: string }>(
|
|
37
|
-
'SELECT * FROM test_items ORDER BY id'
|
|
38
|
-
)
|
|
39
|
-
expect(result.rows).toHaveLength(2)
|
|
40
|
-
expect(result.rows[0].name).toBe('hello')
|
|
41
|
-
expect(result.rows[1].name).toBe('world')
|
|
42
|
-
})
|
|
43
|
-
|
|
44
|
-
test('query with params', async () => {
|
|
45
|
-
const result = await proxy.query<{ name: string }>(
|
|
46
|
-
'SELECT name FROM test_items WHERE name = $1',
|
|
47
|
-
['world']
|
|
48
|
-
)
|
|
49
|
-
expect(result.rows).toHaveLength(1)
|
|
50
|
-
expect(result.rows[0].name).toBe('world')
|
|
51
|
-
})
|
|
52
|
-
|
|
53
|
-
test('exec returns affectedRows', async () => {
|
|
54
|
-
const result = await proxy.exec(`DELETE FROM test_items WHERE name = 'hello'`)
|
|
55
|
-
expect(result[0].affectedRows).toBe(1)
|
|
56
|
-
})
|
|
57
|
-
|
|
58
|
-
test('execProtocolRaw handles wire protocol', async () => {
|
|
59
|
-
// simple query message: SELECT 1 as num
|
|
60
|
-
const query = 'SELECT 1 as num\0'
|
|
61
|
-
const encoder = new TextEncoder()
|
|
62
|
-
const queryBytes = encoder.encode(query)
|
|
63
|
-
const buf = new Uint8Array(5 + queryBytes.length)
|
|
64
|
-
buf[0] = 0x51 // 'Q' simple query
|
|
65
|
-
new DataView(buf.buffer).setInt32(1, 4 + queryBytes.length)
|
|
66
|
-
buf.set(queryBytes, 5)
|
|
67
|
-
|
|
68
|
-
const result = await proxy.execProtocolRaw(buf)
|
|
69
|
-
expect(result).toBeInstanceOf(Uint8Array)
|
|
70
|
-
expect(result.length).toBeGreaterThan(0)
|
|
71
|
-
// should contain a ReadyForQuery message (0x5a)
|
|
72
|
-
let hasRfq = false
|
|
73
|
-
for (let i = 0; i < result.length; i++) {
|
|
74
|
-
if (result[i] === 0x5a) {
|
|
75
|
-
hasRfq = true
|
|
76
|
-
break
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
expect(hasRfq).toBe(true)
|
|
80
|
-
})
|
|
81
|
-
|
|
82
|
-
test('listen receives notifications', async () => {
|
|
83
|
-
const received: string[] = []
|
|
84
|
-
const unsub = await proxy.listen('test_channel', (payload) => {
|
|
85
|
-
received.push(payload)
|
|
86
|
-
})
|
|
87
|
-
|
|
88
|
-
await proxy.exec(`NOTIFY test_channel, 'hello'`)
|
|
89
|
-
// give notification time to propagate
|
|
90
|
-
await new Promise((r) => setTimeout(r, 100))
|
|
91
|
-
|
|
92
|
-
expect(received).toContain('hello')
|
|
93
|
-
await unsub()
|
|
94
|
-
})
|
|
95
|
-
|
|
96
|
-
test('error propagation with SQL code', async () => {
|
|
97
|
-
await expect(proxy.exec('SELECT * FROM nonexistent_table')).rejects.toThrow()
|
|
98
|
-
})
|
|
99
|
-
|
|
100
|
-
test('rejects requests after worker exits', async () => {
|
|
101
|
-
const local = new PGliteWorkerProxy({
|
|
102
|
-
dataDir: 'memory://',
|
|
103
|
-
name: 'exit-test',
|
|
104
|
-
withExtensions: false,
|
|
105
|
-
debug: 0,
|
|
106
|
-
pgliteOptions: {},
|
|
107
|
-
})
|
|
108
|
-
await local.waitReady
|
|
109
|
-
|
|
110
|
-
await (local as any).worker.terminate()
|
|
111
|
-
|
|
112
|
-
await expect(local.query('SELECT 1')).rejects.toThrow(
|
|
113
|
-
/worker exited|worker is closed/
|
|
114
|
-
)
|
|
115
|
-
})
|
|
116
|
-
})
|