From bd7a306536890ec6ff02aca37646ea9c8ed70699 Mon Sep 17 00:00:00 2001 From: David ALLIX Date: Mon, 25 Nov 2024 18:39:57 +0100 Subject: [PATCH] Improvements (#6) --- package.json | 12 +- pnpm-lock.yaml | 94 +++----- src/adapters/betterSqlite3Adapter.ts | 67 ++++-- src/adapters/d1Adapter.ts | 25 ++- src/schemql.ts | 9 +- tests/adapters/betterSqlite3Adapter.test.ts | 233 ++++++++++++++++++++ tests/{index.test.ts => schemql.test.ts} | 10 +- 7 files changed, 340 insertions(+), 110 deletions(-) create mode 100644 tests/adapters/betterSqlite3Adapter.test.ts rename tests/{index.test.ts => schemql.test.ts} (98%) diff --git a/package.json b/package.json index 7339cfe..4d95848 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@a2lix/schemql", - "version": "0.4.1", + "version": "0.4.2", "description": "A lightweight TypeScript library that enhances your SQL workflow by combining raw SQL with targeted type safety and schema validation", "license": "MIT", "keywords": [ @@ -82,7 +82,7 @@ "scripts": { "biome": "biome check --write ./src ./tests", "biome:ci": "biome ci ./src ./tests", - "test": "tsx --test ./tests/**/*.ts", + "test": "tsx --test './tests/**/*.test.ts'", "build": "pkgroll --clean-dist --minify --src src/" }, "dependencies": { @@ -91,17 +91,17 @@ "devDependencies": { "@biomejs/biome": "^1.9.4", "@types/node": "^22.9.1", + "better-sqlite3": "^11.5.0", "pkgroll": "^2.5.1", "ts-node": "^10.9.2", "tsx": "^4.19.2", "typescript": "^5.6.3" }, "peerDependencies": { - "@cloudflare/workers-types": "^4.20241112.0", - "better-sqlite3": "^11.5.0" + "@cloudflare/workers-types": "*", + "better-sqlite3": "*" }, "optionalDependencies": { - "@cloudflare/workers-types": "^4.20241112.0", - "better-sqlite3": "^11.5.0" + "@cloudflare/workers-types": "*" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3f82981..7658f7f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -13,11 +13,8 @@ importers: version: 3.23.8 optionalDependencies: '@cloudflare/workers-types': - specifier: ^4.20241112.0 + specifier: '*' version: 4.20241112.0 - better-sqlite3: - specifier: ^8.7.0 - version: 8.7.0 devDependencies: '@biomejs/biome': specifier: ^1.9.4 @@ -25,6 +22,9 @@ importers: '@types/node': specifier: ^22.9.1 version: 22.9.1 + better-sqlite3: + specifier: ^11.5.0 + version: 11.5.0 pkgroll: specifier: ^2.5.1 version: 2.5.1(typescript@5.6.3) @@ -470,8 +470,8 @@ packages: base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} - better-sqlite3@8.7.0: - resolution: {integrity: sha512-99jZU4le+f3G6aIl6PmmV0cxUIWqKieHxsiF7G34CVFiE+/UabpYqkU0NJIkY/96mQKikHeBjtR27vFfs5JpEw==} + better-sqlite3@11.5.0: + resolution: {integrity: sha512-e/6eggfOutzoK0JWiU36jsisdWoHOfN9iWiW/SieKvb7SAa6aGNmBM/UKyp+/wWSXpLlWNN8tCPwoDNPhzUvuQ==} bindings@1.5.0: resolution: {integrity: sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==} @@ -1103,26 +1103,22 @@ snapshots: balanced-match@1.0.2: {} - base64-js@1.5.1: - optional: true + base64-js@1.5.1: {} - better-sqlite3@8.7.0: + better-sqlite3@11.5.0: dependencies: bindings: 1.5.0 prebuild-install: 7.1.2 - optional: true bindings@1.5.0: dependencies: file-uri-to-path: 1.0.0 - optional: true bl@4.1.0: dependencies: buffer: 5.7.1 inherits: 2.0.4 readable-stream: 3.6.2 - optional: true brace-expansion@2.0.1: dependencies: @@ -1132,10 +1128,8 @@ snapshots: dependencies: base64-js: 1.5.1 ieee754: 1.2.1 - optional: true - chownr@1.1.4: - optional: true + chownr@1.1.4: {} color-convert@2.0.1: dependencies: @@ -1156,15 +1150,12 @@ snapshots: decompress-response@6.0.0: dependencies: mimic-response: 3.1.0 - optional: true - deep-extend@0.6.0: - optional: true + deep-extend@0.6.0: {} deepmerge@4.3.1: {} - detect-libc@2.0.3: - optional: true + detect-libc@2.0.3: {} diff@4.0.2: {} @@ -1177,7 +1168,6 @@ snapshots: end-of-stream@1.4.4: dependencies: once: 1.4.0 - optional: true esbuild@0.23.1: optionalDependencies: @@ -1208,19 +1198,16 @@ snapshots: estree-walker@2.0.2: {} - expand-template@2.0.3: - optional: true + expand-template@2.0.3: {} - file-uri-to-path@1.0.0: - optional: true + file-uri-to-path@1.0.0: {} foreground-child@3.3.0: dependencies: cross-spawn: 7.0.6 signal-exit: 4.1.0 - fs-constants@1.0.0: - optional: true + fs-constants@1.0.0: {} fsevents@2.3.3: optional: true @@ -1231,8 +1218,7 @@ snapshots: dependencies: resolve-pkg-maps: 1.0.0 - github-from-package@0.0.0: - optional: true + github-from-package@0.0.0: {} glob@10.4.5: dependencies: @@ -1247,14 +1233,11 @@ snapshots: dependencies: function-bind: 1.1.2 - ieee754@1.2.1: - optional: true + ieee754@1.2.1: {} - inherits@2.0.4: - optional: true + inherits@2.0.4: {} - ini@1.3.8: - optional: true + ini@1.3.8: {} is-core-module@2.15.1: dependencies: @@ -1284,33 +1267,27 @@ snapshots: make-error@1.3.6: {} - mimic-response@3.1.0: - optional: true + mimic-response@3.1.0: {} minimatch@9.0.5: dependencies: brace-expansion: 2.0.1 - minimist@1.2.8: - optional: true + minimist@1.2.8: {} minipass@7.1.2: {} - mkdirp-classic@0.5.3: - optional: true + mkdirp-classic@0.5.3: {} - napi-build-utils@1.0.2: - optional: true + napi-build-utils@1.0.2: {} node-abi@3.71.0: dependencies: semver: 7.6.3 - optional: true once@1.4.0: dependencies: wrappy: 1.0.2 - optional: true package-json-from-dist@1.0.1: {} @@ -1354,13 +1331,11 @@ snapshots: simple-get: 4.0.1 tar-fs: 2.1.1 tunnel-agent: 0.6.0 - optional: true pump@3.0.2: dependencies: end-of-stream: 1.4.4 once: 1.4.0 - optional: true rc@1.2.8: dependencies: @@ -1368,14 +1343,12 @@ snapshots: ini: 1.3.8 minimist: 1.2.8 strip-json-comments: 2.0.1 - optional: true readable-stream@3.6.2: dependencies: inherits: 2.0.4 string_decoder: 1.3.0 util-deprecate: 1.0.2 - optional: true resolve-pkg-maps@1.0.0: {} @@ -1409,11 +1382,9 @@ snapshots: '@rollup/rollup-win32-x64-msvc': 4.27.3 fsevents: 2.3.3 - safe-buffer@5.2.1: - optional: true + safe-buffer@5.2.1: {} - semver@7.6.3: - optional: true + semver@7.6.3: {} shebang-command@2.0.0: dependencies: @@ -1423,15 +1394,13 @@ snapshots: signal-exit@4.1.0: {} - simple-concat@1.0.1: - optional: true + simple-concat@1.0.1: {} simple-get@4.0.1: dependencies: decompress-response: 6.0.0 once: 1.4.0 simple-concat: 1.0.1 - optional: true string-width@4.2.3: dependencies: @@ -1448,7 +1417,6 @@ snapshots: string_decoder@1.3.0: dependencies: safe-buffer: 5.2.1 - optional: true strip-ansi@6.0.1: dependencies: @@ -1458,8 +1426,7 @@ snapshots: dependencies: ansi-regex: 6.1.0 - strip-json-comments@2.0.1: - optional: true + strip-json-comments@2.0.1: {} supports-preserve-symlinks-flag@1.0.0: {} @@ -1469,7 +1436,6 @@ snapshots: mkdirp-classic: 0.5.3 pump: 3.0.2 tar-stream: 2.2.0 - optional: true tar-stream@2.2.0: dependencies: @@ -1478,7 +1444,6 @@ snapshots: fs-constants: 1.0.0 inherits: 2.0.4 readable-stream: 3.6.2 - optional: true ts-node@10.9.2(@types/node@22.9.1)(typescript@5.6.3): dependencies: @@ -1508,14 +1473,12 @@ snapshots: tunnel-agent@0.6.0: dependencies: safe-buffer: 5.2.1 - optional: true typescript@5.6.3: {} undici-types@6.19.8: {} - util-deprecate@1.0.2: - optional: true + util-deprecate@1.0.2: {} v8-compile-cache-lib@3.0.1: {} @@ -1535,8 +1498,7 @@ snapshots: string-width: 5.1.2 strip-ansi: 7.1.0 - wrappy@1.0.2: - optional: true + wrappy@1.0.2: {} yn@3.1.1: {} diff --git a/src/adapters/betterSqlite3Adapter.ts b/src/adapters/betterSqlite3Adapter.ts index 6a988f3..a2829d1 100644 --- a/src/adapters/betterSqlite3Adapter.ts +++ b/src/adapters/betterSqlite3Adapter.ts @@ -1,44 +1,63 @@ import { AdapterErrorCode, BaseAdapterError } from '@/adapters/baseAdapterError' import type { SchemQlAdapter } from '@/schemql' // @ts-ignore -import SQLite from 'better-sqlite3' +import type SQLite from 'better-sqlite3' -export class BetterSqlite3Adapter implements SchemQlAdapter { - private db: SQLite.Adapter +export class BetterSqlite3Adapter implements SchemQlAdapter { + public constructor(private db: SQLite.Database) {} - public constructor(filename: string, options?: SQLite.Options) { - this.db = new SQLite(filename, { - ...options, - verbose: console.log, - }) - this.db.pragma('journal_mode = WAL') - } - - public queryAll = >(sql: string) => { - const stmt = this.db.prepare(sql) + public queryAll = | undefined = Record | undefined>( + sql: string + ) => { + let stmt: SQLite.Statement + try { + stmt = this.db.prepare(sql) + } catch (e) { + throw SchemQlAdapterError.createFromBetterSqlite3(e) + } return (params?: TParams): TResult[] => { try { return params ? stmt.all(params) : stmt.all() } catch (e) { + if (e instanceof TypeError && e.message === 'This statement does not return data. Use run() instead') { + this.handleTypeErrorRun(stmt, params) + return [] + } throw SchemQlAdapterError.createFromBetterSqlite3(e) } } } - public queryFirst = >(sql: string) => { - const stmt = this.db.prepare(sql) + public queryFirst = | undefined = Record | undefined>( + sql: string + ) => { + let stmt: SQLite.Statement + try { + stmt = this.db.prepare(sql) + } catch (e) { + throw SchemQlAdapterError.createFromBetterSqlite3(e) + } return (params?: TParams): TResult | undefined => { try { - return stmt.get(params) + return params ? stmt.get(params) : stmt.get() } catch (e) { + if (e instanceof TypeError && e.message === 'This statement does not return data. Use run() instead') { + this.handleTypeErrorRun(stmt, params) + return undefined + } throw SchemQlAdapterError.createFromBetterSqlite3(e) } } } - public queryFirstOrThrow = >(sql: string) => { + public queryFirstOrThrow = < + TResult, + TParams extends Record | undefined = Record | undefined, + >( + sql: string + ) => { const prepareFirst = this.queryFirst(sql) return (params?: TParams): NonNullable => { @@ -50,16 +69,22 @@ export class BetterSqlite3Adapter implements SchemQlAdapter { } } - public queryIterate = >(sql: string) => { + public queryIterate = | undefined = Record | undefined>( + sql: string + ) => { const stmt = this.db.prepare(sql) return (params?: TParams) => { - return stmt.iterate(params) + return params ? stmt.iterate(params) : stmt.iterate() } } - public close = () => { - this.db.close() + private handleTypeErrorRun = (stmt: SQLite.Statement, params: Record | undefined) => { + try { + params ? stmt.run(params) : stmt.run() + } catch (e) { + throw SchemQlAdapterError.createFromBetterSqlite3(e) + } } } diff --git a/src/adapters/d1Adapter.ts b/src/adapters/d1Adapter.ts index 43d8645..fc23eed 100644 --- a/src/adapters/d1Adapter.ts +++ b/src/adapters/d1Adapter.ts @@ -2,10 +2,12 @@ import { AdapterErrorCode, BaseAdapterError } from '@/adapters/baseAdapterError' import type { SchemQlAdapter } from '@/schemql' import type { D1Database } from '@cloudflare/workers-types' -export class D1Adapter implements SchemQlAdapter { +export class D1Adapter implements SchemQlAdapter { public constructor(private db: D1Database) {} - public queryAll = >(sql: string) => { + public queryAll = | undefined = Record | undefined>( + sql: string + ) => { const { sql: anonymousSql, paramsOrder } = this.transformToAnonymousParams(sql) const stmt = this.db.prepare(anonymousSql) @@ -20,21 +22,28 @@ export class D1Adapter implements SchemQlAdapter { } } - public queryFirst = >(sql: string) => { + public queryFirst = | undefined = Record | undefined>( + sql: string + ) => { const { sql: anonymousSql, paramsOrder } = this.transformToAnonymousParams(sql) const stmt = this.db.prepare(anonymousSql) return async (params?: TParams) => { try { const arrParams = params ? paramsOrder.map((key) => params[key]) : [] - return await stmt.bind(...arrParams).first() + return (await stmt.bind(...arrParams).first()) ?? undefined } catch (e: any) { throw SchemQlAdapterError.createFromD1(e) } } } - public queryFirstOrThrow = >(sql: string) => { + public queryFirstOrThrow = < + TResult, + TParams extends Record | undefined = Record | undefined, + >( + sql: string + ) => { const prepareFirst = this.queryFirst(sql) return async (params?: TParams) => { @@ -46,14 +55,14 @@ export class D1Adapter implements SchemQlAdapter { } } - public queryIterate = >(sql: string) => { + public queryIterate = | undefined = Record | undefined>( + sql: string + ) => { return (params?: TParams) => { throw new Error('Not implemented') } } - public close = () => {} - private transformToAnonymousParams = (sql: string) => { const paramsOrder: string[] = [] diff --git a/src/schemql.ts b/src/schemql.ts index 22dc6bf..fa0a021 100644 --- a/src/schemql.ts +++ b/src/schemql.ts @@ -8,12 +8,13 @@ export interface SchemQlAdapter { queryIterate: IterativeQueryFn } -type QueryFn | undefined> = ( +type QueryFn | undefined = Record | undefined> = ( sql: string ) => (params?: TParams) => TQueryResult | Promise -type IterativeQueryFn | undefined> = ( - sql: string -) => (params?: TParams) => GeneratorFn | AsyncGeneratorFn +type IterativeQueryFn< + TQueryResult, + TParams extends Record | undefined = Record | undefined, +> = (sql: string) => (params?: TParams) => GeneratorFn | AsyncGeneratorFn // Helpers type ArrayElement = T extends (infer U)[] ? U : T diff --git a/tests/adapters/betterSqlite3Adapter.test.ts b/tests/adapters/betterSqlite3Adapter.test.ts new file mode 100644 index 0000000..9325d9a --- /dev/null +++ b/tests/adapters/betterSqlite3Adapter.test.ts @@ -0,0 +1,233 @@ +import assert from 'node:assert' +import { before, describe, it } from 'node:test' +import { BetterSqlite3Adapter, SchemQlAdapterErrorCode } from '@/adapters/betterSqlite3Adapter' +// @ts-ignore +import SQLite from 'better-sqlite3' + +describe('BetterSqlite3Adapter', () => { + let adapter: BetterSqlite3Adapter + + before(() => { + const db = new SQLite(':memory:', { + // verbose: console.log, + }) + + db.exec(` + CREATE TABLE users ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + name TEXT NOT NULL, + email TEXT NOT NULL UNIQUE + ); + + INSERT INTO users (name, email) VALUES ('Alice', 'alice@example.com'); + `) + + adapter = new BetterSqlite3Adapter(db) + }) + + describe('queryAll', () => { + it('should return all rows matching the query', () => { + const users = adapter.queryAll<{ id: number; name: string; email: string }>('SELECT * FROM users')() + assert.strictEqual(users.length, 1) + assert.strictEqual(users[0]!.name, 'Alice') + assert.strictEqual(users[0]!.email, 'alice@example.com') + }) + + it('should handle parameters correctly', () => { + adapter.queryAll(` + INSERT INTO users (name, email) VALUES ('Bob', 'bob@example.com') + `)() + + const users = adapter.queryAll<{ id: number; name: string; email: string }>( + 'SELECT * FROM users WHERE name = :name' + )({ name: 'Bob' }) + assert.strictEqual(users.length, 1) + assert.strictEqual(users[0]!.name, 'Bob') + assert.strictEqual(users[0]!.email, 'bob@example.com') + }) + }) + + describe('queryFirst', () => { + it('should return the first row matching the query', () => { + const user = adapter.queryFirst<{ id: number; name: string; email: string }>('SELECT * FROM users')() + assert.strictEqual(user?.name, 'Alice') + assert.strictEqual(user?.email, 'alice@example.com') + }) + + it('should handle parameters correctly', () => { + const user = adapter.queryFirst<{ id: number; name: string; email: string }>( + 'SELECT * FROM users WHERE name = :name' + )({ name: 'Alice' }) + assert.strictEqual(user?.name, 'Alice') + assert.strictEqual(user?.email, 'alice@example.com') + }) + + it('should return undefined if no rows match the query', () => { + const user = adapter.queryFirst<{ id: number; name: string; email: string }>( + 'SELECT * FROM users WHERE name = :name' + )({ name: 'Charlie' }) + assert.strictEqual(user, undefined) + }) + }) + + describe('queryFirstOrThrow', () => { + it('should return the first row matching the query', () => { + const user = adapter.queryFirstOrThrow<{ id: number; name: string; email: string }>('SELECT * FROM users')() + assert.strictEqual(user.name, 'Alice') + assert.strictEqual(user.email, 'alice@example.com') + }) + + it('should handle parameters correctly', () => { + const user = adapter.queryFirstOrThrow<{ id: number; name: string; email: string }>( + 'SELECT * FROM users WHERE name = :name' + )({ name: 'Alice' }) + assert.strictEqual(user.name, 'Alice') + assert.strictEqual(user.email, 'alice@example.com') + }) + + it('should throw an error if no rows match the query', () => { + assert.throws( + () => + adapter.queryFirstOrThrow<{ id: number; name: string; email: string }>( + 'SELECT * FROM users WHERE name = :name' + )({ name: 'Charlie' }), + { + code: SchemQlAdapterErrorCode.NoResult, + message: 'No result', + } + ) + }) + }) + + describe('queryIterate', () => { + it('should iterate over all rows matching the query', () => { + const iterator = adapter.queryIterate<{ id: number; name: string; email: string }>('SELECT * FROM users')() + let result = iterator.next() + assert.strictEqual(result.done, false) + assert.strictEqual(result.value.name, 'Alice') + assert.strictEqual(result.value.email, 'alice@example.com') + + result = iterator.next() + assert.strictEqual(result.done, false) + assert.strictEqual(result.value.name, 'Bob') + assert.strictEqual(result.value.email, 'bob@example.com') + + result = iterator.next() + assert.strictEqual(result.done, true) + assert.strictEqual(result.value, undefined) + }) + + it('should handle parameters correctly', () => { + const iterator = adapter.queryIterate<{ id: number; name: string; email: string }>( + 'SELECT * FROM users WHERE name = :name' + )({ name: 'Alice' }) + let result = iterator.next() + assert.strictEqual(result.done, false) + assert.strictEqual(result.value.name, 'Alice') + assert.strictEqual(result.value.email, 'alice@example.com') + + result = iterator.next() + assert.strictEqual(result.done, true) + assert.strictEqual(result.value, undefined) + }) + }) + + describe('Error Handling', () => { + it('should throw a SchemQlAdapterError for a unique constraint violation', () => { + assert.throws( + () => + adapter.queryAll(` + INSERT INTO users (name, email) VALUES ('Charlie', 'alice@example.com') + `)(), + { + code: SchemQlAdapterErrorCode.UniqueConstraint, + message: 'UNIQUE constraint failed: users.email', + } + ) + }) + + it('should throw a SchemQlAdapterError for a foreign key constraint violation', () => { + // Add a table with a foreign key constraint to test + adapter.queryAll(` + CREATE TABLE posts ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + title TEXT NOT NULL, + user_id INTEGER NOT NULL, + FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE + ) + `)() + + assert.throws( + () => + adapter.queryAll(` + INSERT INTO posts (title, user_id) VALUES ('Post 1', 999) + `)(), + { + code: SchemQlAdapterErrorCode.ForeignkeyConstraint, + message: 'FOREIGN KEY constraint failed', + } + ) + }) + + it('should throw a SchemQlAdapterError for a not null constraint violation', () => { + assert.throws( + () => + adapter.queryAll(` + INSERT INTO users (name) VALUES ('Charlie') + `)(), + { + code: SchemQlAdapterErrorCode.NotnullConstraint, + message: 'NOT NULL constraint failed: users.email', + } + ) + }) + + it('should throw a SchemQlAdapterError for a check constraint violation', () => { + // SQLite does not support CHECK constraints natively, but we can test with a CHECK constraint + adapter.queryAll(` + CREATE TABLE products ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + name TEXT NOT NULL, + price REAL NOT NULL CHECK (price > 0) + ) + `)() + + assert.throws( + () => + adapter.queryAll(` + INSERT INTO products (name, price) VALUES ('Product 1', -1) + `)(), + { + code: SchemQlAdapterErrorCode.CheckConstraint, + message: 'CHECK constraint failed: price > 0', + } + ) + }) + + it('should throw a SchemQlAdapterError for a primary key constraint violation', () => { + assert.throws( + () => + adapter.queryAll(` + INSERT INTO users (id, name, email) VALUES (1, 'Charlie', 'charlie@example.com') + `)(), + { + code: SchemQlAdapterErrorCode.PrimarykeyConstraint, + message: 'UNIQUE constraint failed: users.id', + } + ) + }) + + it('should throw a generic SchemQlAdapterError for an unknown error', () => { + assert.throws( + () => + adapter.queryAll(` + SELECT * FROM non_existent_table + `)(), + { + code: SchemQlAdapterErrorCode.Generic, + message: 'no such table: non_existent_table', + } + ) + }) + }) +}) diff --git a/tests/index.test.ts b/tests/schemql.test.ts similarity index 98% rename from tests/index.test.ts rename to tests/schemql.test.ts index 13b4226..89069a1 100644 --- a/tests/index.test.ts +++ b/tests/schemql.test.ts @@ -87,7 +87,7 @@ describe('SchemQl - queryFn related', () => { override queryAll = (sql: string) => { assert.strictEqual(sql, 'SELECT * FROM users') return async (params?: any) => { - return (await fixtureUsers.values().toArray()) + return await Array.from(fixtureUsers.values()) } } override queryIterate = (sql: string) => { @@ -102,7 +102,7 @@ describe('SchemQl - queryFn related', () => { shouldStringifyObjectParams: true, }) const results = await schemQl.all({})('SELECT * FROM users') - assert.deepEqual(results, fixtureUsers.values().toArray()) + assert.deepEqual(results, Array.from(fixtureUsers.values())) const iterResults = await schemQl.iterate({})('SELECT * FROM users') const res1 = await iterResults?.next() @@ -232,9 +232,9 @@ describe('SchemQl - resultSchema related', () => { adapter: new class extends SyncAdapter { override queryAll = (sql: string) => { assert.strictEqual(sql, 'SELECT * FROM users') - return (params?: any) => { - return fixtureUsers.values().toArray() - } + return (params?: any) => { + return Array.from(fixtureUsers.values()) + } } }, shouldStringifyObjectParams: true,