orez 0.1.36 → 0.1.38
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/cli-entry.js +0 -0
- package/dist/cli.js +7 -1
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +1 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +1 -0
- package/dist/config.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +14 -11
- package/dist/index.js.map +1 -1
- package/dist/pg-proxy.d.ts.map +1 -1
- package/dist/pg-proxy.js +8 -4
- package/dist/pg-proxy.js.map +1 -1
- package/dist/pglite-manager.d.ts +12 -0
- package/dist/pglite-manager.d.ts.map +1 -1
- package/dist/pglite-manager.js +81 -0
- package/dist/pglite-manager.js.map +1 -1
- package/dist/recovery.js +2 -2
- package/dist/recovery.js.map +1 -1
- package/dist/replication/change-tracker.js +9 -9
- package/dist/replication/change-tracker.js.map +1 -1
- package/dist/replication/handler.d.ts +12 -0
- package/dist/replication/handler.d.ts.map +1 -1
- package/dist/replication/handler.js +34 -6
- package/dist/replication/handler.js.map +1 -1
- package/dist/worker/browser-build-config.d.ts +59 -0
- package/dist/worker/browser-build-config.d.ts.map +1 -0
- package/dist/worker/browser-build-config.js +101 -0
- package/dist/worker/browser-build-config.js.map +1 -0
- package/dist/worker/browser-embed.d.ts +58 -0
- package/dist/worker/browser-embed.d.ts.map +1 -0
- package/dist/worker/browser-embed.js +195 -0
- package/dist/worker/browser-embed.js.map +1 -0
- package/dist/worker/cf-patches.d.ts +20 -0
- package/dist/worker/cf-patches.d.ts.map +1 -0
- package/dist/worker/cf-patches.js +94 -0
- package/dist/worker/cf-patches.js.map +1 -0
- package/dist/worker/index.d.ts +12 -0
- package/dist/worker/index.d.ts.map +1 -0
- package/dist/worker/index.js +105 -0
- package/dist/worker/index.js.map +1 -0
- package/dist/worker/shims/fastify.d.ts +80 -0
- package/dist/worker/shims/fastify.d.ts.map +1 -0
- package/dist/worker/shims/fastify.js +223 -0
- package/dist/worker/shims/fastify.js.map +1 -0
- package/dist/worker/shims/http-service.d.ts +104 -0
- package/dist/worker/shims/http-service.d.ts.map +1 -0
- package/dist/worker/shims/http-service.js +198 -0
- package/dist/worker/shims/http-service.js.map +1 -0
- package/dist/worker/shims/node-stub.d.ts +147 -0
- package/dist/worker/shims/node-stub.d.ts.map +1 -0
- package/dist/worker/shims/node-stub.js +204 -0
- package/dist/worker/shims/node-stub.js.map +1 -0
- package/dist/worker/shims/postgres.d.ts +115 -0
- package/dist/worker/shims/postgres.d.ts.map +1 -0
- package/dist/worker/shims/postgres.js +1181 -0
- package/dist/worker/shims/postgres.js.map +1 -0
- package/dist/worker/shims/sqlite-browser.d.ts +54 -0
- package/dist/worker/shims/sqlite-browser.d.ts.map +1 -0
- package/dist/worker/shims/sqlite-browser.js +144 -0
- package/dist/worker/shims/sqlite-browser.js.map +1 -0
- package/dist/worker/shims/sqlite.d.ts +126 -0
- package/dist/worker/shims/sqlite.d.ts.map +1 -0
- package/dist/worker/shims/sqlite.js +599 -0
- package/dist/worker/shims/sqlite.js.map +1 -0
- package/dist/worker/shims/stream-browser.d.ts +9 -0
- package/dist/worker/shims/stream-browser.d.ts.map +1 -0
- package/dist/worker/shims/stream-browser.js +13 -0
- package/dist/worker/shims/stream-browser.js.map +1 -0
- package/dist/worker/shims/ws-browser.d.ts +50 -0
- package/dist/worker/shims/ws-browser.d.ts.map +1 -0
- package/dist/worker/shims/ws-browser.js +105 -0
- package/dist/worker/shims/ws-browser.js.map +1 -0
- package/dist/worker/shims/ws.d.ts +62 -0
- package/dist/worker/shims/ws.d.ts.map +1 -0
- package/dist/worker/shims/ws.js +310 -0
- package/dist/worker/shims/ws.js.map +1 -0
- package/dist/worker/types.d.ts +57 -0
- package/dist/worker/types.d.ts.map +1 -0
- package/dist/worker/types.js +9 -0
- package/dist/worker/types.js.map +1 -0
- package/dist/worker/zero-cache-embed-cf.d.ts +63 -0
- package/dist/worker/zero-cache-embed-cf.d.ts.map +1 -0
- package/dist/worker/zero-cache-embed-cf.js +268 -0
- package/dist/worker/zero-cache-embed-cf.js.map +1 -0
- package/dist/worker/zero-cache-embed.d.ts +66 -0
- package/dist/worker/zero-cache-embed.d.ts.map +1 -0
- package/dist/worker/zero-cache-embed.js +200 -0
- package/dist/worker/zero-cache-embed.js.map +1 -0
- package/package.json +62 -3
- package/src/cli-entry.ts +0 -0
- package/src/cli.ts +8 -1
- package/src/config.ts +2 -0
- package/src/index.ts +15 -10
- package/src/integration/integration.test.ts +1 -1
- package/src/integration/restore-live-stress.test.ts +2 -2
- package/src/pg-proxy.ts +9 -4
- package/src/pglite-manager.ts +111 -0
- package/src/recovery.ts +2 -2
- package/src/replication/change-tracker.test.ts +1 -1
- package/src/replication/change-tracker.ts +9 -9
- package/src/replication/handler.test.ts +37 -0
- package/src/replication/handler.ts +46 -6
- package/src/wasm-sqlite.test.ts +2 -1
- package/src/worker/browser-build-config.test.ts +59 -0
- package/src/worker/browser-build-config.ts +105 -0
- package/src/worker/browser-embed.ts +306 -0
- package/src/worker/cf-patches.ts +114 -0
- package/src/worker/embed-integration.test.ts +321 -0
- package/src/worker/index.ts +138 -0
- package/src/worker/shims/fastify.test.ts +255 -0
- package/src/worker/shims/fastify.ts +292 -0
- package/src/worker/shims/http-service.test.ts +355 -0
- package/src/worker/shims/http-service.ts +293 -0
- package/src/worker/shims/node-stub.ts +223 -0
- package/src/worker/shims/postgres.test.ts +364 -0
- package/src/worker/shims/postgres.ts +1434 -0
- package/src/worker/shims/sqlite-browser.test.ts +233 -0
- package/src/worker/shims/sqlite-browser.ts +178 -0
- package/src/worker/shims/sqlite.test.ts +641 -0
- package/src/worker/shims/sqlite.ts +731 -0
- package/src/worker/shims/ws-browser.test.ts +184 -0
- package/src/worker/shims/ws-browser.ts +125 -0
- package/src/worker/shims/ws.test.ts +288 -0
- package/src/worker/shims/ws.ts +367 -0
- package/src/worker/types.ts +75 -0
- package/src/worker/worker-integration.test.ts +223 -0
- package/src/worker/worker.test.ts +136 -0
- package/src/worker/zero-cache-embed-cf.ts +367 -0
- package/src/worker/zero-cache-embed.ts +277 -0
|
@@ -0,0 +1,364 @@
|
|
|
1
|
+
import { PGlite } from '@electric-sql/pglite'
|
|
2
|
+
import { describe, it, expect, beforeEach, afterEach } from 'vitest'
|
|
3
|
+
|
|
4
|
+
import { createPostgresShim, PostgresError } from './postgres.js'
|
|
5
|
+
|
|
6
|
+
describe('postgres shim', () => {
|
|
7
|
+
let pglite: PGlite
|
|
8
|
+
let sql: ReturnType<typeof createPostgresShim>
|
|
9
|
+
|
|
10
|
+
beforeEach(async () => {
|
|
11
|
+
pglite = new PGlite()
|
|
12
|
+
await pglite.waitReady
|
|
13
|
+
sql = createPostgresShim(pglite)
|
|
14
|
+
|
|
15
|
+
// set up test table
|
|
16
|
+
await sql.unsafe(`
|
|
17
|
+
CREATE TABLE test_users (
|
|
18
|
+
id SERIAL PRIMARY KEY,
|
|
19
|
+
name TEXT NOT NULL,
|
|
20
|
+
email TEXT,
|
|
21
|
+
active BOOLEAN DEFAULT true,
|
|
22
|
+
metadata JSONB,
|
|
23
|
+
score NUMERIC
|
|
24
|
+
)
|
|
25
|
+
`)
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
afterEach(async () => {
|
|
29
|
+
await pglite.close()
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
// -- tagged template queries --
|
|
33
|
+
|
|
34
|
+
describe('tagged template queries', () => {
|
|
35
|
+
it('basic select', async () => {
|
|
36
|
+
await sql.unsafe(
|
|
37
|
+
`INSERT INTO test_users (name, email) VALUES ('alice', 'alice@test.com')`
|
|
38
|
+
)
|
|
39
|
+
const rows = await sql`SELECT * FROM test_users WHERE name = ${'alice'}`
|
|
40
|
+
expect(rows).toHaveLength(1)
|
|
41
|
+
expect(rows[0].name).toBe('alice')
|
|
42
|
+
expect(rows[0].email).toBe('alice@test.com')
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
it('multiple parameters', async () => {
|
|
46
|
+
await sql.unsafe(
|
|
47
|
+
`INSERT INTO test_users (name, email) VALUES ('bob', 'bob@test.com')`
|
|
48
|
+
)
|
|
49
|
+
await sql.unsafe(
|
|
50
|
+
`INSERT INTO test_users (name, email) VALUES ('carol', 'carol@test.com')`
|
|
51
|
+
)
|
|
52
|
+
const rows =
|
|
53
|
+
await sql`SELECT * FROM test_users WHERE name = ${'bob'} OR email = ${'carol@test.com'}`
|
|
54
|
+
expect(rows).toHaveLength(2)
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
it('empty result set', async () => {
|
|
58
|
+
const rows = await sql`SELECT * FROM test_users WHERE name = ${'nobody'}`
|
|
59
|
+
expect(rows).toHaveLength(0)
|
|
60
|
+
expect(rows.length).toBe(0)
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
it('null parameter', async () => {
|
|
64
|
+
await sql`INSERT INTO test_users (name, email) VALUES (${'dave'}, ${null})`
|
|
65
|
+
const rows = await sql`SELECT * FROM test_users WHERE name = ${'dave'}`
|
|
66
|
+
expect(rows).toHaveLength(1)
|
|
67
|
+
expect(rows[0].email).toBeNull()
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
it('boolean parameter', async () => {
|
|
71
|
+
await sql`INSERT INTO test_users (name, active) VALUES (${'eve'}, ${false})`
|
|
72
|
+
const rows = await sql`SELECT * FROM test_users WHERE name = ${'eve'}`
|
|
73
|
+
expect(rows[0].active).toBe(false)
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
it('json parameter', async () => {
|
|
77
|
+
const meta = { role: 'admin', tags: ['a', 'b'] }
|
|
78
|
+
await sql`INSERT INTO test_users (name, metadata) VALUES (${'frank'}, ${meta})`
|
|
79
|
+
const rows = await sql`SELECT * FROM test_users WHERE name = ${'frank'}`
|
|
80
|
+
expect(rows[0].metadata).toEqual(meta)
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
it('bigint parameter', async () => {
|
|
84
|
+
// bigint gets serialized to string, numeric column can hold it
|
|
85
|
+
const big = BigInt('99999999999999999')
|
|
86
|
+
await sql`INSERT INTO test_users (name, score) VALUES (${'grace'}, ${big})`
|
|
87
|
+
const rows = await sql`SELECT * FROM test_users WHERE name = ${'grace'}`
|
|
88
|
+
expect(rows[0].score).toBe('99999999999999999')
|
|
89
|
+
})
|
|
90
|
+
})
|
|
91
|
+
|
|
92
|
+
// -- result format --
|
|
93
|
+
|
|
94
|
+
describe('result format', () => {
|
|
95
|
+
it('array-like with indexed access', async () => {
|
|
96
|
+
await sql.unsafe(`INSERT INTO test_users (name) VALUES ('a'), ('b'), ('c')`)
|
|
97
|
+
const rows = await sql`SELECT name FROM test_users ORDER BY name`
|
|
98
|
+
expect(rows.length).toBe(3)
|
|
99
|
+
expect(rows[0].name).toBe('a')
|
|
100
|
+
expect(rows[1].name).toBe('b')
|
|
101
|
+
expect(rows[2].name).toBe('c')
|
|
102
|
+
})
|
|
103
|
+
|
|
104
|
+
it('iterable', async () => {
|
|
105
|
+
await sql.unsafe(`INSERT INTO test_users (name) VALUES ('x'), ('y')`)
|
|
106
|
+
const rows = await sql`SELECT name FROM test_users ORDER BY name`
|
|
107
|
+
const names: string[] = []
|
|
108
|
+
for (const row of rows) {
|
|
109
|
+
names.push(row.name)
|
|
110
|
+
}
|
|
111
|
+
expect(names).toEqual(['x', 'y'])
|
|
112
|
+
})
|
|
113
|
+
|
|
114
|
+
it('destructurable', async () => {
|
|
115
|
+
await sql.unsafe(
|
|
116
|
+
`INSERT INTO test_users (name, email) VALUES ('zara', 'z@test.com')`
|
|
117
|
+
)
|
|
118
|
+
const [{ name, email }] =
|
|
119
|
+
await sql`SELECT name, email FROM test_users WHERE name = ${'zara'}`
|
|
120
|
+
expect(name).toBe('zara')
|
|
121
|
+
expect(email).toBe('z@test.com')
|
|
122
|
+
})
|
|
123
|
+
|
|
124
|
+
it('has count metadata', async () => {
|
|
125
|
+
await sql.unsafe(`INSERT INTO test_users (name) VALUES ('a'), ('b')`)
|
|
126
|
+
const rows = await sql`SELECT * FROM test_users`
|
|
127
|
+
expect(rows.count).toBeGreaterThanOrEqual(2)
|
|
128
|
+
})
|
|
129
|
+
|
|
130
|
+
it('has command metadata', async () => {
|
|
131
|
+
const rows = await sql`SELECT 1 as val`
|
|
132
|
+
expect(rows.command).toBe('SELECT')
|
|
133
|
+
})
|
|
134
|
+
|
|
135
|
+
it('has columns metadata', async () => {
|
|
136
|
+
await sql.unsafe(`INSERT INTO test_users (name) VALUES ('test')`)
|
|
137
|
+
const rows = await sql`SELECT name, email FROM test_users`
|
|
138
|
+
expect(rows.columns).toHaveLength(2)
|
|
139
|
+
expect(rows.columns[0].name).toBe('name')
|
|
140
|
+
expect(rows.columns[1].name).toBe('email')
|
|
141
|
+
})
|
|
142
|
+
})
|
|
143
|
+
|
|
144
|
+
// -- unsafe queries --
|
|
145
|
+
|
|
146
|
+
describe('unsafe queries', () => {
|
|
147
|
+
it('DDL without params', async () => {
|
|
148
|
+
await sql.unsafe(`CREATE TABLE unsafe_test (id INT)`)
|
|
149
|
+
const rows =
|
|
150
|
+
await sql`SELECT table_name FROM information_schema.tables WHERE table_name = 'unsafe_test'`
|
|
151
|
+
expect(rows).toHaveLength(1)
|
|
152
|
+
})
|
|
153
|
+
|
|
154
|
+
it('query with params', async () => {
|
|
155
|
+
await sql.unsafe(`INSERT INTO test_users (name) VALUES ('unsafe_user')`)
|
|
156
|
+
const rows = await sql.unsafe('SELECT * FROM test_users WHERE name = $1', [
|
|
157
|
+
'unsafe_user',
|
|
158
|
+
])
|
|
159
|
+
expect(rows).toHaveLength(1)
|
|
160
|
+
expect(rows[0].name).toBe('unsafe_user')
|
|
161
|
+
})
|
|
162
|
+
|
|
163
|
+
it('multi-statement', async () => {
|
|
164
|
+
// pglite.query handles single statements; multi-statement DDL
|
|
165
|
+
// typically uses exec. unsafe forwards to query which handles most cases.
|
|
166
|
+
const result = await sql.unsafe(`SELECT 1 as a`)
|
|
167
|
+
expect(result[0].a).toBe(1)
|
|
168
|
+
})
|
|
169
|
+
})
|
|
170
|
+
|
|
171
|
+
// -- transactions --
|
|
172
|
+
|
|
173
|
+
describe('transactions', () => {
|
|
174
|
+
it('commit on success', async () => {
|
|
175
|
+
await sql.begin(async (tx) => {
|
|
176
|
+
await tx`INSERT INTO test_users (name) VALUES (${'tx_user'})`
|
|
177
|
+
})
|
|
178
|
+
const rows = await sql`SELECT * FROM test_users WHERE name = ${'tx_user'}`
|
|
179
|
+
expect(rows).toHaveLength(1)
|
|
180
|
+
})
|
|
181
|
+
|
|
182
|
+
it('rollback on error', async () => {
|
|
183
|
+
await expect(
|
|
184
|
+
sql.begin(async (tx) => {
|
|
185
|
+
await tx`INSERT INTO test_users (name) VALUES (${'rollback_user'})`
|
|
186
|
+
throw new Error('intentional rollback')
|
|
187
|
+
})
|
|
188
|
+
).rejects.toThrow('intentional rollback')
|
|
189
|
+
|
|
190
|
+
const rows = await sql`SELECT * FROM test_users WHERE name = ${'rollback_user'}`
|
|
191
|
+
expect(rows).toHaveLength(0)
|
|
192
|
+
})
|
|
193
|
+
|
|
194
|
+
it('with isolation level string (ignored but accepted)', async () => {
|
|
195
|
+
await sql.begin('serializable', async (tx) => {
|
|
196
|
+
await tx`INSERT INTO test_users (name) VALUES (${'iso_user'})`
|
|
197
|
+
})
|
|
198
|
+
const rows = await sql`SELECT * FROM test_users WHERE name = ${'iso_user'}`
|
|
199
|
+
expect(rows).toHaveLength(1)
|
|
200
|
+
})
|
|
201
|
+
|
|
202
|
+
it('tx.unsafe works', async () => {
|
|
203
|
+
await sql.begin(async (tx) => {
|
|
204
|
+
await tx.unsafe(`INSERT INTO test_users (name) VALUES ('tx_unsafe')`)
|
|
205
|
+
})
|
|
206
|
+
const rows = await sql`SELECT * FROM test_users WHERE name = ${'tx_unsafe'}`
|
|
207
|
+
expect(rows).toHaveLength(1)
|
|
208
|
+
})
|
|
209
|
+
|
|
210
|
+
it('nested queries in transaction', async () => {
|
|
211
|
+
const result = await sql.begin(async (tx) => {
|
|
212
|
+
await tx`INSERT INTO test_users (name) VALUES (${'nested_a'})`
|
|
213
|
+
await tx`INSERT INTO test_users (name) VALUES (${'nested_b'})`
|
|
214
|
+
return tx`SELECT name FROM test_users WHERE name LIKE 'nested_%' ORDER BY name`
|
|
215
|
+
})
|
|
216
|
+
expect(result).toHaveLength(2)
|
|
217
|
+
expect(result[0].name).toBe('nested_a')
|
|
218
|
+
expect(result[1].name).toBe('nested_b')
|
|
219
|
+
})
|
|
220
|
+
})
|
|
221
|
+
|
|
222
|
+
// -- PostgresError --
|
|
223
|
+
|
|
224
|
+
describe('PostgresError', () => {
|
|
225
|
+
it('has correct .code property', () => {
|
|
226
|
+
const err = new PostgresError({ message: 'duplicate key', code: '23505' })
|
|
227
|
+
expect(err.code).toBe('23505')
|
|
228
|
+
expect(err.message).toBe('duplicate key')
|
|
229
|
+
expect(err.name).toBe('PostgresError')
|
|
230
|
+
expect(err).toBeInstanceOf(Error)
|
|
231
|
+
expect(err).toBeInstanceOf(PostgresError)
|
|
232
|
+
})
|
|
233
|
+
|
|
234
|
+
it('has all standard fields', () => {
|
|
235
|
+
const err = new PostgresError({
|
|
236
|
+
message: 'test',
|
|
237
|
+
code: '42P01',
|
|
238
|
+
severity: 'ERROR',
|
|
239
|
+
detail: 'some detail',
|
|
240
|
+
hint: 'some hint',
|
|
241
|
+
schema_name: 'public',
|
|
242
|
+
table_name: 'users',
|
|
243
|
+
})
|
|
244
|
+
expect(err.severity).toBe('ERROR')
|
|
245
|
+
expect(err.detail).toBe('some detail')
|
|
246
|
+
expect(err.hint).toBe('some hint')
|
|
247
|
+
expect(err.schema_name).toBe('public')
|
|
248
|
+
expect(err.table_name).toBe('users')
|
|
249
|
+
})
|
|
250
|
+
})
|
|
251
|
+
|
|
252
|
+
// -- identifier escaping --
|
|
253
|
+
|
|
254
|
+
describe('identifier escaping', () => {
|
|
255
|
+
it('sql(string) returns escaped identifier usable in templates', async () => {
|
|
256
|
+
const tableName = 'test_users'
|
|
257
|
+
const colName = 'name'
|
|
258
|
+
await sql.unsafe(`INSERT INTO test_users (name) VALUES ('ident_test')`)
|
|
259
|
+
const rows =
|
|
260
|
+
await sql`SELECT ${sql(colName)} FROM ${sql(tableName)} WHERE name = ${'ident_test'}`
|
|
261
|
+
expect(rows).toHaveLength(1)
|
|
262
|
+
expect(rows[0].name).toBe('ident_test')
|
|
263
|
+
})
|
|
264
|
+
|
|
265
|
+
it('escapes quotes in identifiers', () => {
|
|
266
|
+
const ident = sql('my"table')
|
|
267
|
+
expect(ident.value).toBe('"my""table"')
|
|
268
|
+
})
|
|
269
|
+
|
|
270
|
+
it('escapes dots as schema separators', () => {
|
|
271
|
+
const ident = sql('public.users')
|
|
272
|
+
expect(ident.value).toBe('"public"."users"')
|
|
273
|
+
})
|
|
274
|
+
})
|
|
275
|
+
|
|
276
|
+
// -- options and metadata --
|
|
277
|
+
|
|
278
|
+
describe('options and metadata', () => {
|
|
279
|
+
it('sql.options has expected shape', () => {
|
|
280
|
+
expect(sql.options).toBeDefined()
|
|
281
|
+
expect(sql.options.host).toEqual(['localhost'])
|
|
282
|
+
expect(sql.options.port).toEqual([5432])
|
|
283
|
+
expect(sql.options.database).toBe('pglite')
|
|
284
|
+
expect(sql.options.max).toBe(1)
|
|
285
|
+
expect(typeof sql.options.fetch_types).toBe('boolean')
|
|
286
|
+
})
|
|
287
|
+
|
|
288
|
+
it('sql.PostgresError is the error class', () => {
|
|
289
|
+
expect(sql.PostgresError).toBe(PostgresError)
|
|
290
|
+
})
|
|
291
|
+
|
|
292
|
+
it('sql.end() resolves without error', async () => {
|
|
293
|
+
await expect(sql.end()).resolves.toBeUndefined()
|
|
294
|
+
})
|
|
295
|
+
})
|
|
296
|
+
|
|
297
|
+
// -- simple() modifier --
|
|
298
|
+
|
|
299
|
+
describe('query modifiers', () => {
|
|
300
|
+
it('.simple() returns the same pending query', async () => {
|
|
301
|
+
await sql.unsafe(`INSERT INTO test_users (name) VALUES ('simple_test')`)
|
|
302
|
+
const rows =
|
|
303
|
+
await sql`SELECT * FROM test_users WHERE name = ${'simple_test'}`.simple()
|
|
304
|
+
expect(rows).toHaveLength(1)
|
|
305
|
+
})
|
|
306
|
+
})
|
|
307
|
+
|
|
308
|
+
// -- error propagation --
|
|
309
|
+
|
|
310
|
+
describe('error propagation', () => {
|
|
311
|
+
it('propagates SQL errors from tagged template', async () => {
|
|
312
|
+
await expect(sql`SELECT * FROM nonexistent_table`).rejects.toThrow()
|
|
313
|
+
})
|
|
314
|
+
|
|
315
|
+
it('propagates SQL errors from unsafe', async () => {
|
|
316
|
+
await expect(sql.unsafe('SELECT * FROM nonexistent_table')).rejects.toThrow()
|
|
317
|
+
})
|
|
318
|
+
})
|
|
319
|
+
|
|
320
|
+
// -- multi-statement queries --
|
|
321
|
+
|
|
322
|
+
describe('multi-statement DDL', () => {
|
|
323
|
+
it('handles multi-statement via unsafe()', async () => {
|
|
324
|
+
await sql.unsafe(`
|
|
325
|
+
CREATE SCHEMA IF NOT EXISTS test_schema;
|
|
326
|
+
CREATE TABLE IF NOT EXISTS test_schema.items (
|
|
327
|
+
id TEXT PRIMARY KEY,
|
|
328
|
+
value TEXT
|
|
329
|
+
)
|
|
330
|
+
`)
|
|
331
|
+
// verify schema and table were created
|
|
332
|
+
const result =
|
|
333
|
+
await sql`SELECT table_name FROM information_schema.tables WHERE table_schema = 'test_schema'`
|
|
334
|
+
expect(result.length).toBeGreaterThan(0)
|
|
335
|
+
})
|
|
336
|
+
|
|
337
|
+
it('handles multi-statement via tagged template', async () => {
|
|
338
|
+
await sql`
|
|
339
|
+
CREATE SCHEMA IF NOT EXISTS test_schema2;
|
|
340
|
+
CREATE TABLE IF NOT EXISTS test_schema2.things (
|
|
341
|
+
id TEXT PRIMARY KEY,
|
|
342
|
+
name TEXT
|
|
343
|
+
)
|
|
344
|
+
`
|
|
345
|
+
const result =
|
|
346
|
+
await sql`SELECT table_name FROM information_schema.tables WHERE table_schema = 'test_schema2'`
|
|
347
|
+
expect(result.length).toBeGreaterThan(0)
|
|
348
|
+
})
|
|
349
|
+
|
|
350
|
+
it('handles multi-statement with quoted identifiers containing special chars', async () => {
|
|
351
|
+
await sql.unsafe(`
|
|
352
|
+
CREATE SCHEMA IF NOT EXISTS "zero_0/cvr";
|
|
353
|
+
CREATE TABLE IF NOT EXISTS "zero_0/cvr"."clients" (
|
|
354
|
+
"clientGroupID" TEXT NOT NULL,
|
|
355
|
+
"clientID" TEXT NOT NULL,
|
|
356
|
+
PRIMARY KEY ("clientGroupID", "clientID")
|
|
357
|
+
)
|
|
358
|
+
`)
|
|
359
|
+
const result =
|
|
360
|
+
await sql`SELECT table_name FROM information_schema.tables WHERE table_schema = 'zero_0/cvr'`
|
|
361
|
+
expect(result.length).toBeGreaterThan(0)
|
|
362
|
+
})
|
|
363
|
+
})
|
|
364
|
+
})
|