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