@steadybrew/postgresjs 4.3.0 → 4.4.0
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/README.md +18 -2
- package/cf/src/connection.js +58 -19
- package/cf/src/errors.js +8 -0
- package/cf/src/index.js +47 -32
- package/cf/src/subscribe.js +122 -47
- package/cjs/src/connection.js +58 -19
- package/cjs/src/errors.js +8 -0
- package/cjs/src/index.js +47 -32
- package/cjs/src/subscribe.js +122 -47
- package/package.json +1 -1
- package/src/connection.js +58 -19
- package/src/errors.js +8 -0
- package/src/index.js +47 -32
- package/src/subscribe.js +122 -47
- package/types/index.d.ts +9 -9
package/cjs/src/index.js
CHANGED
|
@@ -8,6 +8,7 @@ const {
|
|
|
8
8
|
Parameter,
|
|
9
9
|
Identifier,
|
|
10
10
|
Builder,
|
|
11
|
+
escapeIdentifier,
|
|
11
12
|
toPascal,
|
|
12
13
|
pascal,
|
|
13
14
|
toCamel,
|
|
@@ -19,12 +20,12 @@ const {
|
|
|
19
20
|
fromKebab
|
|
20
21
|
} = require('./types.js')
|
|
21
22
|
|
|
22
|
-
const Connection = require('./connection.js')
|
|
23
|
+
const { Connection, defaultBackoff } = require('./connection.js')
|
|
23
24
|
const { cancelRequest } = require('./transport.js')
|
|
24
25
|
const clampedTimeout = require('./timeout.js')
|
|
25
26
|
const { Query, CLOSE } = require('./query.js')
|
|
26
27
|
const Queue = require('./queue.js')
|
|
27
|
-
const { Errors, PostgresError } = require('./errors.js')
|
|
28
|
+
const { Errors, PostgresError, callback } = require('./errors.js')
|
|
28
29
|
const Subscribe = require('./subscribe.js')
|
|
29
30
|
const largeObject = require('./large.js')
|
|
30
31
|
|
|
@@ -218,7 +219,7 @@ function Postgres(a, b) {
|
|
|
218
219
|
})
|
|
219
220
|
},
|
|
220
221
|
onnotify(c, x) {
|
|
221
|
-
c in listen.channels && listen.channels[c].listeners.forEach(l => l.fn
|
|
222
|
+
c in listen.channels && listen.channels[c].listeners.forEach(l => callback(l.fn, x))
|
|
222
223
|
}
|
|
223
224
|
}))
|
|
224
225
|
|
|
@@ -228,7 +229,7 @@ function Postgres(a, b) {
|
|
|
228
229
|
if (exists) {
|
|
229
230
|
channels[name].listeners.push(listener)
|
|
230
231
|
const result = await channels[name].result
|
|
231
|
-
listener.onlisten
|
|
232
|
+
callback(listener.onlisten)
|
|
232
233
|
return { state: result.state, unlisten }
|
|
233
234
|
}
|
|
234
235
|
|
|
@@ -236,7 +237,7 @@ function Postgres(a, b) {
|
|
|
236
237
|
sql.unsafe('"' + name.replace(/"/g, '""') + '"')
|
|
237
238
|
}`, listeners: [listener] }
|
|
238
239
|
const result = await channels[name].result
|
|
239
|
-
listener.onlisten
|
|
240
|
+
callback(listener.onlisten)
|
|
240
241
|
return { state: result.state, unlisten }
|
|
241
242
|
|
|
242
243
|
async function unlisten() {
|
|
@@ -294,9 +295,9 @@ function Postgres(a, b) {
|
|
|
294
295
|
function send(l, q, expected = Lease.Active) {
|
|
295
296
|
const c = l.connection
|
|
296
297
|
l.state === expected
|
|
297
|
-
? c.queue
|
|
298
|
-
? (q
|
|
299
|
-
:
|
|
298
|
+
? c.copying || (c.queue !== full && c.accepting)
|
|
299
|
+
? c.execute(q) || move(c, full)
|
|
300
|
+
: (move(c, full), q.queue = l.queue, l.queue.push(q))
|
|
300
301
|
: q.reject(leaseError(l.state))
|
|
301
302
|
}
|
|
302
303
|
|
|
@@ -352,14 +353,16 @@ function Postgres(a, b) {
|
|
|
352
353
|
}
|
|
353
354
|
|
|
354
355
|
async function finish(statement) {
|
|
356
|
+
let result
|
|
355
357
|
l.state = Lease.Settling
|
|
356
358
|
try {
|
|
357
|
-
await statement(Sql(q => send(l, q, Lease.Settling)))
|
|
359
|
+
result = await statement(Sql(q => send(l, q, Lease.Settling)))
|
|
358
360
|
} catch (e) {
|
|
359
361
|
settle(l, Lease.Discarded)
|
|
360
362
|
throw e
|
|
361
363
|
}
|
|
362
364
|
settle(l, Lease.Released)
|
|
365
|
+
return result
|
|
363
366
|
}
|
|
364
367
|
|
|
365
368
|
async function scope(fn, name) {
|
|
@@ -374,7 +377,7 @@ function Postgres(a, b) {
|
|
|
374
377
|
let uncaughtError
|
|
375
378
|
, result
|
|
376
379
|
|
|
377
|
-
name && await sql
|
|
380
|
+
name && await sql.unsafe('savepoint ' + escapeIdentifier(name))
|
|
378
381
|
try {
|
|
379
382
|
result = await new Promise((resolve, reject) => {
|
|
380
383
|
const x = fn(sql)
|
|
@@ -385,8 +388,8 @@ function Postgres(a, b) {
|
|
|
385
388
|
throw uncaughtError
|
|
386
389
|
} catch (e) {
|
|
387
390
|
l.state === Lease.Active && await (name
|
|
388
|
-
? sql
|
|
389
|
-
: finish(final => final
|
|
391
|
+
? sql.unsafe('rollback to ' + escapeIdentifier(name))
|
|
392
|
+
: finish(final => final.unsafe('rollback'))
|
|
390
393
|
)
|
|
391
394
|
throw e instanceof PostgresError && e.code === '25P02' && uncaughtError || e
|
|
392
395
|
}
|
|
@@ -394,10 +397,18 @@ function Postgres(a, b) {
|
|
|
394
397
|
if (l.state !== Lease.Active)
|
|
395
398
|
throw l.error || leaseError(l.state)
|
|
396
399
|
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
400
|
+
if (!name) {
|
|
401
|
+
const done = await finish(final => prepare
|
|
402
|
+
? final.unsafe('prepare transaction ' + prepare)
|
|
403
|
+
: final.unsafe('commit')
|
|
404
|
+
)
|
|
405
|
+
if (done.command === 'ROLLBACK') {
|
|
406
|
+
throw Object.assign(
|
|
407
|
+
Errors.generic('TRANSACTION_ROLLED_BACK', 'The server rolled the transaction back instead of committing it'),
|
|
408
|
+
uncaughtError && { cause: uncaughtError }
|
|
409
|
+
)
|
|
410
|
+
}
|
|
411
|
+
}
|
|
401
412
|
|
|
402
413
|
return result
|
|
403
414
|
|
|
@@ -426,14 +437,6 @@ function Postgres(a, b) {
|
|
|
426
437
|
return c
|
|
427
438
|
}
|
|
428
439
|
|
|
429
|
-
function callback(fn, ...args) {
|
|
430
|
-
try {
|
|
431
|
-
fn && fn(...args)
|
|
432
|
-
} catch (e) {
|
|
433
|
-
queueMicrotask(() => { throw e })
|
|
434
|
-
}
|
|
435
|
-
}
|
|
436
|
-
|
|
437
440
|
function json(x) {
|
|
438
441
|
return new Parameter(x, 3802)
|
|
439
442
|
}
|
|
@@ -456,11 +459,24 @@ function Postgres(a, b) {
|
|
|
456
459
|
if (closed.length)
|
|
457
460
|
return connect(closed.shift(), query)
|
|
458
461
|
|
|
459
|
-
|
|
460
|
-
|
|
462
|
+
const c = takeBusy()
|
|
463
|
+
c
|
|
464
|
+
? go(c, query)
|
|
461
465
|
: queries.push(query)
|
|
462
466
|
}
|
|
463
467
|
|
|
468
|
+
function takeBusy() {
|
|
469
|
+
while (busy.length) {
|
|
470
|
+
const c = busy.shift()
|
|
471
|
+
if (c.accepting)
|
|
472
|
+
return c
|
|
473
|
+
|
|
474
|
+
move(c, full)
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
return null
|
|
478
|
+
}
|
|
479
|
+
|
|
464
480
|
function takeOpen() {
|
|
465
481
|
while (open.length) {
|
|
466
482
|
const c = open.shift()
|
|
@@ -545,6 +561,9 @@ function Postgres(a, b) {
|
|
|
545
561
|
if (initial && initial.reserve)
|
|
546
562
|
return initial.reserve(c)
|
|
547
563
|
|
|
564
|
+
if (!initial && !c.accepting)
|
|
565
|
+
return move(c, full)
|
|
566
|
+
|
|
548
567
|
if (!initial && !queries.length)
|
|
549
568
|
return move(c, open)
|
|
550
569
|
|
|
@@ -583,7 +602,7 @@ function Postgres(a, b) {
|
|
|
583
602
|
function onclose(c, e) {
|
|
584
603
|
move(c, closed)
|
|
585
604
|
c.owner && settle(c.owner, Lease.Closed, e)
|
|
586
|
-
options.onclose
|
|
605
|
+
callback(options.onclose, c.id)
|
|
587
606
|
if (ending)
|
|
588
607
|
return closedWhileEnding(c, e)
|
|
589
608
|
|
|
@@ -638,7 +657,7 @@ function parseOptions(a, b) {
|
|
|
638
657
|
connect_timeout : 30,
|
|
639
658
|
max_lifetime : max_lifetime,
|
|
640
659
|
max_pipeline : 100,
|
|
641
|
-
backoff :
|
|
660
|
+
backoff : defaultBackoff,
|
|
642
661
|
keep_alive : 60,
|
|
643
662
|
prepare : true,
|
|
644
663
|
debug : false,
|
|
@@ -697,10 +716,6 @@ function tsa(o, url, env) {
|
|
|
697
716
|
throw new Error('target_session_attrs ' + x + ' is not supported')
|
|
698
717
|
}
|
|
699
718
|
|
|
700
|
-
function backoff(retries) {
|
|
701
|
-
return (0.5 + Math.random() / 2) * Math.min(3 ** retries / 100, 20)
|
|
702
|
-
}
|
|
703
|
-
|
|
704
719
|
function max_lifetime() {
|
|
705
720
|
return 60 * (30 + Math.random() * 30)
|
|
706
721
|
}
|
package/cjs/src/subscribe.js
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
|
+
const { callback } = require('./errors.js')
|
|
2
|
+
const { defaultBackoff, backoffSeconds } = require('./connection.js')
|
|
3
|
+
|
|
1
4
|
const noop = () => { /* noop */ }
|
|
5
|
+
, commands = { 68: 'delete', 73: 'insert', 85: 'update' }
|
|
2
6
|
|
|
3
7
|
module.exports = Subscribe;function Subscribe(postgres, options) {
|
|
4
8
|
const subscribers = new Map()
|
|
@@ -7,6 +11,9 @@ module.exports = Subscribe;function Subscribe(postgres, options) {
|
|
|
7
11
|
|
|
8
12
|
let connection
|
|
9
13
|
, stream
|
|
14
|
+
, timer
|
|
15
|
+
, inflight = false
|
|
16
|
+
, retries = 0
|
|
10
17
|
, ended = false
|
|
11
18
|
|
|
12
19
|
const sql = subscribe.sql = postgres({
|
|
@@ -21,13 +28,12 @@ module.exports = Subscribe;function Subscribe(postgres, options) {
|
|
|
21
28
|
...options.connection,
|
|
22
29
|
replication: 'database'
|
|
23
30
|
},
|
|
24
|
-
onclose:
|
|
31
|
+
onclose: function() {
|
|
25
32
|
if (ended)
|
|
26
33
|
return
|
|
27
34
|
stream = null
|
|
28
35
|
state.pid = state.secret = undefined
|
|
29
|
-
|
|
30
|
-
subscribers.forEach(event => event.forEach(({ onsubscribe }) => onsubscribe()))
|
|
36
|
+
inflight || timer || !connection || connect().catch(noop)
|
|
31
37
|
},
|
|
32
38
|
no_subscribe: true
|
|
33
39
|
})
|
|
@@ -37,6 +43,9 @@ module.exports = Subscribe;function Subscribe(postgres, options) {
|
|
|
37
43
|
|
|
38
44
|
sql.end = async() => {
|
|
39
45
|
ended = true
|
|
46
|
+
clearTimeout(timer)
|
|
47
|
+
timer = null
|
|
48
|
+
connection && await connection.catch(noop)
|
|
40
49
|
stream && (await new Promise(r => (stream.once('close', r), stream.end())))
|
|
41
50
|
return end()
|
|
42
51
|
}
|
|
@@ -48,34 +57,74 @@ module.exports = Subscribe;function Subscribe(postgres, options) {
|
|
|
48
57
|
|
|
49
58
|
return subscribe
|
|
50
59
|
|
|
51
|
-
async function subscribe(event, fn, onsubscribe = noop, onerror
|
|
60
|
+
async function subscribe(event, fn, onsubscribe = noop, onerror) {
|
|
52
61
|
event = parseEvent(event)
|
|
53
62
|
|
|
54
|
-
|
|
55
|
-
connection = init(sql, slot, options.publications)
|
|
63
|
+
const subscriber = { fn, onsubscribe, onerror }
|
|
56
64
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
65
|
+
return (connection || connect()).then(() => {
|
|
66
|
+
const fns = subscribers.has(event)
|
|
67
|
+
? subscribers.get(event).add(subscriber)
|
|
68
|
+
: subscribers.set(event, new Set([subscriber])).get(event)
|
|
61
69
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
70
|
+
const unsubscribe = () => {
|
|
71
|
+
fns.delete(subscriber)
|
|
72
|
+
fns.size === 0 && subscribers.delete(event)
|
|
73
|
+
subscribers.size === 0 && (clearTimeout(timer), timer = null)
|
|
74
|
+
}
|
|
66
75
|
|
|
67
|
-
|
|
68
|
-
connected(x)
|
|
69
|
-
onsubscribe()
|
|
70
|
-
stream && stream.on('error', onerror)
|
|
76
|
+
callback(onsubscribe)
|
|
71
77
|
return { unsubscribe, state, sql }
|
|
72
78
|
})
|
|
73
79
|
}
|
|
74
80
|
|
|
75
|
-
function
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
81
|
+
function connect() {
|
|
82
|
+
clearTimeout(timer)
|
|
83
|
+
timer = null
|
|
84
|
+
inflight = true
|
|
85
|
+
const resume = subscribers.size > 0
|
|
86
|
+
const current = connection = init(sql, slot, options.publications).then(x => {
|
|
87
|
+
stream = x.stream
|
|
88
|
+
state.pid = x.state.pid
|
|
89
|
+
state.secret = x.state.secret
|
|
90
|
+
})
|
|
91
|
+
|
|
92
|
+
current.then(
|
|
93
|
+
() => {
|
|
94
|
+
inflight = false
|
|
95
|
+
retries = 0
|
|
96
|
+
resume && !ended && subscribers.forEach(event => event.forEach(({ onsubscribe }) => callback(onsubscribe)))
|
|
97
|
+
},
|
|
98
|
+
error => {
|
|
99
|
+
inflight = false
|
|
100
|
+
connection === current && (connection = null)
|
|
101
|
+
if (ended || subscribers.size === 0)
|
|
102
|
+
return
|
|
103
|
+
reportConnection(error)
|
|
104
|
+
timer = setTimeout(() => connect().catch(noop), retryDelay(retries++))
|
|
105
|
+
}
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
return current
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function retryDelay(n) {
|
|
112
|
+
let seconds = backoffSeconds(sql.options.backoff, n)
|
|
113
|
+
seconds = Number.isFinite(seconds) ? seconds : defaultBackoff(n)
|
|
114
|
+
return Math.min(Math.max(seconds * 1000, 100), 2 ** 31 - 1)
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function reportConnection(error) {
|
|
118
|
+
console.error('Unexpected error during logical streaming - reconnecting', error) // eslint-disable-line
|
|
119
|
+
subscribers.forEach(fns => fns.forEach(({ onerror }) => callback(onerror, error)))
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function report(error, match) {
|
|
123
|
+
let uncaught = false
|
|
124
|
+
subscribers.forEach((fns, event) => match(event) && fns.forEach(({ onerror }) =>
|
|
125
|
+
onerror ? callback(onerror, error) : uncaught = true
|
|
126
|
+
))
|
|
127
|
+
uncaught && callback(() => { throw error })
|
|
79
128
|
}
|
|
80
129
|
|
|
81
130
|
async function init(sql, slot, publications) {
|
|
@@ -99,18 +148,18 @@ module.exports = Subscribe;function Subscribe(postgres, options) {
|
|
|
99
148
|
}
|
|
100
149
|
|
|
101
150
|
stream.on('data', data)
|
|
102
|
-
stream.on('error',
|
|
151
|
+
stream.on('error', reportConnection)
|
|
103
152
|
stream.on('close', sql.close)
|
|
104
153
|
|
|
105
154
|
return { stream, state: xs.state }
|
|
106
155
|
|
|
107
|
-
function error(e) {
|
|
108
|
-
console.error('Unexpected error during logical streaming - reconnecting', e) // eslint-disable-line
|
|
109
|
-
}
|
|
110
|
-
|
|
111
156
|
function data(x) {
|
|
112
157
|
if (x[0] === 0x77) {
|
|
113
|
-
|
|
158
|
+
try {
|
|
159
|
+
parse(x.subarray(25), state, sql.options.parsers, handle, options.transform)
|
|
160
|
+
} catch (error) {
|
|
161
|
+
skip(x.subarray(25), error)
|
|
162
|
+
}
|
|
114
163
|
} else if (x[0] === 0x6b && x[17]) {
|
|
115
164
|
state.lsn = x.subarray(1, 9)
|
|
116
165
|
pong()
|
|
@@ -119,12 +168,26 @@ module.exports = Subscribe;function Subscribe(postgres, options) {
|
|
|
119
168
|
|
|
120
169
|
function handle(a, b) {
|
|
121
170
|
const path = b.relation.schema + '.' + b.relation.table
|
|
171
|
+
, key = b.relation.keys.length && '=' + b.relation.keys.map(x => a[x.name])
|
|
122
172
|
call('*', a, b)
|
|
123
173
|
call('*:' + path, a, b)
|
|
124
|
-
|
|
174
|
+
key && call('*:' + path + key, a, b)
|
|
125
175
|
call(b.command, a, b)
|
|
126
176
|
call(b.command + ':' + path, a, b)
|
|
127
|
-
|
|
177
|
+
key && call(b.command + ':' + path + key, a, b)
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
function skip(x, error) {
|
|
181
|
+
const command = commands[x[0]]
|
|
182
|
+
, relation = command && state[x.readUInt32BE(1)]
|
|
183
|
+
|
|
184
|
+
if (!relation)
|
|
185
|
+
throw error
|
|
186
|
+
|
|
187
|
+
const path = relation.schema + '.' + relation.table
|
|
188
|
+
, events = ['*', '*:' + path, command, command + ':' + path]
|
|
189
|
+
|
|
190
|
+
report(error, event => events.includes(event.split('=')[0]))
|
|
128
191
|
}
|
|
129
192
|
|
|
130
193
|
function pong() {
|
|
@@ -137,7 +200,7 @@ module.exports = Subscribe;function Subscribe(postgres, options) {
|
|
|
137
200
|
}
|
|
138
201
|
|
|
139
202
|
function call(x, a, b) {
|
|
140
|
-
subscribers.has(x) && subscribers.get(x).forEach(({ fn }) => fn
|
|
203
|
+
subscribers.has(x) && subscribers.get(x).forEach(({ fn }) => callback(fn, a, b, x))
|
|
141
204
|
}
|
|
142
205
|
}
|
|
143
206
|
|
|
@@ -162,19 +225,24 @@ function parse(x, state, parsers, handle, transform) {
|
|
|
162
225
|
let columnIndex = 0
|
|
163
226
|
, column
|
|
164
227
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
228
|
+
try {
|
|
229
|
+
while (i < x.length) {
|
|
230
|
+
column = r.columns[columnIndex++] = {
|
|
231
|
+
key: x[i++],
|
|
232
|
+
name: transform.column.from
|
|
233
|
+
? transform.column.from(x.toString('utf8', i, i = x.indexOf(0, i)))
|
|
234
|
+
: x.toString('utf8', i, i = x.indexOf(0, i)),
|
|
235
|
+
type: x.readUInt32BE(i += 1),
|
|
236
|
+
parser: parsers[x.readUInt32BE(i)],
|
|
237
|
+
atttypmod: x.readUInt32BE(i += 4)
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
column.key && r.keys.push(column)
|
|
241
|
+
i += 4
|
|
174
242
|
}
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
243
|
+
} catch (error) {
|
|
244
|
+
r.error = error
|
|
245
|
+
r.failed = true
|
|
178
246
|
}
|
|
179
247
|
},
|
|
180
248
|
Y: () => { /* noop */ }, // Type
|
|
@@ -185,7 +253,7 @@ function parse(x, state, parsers, handle, transform) {
|
|
|
185
253
|
},
|
|
186
254
|
I: x => { // Insert
|
|
187
255
|
let i = 1
|
|
188
|
-
const relation = state[x.readUInt32BE(i)]
|
|
256
|
+
const relation = decodable(state[x.readUInt32BE(i)])
|
|
189
257
|
const { row } = tuples(x, relation.columns, i += 7, transform)
|
|
190
258
|
|
|
191
259
|
handle(row, {
|
|
@@ -195,7 +263,7 @@ function parse(x, state, parsers, handle, transform) {
|
|
|
195
263
|
},
|
|
196
264
|
D: x => { // Delete
|
|
197
265
|
let i = 1
|
|
198
|
-
const relation = state[x.readUInt32BE(i)]
|
|
266
|
+
const relation = decodable(state[x.readUInt32BE(i)])
|
|
199
267
|
i += 4
|
|
200
268
|
const key = x[i] === 75
|
|
201
269
|
handle(key || x[i] === 79
|
|
@@ -209,7 +277,7 @@ function parse(x, state, parsers, handle, transform) {
|
|
|
209
277
|
},
|
|
210
278
|
U: x => { // Update
|
|
211
279
|
let i = 1
|
|
212
|
-
const relation = state[x.readUInt32BE(i)]
|
|
280
|
+
const relation = decodable(state[x.readUInt32BE(i)])
|
|
213
281
|
i += 4
|
|
214
282
|
const key = x[i] === 75
|
|
215
283
|
const xs = key || x[i] === 79
|
|
@@ -232,6 +300,13 @@ function parse(x, state, parsers, handle, transform) {
|
|
|
232
300
|
}).reduce(char, {})[x[0]](x)
|
|
233
301
|
}
|
|
234
302
|
|
|
303
|
+
function decodable(relation) {
|
|
304
|
+
if (relation.failed)
|
|
305
|
+
throw relation.error
|
|
306
|
+
|
|
307
|
+
return relation
|
|
308
|
+
}
|
|
309
|
+
|
|
235
310
|
function tuples(x, columns, xi, transform) {
|
|
236
311
|
let type
|
|
237
312
|
, column
|
|
@@ -265,7 +340,7 @@ function tuples(x, columns, xi, transform) {
|
|
|
265
340
|
}
|
|
266
341
|
|
|
267
342
|
function parseEvent(x) {
|
|
268
|
-
const xs = x.match(/^(\*|insert|update|delete)?:?([
|
|
343
|
+
const xs = x.match(/^(\*|insert|update|delete)?:?([^.=]+(?:\.[^=]+)?)?=?(.+)?/i) || []
|
|
269
344
|
|
|
270
345
|
if (!xs)
|
|
271
346
|
throw new Error('Malformed subscribe pattern: ' + x)
|