Skip to content

Commit 8b405b3

Browse files
authored
Add raw() method - fixes porsager#194 (porsager#196)
* Add raw() method - fixes porsager#194
1 parent 1e7713e commit 8b405b3

File tree

4 files changed

+49
-22
lines changed

4 files changed

+49
-22
lines changed

README.md

+7-1
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ const sql = postgres()
126126

127127
## Query ```sql` ` -> Promise```
128128

129-
A query will always return a `Promise` which resolves to a results array `[...]{ count, command }`. Destructuring is great to immediately access the first element.
129+
A query will always return a `Promise` which resolves to a results array `[...]{ count, command, columns }`. Destructuring is great to immediately access the first element.
130130

131131
```js
132132

@@ -278,6 +278,12 @@ await sql`
278278

279279
```
280280

281+
## Raw ```sql``.raw()```
282+
283+
Using `.raw()` will return rows as an array with `Buffer` values for each column, instead of objects.
284+
285+
This can be useful to receive identical named columns, or for specific performance / transformation reasons. The column definitions are still included on the result array with access to parsers for each column.
286+
281287
## Listen and notify
282288

283289
When you call listen, a dedicated connection will automatically be made to ensure that you receive notifications in real time. This connection will be used for any further calls to listen. Listen returns a promise which resolves once the `LISTEN` query to Postgres completes, or if there is already a listener active.

lib/backend.js

+12-8
Original file line numberDiff line numberDiff line change
@@ -100,21 +100,25 @@ function Backend({
100100
let column
101101
let value
102102

103-
const row = {}
103+
const row = backend.query.raw ? new Array(backend.query.statement.columns.length) : {}
104104
for (let i = 0; i < backend.query.statement.columns.length; i++) {
105105
column = backend.query.statement.columns[i]
106106
length = x.readInt32BE(index)
107107
index += 4
108108

109109
value = length === -1
110110
? null
111-
: column.parser === undefined
112-
? x.toString('utf8', index, index += length)
113-
: column.parser.array === true
114-
? column.parser(x.toString('utf8', index + 1, index += length))
115-
: column.parser(x.toString('utf8', index, index += length))
116-
117-
row[column.name] = transform.value ? transform.value(value) : value
111+
: backend.query.raw
112+
? x.slice(index, index += length)
113+
: column.parser === undefined
114+
? x.toString('utf8', index, index += length)
115+
: column.parser.array === true
116+
? column.parser(x.toString('utf8', index + 1, index += length))
117+
: column.parser(x.toString('utf8', index, index += length))
118+
119+
backend.query.raw
120+
? (row[i] = value)
121+
: (row[column.name] = transform.value ? transform.value(value) : value)
118122
}
119123

120124
backend.query.stream

lib/index.js

+14-13
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({ prepare: options.prepare }, getConnection(), xs, Array.from(arguments).slice(1))
70+
return query({ tagged: true, prepare: options.prepare }, getConnection(), xs, Array.from(arguments).slice(1))
7171
}
7272

7373
Object.assign(postgres, {
@@ -124,7 +124,7 @@ function Postgres(a, b) {
124124
}, connection)
125125
})
126126

127-
query({ raw: true }, connection, begin || savepoint)
127+
query({}, connection, begin || savepoint)
128128
.then(() => {
129129
const result = fn(scoped)
130130
return Array.isArray(result)
@@ -137,7 +137,7 @@ function Postgres(a, b) {
137137
: resolve(x)
138138
)
139139
.catch((err) => {
140-
query({ raw: true }, connection,
140+
query({}, connection,
141141
begin
142142
? 'rollback'
143143
: 'rollback to ' + savepoint
@@ -150,7 +150,7 @@ function Postgres(a, b) {
150150
}))
151151

152152
function scoped(xs) {
153-
return query({}, connection, xs, Array.from(arguments).slice(1))
153+
return query({ tagged: true }, connection, xs, Array.from(arguments).slice(1))
154154
}
155155
}
156156

@@ -168,7 +168,7 @@ function Postgres(a, b) {
168168
function query(query, connection, xs, args) {
169169
query.origin = options.debug ? new Error().stack : cachedError(xs)
170170
query.prepare = 'prepare' in query ? query.prepare : options.prepare
171-
if (!query.raw && (!Array.isArray(xs) || !Array.isArray(xs.raw)))
171+
if (query.tagged && (!Array.isArray(xs) || !Array.isArray(xs.raw)))
172172
return nested(xs, args)
173173

174174
const promise = new Promise((resolve, reject) => {
@@ -206,7 +206,7 @@ function Postgres(a, b) {
206206

207207
function send(connection, query, xs, args) {
208208
connection
209-
? process.nextTick(connection.send, query, query.raw ? parseRaw(query, xs, args) : parse(query, xs, args))
209+
? process.nextTick(connection.send, query, query.tagged ? parseTagged(query, xs, args) : parseUnsafe(query, xs, args))
210210
: queries.push({ query, xs, args })
211211
}
212212

@@ -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, prepare: false, origin: new Error().stack }, `
244+
send(connection, { resolve, reject, tagged: false, prepare: false, origin: new Error().stack }, `
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
@@ -286,7 +286,7 @@ function Postgres(a, b) {
286286

287287
function unsafe(xs, args, queryOptions) {
288288
const prepare = queryOptions && queryOptions.prepare || false
289-
return query({ raw: true, simple: !args, prepare }, connection || getConnection(), xs, args || [])
289+
return query({ simple: !args, prepare }, connection || getConnection(), xs, args || [])
290290
}
291291

292292
function file(path, args, options = {}) {
@@ -299,7 +299,7 @@ function Postgres(a, b) {
299299
options.cache = true
300300

301301
const file = files[path]
302-
const q = { raw: true, simple: !args }
302+
const q = { tagged: false, simple: !args }
303303

304304
if (options.cache && typeof file === 'string')
305305
return query(q, connection || getConnection(), file, args || [])
@@ -325,6 +325,7 @@ function Postgres(a, b) {
325325
}
326326

327327
function addMethods(promise, query) {
328+
promise.raw = () => (query.raw = true, promise)
328329
promise.stream = (fn) => (query.stream = fn, promise)
329330
promise.cursor = (rows, fn) => {
330331
if (typeof rows === 'function') {
@@ -350,7 +351,7 @@ function Postgres(a, b) {
350351

351352
listeners[channel] = [fn]
352353

353-
return query({ raw: true }, listener.conn, 'listen ' + escape(channel))
354+
return query({}, listener.conn, 'listen ' + escape(channel))
354355
.then((result) => {
355356
Object.assign(listener.result, result)
356357
return Object.create(listener.result, {
@@ -368,7 +369,7 @@ function Postgres(a, b) {
368369
return Promise.resolve()
369370

370371
delete listeners[channel]
371-
return query({ raw: true }, getListener().conn, 'unlisten ' + escape(channel)).then(() => undefined)
372+
return query({}, getListener().conn, 'unlisten ' + escape(channel)).then(() => undefined)
372373
}
373374
}
374375

@@ -409,7 +410,7 @@ function Postgres(a, b) {
409410
.then(() => clearTimeout(destroy))
410411
}
411412

412-
function parseRaw(query, str, args = []) {
413+
function parseUnsafe(query, str, args = []) {
413414
const types = []
414415
, xargs = []
415416

@@ -422,7 +423,7 @@ function Postgres(a, b) {
422423
}
423424
}
424425

425-
function parse(query, xs, args = []) {
426+
function parseTagged(query, xs, args = []) {
426427
const xargs = []
427428
, types = []
428429

tests/index.js

+16
Original file line numberDiff line numberDiff line change
@@ -1321,3 +1321,19 @@ t('Escaping supports schemas and tables', async() => {
13211321
await sql`drop schema a`
13221322
]
13231323
})
1324+
1325+
t('Raw method returns rows as arrays', async() => {
1326+
const [x] = await sql`select 1`.raw()
1327+
return [
1328+
Array.isArray(x),
1329+
true
1330+
]
1331+
})
1332+
1333+
t('Raw method returns values unparsed as Buffer', async() => {
1334+
const [[x]] = await sql`select 1`.raw()
1335+
return [
1336+
x instanceof Buffer,
1337+
true
1338+
]
1339+
})

0 commit comments

Comments
 (0)