@pikku/kysely-node-sqlite 0.12.2 → 0.12.4
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/CHANGELOG.md +48 -0
- package/LICENSE +21 -0
- package/README.md +59 -0
- package/dist/src/create-node-sqlite-kysely.d.ts +10 -0
- package/dist/src/create-node-sqlite-kysely.js +3 -0
- package/dist/src/index.d.ts +2 -0
- package/dist/src/index.js +2 -0
- package/dist/src/register-functions.d.ts +19 -0
- package/dist/src/register-functions.js +21 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +13 -4
- package/run-tests.sh +33 -0
- package/src/create-node-sqlite-kysely.ts +12 -0
- package/src/index.ts +6 -0
- package/src/register-functions.test.ts +52 -0
- package/src/register-functions.ts +27 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,53 @@
|
|
|
1
1
|
# @pikku/kysely-node-sqlite
|
|
2
2
|
|
|
3
|
+
## 0.12.4
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 9d62571: Make user-defined SQL functions an explicit, checked capability of the SQLite drivers.
|
|
8
|
+
|
|
9
|
+
`node:sqlite` can register scalar UDFs (`db.function()`); `bun:sqlite` cannot. Until now
|
|
10
|
+
neither driver mentioned that, so an app that registered a UDF by reaching for the raw
|
|
11
|
+
connection worked on Node and, on bun, failed as `no such function: …` from whichever
|
|
12
|
+
query used it — typically one endpoint breaking in production while everything else
|
|
13
|
+
looked healthy.
|
|
14
|
+
|
|
15
|
+
Both drivers now export `registerSqliteFunctions(db, functions)` and accept a
|
|
16
|
+
`functions` option on `createNodeSqliteKysely` / `createBunSqliteKysely`. The Node
|
|
17
|
+
implementation registers them as deterministic; the bun implementation throws
|
|
18
|
+
`SqliteFunctionsUnsupportedError` — exported from `@pikku/kysely-sqlite`, and naming
|
|
19
|
+
every function requested — so the incompatibility surfaces at wiring time with a message
|
|
20
|
+
saying what to do about it.
|
|
21
|
+
|
|
22
|
+
- Updated dependencies [32277d5]
|
|
23
|
+
- Updated dependencies [ea8aabf]
|
|
24
|
+
- Updated dependencies [33e96ab]
|
|
25
|
+
- Updated dependencies [fd72e58]
|
|
26
|
+
- Updated dependencies [cabd9dc]
|
|
27
|
+
- Updated dependencies [fd72e58]
|
|
28
|
+
- Updated dependencies [fd72e58]
|
|
29
|
+
- Updated dependencies [894b2f8]
|
|
30
|
+
- Updated dependencies [dd19aa7]
|
|
31
|
+
- Updated dependencies [50ec500]
|
|
32
|
+
- Updated dependencies [9d62571]
|
|
33
|
+
- @pikku/core@0.12.75
|
|
34
|
+
- @pikku/kysely@0.13.8
|
|
35
|
+
- @pikku/kysely-sqlite@0.12.10
|
|
36
|
+
|
|
37
|
+
## 0.12.3
|
|
38
|
+
|
|
39
|
+
### Patch Changes
|
|
40
|
+
|
|
41
|
+
- 41ce2cb: Upgrade to TypeScript 6 and raise the minimum Node.js version to 22.
|
|
42
|
+
|
|
43
|
+
All packages now build against `typescript@^6.0.3` and declare `engines.node >= 22`. Internal tooling (`ts-json-schema-generator`, `zod-to-ts`) was bumped to TypeScript 6-compatible releases.
|
|
44
|
+
|
|
45
|
+
- Updated dependencies [241e6cf]
|
|
46
|
+
- Updated dependencies [41ce2cb]
|
|
47
|
+
- @pikku/kysely@0.13.0
|
|
48
|
+
- @pikku/core@0.12.44
|
|
49
|
+
- @pikku/kysely-sqlite@0.12.7
|
|
50
|
+
|
|
3
51
|
## 0.12.2
|
|
4
52
|
|
|
5
53
|
### Patch Changes
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2021 - present Yasser Fadl and Pikku contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# @pikku/kysely-node-sqlite
|
|
2
|
+
|
|
3
|
+
Kysely driver for Pikku backed by Node's built-in `node:sqlite` module — no
|
|
4
|
+
native dependency to install or compile.
|
|
5
|
+
|
|
6
|
+
Ships a coercion plugin that maps SQLite's storage classes back to the types
|
|
7
|
+
your schema declares (booleans, dates, JSON).
|
|
8
|
+
|
|
9
|
+
## Install
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm install @pikku/kysely-node-sqlite
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Requires a Node version with `node:sqlite` available.
|
|
16
|
+
|
|
17
|
+
## Usage
|
|
18
|
+
|
|
19
|
+
```typescript
|
|
20
|
+
import { createNodeSqliteKysely } from '@pikku/kysely-node-sqlite'
|
|
21
|
+
import type { KyselyPikkuDB } from '@pikku/kysely'
|
|
22
|
+
|
|
23
|
+
const db = createNodeSqliteKysely<KyselyPikkuDB>({
|
|
24
|
+
filename: 'app.db',
|
|
25
|
+
})
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
`camelCase` (default `true`) applies Kysely's `CamelCasePlugin`; pass extra
|
|
29
|
+
`plugins` to layer more on top. Use `':memory:'` for an in-memory database.
|
|
30
|
+
|
|
31
|
+
## User-defined SQL functions
|
|
32
|
+
|
|
33
|
+
`node:sqlite` can register scalar functions, so SQL can call your own code:
|
|
34
|
+
|
|
35
|
+
```typescript
|
|
36
|
+
const db = createNodeSqliteKysely<KyselyPikkuDB>({
|
|
37
|
+
filename: 'app.db',
|
|
38
|
+
functions: {
|
|
39
|
+
similarity: (a, b) => trigramSimilarity(String(a), String(b)),
|
|
40
|
+
},
|
|
41
|
+
})
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
They are registered as **deterministic**, which is what allows SQLite to use
|
|
45
|
+
them in an index and to cache repeated calls. Do not register a function whose
|
|
46
|
+
result depends on the clock, a random source, or anything mutable.
|
|
47
|
+
|
|
48
|
+
If you build the connection yourself — as you must when you need pragmas like
|
|
49
|
+
WAL or `busy_timeout` — call `registerSqliteFunctions(db, { … })` on it directly.
|
|
50
|
+
|
|
51
|
+
**This option has no bun equivalent.** `bun:sqlite` cannot register functions at
|
|
52
|
+
all, so `@pikku/kysely-bun-sqlite` throws `SqliteFunctionsUnsupportedError`
|
|
53
|
+
rather than accepting them. Using this is a decision to stay on Node; if you may
|
|
54
|
+
want to move, do the computation outside SQL over an indexed candidate set
|
|
55
|
+
instead.
|
|
56
|
+
|
|
57
|
+
## Docs
|
|
58
|
+
|
|
59
|
+
https://pikku.dev/docs
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Kysely, type KyselyPlugin } from 'kysely';
|
|
2
|
+
import type { SqliteFunctionMap } from '@pikku/kysely-sqlite';
|
|
2
3
|
export interface CreateNodeSqliteKyselyOptions {
|
|
3
4
|
/** Path to the SQLite file. Use ':memory:' for an in-memory DB. */
|
|
4
5
|
filename: string;
|
|
@@ -6,5 +7,14 @@ export interface CreateNodeSqliteKyselyOptions {
|
|
|
6
7
|
camelCase?: boolean;
|
|
7
8
|
/** Extra plugins to layer on top. */
|
|
8
9
|
plugins?: KyselyPlugin[];
|
|
10
|
+
/**
|
|
11
|
+
* Scalar user-defined SQL functions to register, keyed by the name SQL calls
|
|
12
|
+
* them by. Registered as deterministic.
|
|
13
|
+
*
|
|
14
|
+
* Note that this is the one option with no bun equivalent:
|
|
15
|
+
* `createBunSqliteKysely` throws if it is set, because bun:sqlite cannot
|
|
16
|
+
* register functions. Using it is a decision to stay on Node.
|
|
17
|
+
*/
|
|
18
|
+
functions?: SqliteFunctionMap;
|
|
9
19
|
}
|
|
10
20
|
export declare function createNodeSqliteKysely<DB>(options: CreateNodeSqliteKyselyOptions): Kysely<DB>;
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import { DatabaseSync } from 'node:sqlite';
|
|
2
2
|
import { Kysely, SqliteDialect, CamelCasePlugin, } from 'kysely';
|
|
3
3
|
import { NodeSqliteDatabase } from './node-sqlite-adapter.js';
|
|
4
|
+
import { registerSqliteFunctions } from './register-functions.js';
|
|
4
5
|
export function createNodeSqliteKysely(options) {
|
|
5
6
|
const db = new DatabaseSync(options.filename);
|
|
7
|
+
if (options.functions)
|
|
8
|
+
registerSqliteFunctions(db, options.functions);
|
|
6
9
|
const plugins = [];
|
|
7
10
|
if (options.camelCase ?? true)
|
|
8
11
|
plugins.push(new CamelCasePlugin());
|
package/dist/src/index.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
1
|
export { NodeSqliteDatabase } from './node-sqlite-adapter.js';
|
|
2
2
|
export { createNodeSqliteKysely, type CreateNodeSqliteKyselyOptions, } from './create-node-sqlite-kysely.js';
|
|
3
|
+
export { registerSqliteFunctions } from './register-functions.js';
|
|
4
|
+
export { SqliteFunctionsUnsupportedError, type SqliteFunction, type SqliteFunctionMap, } from '@pikku/kysely-sqlite';
|
|
3
5
|
export { createCoercionPlugin, type CoercionMap, type ColumnKind, type CreateCoercionPluginOptions, } from './coercion-plugin.js';
|
package/dist/src/index.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
1
|
export { NodeSqliteDatabase } from './node-sqlite-adapter.js';
|
|
2
2
|
export { createNodeSqliteKysely, } from './create-node-sqlite-kysely.js';
|
|
3
|
+
export { registerSqliteFunctions } from './register-functions.js';
|
|
4
|
+
export { SqliteFunctionsUnsupportedError, } from '@pikku/kysely-sqlite';
|
|
3
5
|
export { createCoercionPlugin, } from './coercion-plugin.js';
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { DatabaseSync } from 'node:sqlite';
|
|
2
|
+
import type { SqliteFunctionMap } from '@pikku/kysely-sqlite';
|
|
3
|
+
/**
|
|
4
|
+
* Registers scalar user-defined SQL functions on a node:sqlite connection.
|
|
5
|
+
*
|
|
6
|
+
* Exported separately from `createNodeSqliteKysely` because an app that needs
|
|
7
|
+
* pragmas — WAL, `foreign_keys`, `busy_timeout` — has to build the connection
|
|
8
|
+
* itself, and would otherwise have no supported way to add UDFs to it.
|
|
9
|
+
*
|
|
10
|
+
* Registered as `deterministic`, which is what makes them usable in indexes and
|
|
11
|
+
* lets SQLite cache repeated calls with the same arguments. That is a promise
|
|
12
|
+
* about the function, not a hint: one whose output depends on the clock, a
|
|
13
|
+
* random source or anything mutable must not go through here.
|
|
14
|
+
*
|
|
15
|
+
* There is no bun counterpart. `@pikku/kysely-bun-sqlite` exports the same name
|
|
16
|
+
* so the import resolves either way, but it throws — see
|
|
17
|
+
* SqliteFunctionsUnsupportedError.
|
|
18
|
+
*/
|
|
19
|
+
export declare function registerSqliteFunctions(db: DatabaseSync, functions: SqliteFunctionMap): void;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Registers scalar user-defined SQL functions on a node:sqlite connection.
|
|
3
|
+
*
|
|
4
|
+
* Exported separately from `createNodeSqliteKysely` because an app that needs
|
|
5
|
+
* pragmas — WAL, `foreign_keys`, `busy_timeout` — has to build the connection
|
|
6
|
+
* itself, and would otherwise have no supported way to add UDFs to it.
|
|
7
|
+
*
|
|
8
|
+
* Registered as `deterministic`, which is what makes them usable in indexes and
|
|
9
|
+
* lets SQLite cache repeated calls with the same arguments. That is a promise
|
|
10
|
+
* about the function, not a hint: one whose output depends on the clock, a
|
|
11
|
+
* random source or anything mutable must not go through here.
|
|
12
|
+
*
|
|
13
|
+
* There is no bun counterpart. `@pikku/kysely-bun-sqlite` exports the same name
|
|
14
|
+
* so the import resolves either way, but it throws — see
|
|
15
|
+
* SqliteFunctionsUnsupportedError.
|
|
16
|
+
*/
|
|
17
|
+
export function registerSqliteFunctions(db, functions) {
|
|
18
|
+
for (const [name, fn] of Object.entries(functions)) {
|
|
19
|
+
db.function(name, { deterministic: true }, fn);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"root":["../src/coercion-plugin.ts","../src/create-node-sqlite-kysely.ts","../src/index.ts","../src/node-sqlite-adapter.ts"],"version":"
|
|
1
|
+
{"root":["../src/coercion-plugin.ts","../src/create-node-sqlite-kysely.ts","../src/index.ts","../src/node-sqlite-adapter.ts","../src/register-functions.ts"],"version":"6.0.3"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pikku/kysely-node-sqlite",
|
|
3
|
-
"version": "0.12.
|
|
3
|
+
"version": "0.12.4",
|
|
4
|
+
"description": "Kysely driver for Pikku backed by the built-in node:sqlite module",
|
|
4
5
|
"author": "yasser.fadl@gmail.com",
|
|
5
6
|
"license": "MIT",
|
|
6
7
|
"module": "dist/src/index.js",
|
|
@@ -10,19 +11,27 @@
|
|
|
10
11
|
"tsc": "tsc",
|
|
11
12
|
"ncu": "npx npm-check-updates",
|
|
12
13
|
"build": "tsc -b",
|
|
14
|
+
"test": "bash run-tests.sh",
|
|
15
|
+
"test:watch": "bash run-tests.sh --watch",
|
|
16
|
+
"test:coverage": "bash run-tests.sh --coverage",
|
|
13
17
|
"prepublishOnly": "yarn build"
|
|
14
18
|
},
|
|
15
19
|
"engines": {
|
|
16
20
|
"node": ">=22.10"
|
|
17
21
|
},
|
|
18
22
|
"dependencies": {
|
|
19
|
-
"@pikku/kysely": "^0.
|
|
20
|
-
"@pikku/kysely-sqlite": "^0.12.
|
|
23
|
+
"@pikku/kysely": "^0.13.8",
|
|
24
|
+
"@pikku/kysely-sqlite": "^0.12.10",
|
|
21
25
|
"kysely": "^0.29.0"
|
|
22
26
|
},
|
|
27
|
+
"peerDependencies": {
|
|
28
|
+
"@pikku/core": "^0.12.75"
|
|
29
|
+
},
|
|
23
30
|
"devDependencies": {
|
|
31
|
+
"@pikku/core": "^0.12.75",
|
|
24
32
|
"@types/node": "^22",
|
|
25
|
-
"
|
|
33
|
+
"tsx": "^4.19.2",
|
|
34
|
+
"typescript": "^6.0.3"
|
|
26
35
|
},
|
|
27
36
|
"exports": {
|
|
28
37
|
".": "./dist/src/index.js"
|
package/run-tests.sh
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
# Parse command line arguments
|
|
4
|
+
WATCH_MODE=false
|
|
5
|
+
COVERAGE_MODE=false
|
|
6
|
+
|
|
7
|
+
for arg in "$@"
|
|
8
|
+
do
|
|
9
|
+
case $arg in
|
|
10
|
+
--watch)
|
|
11
|
+
WATCH_MODE=true
|
|
12
|
+
shift
|
|
13
|
+
;;
|
|
14
|
+
--coverage)
|
|
15
|
+
COVERAGE_MODE=true
|
|
16
|
+
shift
|
|
17
|
+
;;
|
|
18
|
+
esac
|
|
19
|
+
done
|
|
20
|
+
|
|
21
|
+
# Build the command
|
|
22
|
+
CMD="node --import tsx --test --test-force-exit src/**/*.test.ts"
|
|
23
|
+
|
|
24
|
+
if [ "$WATCH_MODE" = true ]; then
|
|
25
|
+
CMD="$CMD --watch"
|
|
26
|
+
fi
|
|
27
|
+
|
|
28
|
+
if [ "$COVERAGE_MODE" = true ]; then
|
|
29
|
+
CMD="$CMD --experimental-test-coverage"
|
|
30
|
+
fi
|
|
31
|
+
|
|
32
|
+
# Execute the command
|
|
33
|
+
eval $CMD
|
|
@@ -5,7 +5,9 @@ import {
|
|
|
5
5
|
CamelCasePlugin,
|
|
6
6
|
type KyselyPlugin,
|
|
7
7
|
} from 'kysely'
|
|
8
|
+
import type { SqliteFunctionMap } from '@pikku/kysely-sqlite'
|
|
8
9
|
import { NodeSqliteDatabase } from './node-sqlite-adapter.js'
|
|
10
|
+
import { registerSqliteFunctions } from './register-functions.js'
|
|
9
11
|
|
|
10
12
|
export interface CreateNodeSqliteKyselyOptions {
|
|
11
13
|
/** Path to the SQLite file. Use ':memory:' for an in-memory DB. */
|
|
@@ -14,12 +16,22 @@ export interface CreateNodeSqliteKyselyOptions {
|
|
|
14
16
|
camelCase?: boolean
|
|
15
17
|
/** Extra plugins to layer on top. */
|
|
16
18
|
plugins?: KyselyPlugin[]
|
|
19
|
+
/**
|
|
20
|
+
* Scalar user-defined SQL functions to register, keyed by the name SQL calls
|
|
21
|
+
* them by. Registered as deterministic.
|
|
22
|
+
*
|
|
23
|
+
* Note that this is the one option with no bun equivalent:
|
|
24
|
+
* `createBunSqliteKysely` throws if it is set, because bun:sqlite cannot
|
|
25
|
+
* register functions. Using it is a decision to stay on Node.
|
|
26
|
+
*/
|
|
27
|
+
functions?: SqliteFunctionMap
|
|
17
28
|
}
|
|
18
29
|
|
|
19
30
|
export function createNodeSqliteKysely<DB>(
|
|
20
31
|
options: CreateNodeSqliteKyselyOptions
|
|
21
32
|
): Kysely<DB> {
|
|
22
33
|
const db = new DatabaseSync(options.filename)
|
|
34
|
+
if (options.functions) registerSqliteFunctions(db, options.functions)
|
|
23
35
|
const plugins: KyselyPlugin[] = []
|
|
24
36
|
if (options.camelCase ?? true) plugins.push(new CamelCasePlugin())
|
|
25
37
|
if (options.plugins) plugins.push(...options.plugins)
|
package/src/index.ts
CHANGED
|
@@ -3,6 +3,12 @@ export {
|
|
|
3
3
|
createNodeSqliteKysely,
|
|
4
4
|
type CreateNodeSqliteKyselyOptions,
|
|
5
5
|
} from './create-node-sqlite-kysely.js'
|
|
6
|
+
export { registerSqliteFunctions } from './register-functions.js'
|
|
7
|
+
export {
|
|
8
|
+
SqliteFunctionsUnsupportedError,
|
|
9
|
+
type SqliteFunction,
|
|
10
|
+
type SqliteFunctionMap,
|
|
11
|
+
} from '@pikku/kysely-sqlite'
|
|
6
12
|
export {
|
|
7
13
|
createCoercionPlugin,
|
|
8
14
|
type CoercionMap,
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { describe, test } from 'node:test'
|
|
2
|
+
import assert from 'node:assert/strict'
|
|
3
|
+
import { DatabaseSync } from 'node:sqlite'
|
|
4
|
+
import { sql } from 'kysely'
|
|
5
|
+
import { registerSqliteFunctions } from './register-functions.js'
|
|
6
|
+
import { createNodeSqliteKysely } from './create-node-sqlite-kysely.js'
|
|
7
|
+
|
|
8
|
+
describe('registerSqliteFunctions', () => {
|
|
9
|
+
test('makes the function callable from SQL', () => {
|
|
10
|
+
const db = new DatabaseSync(':memory:')
|
|
11
|
+
registerSqliteFunctions(db, {
|
|
12
|
+
shout: (value) => `${String(value).toUpperCase()}!`,
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
const row = db.prepare(`SELECT shout('hello') AS v`).get() as { v: string }
|
|
16
|
+
assert.equal(row.v, 'HELLO!')
|
|
17
|
+
db.close()
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
test('registers as deterministic, so it is usable in an index', () => {
|
|
21
|
+
const db = new DatabaseSync(':memory:')
|
|
22
|
+
registerSqliteFunctions(db, { half: (n) => Number(n) / 2 })
|
|
23
|
+
|
|
24
|
+
db.exec('CREATE TABLE t (n INTEGER)')
|
|
25
|
+
// SQLite rejects non-deterministic functions in an index outright, so this
|
|
26
|
+
// statement succeeding IS the assertion about how they were registered.
|
|
27
|
+
db.exec('CREATE INDEX t_half ON t (half(n))')
|
|
28
|
+
db.close()
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
test('registers every entry in the map', () => {
|
|
32
|
+
const db = new DatabaseSync(':memory:')
|
|
33
|
+
registerSqliteFunctions(db, { a: () => 1, b: () => 2 })
|
|
34
|
+
|
|
35
|
+
const row = db.prepare('SELECT a() + b() AS v').get() as { v: number }
|
|
36
|
+
assert.equal(row.v, 3)
|
|
37
|
+
db.close()
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
test('createNodeSqliteKysely registers them on the connection it builds', async () => {
|
|
41
|
+
const db = createNodeSqliteKysely<{ t: { id: number } }>({
|
|
42
|
+
filename: ':memory:',
|
|
43
|
+
functions: { double: (n) => Number(n) * 2 },
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
const result = await sql<{
|
|
47
|
+
v: number
|
|
48
|
+
}>`SELECT double(21) AS v`.execute(db)
|
|
49
|
+
assert.equal(result.rows[0]!.v, 42)
|
|
50
|
+
await db.destroy()
|
|
51
|
+
})
|
|
52
|
+
})
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { DatabaseSync } from 'node:sqlite'
|
|
2
|
+
import type { SqliteFunctionMap } from '@pikku/kysely-sqlite'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Registers scalar user-defined SQL functions on a node:sqlite connection.
|
|
6
|
+
*
|
|
7
|
+
* Exported separately from `createNodeSqliteKysely` because an app that needs
|
|
8
|
+
* pragmas — WAL, `foreign_keys`, `busy_timeout` — has to build the connection
|
|
9
|
+
* itself, and would otherwise have no supported way to add UDFs to it.
|
|
10
|
+
*
|
|
11
|
+
* Registered as `deterministic`, which is what makes them usable in indexes and
|
|
12
|
+
* lets SQLite cache repeated calls with the same arguments. That is a promise
|
|
13
|
+
* about the function, not a hint: one whose output depends on the clock, a
|
|
14
|
+
* random source or anything mutable must not go through here.
|
|
15
|
+
*
|
|
16
|
+
* There is no bun counterpart. `@pikku/kysely-bun-sqlite` exports the same name
|
|
17
|
+
* so the import resolves either way, but it throws — see
|
|
18
|
+
* SqliteFunctionsUnsupportedError.
|
|
19
|
+
*/
|
|
20
|
+
export function registerSqliteFunctions(
|
|
21
|
+
db: DatabaseSync,
|
|
22
|
+
functions: SqliteFunctionMap
|
|
23
|
+
): void {
|
|
24
|
+
for (const [name, fn] of Object.entries(functions)) {
|
|
25
|
+
db.function(name, { deterministic: true }, fn as never)
|
|
26
|
+
}
|
|
27
|
+
}
|