diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index b08f879..ff15f5f 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -4,7 +4,7 @@ on: push: branches: ["main"] pull_request: - branches: ["main"] + branches: ["main", "release/**/*"] permissions: contents: read diff --git a/.github/workflows/test_map_kv.yml b/.github/workflows/test_map_kv.yml new file mode 100644 index 0000000..7a16f96 --- /dev/null +++ b/.github/workflows/test_map_kv.yml @@ -0,0 +1,25 @@ +name: Test KV map + +on: + push: + branches: ["main"] + pull_request: + branches: ["main", "release/**/*"] + +permissions: + contents: read + id-token: write # The OIDC ID token is used for authentication with JSR. + +jobs: + test: + runs-on: ubuntu-latest + + steps: + - name: Setup repo + uses: actions/checkout@v3 + + - name: Setup Deno + uses: denoland/setup-deno@v2 + + - name: Run tests + run: deno task test -- map diff --git a/.github/workflows/test_minimum_deno_version.yml b/.github/workflows/test_minimum_deno_version.yml index 2ffe9ab..2491f84 100644 --- a/.github/workflows/test_minimum_deno_version.yml +++ b/.github/workflows/test_minimum_deno_version.yml @@ -4,7 +4,7 @@ on: push: branches: ["main"] pull_request: - branches: ["main"] + branches: ["main", "release/**/*"] permissions: contents: read @@ -21,7 +21,7 @@ jobs: - name: Setup Deno uses: denoland/setup-deno@v2 with: - deno-version: v2.0.0 + deno-version: v2.2.0 - name: Check Types run: deno task check diff --git a/README.md b/README.md index 317f198..af51428 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ native functionality as possible, like atomic operations, real-time data updates and queue listeners. Also works with other runtimes such as Node.js and Bun, and has compatibility options for the browser. -_Supported Deno verisons:_ **^2.0.0** +_Supported Deno verisons:_ **^2.2.0** ## Highlights diff --git a/benchmarks/utils/encoder.bench.ts b/benchmarks/utils/encoder.bench.ts new file mode 100644 index 0000000..25d3296 --- /dev/null +++ b/benchmarks/utils/encoder.bench.ts @@ -0,0 +1,10 @@ +import { brotliCompressor } from "../../src/ext/encoding/brotli/brotli_compressor.ts"; +import { v8Serialize } from "../../src/ext/encoding/v8/utils.ts"; +import { obj } from "./_object.ts"; + +const data = v8Serialize(obj); +const compressor = brotliCompressor(); + +Deno.bench("encoder - brotli_compress", async () => { + await compressor.compress(data); +}); diff --git a/deno.json b/deno.json index 06f46b8..678d39e 100644 --- a/deno.json +++ b/deno.json @@ -1,6 +1,6 @@ { "name": "@olli/kvdex", - "version": "3.1.4", + "version": "3.2.0", "exports": { ".": "./mod.ts", "./zod": "./src/ext/zod/mod.ts", diff --git a/src/ext/encoding/brotli/brotli_compressor.ts b/src/ext/encoding/brotli/brotli_compressor.ts index ca2b9b8..2bf81cf 100644 --- a/src/ext/encoding/brotli/brotli_compressor.ts +++ b/src/ext/encoding/brotli/brotli_compressor.ts @@ -1,5 +1,5 @@ import type { Compressor } from "../../../types.ts"; -import { brotliCompressSync, brotliDecompressSync, constants } from "node:zlib"; +import { brotliCompress, brotliDecompress, constants } from "node:zlib"; import type { BrotliCompressorOptions } from "./types.ts"; /** @@ -23,19 +23,35 @@ class BrotliCompressor implements Compressor { this.quality = quality; } - compress(data: Uint8Array): Uint8Array { - const buffer = brotliCompressSync(data, { + compress(data: Uint8Array): Promise { + const { promise, resolve, reject } = Promise.withResolvers(); + + brotliCompress(data, { params: { [constants.BROTLI_PARAM_QUALITY]: this.quality }, + }, (err, result) => { + if (err) { + reject(err); + } + + resolve(new Uint8Array(result)); }); - return new Uint8Array(buffer); + return promise; } - decompress(data: Uint8Array): Uint8Array { - const buffer = brotliDecompressSync(data, { + decompress(data: Uint8Array): Promise { + const { promise, resolve, reject } = Promise.withResolvers(); + + brotliDecompress(data, { params: { [constants.BROTLI_PARAM_QUALITY]: this.quality }, + }, (err, result) => { + if (err) { + reject(err); + } + + resolve(new Uint8Array(result)); }); - return new Uint8Array(buffer); + return promise; } } diff --git a/src/ext/kv/atomic.ts b/src/ext/kv/atomic.ts index 87b5380..028ce59 100644 --- a/src/ext/kv/atomic.ts +++ b/src/ext/kv/atomic.ts @@ -31,7 +31,7 @@ export class MapKvAtomicOperation implements DenoAtomicOperation { options?: DenoKvSetOptions, ): DenoAtomicOperation { this.ops.push(async (versionstamp) => { - await this.kv._set(key, value, versionstamp, options); + await this.kv["setDocument"](key, value, versionstamp, options); }); return this; } @@ -45,7 +45,7 @@ export class MapKvAtomicOperation implements DenoAtomicOperation { this.ops.push(async (versionstamp) => { const { value } = await this.kv.get(key); if (!value) { - await this.kv._set(key, { value: n }, versionstamp); + await this.kv["setDocument"](key, { value: n }, versionstamp); return; } @@ -54,7 +54,7 @@ export class MapKvAtomicOperation implements DenoAtomicOperation { throw new Error("Min operation can only be performed on KvU64 value"); } - await this.kv._set(key, { + await this.kv["setDocument"](key, { value: n < val ? n : val, }, versionstamp); }); @@ -66,7 +66,7 @@ export class MapKvAtomicOperation implements DenoAtomicOperation { this.ops.push(async (versionstamp) => { const { value } = await this.kv.get(key); if (!value) { - await this.kv._set(key, { value: n }, versionstamp); + await this.kv["setDocument"](key, { value: n }, versionstamp); return; } @@ -75,7 +75,7 @@ export class MapKvAtomicOperation implements DenoAtomicOperation { throw new Error("Max operation can only be performed on KvU64 value"); } - await this.kv._set(key, { + await this.kv["setDocument"](key, { value: n > val ? n : val, }, versionstamp); }); @@ -87,7 +87,7 @@ export class MapKvAtomicOperation implements DenoAtomicOperation { this.ops.push(async (versionstamp) => { const { value } = await this.kv.get(key); if (!value) { - await this.kv._set(key, { value: n }, versionstamp); + await this.kv["setDocument"](key, { value: n }, versionstamp); return; } @@ -96,7 +96,7 @@ export class MapKvAtomicOperation implements DenoAtomicOperation { throw new Error("Sum operation can only be performed on KvU64 value"); } - await this.kv._set(key, { + await this.kv["setDocument"](key, { value: n + val, }, versionstamp); }); @@ -117,7 +117,7 @@ export class MapKvAtomicOperation implements DenoAtomicOperation { enqueue(value: unknown, options?: DenoKvEnqueueOptions): DenoAtomicOperation { this.ops.push(async (versionstamp) => { - await this.kv._enqueue(value, versionstamp, options); + await this.kv["enqueueValue"](value, versionstamp, options); }); return this; diff --git a/src/ext/kv/map_kv.ts b/src/ext/kv/map_kv.ts index a8eb7ba..7c0431d 100644 --- a/src/ext/kv/map_kv.ts +++ b/src/ext/kv/map_kv.ts @@ -112,7 +112,7 @@ export class MapKv implements DenoKv { value: unknown, options?: DenoKvSetOptions, ): Promise { - return await this._set(key, value, createVersionstamp(), options); + return await this.setDocument(key, value, createVersionstamp(), options); } async list( @@ -208,7 +208,7 @@ export class MapKv implements DenoKv { value: unknown, options?: DenoKvEnqueueOptions, ): Promise | DenoKvCommitResult { - return this._enqueue(value, createVersionstamp(), options); + return this.enqueueValue(value, createVersionstamp(), options); } watch( @@ -224,7 +224,7 @@ export class MapKv implements DenoKv { return new MapKvAtomicOperation(this, this.atomicLock); } - async _set( + private async setDocument( key: DenoKvStrictKey, value: unknown, versionstamp: string, @@ -252,7 +252,7 @@ export class MapKv implements DenoKv { }; } - _enqueue( + private enqueueValue( value: unknown, versionstamp: string, options?: DenoKvEnqueueOptions, diff --git a/tests/db/deleteAll.test.ts b/tests/db/deleteAll.test.ts index 350d017..9fd3ee6 100644 --- a/tests/db/deleteAll.test.ts +++ b/tests/db/deleteAll.test.ts @@ -1,5 +1,5 @@ import { collection, kvdex, model } from "../../mod.ts"; -import { assert } from "@std/assert"; +import { assert, assertEquals } from "@std/assert"; import type { User } from "../models.ts"; import { generateLargeUsers, generateUsers, useKv } from "../utils.ts"; import { jsonEncoder } from "../../src/ext/encoding/mod.ts"; @@ -49,7 +49,7 @@ Deno.test("db - deleteAll", async (t) => { const { result: docs3 } = await db.u64s.getMany({ limit: 1 }); const count1 = await db.countAll(); - assert(count1 === users.length + largeUsers.length + u64s.length); + assertEquals(count1, users.length + largeUsers.length + u64s.length); await db.deleteAll(); diff --git a/tests/db/wipe.test.ts b/tests/db/wipe.test.ts index 6e28199..25aed63 100644 --- a/tests/db/wipe.test.ts +++ b/tests/db/wipe.test.ts @@ -1,5 +1,5 @@ import { collection, kvdex, model } from "../../mod.ts"; -import { assert } from "@std/assert"; +import { assert, assertEquals } from "@std/assert"; import type { User } from "../models.ts"; import { generateLargeUsers, generateUsers, useKv } from "../utils.ts"; import { jsonEncoder } from "../../src/ext/encoding/mod.ts"; @@ -49,7 +49,7 @@ Deno.test("db - wipe", async (t) => { const { result: docs3 } = await db.u64s.getMany({ limit: 1 }); const count1 = await db.countAll(); - assert(count1 === users.length + largeUsers.length + u64s.length); + assertEquals(count1, users.length + largeUsers.length + u64s.length); await db.wipe(); diff --git a/tests/ext/kv.test.ts b/tests/ext/kv.test.ts index cfa9385..690b5d3 100644 --- a/tests/ext/kv.test.ts +++ b/tests/ext/kv.test.ts @@ -165,7 +165,7 @@ Deno.test("ext - kv", async (t) => { }); }); - await t.step("Should delete entry by key", async () => { + await t.step("Should delete all entries", async () => { await useStore((store) => { const entries = [ ["1", 10], diff --git a/tests/utils.ts b/tests/utils.ts index d8104af..3102982 100644 --- a/tests/utils.ts +++ b/tests/utils.ts @@ -2,6 +2,7 @@ import { collection, type DenoKv, type DenoKvU64, kvdex } from "../mod.ts"; import { brotliCompressor } from "../src/ext/encoding/brotli/brotli_compressor.ts"; import { jsonEncoder } from "../src/ext/encoding/mod.ts"; import { MapKv } from "../src/ext/kv/map_kv.ts"; +import { StorageAdapter } from "../src/ext/kv/mod.ts"; import { model } from "../src/model.ts"; import { TransformUserModel, type User, UserSchema } from "./models.ts"; @@ -77,8 +78,12 @@ export function createDb(kv: DenoKv) { export async function useKv( fn: (kv: DenoKv) => unknown, ) { - const kv = Deno.args[0] === "map" - ? new MapKv() + const kvArg = Deno.args[0]; + + const kv = kvArg === "map" + ? new MapKv({ clearOnClose: true }) + : kvArg === "map-local" + ? new MapKv({ map: new StorageAdapter(localStorage), clearOnClose: true }) : await Deno.openKv(":memory:"); const result = await fn(kv);