Skip to content

Commit ae6c350

Browse files
authored
feat: adds support for prepared statements in sql.unsafe (#176)
Fixes #122
1 parent 2b5cbc2 commit ae6c350

File tree

3 files changed

+52
-11
lines changed

3 files changed

+52
-11
lines changed

lib/index.js

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ function Postgres(a, b) {
6767
, listener
6868

6969
function postgres(xs) {
70-
return query({}, getConnection(), xs, Array.from(arguments).slice(1))
70+
return query({ prepare: options.prepare }, getConnection(), xs, Array.from(arguments).slice(1))
7171
}
7272

7373
Object.assign(postgres, {
@@ -167,7 +167,7 @@ function Postgres(a, b) {
167167

168168
function query(query, connection, xs, args) {
169169
query.origin = options.debug ? new Error().stack : cachedError(xs)
170-
query.dynamic = query.dynamic || options.no_prepare
170+
query.prepare = 'prepare' in query ? query.prepare : options.prepare
171171
if (!query.raw && (!Array.isArray(xs) || !Array.isArray(xs.raw)))
172172
return nested(xs, args)
173173

@@ -241,7 +241,7 @@ function Postgres(a, b) {
241241
function fetchArrayTypes(connection) {
242242
return arrayTypesPromise || (arrayTypesPromise =
243243
new Promise((resolve, reject) => {
244-
send(connection, { resolve, reject, raw: true, dynamic: true }, `
244+
send(connection, { resolve, reject, raw: true, prepare: false }, `
245245
select b.oid, b.typarray
246246
from pg_catalog.pg_type a
247247
left join pg_catalog.pg_type b on b.oid = a.typelem
@@ -284,8 +284,9 @@ function Postgres(a, b) {
284284
return sql`select pg_notify(${ channel }, ${ '' + payload })`
285285
}
286286

287-
function unsafe(xs, args) {
288-
return query({ raw: true, simple: !args, dynamic: true }, connection || getConnection(), xs, args || [])
287+
function unsafe(xs, args, queryOptions) {
288+
const prepare = queryOptions && queryOptions.prepare || false;
289+
return query({ raw: true, simple: !args, prepare }, connection || getConnection(), xs, args || [])
289290
}
290291

291292
function file(path, args, options = {}) {
@@ -414,7 +415,7 @@ function Postgres(a, b) {
414415
args.forEach(x => parseValue(x, xargs, types))
415416

416417
return {
417-
sig: !query.dynamic && types + str,
418+
sig: query.prepare && types + str,
418419
str,
419420
args: xargs
420421
}
@@ -433,7 +434,7 @@ function Postgres(a, b) {
433434
}
434435

435436
return {
436-
sig: !query.dynamic && !xargs.dynamic && types + str,
437+
sig: query.prepare && !xargs.dynamic && types + str,
437438
str: str.trim(),
438439
args: xargs
439440
}
@@ -559,7 +560,7 @@ function parseOptions(a, b) {
559560
ssl : o.ssl || url.query.sslmode || url.query.ssl || false,
560561
idle_timeout : o.idle_timeout || url.query.idle_timeout || env.PGIDLE_TIMEOUT || warn(o.timeout),
561562
connect_timeout : o.connect_timeout || url.query.connect_timeout || env.PGCONNECT_TIMEOUT || 30,
562-
no_prepare : o.no_prepare,
563+
prepare : 'prepare' in o ? o.prepare : 'no_prepare' in o ? !o.no_prepare : true,
563564
onnotice : o.onnotice,
564565
onparameter : o.onparameter,
565566
transform : Object.assign({}, o.transform),

tests/index.js

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1204,12 +1204,36 @@ t('Automatically creates prepared statements', async() => {
12041204
return [result[0].statement, 'select * from pg_prepared_statements']
12051205
})
12061206

1207-
t('no_prepare: true disables prepared transactions', async() => {
1207+
t('no_prepare: true disables prepared transactions (deprecated)', async() => {
12081208
const sql = postgres({ ...options, no_prepare: true })
12091209
const result = await sql`select * from pg_prepared_statements`
12101210
return [0, result.count]
12111211
})
12121212

1213+
t('prepare: false disables prepared transactions', async() => {
1214+
const sql = postgres({ ...options, prepare: false })
1215+
const result = await sql`select * from pg_prepared_statements`
1216+
return [0, result.count]
1217+
})
1218+
1219+
t('prepare: true enables prepared transactions', async() => {
1220+
const sql = postgres({ ...options, prepare: true })
1221+
const result = await sql`select * from pg_prepared_statements`
1222+
return [result[0].statement, 'select * from pg_prepared_statements']
1223+
})
1224+
1225+
t('prepares unsafe query when "prepare" option is true', async() => {
1226+
const sql = postgres({ ...options, prepare: true })
1227+
const result = await sql.unsafe('select * from pg_prepared_statements where name <> $1', ["bla"], { prepare: true })
1228+
return [result[0].statement, 'select * from pg_prepared_statements where name <> $1']
1229+
})
1230+
1231+
t('does not prepare unsafe query by default', async() => {
1232+
const sql = postgres({ ...options, prepare: true });
1233+
const result = await sql.unsafe('select * from pg_prepared_statements where name <> $1', ["bla"])
1234+
return [0, result.count]
1235+
})
1236+
12131237
t('Catches connection config errors', async() => {
12141238
const sql = postgres({ ...options, user: { toString: () => { throw new Error('wat') } }, database: 'prut' })
12151239

types/index.d.ts

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,16 @@ interface BaseOptions<T extends JSToPostgresTypeMap> {
3434
connect_timeout: number;
3535
/** Array of custom types; see more below */
3636
types: PostgresTypeList<T>;
37-
/** Disable prepared mode */
37+
/**
38+
* Disable prepared mode
39+
* @deprecated use "prepare" option instead
40+
*/
3841
no_prepare: boolean;
42+
/**
43+
* Enables prepare mode.
44+
* @default true
45+
*/
46+
prepare: boolean;
3947
/** Defaults to console.log */
4048
onnotice: (notice: postgres.Notice) => void;
4149
/** (key; value) when server param change */
@@ -372,7 +380,7 @@ declare namespace postgres {
372380
? (...args: Parameters<TTypes[name]>) => postgres.Parameter<ReturnType<TTypes[name]>>
373381
: (...args: any) => postgres.Parameter<any>;
374382
};
375-
unsafe<T extends any[] = Row[]>(query: string, parameters?: SerializableParameter[]): PendingQuery<AsRowList<T>>;
383+
unsafe<T extends any[] = Row[]>(query: string, parameters?: SerializableParameter[], queryOptions?: UnsafeQueryOptions): PendingQuery<AsRowList<T>>;
376384
}
377385

378386
interface TransactionSql<TTypes extends JSToPostgresTypeMap> extends Sql<TTypes> {
@@ -382,4 +390,12 @@ declare namespace postgres {
382390

383391
}
384392

393+
interface UnsafeQueryOptions {
394+
/**
395+
* When executes query as prepared statement.
396+
* @default false
397+
*/
398+
prepare?: boolean;
399+
}
400+
385401
export = postgres;

0 commit comments

Comments
 (0)