@steadybrew/postgresjs 0.0.0-stage → 4.0.0-rc1

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.
@@ -0,0 +1,391 @@
1
+ import { Buffer } from 'node:buffer'
2
+ import { Query } from './query.js'
3
+ import { Errors } from './errors.js'
4
+
5
+ export const types = {
6
+ string: {
7
+ to: 25,
8
+ from: null, // defaults to string
9
+ serialize: x => '' + x
10
+ },
11
+ number: {
12
+ to: 0,
13
+ from: [21, 23, 26, 700, 701],
14
+ serialize: x => '' + x,
15
+ parse: x => +x
16
+ },
17
+ json: {
18
+ to: 114,
19
+ from: [114, 3802],
20
+ serialize: x => JSON.stringify(x),
21
+ parse: x => JSON.parse(x)
22
+ },
23
+ boolean: {
24
+ to: 16,
25
+ from: 16,
26
+ serialize: x => x === true ? 't' : 'f',
27
+ parse: x => x === 't'
28
+ },
29
+ date: {
30
+ to: 1184,
31
+ from: [1082, 1114, 1184],
32
+ serialize: x => (x instanceof Date ? x : new Date(x)).toISOString(),
33
+ parse: x => new Date(x)
34
+ },
35
+ bytea: {
36
+ to: 17,
37
+ from: 17,
38
+ serialize: x => '\\x' + Buffer.from(x).toString('hex'),
39
+ parse: x => Buffer.from(x.slice(2), 'hex')
40
+ }
41
+ }
42
+
43
+ class NotTagged { then() { notTagged() } catch() { notTagged() } finally() { notTagged() }}
44
+
45
+ export class Identifier extends NotTagged {
46
+ constructor(value) {
47
+ super()
48
+ this.value = escapeIdentifier(value)
49
+ }
50
+ }
51
+
52
+ export class Parameter extends NotTagged {
53
+ constructor(value, type, array) {
54
+ super()
55
+ this.value = value
56
+ this.type = type
57
+ this.array = array
58
+ }
59
+ }
60
+
61
+ export class Builder extends NotTagged {
62
+ constructor(first, rest) {
63
+ super()
64
+ this.first = first
65
+ this.rest = rest
66
+ }
67
+
68
+ build(before, parameters, types, options) {
69
+ const keyword = builders.map(([x, fn]) => ({ fn, i: before.search(x) })).sort((a, b) => a.i - b.i).pop()
70
+ return keyword.i === -1
71
+ ? escapeIdentifiers(this.first, options)
72
+ : keyword.fn(this.first, this.rest, parameters, types, options)
73
+ }
74
+ }
75
+
76
+ export function handleValue(x, parameters, types, options) {
77
+ let value = x instanceof Parameter ? x.value : x
78
+ if (value === undefined) {
79
+ x instanceof Parameter
80
+ ? x.value = options.transform.undefined
81
+ : value = x = options.transform.undefined
82
+
83
+ if (value === undefined)
84
+ throw Errors.generic('UNDEFINED_VALUE', 'Undefined values are not allowed')
85
+ }
86
+
87
+ return '$' + (types.push(
88
+ x instanceof Parameter
89
+ ? (parameters.push(x.value), x.array
90
+ ? x.array[x.type || inferType(x.value)] || x.type || firstIsString(x.value)
91
+ : x.type
92
+ )
93
+ : (parameters.push(x), inferType(x))
94
+ ))
95
+ }
96
+
97
+ const defaultHandlers = typeHandlers(types)
98
+
99
+ export function stringify(q, string, value, parameters, types, options) { // eslint-disable-line
100
+ for (let i = 1; i < q.strings.length; i++) {
101
+ string += (stringifyValue(string, value, parameters, types, options)) + q.strings[i]
102
+ value = q.args[i]
103
+ }
104
+
105
+ return string
106
+ }
107
+
108
+ function stringifyValue(string, value, parameters, types, o) {
109
+ return (
110
+ value instanceof Builder ? value.build(string, parameters, types, o) :
111
+ value instanceof Query ? fragment(value, parameters, types, o) :
112
+ value instanceof Identifier ? value.value :
113
+ value && value[0] instanceof Query ? value.reduce((acc, x) => acc + ' ' + fragment(x, parameters, types, o), '') :
114
+ handleValue(value, parameters, types, o)
115
+ )
116
+ }
117
+
118
+ function fragment(q, parameters, types, options) {
119
+ q.fragment = true
120
+ return stringify(q, q.strings[0], q.args[0], parameters, types, options)
121
+ }
122
+
123
+ function valuesBuilder(first, parameters, types, columns, options) {
124
+ return first.map(row =>
125
+ '(' + columns.map(column =>
126
+ stringifyValue('values', row[column], parameters, types, options)
127
+ ).join(',') + ')'
128
+ ).join(',')
129
+ }
130
+
131
+ function values(first, rest, parameters, types, options) {
132
+ const multi = Array.isArray(first[0])
133
+ const columns = rest.length ? rest.flat() : Object.keys(multi ? first[0] : first)
134
+ return valuesBuilder(multi ? first : [first], parameters, types, columns, options)
135
+ }
136
+
137
+ function select(first, rest, parameters, types, options) {
138
+ typeof first === 'string' && (first = [first].concat(rest))
139
+ if (Array.isArray(first))
140
+ return escapeIdentifiers(first, options)
141
+
142
+ let value
143
+ const columns = rest.length ? rest.flat() : Object.keys(first)
144
+ return columns.map(x => {
145
+ value = first[x]
146
+ return (
147
+ value instanceof Query ? fragment(value, parameters, types, options) :
148
+ value instanceof Identifier ? value.value :
149
+ handleValue(value, parameters, types, options)
150
+ ) + ' as ' + escapeIdentifier(options.transform.column.to ? options.transform.column.to(x) : x)
151
+ }).join(',')
152
+ }
153
+
154
+ const builders = Object.entries({
155
+ values,
156
+ in: (...xs) => {
157
+ const x = values(...xs)
158
+ return x === '()' ? '(null)' : x
159
+ },
160
+ select,
161
+ as: select,
162
+ returning: select,
163
+ '\\(': select,
164
+
165
+ update(first, rest, parameters, types, options) {
166
+ return (rest.length ? rest.flat() : Object.keys(first)).map(x =>
167
+ escapeIdentifier(options.transform.column.to ? options.transform.column.to(x) : x) +
168
+ '=' + stringifyValue('values', first[x], parameters, types, options)
169
+ )
170
+ },
171
+
172
+ insert(first, rest, parameters, types, options) {
173
+ const columns = rest.length ? rest.flat() : Object.keys(Array.isArray(first) ? first[0] : first)
174
+ return '(' + escapeIdentifiers(columns, options) + ')values' +
175
+ valuesBuilder(Array.isArray(first) ? first : [first], parameters, types, columns, options)
176
+ }
177
+ }).map(([x, fn]) => ([new RegExp('((?:^|[\\s(])' + x + '(?:$|[\\s(]))(?![\\s\\S]*\\1)', 'i'), fn]))
178
+
179
+ function notTagged() {
180
+ throw Errors.generic('NOT_TAGGED_CALL', 'Query not called as a tagged template literal')
181
+ }
182
+
183
+ export const serializers = defaultHandlers.serializers
184
+ export const parsers = defaultHandlers.parsers
185
+
186
+ export const END = {}
187
+
188
+ function firstIsString(x) {
189
+ if (Array.isArray(x))
190
+ return firstIsString(x[0])
191
+ return typeof x === 'string' ? 1009 : 0
192
+ }
193
+
194
+ const builtInArrays = [[16, 1000], [17, 1001], [18, 1002], [19, 1003], [20, 1016], [21, 1005], [23, 1007], [25, 1009],
195
+ [26, 1028], [114, 199], [700, 1021], [701, 1022], [1042, 1014], [1043, 1015], [1082, 1182],
196
+ [1083, 1183], [1114, 1115], [1184, 1185], [1186, 1187], [1700, 1231], [2950, 2951], [3802, 3807]]
197
+
198
+ export function addDefaultArrayTypes(options) {
199
+ builtInArrays.forEach(([oid, typarray]) => addArrayType(options, oid, typarray))
200
+ }
201
+
202
+ export function addArrayType(options, oid, typarray) {
203
+ options.shared.typeArrayMap[oid] = typarray
204
+ if (!options.parsers[typarray]) {
205
+ const parser = options.parsers[oid]
206
+ options.parsers[typarray] = xs => arrayParser(xs, parser, typarray)
207
+ options.parsers[typarray].array = true
208
+ }
209
+ if (!options.serializers[typarray])
210
+ options.serializers[typarray] = xs => arraySerializer(xs, options.serializers[oid], options, typarray)
211
+ }
212
+
213
+ export const mergeUserTypes = function(types) {
214
+ const user = typeHandlers(types || {})
215
+ return {
216
+ serializers: Object.assign({}, serializers, user.serializers),
217
+ parsers: Object.assign({}, parsers, user.parsers)
218
+ }
219
+ }
220
+
221
+ function typeHandlers(types) {
222
+ return Object.keys(types).reduce((acc, k) => {
223
+ types[k].from && [].concat(types[k].from).forEach(x => acc.parsers[x] = types[k].parse)
224
+ if (types[k].serialize) {
225
+ acc.serializers[types[k].to] = types[k].serialize
226
+ types[k].from && [].concat(types[k].from).forEach(x => acc.serializers[x] = types[k].serialize)
227
+ }
228
+ return acc
229
+ }, { parsers: {}, serializers: {} })
230
+ }
231
+
232
+ function escapeIdentifiers(xs, { transform: { column } }) {
233
+ return xs.map(x => escapeIdentifier(column.to ? column.to(x) : x)).join(',')
234
+ }
235
+
236
+ export const escapeIdentifier = function escape(str) {
237
+ return '"' + str.replace(/"/g, '""').replace(/\./g, '"."') + '"'
238
+ }
239
+
240
+ export const inferType = function inferType(x) {
241
+ return (
242
+ x instanceof Parameter ? x.type :
243
+ x instanceof Date ? 1184 :
244
+ x instanceof Uint8Array ? 17 :
245
+ (x === true || x === false) ? 16 :
246
+ typeof x === 'bigint' ? 20 :
247
+ Array.isArray(x) ? inferType(x[0]) :
248
+ 0
249
+ )
250
+ }
251
+
252
+ const escapeBackslash = /\\/g
253
+ const escapeQuote = /"/g
254
+
255
+ function arrayEscape(x) {
256
+ return x
257
+ .replace(escapeBackslash, '\\\\')
258
+ .replace(escapeQuote, '\\"')
259
+ }
260
+
261
+ export const arraySerializer = function arraySerializer(xs, serializer, options, typarray) {
262
+ if (Array.isArray(xs) === false)
263
+ return xs
264
+
265
+ if (!xs.length)
266
+ return '{}'
267
+
268
+ const first = xs[0]
269
+ // Only _box (1020) has the ';' delimiter for arrays, all other types use the ',' delimiter
270
+ const delimiter = typarray === 1020 ? ';' : ','
271
+
272
+ if (Array.isArray(first) && !first.type)
273
+ return '{' + xs.map(x => arraySerializer(x, serializer, options, typarray)).join(delimiter) + '}'
274
+
275
+ return '{' + xs.map(x => {
276
+ if (x === undefined) {
277
+ x = options.transform.undefined
278
+ if (x === undefined)
279
+ throw Errors.generic('UNDEFINED_VALUE', 'Undefined values are not allowed')
280
+ }
281
+
282
+ return x === null
283
+ ? 'null'
284
+ : '"' + arrayEscape(serializer ? serializer(x.type ? x.value : x) : '' + x) + '"'
285
+ }).join(delimiter) + '}'
286
+ }
287
+
288
+ const arrayParserState = {
289
+ i: 0,
290
+ char: null,
291
+ str: '',
292
+ quoted: false,
293
+ last: 0
294
+ }
295
+
296
+ export const arrayParser = function arrayParser(x, parser, typarray) {
297
+ arrayParserState.i = arrayParserState.last = 0
298
+ return arrayParserLoop(arrayParserState, x, parser, typarray)
299
+ }
300
+
301
+ function parseArrayValue(value, parser) {
302
+ return value === 'NULL' ? null : parser ? parser(value) : value
303
+ }
304
+
305
+ function arrayParserLoop(s, x, parser, typarray) {
306
+ const xs = []
307
+ // Only _box (1020) has the ';' delimiter for arrays, all other types use the ',' delimiter
308
+ const delimiter = typarray === 1020 ? ';' : ','
309
+ for (; s.i < x.length; s.i++) {
310
+ s.char = x[s.i]
311
+ if (s.quoted) {
312
+ if (s.char === '\\') {
313
+ s.str += x[++s.i]
314
+ } else if (s.char === '"') {
315
+ xs.push(parser ? parser(s.str) : s.str)
316
+ s.str = ''
317
+ s.quoted = x[s.i + 1] === '"'
318
+ s.last = s.i + 2
319
+ } else {
320
+ s.str += s.char
321
+ }
322
+ } else if (s.char === '"') {
323
+ s.quoted = true
324
+ } else if (s.char === '{') {
325
+ s.last = ++s.i
326
+ xs.push(arrayParserLoop(s, x, parser, typarray))
327
+ } else if (s.char === '}') {
328
+ s.quoted = false
329
+ s.last < s.i && xs.push(parseArrayValue(x.slice(s.last, s.i), parser))
330
+ s.last = s.i + 1
331
+ break
332
+ } else if (s.char === delimiter && s.p !== '}' && s.p !== '"') {
333
+ xs.push(parseArrayValue(x.slice(s.last, s.i), parser))
334
+ s.last = s.i + 1
335
+ }
336
+ s.p = s.char
337
+ }
338
+ s.last < s.i && xs.push(parseArrayValue(x.slice(s.last, s.i + 1), parser))
339
+ return xs
340
+ }
341
+
342
+ export const toCamel = x => {
343
+ let str = x[0]
344
+ for (let i = 1; i < x.length; i++)
345
+ str += x[i] === '_' ? x[++i].toUpperCase() : x[i]
346
+ return str
347
+ }
348
+
349
+ export const toPascal = x => {
350
+ let str = x[0].toUpperCase()
351
+ for (let i = 1; i < x.length; i++)
352
+ str += x[i] === '_' ? x[++i].toUpperCase() : x[i]
353
+ return str
354
+ }
355
+
356
+ export const toKebab = x => x.replace(/_/g, '-')
357
+
358
+ export const fromCamel = x => x.replace(/([A-Z])/g, '_$1').toLowerCase()
359
+ export const fromPascal = x => (x.slice(0, 1) + x.slice(1).replace(/([A-Z])/g, '_$1')).toLowerCase()
360
+ export const fromKebab = x => x.replace(/-/g, '_')
361
+
362
+ function createJsonTransform(fn) {
363
+ return function jsonTransform(x, column) {
364
+ return typeof x === 'object' && x !== null && (column.type === 114 || column.type === 3802)
365
+ ? Array.isArray(x)
366
+ ? x.map(x => jsonTransform(x, column))
367
+ : Object.entries(x).reduce((acc, [k, v]) => Object.assign(acc, { [fn(k)]: jsonTransform(v, column) }), {})
368
+ : x
369
+ }
370
+ }
371
+
372
+ toCamel.column = { from: toCamel }
373
+ toCamel.value = { from: createJsonTransform(toCamel) }
374
+ fromCamel.column = { to: fromCamel }
375
+
376
+ export const camel = { ...toCamel }
377
+ camel.column.to = fromCamel
378
+
379
+ toPascal.column = { from: toPascal }
380
+ toPascal.value = { from: createJsonTransform(toPascal) }
381
+ fromPascal.column = { to: fromPascal }
382
+
383
+ export const pascal = { ...toPascal }
384
+ pascal.column.to = fromPascal
385
+
386
+ toKebab.column = { from: toKebab }
387
+ toKebab.value = { from: createJsonTransform(toKebab) }
388
+ fromKebab.column = { to: fromKebab }
389
+
390
+ export const kebab = { ...toKebab }
391
+ kebab.column.to = fromKebab
@@ -0,0 +1 @@
1
+ {"type":"commonjs"}
@@ -0,0 +1,78 @@
1
+ const size = 256
2
+ let buffer = Buffer.allocUnsafe(size)
3
+
4
+ const messages = 'BCcDdEFfHPpQSX'.split('').reduce((acc, x) => {
5
+ const v = x.charCodeAt(0)
6
+ acc[x] = () => {
7
+ buffer[0] = v
8
+ b.i = 5
9
+ return b
10
+ }
11
+ return acc
12
+ }, {})
13
+
14
+ const b = Object.assign(reset, messages, {
15
+ N: String.fromCharCode(0),
16
+ i: 0,
17
+ inc(x) {
18
+ b.i += x
19
+ return b
20
+ },
21
+ str(x) {
22
+ const length = Buffer.byteLength(x)
23
+ fit(length)
24
+ b.i += buffer.write(x, b.i, length, 'utf8')
25
+ return b
26
+ },
27
+ i16(x) {
28
+ fit(2)
29
+ buffer.writeUInt16BE(x, b.i)
30
+ b.i += 2
31
+ return b
32
+ },
33
+ i32(x, i) {
34
+ if (i || i === 0) {
35
+ buffer.writeUInt32BE(x, i)
36
+ return b
37
+ }
38
+ fit(4)
39
+ buffer.writeUInt32BE(x, b.i)
40
+ b.i += 4
41
+ return b
42
+ },
43
+ z(x) {
44
+ fit(x)
45
+ buffer.fill(0, b.i, b.i + x)
46
+ b.i += x
47
+ return b
48
+ },
49
+ raw(x) {
50
+ buffer = Buffer.concat([buffer.subarray(0, b.i), x])
51
+ b.i = buffer.length
52
+ return b
53
+ },
54
+ end(at = 1) {
55
+ buffer.writeUInt32BE(b.i - at, at)
56
+ const out = buffer.subarray(0, b.i)
57
+ b.i = 0
58
+ buffer = Buffer.allocUnsafe(size)
59
+ return out
60
+ }
61
+ })
62
+
63
+ module.exports = b
64
+
65
+ function fit(x) {
66
+ if (buffer.length - b.i < x) {
67
+ const prev = buffer
68
+ , length = prev.length
69
+
70
+ buffer = Buffer.allocUnsafe(length + (length >> 1) + x)
71
+ prev.copy(buffer)
72
+ }
73
+ }
74
+
75
+ function reset() {
76
+ b.i = 0
77
+ return b
78
+ }