@keyv/postgres 2.2.2 → 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 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;
@@ -159,24 +162,44 @@ var KeyvPostgres = class extends import_node_events.default {
159
162
  }
160
163
  async *iterator(namespace) {
161
164
  const limit = Number.parseInt(String(this.opts.iterationLimit), 10) || 10;
162
- async function* iterate(offset, options, query) {
163
- const select = `SELECT * FROM ${options.schema}.${options.table} WHERE key LIKE $1 LIMIT $2 OFFSET $3`;
164
- const entries = await query(select, [
165
- // biome-ignore lint/style/useTemplate: need to fix
166
- `${namespace ? namespace + ":" : ""}%`,
167
- limit,
168
- offset
169
- ]);
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
+ }
170
190
  if (entries.length === 0) {
171
191
  return;
172
192
  }
173
193
  for (const entry of entries) {
174
- offset += 1;
175
- yield [entry.key, entry.value];
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;
176
201
  }
177
- yield* iterate(offset, options, query);
178
202
  }
179
- yield* iterate(0, this.opts, this.query);
180
203
  }
181
204
  async has(key) {
182
205
  const exists = `SELECT EXISTS ( SELECT * FROM ${this.opts.schema}.${this.opts.table} WHERE key = $1 )`;
package/dist/index.d.cts CHANGED
@@ -27,7 +27,7 @@ declare class KeyvPostgres extends EventEmitter implements KeyvStoreAdapter {
27
27
  delete(key: string): Promise<boolean>;
28
28
  deleteMany(keys: string[]): Promise<boolean>;
29
29
  clear(): Promise<void>;
30
- iterator(namespace?: string): AsyncGenerator<any, void, any>;
30
+ iterator(namespace?: string): AsyncGenerator<string[], void, unknown>;
31
31
  has(key: string): Promise<any>;
32
32
  connect(): Promise<(sql: string, values?: any) => Promise<any[]>>;
33
33
  disconnect(): Promise<void>;
package/dist/index.d.ts CHANGED
@@ -27,7 +27,7 @@ declare class KeyvPostgres extends EventEmitter implements KeyvStoreAdapter {
27
27
  delete(key: string): Promise<boolean>;
28
28
  deleteMany(keys: string[]): Promise<boolean>;
29
29
  clear(): Promise<void>;
30
- iterator(namespace?: string): AsyncGenerator<any, void, any>;
30
+ iterator(namespace?: string): AsyncGenerator<string[], void, unknown>;
31
31
  has(key: string): Promise<any>;
32
32
  connect(): Promise<(sql: string, values?: any) => Promise<any[]>>;
33
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;
@@ -123,24 +126,44 @@ var KeyvPostgres = class extends EventEmitter {
123
126
  }
124
127
  async *iterator(namespace) {
125
128
  const limit = Number.parseInt(String(this.opts.iterationLimit), 10) || 10;
126
- async function* iterate(offset, options, query) {
127
- const select = `SELECT * FROM ${options.schema}.${options.table} WHERE key LIKE $1 LIMIT $2 OFFSET $3`;
128
- const entries = await query(select, [
129
- // biome-ignore lint/style/useTemplate: need to fix
130
- `${namespace ? namespace + ":" : ""}%`,
131
- limit,
132
- offset
133
- ]);
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
+ }
134
154
  if (entries.length === 0) {
135
155
  return;
136
156
  }
137
157
  for (const entry of entries) {
138
- offset += 1;
139
- yield [entry.key, entry.value];
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;
140
165
  }
141
- yield* iterate(offset, options, query);
142
166
  }
143
- yield* iterate(0, this.opts, this.query);
144
167
  }
145
168
  async has(key) {
146
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.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.16.3"
45
+ "pg": "^8.17.1"
46
46
  },
47
47
  "peerDependencies": {
48
- "keyv": "^5.5.4"
48
+ "keyv": "^5.6.0"
49
49
  },
50
50
  "devDependencies": {
51
- "@biomejs/biome": "^2.3.6",
52
- "@types/pg": "^8.15.6",
53
- "@vitest/coverage-v8": "^4.0.10",
54
- "rimraf": "^6.1.0",
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.10",
57
+ "vitest": "^4.0.17",
57
58
  "@keyv/test-suite": "^2.1.2"
58
59
  },
59
60
  "tsd": {