bun-sqlite-key-value
Advanced tools
Comparing version 1.3.13 to 1.3.14
{ | ||
"name": "bun-sqlite-key-value", | ||
"version": "1.3.13", | ||
"version": "1.3.14", | ||
"author": "Gerold Penz<gerold@gp-softwaretechnik.at>", | ||
@@ -5,0 +5,0 @@ "repository": { |
@@ -411,7 +411,18 @@ # Bun SQLite Key Value | ||
```typescript | ||
getKeys(): string[] | ||
getKeys(startsWithOrKeys: string | string[]): string[] | ||
``` | ||
Returns the unexpired keys as array. | ||
Reads the keys from the database and returns an array. | ||
### startsWithOrKeys | ||
`string`: Returns an array with the keys that begin with the passed string. | ||
If you plan the names of the keys well, more complex data can be stored. | ||
It is advisable to divide keys into ranges using separators. | ||
For example `"language:de"`, `"language:en"`, `"language:it"`. | ||
A search for `"language:"` would return all languages. | ||
`string[]`: Array with keys. | ||
Only exact matches with the keys are returned. | ||
### Example | ||
@@ -424,8 +435,19 @@ | ||
store.getKeys() --> ["key1", "key2"] | ||
``` | ||
store.set("language:de", "German") | ||
store.set("language:en", "English") | ||
store.set("language:es", "Esperanto") | ||
let keys | ||
keys = store.getKeys() | ||
console.log(keys) // --> ["language:de", "language:en", "language:es"] | ||
keys = store.getKeys("language:e") | ||
console.log(keys) // --> ["language:en", "language:es"] | ||
keys = store.getKeys(["language:de", "language:fr"]) | ||
console.log(keys) // --> ["language:de"] | ||
``` | ||
## All Methods | ||
@@ -495,4 +517,4 @@ | ||
- `getKeys()` --> Array with all Keys | ||
- [ ] `getKeys(startsWith: string)` --> Array | ||
- [ ] `getKeys(keys: string[])` --> Array | ||
- `getKeys(startsWith: string)` --> Array | ||
- `getKeys(keys: string[])` --> Array | ||
@@ -48,5 +48,5 @@ import { Database, type Statement } from "bun:sqlite" | ||
private getItemsStartsWithStatement: Statement<Record> | ||
private getKeyStatement: Statement<Omit<Record, "value">> | ||
private getAllKeysStatement: Statement<{key: string}> | ||
// private getKeysStartsWithStatement: Statement<Omit<Record, "value">> | ||
private getKeyStatement: Statement<Omit<Record, "key" | "value">> | ||
private getAllKeysStatement: Statement<Omit<Record, "value">> | ||
private getKeysStartsWithStatement: Statement<Omit<Record, "value">> | ||
@@ -81,14 +81,17 @@ | ||
// Prepare and cache statements | ||
this.getAllItemsStatement = this.db.query("SELECT key, value, expires FROM items") | ||
this.clearStatement = this.db.query("DELETE FROM items") | ||
this.countStatement = this.db.query("SELECT COUNT(*) AS count FROM items") | ||
this.deleteStatement = this.db.query("DELETE FROM items WHERE key = $key") | ||
this.deleteExpiredStatement = this.db.query("DELETE FROM items WHERE expires < $now") | ||
this.setItemStatement = this.db.query("INSERT OR REPLACE INTO items (key, value, expires) VALUES ($key, $value, $expires)") | ||
this.countStatement = this.db.query("SELECT COUNT(*) AS count FROM items") | ||
this.getAllItemsStatement = this.db.query("SELECT key, value, expires FROM items") | ||
this.getItemStatement = this.db.query("SELECT value, expires FROM items WHERE key = $key") | ||
this.getItemsStartsWithStatement = this.db.query("SELECT key, value, expires FROM items WHERE key = $key OR key >= $gte AND key < $lt") | ||
this.deleteStatement = this.db.query("DELETE FROM items WHERE key = $key") | ||
this.getKeyStatement = this.db.query("SELECT key, expires FROM items WHERE key = $key") | ||
this.getAllKeysStatement = this.db.query("SELECT key FROM items WHERE expires IS NULL OR expires > $now") | ||
// this.getKeysStartsWithStatement = this.db.query("SELECT key, expires FROM items WHERE key LIKE $startsWith") | ||
this.getAllKeysStatement = this.db.query("SELECT key, expires FROM items") | ||
this.getKeyStatement = this.db.query("SELECT expires FROM items WHERE key = $key") | ||
this.getKeysStartsWithStatement = this.db.query("SELECT key, expires FROM items WHERE (key = $key OR key >= $gte AND key < $lt)") | ||
// Delete expired items | ||
@@ -228,3 +231,3 @@ this.deleteExpired() | ||
} | ||
if (!records) return | ||
if (!records.length) return | ||
const now = Date.now() | ||
@@ -301,9 +304,39 @@ const result: Item<T>[] = [] | ||
// Returns all unexpired keys as an Array | ||
getKeys(): string[] | undefined { | ||
const records = this.getAllKeysStatement.all({now: Date.now()}) | ||
// Get multiple keys as array | ||
getKeys(startsWithOrKeys?: string | string[]): string[] | undefined { | ||
let records: Omit<Record, "value">[] | ||
if (startsWithOrKeys && typeof startsWithOrKeys === "string") { | ||
const key: string = startsWithOrKeys | ||
const gte: string = key + MIN_UTF8_CHAR | ||
const lt: string = key + MAX_UTF8_CHAR | ||
records = this.getKeysStartsWithStatement.all({key, gte, lt}) | ||
} else if (startsWithOrKeys) { | ||
// Filtered items (array with keys) | ||
records = this.db.transaction(() => { | ||
return (startsWithOrKeys as string[]).map((key: string) => { | ||
const record = this.getKeyStatement.get({key}) | ||
return record ? {...record, key} : undefined | ||
}) | ||
})() | ||
} else { | ||
// All items | ||
records = this.getAllKeysStatement.all() | ||
} | ||
if (!records?.length) return | ||
return records.map((record) => record.key) | ||
const now = Date.now() | ||
const result: string[] = [] | ||
for (const record of records) { | ||
if (!record) continue | ||
const {key, expires} = record | ||
if (expires && expires < now) { | ||
this.delete(key) | ||
} else { | ||
result.push(key) | ||
} | ||
} | ||
if (result.length) { | ||
return result | ||
} | ||
} | ||
} |
@@ -59,6 +59,6 @@ import { expect, test } from "bun:test" | ||
store.set<string>(KEY_1, STRING_VALUE_1, 50) | ||
store.set<string>(KEY_1, STRING_VALUE_1, 30) | ||
expect(store.getCount()).toEqual(1) | ||
await Bun.sleep(100) | ||
await Bun.sleep(40) | ||
store.deleteExpired() | ||
@@ -72,7 +72,7 @@ expect(store.getCount()).toEqual(0) | ||
store.set<string>(KEY_1, STRING_VALUE_1, 50) | ||
store.set<string>(KEY_1, STRING_VALUE_1, 30) | ||
expect(store.get<string>(KEY_1)).toEqual(STRING_VALUE_1) | ||
expect(store.getCount()).toEqual(1) | ||
await Bun.sleep(100) | ||
await Bun.sleep(40) | ||
expect(store.get(KEY_1)).toBeUndefined() | ||
@@ -84,3 +84,3 @@ expect(store.getCount()).toEqual(0) | ||
test("Default expiration ttlMs", async () => { | ||
const store: BunSqliteKeyValue = new BunSqliteKeyValue(undefined, {ttlMs: 50}) | ||
const store: BunSqliteKeyValue = new BunSqliteKeyValue(undefined, {ttlMs: 30}) | ||
@@ -91,3 +91,3 @@ store.set<string>(KEY_1, STRING_VALUE_1) | ||
await Bun.sleep(100) | ||
await Bun.sleep(40) | ||
store.deleteExpired() | ||
@@ -342,22 +342,38 @@ expect(store.length).toEqual(1) | ||
test("Has key", () => { | ||
test("Has key", async () => { | ||
const store: BunSqliteKeyValue = new BunSqliteKeyValue() | ||
store.set<string>(KEY_1, STRING_VALUE_1) | ||
store.set<string>(KEY_1, STRING_VALUE_1, 30) | ||
expect(store.has(KEY_1)).toEqual(true) | ||
expect(store.has(KEY_2)).toEqual(false) | ||
await Bun.sleep(40) | ||
expect(store.has(KEY_1)).toEqual(false) | ||
}) | ||
test("Get keys", async () => { | ||
test("Get all keys", async () => { | ||
const store: BunSqliteKeyValue = new BunSqliteKeyValue() | ||
store.set<string>(KEY_1, STRING_VALUE_1) | ||
store.set<string>(KEY_2, STRING_VALUE_2, 50) | ||
store.set<string>(KEY_2, STRING_VALUE_2, 30) | ||
// All keys | ||
expect(store.getKeys()).toHaveLength(2) | ||
await Bun.sleep(100) | ||
await Bun.sleep(40) | ||
expect(store.getKeys()).toEqual([KEY_1]) | ||
}) | ||
test("Get keys as array", () => { | ||
const store: BunSqliteKeyValue = new BunSqliteKeyValue() | ||
store.set("addresses:1:aaa", STRING_VALUE_1) | ||
store.set("addresses:1:bbb", STRING_VALUE_1) | ||
store.set("addresses:2:aaa", STRING_VALUE_2) | ||
store.set("addresses:2:bbb", STRING_VALUE_2) | ||
expect(store.getKeys("addresses:1:")).toEqual(["addresses:1:aaa", "addresses:1:bbb"]) | ||
expect(store.getKeys(["addresses:1:aaa", "addresses:1:bbb"])).toEqual(["addresses:1:aaa", "addresses:1:bbb"]) | ||
expect(store.getKeys("addresses:2:")).toEqual(["addresses:2:aaa", "addresses:2:bbb"]) | ||
expect(store.getKeys(["addresses:2:aaa", "addresses:2:bbb", "addresses:2:ccc"])).toEqual(["addresses:2:aaa", "addresses:2:bbb"]) | ||
}) |
55819
25
869
518