@keyv/postgres 2.2.1 → 2.2.3
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/dist/index.cjs +48 -12
- package/dist/index.d.cts +3 -2
- package/dist/index.d.ts +3 -2
- package/dist/index.js +48 -12
- package/package.json +9 -8
package/dist/index.cjs
CHANGED
|
@@ -56,6 +56,9 @@ var endPool = async () => {
|
|
|
56
56
|
};
|
|
57
57
|
|
|
58
58
|
// src/index.ts
|
|
59
|
+
function escapeIdentifier(identifier) {
|
|
60
|
+
return `"${identifier.replace(/"/g, '""')}"`;
|
|
61
|
+
}
|
|
59
62
|
var KeyvPostgres = class extends import_node_events.default {
|
|
60
63
|
ttlSupport;
|
|
61
64
|
opts;
|
|
@@ -120,6 +123,19 @@ var KeyvPostgres = class extends import_node_events.default {
|
|
|
120
123
|
DO UPDATE SET value=excluded.value;`;
|
|
121
124
|
await this.query(upsert, [key, value]);
|
|
122
125
|
}
|
|
126
|
+
async setMany(entries) {
|
|
127
|
+
const keys = [];
|
|
128
|
+
const values = [];
|
|
129
|
+
for (const { key, value } of entries) {
|
|
130
|
+
keys.push(key);
|
|
131
|
+
values.push(value);
|
|
132
|
+
}
|
|
133
|
+
const upsert = `INSERT INTO ${this.opts.schema}.${this.opts.table} (key, value)
|
|
134
|
+
SELECT * FROM UNNEST($1::text[], $2::text[])
|
|
135
|
+
ON CONFLICT(key)
|
|
136
|
+
DO UPDATE SET value=excluded.value;`;
|
|
137
|
+
await this.query(upsert, [keys, values]);
|
|
138
|
+
}
|
|
123
139
|
async delete(key) {
|
|
124
140
|
const select = `SELECT * FROM ${this.opts.schema}.${this.opts.table} WHERE key = $1`;
|
|
125
141
|
const del = `DELETE FROM ${this.opts.schema}.${this.opts.table} WHERE key = $1`;
|
|
@@ -146,24 +162,44 @@ var KeyvPostgres = class extends import_node_events.default {
|
|
|
146
162
|
}
|
|
147
163
|
async *iterator(namespace) {
|
|
148
164
|
const limit = Number.parseInt(String(this.opts.iterationLimit), 10) || 10;
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
165
|
+
const escapedNamespace = namespace ? `${namespace.replace(/[%_\\]/g, "\\$&")}:` : "";
|
|
166
|
+
const pattern = `${escapedNamespace}%`;
|
|
167
|
+
let lastKey = null;
|
|
168
|
+
while (true) {
|
|
169
|
+
let entries;
|
|
170
|
+
try {
|
|
171
|
+
let select;
|
|
172
|
+
let params;
|
|
173
|
+
if (lastKey === null) {
|
|
174
|
+
select = `SELECT * FROM ${escapeIdentifier(this.opts.schema)}.${escapeIdentifier(this.opts.table)} WHERE key LIKE $1 ORDER BY key LIMIT $2`;
|
|
175
|
+
params = [pattern, limit];
|
|
176
|
+
} else {
|
|
177
|
+
select = `SELECT * FROM ${escapeIdentifier(this.opts.schema)}.${escapeIdentifier(this.opts.table)} WHERE key LIKE $1 AND key > $2 ORDER BY key LIMIT $3`;
|
|
178
|
+
params = [pattern, lastKey, limit];
|
|
179
|
+
}
|
|
180
|
+
entries = await this.query(select, params);
|
|
181
|
+
} catch (error) {
|
|
182
|
+
this.emit(
|
|
183
|
+
"error",
|
|
184
|
+
new Error(
|
|
185
|
+
`Iterator failed at cursor ${lastKey ?? "start"}: ${error.message}`
|
|
186
|
+
)
|
|
187
|
+
);
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
157
190
|
if (entries.length === 0) {
|
|
158
191
|
return;
|
|
159
192
|
}
|
|
160
193
|
for (const entry of entries) {
|
|
161
|
-
|
|
162
|
-
|
|
194
|
+
if (entry.key !== void 0 && entry.key !== null) {
|
|
195
|
+
yield [entry.key, entry.value];
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
lastKey = entries[entries.length - 1].key;
|
|
199
|
+
if (entries.length < limit) {
|
|
200
|
+
return;
|
|
163
201
|
}
|
|
164
|
-
yield* iterate(offset, options, query);
|
|
165
202
|
}
|
|
166
|
-
yield* iterate(0, this.opts, this.query);
|
|
167
203
|
}
|
|
168
204
|
async has(key) {
|
|
169
205
|
const exists = `SELECT EXISTS ( SELECT * FROM ${this.opts.schema}.${this.opts.table} WHERE key = $1 )`;
|
package/dist/index.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import EventEmitter from 'node:events';
|
|
2
|
-
import Keyv, { KeyvStoreAdapter } from 'keyv';
|
|
2
|
+
import Keyv, { KeyvStoreAdapter, KeyvEntry } from 'keyv';
|
|
3
3
|
import { PoolConfig } from 'pg';
|
|
4
4
|
|
|
5
5
|
type KeyvPostgresOptions = {
|
|
@@ -23,10 +23,11 @@ declare class KeyvPostgres extends EventEmitter implements KeyvStoreAdapter {
|
|
|
23
23
|
get(key: string): Promise<any>;
|
|
24
24
|
getMany(keys: string[]): Promise<any[]>;
|
|
25
25
|
set(key: string, value: any): Promise<void>;
|
|
26
|
+
setMany(entries: KeyvEntry[]): Promise<void>;
|
|
26
27
|
delete(key: string): Promise<boolean>;
|
|
27
28
|
deleteMany(keys: string[]): Promise<boolean>;
|
|
28
29
|
clear(): Promise<void>;
|
|
29
|
-
iterator(namespace?: string): AsyncGenerator<
|
|
30
|
+
iterator(namespace?: string): AsyncGenerator<string[], void, unknown>;
|
|
30
31
|
has(key: string): Promise<any>;
|
|
31
32
|
connect(): Promise<(sql: string, values?: any) => Promise<any[]>>;
|
|
32
33
|
disconnect(): Promise<void>;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import EventEmitter from 'node:events';
|
|
2
|
-
import Keyv, { KeyvStoreAdapter } from 'keyv';
|
|
2
|
+
import Keyv, { KeyvStoreAdapter, KeyvEntry } from 'keyv';
|
|
3
3
|
import { PoolConfig } from 'pg';
|
|
4
4
|
|
|
5
5
|
type KeyvPostgresOptions = {
|
|
@@ -23,10 +23,11 @@ declare class KeyvPostgres extends EventEmitter implements KeyvStoreAdapter {
|
|
|
23
23
|
get(key: string): Promise<any>;
|
|
24
24
|
getMany(keys: string[]): Promise<any[]>;
|
|
25
25
|
set(key: string, value: any): Promise<void>;
|
|
26
|
+
setMany(entries: KeyvEntry[]): Promise<void>;
|
|
26
27
|
delete(key: string): Promise<boolean>;
|
|
27
28
|
deleteMany(keys: string[]): Promise<boolean>;
|
|
28
29
|
clear(): Promise<void>;
|
|
29
|
-
iterator(namespace?: string): AsyncGenerator<
|
|
30
|
+
iterator(namespace?: string): AsyncGenerator<string[], void, unknown>;
|
|
30
31
|
has(key: string): Promise<any>;
|
|
31
32
|
connect(): Promise<(sql: string, values?: any) => Promise<any[]>>;
|
|
32
33
|
disconnect(): Promise<void>;
|
package/dist/index.js
CHANGED
|
@@ -20,6 +20,9 @@ var endPool = async () => {
|
|
|
20
20
|
};
|
|
21
21
|
|
|
22
22
|
// src/index.ts
|
|
23
|
+
function escapeIdentifier(identifier) {
|
|
24
|
+
return `"${identifier.replace(/"/g, '""')}"`;
|
|
25
|
+
}
|
|
23
26
|
var KeyvPostgres = class extends EventEmitter {
|
|
24
27
|
ttlSupport;
|
|
25
28
|
opts;
|
|
@@ -84,6 +87,19 @@ var KeyvPostgres = class extends EventEmitter {
|
|
|
84
87
|
DO UPDATE SET value=excluded.value;`;
|
|
85
88
|
await this.query(upsert, [key, value]);
|
|
86
89
|
}
|
|
90
|
+
async setMany(entries) {
|
|
91
|
+
const keys = [];
|
|
92
|
+
const values = [];
|
|
93
|
+
for (const { key, value } of entries) {
|
|
94
|
+
keys.push(key);
|
|
95
|
+
values.push(value);
|
|
96
|
+
}
|
|
97
|
+
const upsert = `INSERT INTO ${this.opts.schema}.${this.opts.table} (key, value)
|
|
98
|
+
SELECT * FROM UNNEST($1::text[], $2::text[])
|
|
99
|
+
ON CONFLICT(key)
|
|
100
|
+
DO UPDATE SET value=excluded.value;`;
|
|
101
|
+
await this.query(upsert, [keys, values]);
|
|
102
|
+
}
|
|
87
103
|
async delete(key) {
|
|
88
104
|
const select = `SELECT * FROM ${this.opts.schema}.${this.opts.table} WHERE key = $1`;
|
|
89
105
|
const del = `DELETE FROM ${this.opts.schema}.${this.opts.table} WHERE key = $1`;
|
|
@@ -110,24 +126,44 @@ var KeyvPostgres = class extends EventEmitter {
|
|
|
110
126
|
}
|
|
111
127
|
async *iterator(namespace) {
|
|
112
128
|
const limit = Number.parseInt(String(this.opts.iterationLimit), 10) || 10;
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
129
|
+
const escapedNamespace = namespace ? `${namespace.replace(/[%_\\]/g, "\\$&")}:` : "";
|
|
130
|
+
const pattern = `${escapedNamespace}%`;
|
|
131
|
+
let lastKey = null;
|
|
132
|
+
while (true) {
|
|
133
|
+
let entries;
|
|
134
|
+
try {
|
|
135
|
+
let select;
|
|
136
|
+
let params;
|
|
137
|
+
if (lastKey === null) {
|
|
138
|
+
select = `SELECT * FROM ${escapeIdentifier(this.opts.schema)}.${escapeIdentifier(this.opts.table)} WHERE key LIKE $1 ORDER BY key LIMIT $2`;
|
|
139
|
+
params = [pattern, limit];
|
|
140
|
+
} else {
|
|
141
|
+
select = `SELECT * FROM ${escapeIdentifier(this.opts.schema)}.${escapeIdentifier(this.opts.table)} WHERE key LIKE $1 AND key > $2 ORDER BY key LIMIT $3`;
|
|
142
|
+
params = [pattern, lastKey, limit];
|
|
143
|
+
}
|
|
144
|
+
entries = await this.query(select, params);
|
|
145
|
+
} catch (error) {
|
|
146
|
+
this.emit(
|
|
147
|
+
"error",
|
|
148
|
+
new Error(
|
|
149
|
+
`Iterator failed at cursor ${lastKey ?? "start"}: ${error.message}`
|
|
150
|
+
)
|
|
151
|
+
);
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
121
154
|
if (entries.length === 0) {
|
|
122
155
|
return;
|
|
123
156
|
}
|
|
124
157
|
for (const entry of entries) {
|
|
125
|
-
|
|
126
|
-
|
|
158
|
+
if (entry.key !== void 0 && entry.key !== null) {
|
|
159
|
+
yield [entry.key, entry.value];
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
lastKey = entries[entries.length - 1].key;
|
|
163
|
+
if (entries.length < limit) {
|
|
164
|
+
return;
|
|
127
165
|
}
|
|
128
|
-
yield* iterate(offset, options, query);
|
|
129
166
|
}
|
|
130
|
-
yield* iterate(0, this.opts, this.query);
|
|
131
167
|
}
|
|
132
168
|
async has(key) {
|
|
133
169
|
const exists = `SELECT EXISTS ( SELECT * FROM ${this.opts.schema}.${this.opts.table} WHERE key = $1 )`;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@keyv/postgres",
|
|
3
|
-
"version": "2.2.
|
|
3
|
+
"version": "2.2.3",
|
|
4
4
|
"description": "PostgreSQL storage adapter for Keyv",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -42,18 +42,19 @@
|
|
|
42
42
|
},
|
|
43
43
|
"homepage": "https://github.com/jaredwray/keyv",
|
|
44
44
|
"dependencies": {
|
|
45
|
-
"pg": "^8.
|
|
45
|
+
"pg": "^8.17.1"
|
|
46
46
|
},
|
|
47
47
|
"peerDependencies": {
|
|
48
|
-
"keyv": "^5.
|
|
48
|
+
"keyv": "^5.6.0"
|
|
49
49
|
},
|
|
50
50
|
"devDependencies": {
|
|
51
|
-
"@biomejs/biome": "^2.3.
|
|
52
|
-
"@
|
|
53
|
-
"@
|
|
54
|
-
"
|
|
51
|
+
"@biomejs/biome": "^2.3.11",
|
|
52
|
+
"@faker-js/faker": "^10.2.0",
|
|
53
|
+
"@types/pg": "^8.16.0",
|
|
54
|
+
"@vitest/coverage-v8": "^4.0.17",
|
|
55
|
+
"rimraf": "^6.1.2",
|
|
55
56
|
"tsd": "^0.33.0",
|
|
56
|
-
"vitest": "^4.0.
|
|
57
|
+
"vitest": "^4.0.17",
|
|
57
58
|
"@keyv/test-suite": "^2.1.2"
|
|
58
59
|
},
|
|
59
60
|
"tsd": {
|