@prisma-next/sqlite 0.0.1
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/README.md +69 -0
- package/package.json +53 -0
- package/src/exports/runtime.ts +10 -0
- package/src/runtime/binding.ts +16 -0
- package/src/runtime/sqlite.ts +199 -0
package/README.md
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# @prisma-next/sqlite
|
|
2
|
+
|
|
3
|
+
Composition-root SQLite helper that builds a Prisma Next runtime client and exposes SQL, ORM, and schema query access.
|
|
4
|
+
|
|
5
|
+
## Package Classification
|
|
6
|
+
|
|
7
|
+
- **Domain**: extensions
|
|
8
|
+
- **Layer**: adapters
|
|
9
|
+
- **Plane**: runtime
|
|
10
|
+
|
|
11
|
+
## Overview
|
|
12
|
+
|
|
13
|
+
`@prisma-next/sqlite/runtime` exposes a single `sqlite(...)` helper that composes the SQLite execution stack and returns query/runtime roots:
|
|
14
|
+
|
|
15
|
+
- `db.sql`
|
|
16
|
+
- `db.orm`
|
|
17
|
+
- `db.context`
|
|
18
|
+
- `db.stack`
|
|
19
|
+
|
|
20
|
+
Runtime resources are deferred until `db.runtime()` or `db.connect(...)` is called.
|
|
21
|
+
Connection binding can be provided up front (`path`) or deferred via `db.connect(...)`.
|
|
22
|
+
|
|
23
|
+
## Responsibilities
|
|
24
|
+
|
|
25
|
+
- Build a static SQLite execution stack from target, adapter, and driver descriptors
|
|
26
|
+
- Build typed SQL surface from the execution context via `sql-query-builder-new`
|
|
27
|
+
- Build ORM surface from the execution context
|
|
28
|
+
- Normalize runtime binding input (file path or `:memory:`)
|
|
29
|
+
- Lazily instantiate runtime resources on first `db.runtime()` or `db.connect(...)` call
|
|
30
|
+
- Connect the internal SQLite driver through `db.connect(...)` or from initial binding options
|
|
31
|
+
- Memoize runtime so repeated `db.runtime()` calls return one instance
|
|
32
|
+
|
|
33
|
+
## Dependencies
|
|
34
|
+
|
|
35
|
+
- **`@prisma-next/sql-runtime`** for stack/context/runtime primitives
|
|
36
|
+
- **`@prisma-next/framework-components`** for stack instantiation
|
|
37
|
+
- **`@prisma-next/target-sqlite`** for target descriptor
|
|
38
|
+
- **`@prisma-next/adapter-sqlite`** for adapter descriptor
|
|
39
|
+
- **`@prisma-next/driver-sqlite`** for driver descriptor
|
|
40
|
+
- **`@prisma-next/sql-builder`** for `sql(...)` query builder
|
|
41
|
+
- **`@prisma-next/sql-relational-core`** for `schema(...)`
|
|
42
|
+
- **`@prisma-next/sql-orm-client`** for `orm(...)`
|
|
43
|
+
- **`@prisma-next/sql-contract`** for `validateContract(...)` and contract types
|
|
44
|
+
|
|
45
|
+
## Architecture
|
|
46
|
+
|
|
47
|
+
```mermaid
|
|
48
|
+
flowchart TD
|
|
49
|
+
App[App Code] --> Client["sqlite(...)"]
|
|
50
|
+
Client --> Static["Roots: sql orm context stack"]
|
|
51
|
+
Client --> Lazy["runtime()"]
|
|
52
|
+
|
|
53
|
+
Lazy --> Instantiate[instantiateExecutionStack]
|
|
54
|
+
Lazy --> Bind["Resolve binding: path or :memory:"]
|
|
55
|
+
Bind --> DB["DatabaseSync via node:sqlite"]
|
|
56
|
+
Lazy --> Runtime[createRuntime]
|
|
57
|
+
|
|
58
|
+
Runtime --> Target["@prisma-next/target-sqlite"]
|
|
59
|
+
Runtime --> Adapter["@prisma-next/adapter-sqlite"]
|
|
60
|
+
Runtime --> Driver["@prisma-next/driver-sqlite"]
|
|
61
|
+
Runtime --> SqlRuntime["@prisma-next/sql-runtime"]
|
|
62
|
+
Runtime --> ExecPlane["@prisma-next/framework-components/execution"]
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Related Docs
|
|
66
|
+
|
|
67
|
+
- Architecture: `docs/Architecture Overview.md`
|
|
68
|
+
- Subsystem: `docs/architecture docs/subsystems/4. Runtime & Middleware Framework.md`
|
|
69
|
+
- Subsystem: `docs/architecture docs/subsystems/5. Adapters & Targets.md`
|
package/package.json
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@prisma-next/sqlite",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"sideEffects": false,
|
|
6
|
+
"description": "One-liner lazy SQLite client composition for Prisma Next",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"build": "tsdown",
|
|
9
|
+
"test": "vitest run --passWithNoTests",
|
|
10
|
+
"test:coverage": "vitest run --coverage --passWithNoTests",
|
|
11
|
+
"typecheck": "tsc --project tsconfig.json --noEmit",
|
|
12
|
+
"lint": "biome check . --error-on-warnings",
|
|
13
|
+
"lint:fix": "biome check --write .",
|
|
14
|
+
"lint:fix:unsafe": "biome check --write --unsafe .",
|
|
15
|
+
"clean": "rm -rf dist dist-tsc dist-tsc-prod coverage .tmp-output"
|
|
16
|
+
},
|
|
17
|
+
"dependencies": {
|
|
18
|
+
"@prisma-next/adapter-sqlite": "workspace:*",
|
|
19
|
+
"@prisma-next/contract": "workspace:*",
|
|
20
|
+
"@prisma-next/driver-sqlite": "workspace:*",
|
|
21
|
+
"@prisma-next/framework-components": "workspace:*",
|
|
22
|
+
"@prisma-next/sql-builder": "workspace:*",
|
|
23
|
+
"@prisma-next/sql-contract": "workspace:*",
|
|
24
|
+
"@prisma-next/sql-orm-client": "workspace:*",
|
|
25
|
+
"@prisma-next/sql-relational-core": "workspace:*",
|
|
26
|
+
"@prisma-next/sql-runtime": "workspace:*",
|
|
27
|
+
"@prisma-next/target-sqlite": "workspace:*"
|
|
28
|
+
},
|
|
29
|
+
"devDependencies": {
|
|
30
|
+
"@prisma-next/test-utils": "workspace:*",
|
|
31
|
+
"@prisma-next/tsconfig": "workspace:*",
|
|
32
|
+
"@prisma-next/tsdown": "workspace:*",
|
|
33
|
+
"tsdown": "catalog:",
|
|
34
|
+
"typescript": "catalog:",
|
|
35
|
+
"vitest": "catalog:"
|
|
36
|
+
},
|
|
37
|
+
"files": [
|
|
38
|
+
"dist",
|
|
39
|
+
"src"
|
|
40
|
+
],
|
|
41
|
+
"repository": {
|
|
42
|
+
"type": "git",
|
|
43
|
+
"url": "https://github.com/prisma/prisma-next.git",
|
|
44
|
+
"directory": "packages/3-extensions/sqlite"
|
|
45
|
+
},
|
|
46
|
+
"exports": {
|
|
47
|
+
"./runtime": "./dist/runtime.mjs",
|
|
48
|
+
"./package.json": "./package.json"
|
|
49
|
+
},
|
|
50
|
+
"main": "./dist/runtime.mjs",
|
|
51
|
+
"module": "./dist/runtime.mjs",
|
|
52
|
+
"types": "./dist/runtime.d.mts"
|
|
53
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export type { SqliteBindingInput } from '../runtime/binding';
|
|
2
|
+
export type {
|
|
3
|
+
SqliteClient,
|
|
4
|
+
SqliteOptions,
|
|
5
|
+
SqliteOptionsBase,
|
|
6
|
+
SqliteOptionsWithContract,
|
|
7
|
+
SqliteOptionsWithContractJson,
|
|
8
|
+
SqliteTargetId,
|
|
9
|
+
} from '../runtime/sqlite';
|
|
10
|
+
export { default } from '../runtime/sqlite';
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { SqliteBinding } from '@prisma-next/driver-sqlite/runtime';
|
|
2
|
+
|
|
3
|
+
export type SqliteBindingInput = { readonly path: string };
|
|
4
|
+
|
|
5
|
+
export function resolveSqliteBinding(input: SqliteBindingInput): SqliteBinding {
|
|
6
|
+
return { kind: 'path', path: input.path };
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function resolveOptionalSqliteBinding(options: {
|
|
10
|
+
readonly path?: string;
|
|
11
|
+
}): SqliteBinding | undefined {
|
|
12
|
+
if (options.path === undefined) {
|
|
13
|
+
return undefined;
|
|
14
|
+
}
|
|
15
|
+
return { kind: 'path', path: options.path };
|
|
16
|
+
}
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
import sqliteAdapter from '@prisma-next/adapter-sqlite/runtime';
|
|
2
|
+
import type { Contract } from '@prisma-next/contract/types';
|
|
3
|
+
import type { SqliteBinding } from '@prisma-next/driver-sqlite/runtime';
|
|
4
|
+
import sqliteDriver from '@prisma-next/driver-sqlite/runtime';
|
|
5
|
+
import { emptyCodecLookup } from '@prisma-next/framework-components/codec';
|
|
6
|
+
import { instantiateExecutionStack } from '@prisma-next/framework-components/execution';
|
|
7
|
+
import { sql as sqlBuilder } from '@prisma-next/sql-builder/runtime';
|
|
8
|
+
import type { Db } from '@prisma-next/sql-builder/types';
|
|
9
|
+
import type { SqlStorage } from '@prisma-next/sql-contract/types';
|
|
10
|
+
import { validateContract } from '@prisma-next/sql-contract/validate';
|
|
11
|
+
import { orm as ormBuilder } from '@prisma-next/sql-orm-client';
|
|
12
|
+
import type {
|
|
13
|
+
ExecutionContext,
|
|
14
|
+
Middleware,
|
|
15
|
+
Runtime,
|
|
16
|
+
RuntimeVerifyOptions,
|
|
17
|
+
SqlExecutionStackWithDriver,
|
|
18
|
+
SqlRuntimeExtensionDescriptor,
|
|
19
|
+
} from '@prisma-next/sql-runtime';
|
|
20
|
+
import {
|
|
21
|
+
createExecutionContext,
|
|
22
|
+
createRuntime,
|
|
23
|
+
createSqlExecutionStack,
|
|
24
|
+
} from '@prisma-next/sql-runtime';
|
|
25
|
+
import sqliteTarget from '@prisma-next/target-sqlite/runtime';
|
|
26
|
+
import { resolveOptionalSqliteBinding, resolveSqliteBinding } from './binding';
|
|
27
|
+
|
|
28
|
+
export type SqliteTargetId = 'sqlite';
|
|
29
|
+
type OrmClient<TContract extends Contract<SqlStorage>> = ReturnType<typeof ormBuilder<TContract>>;
|
|
30
|
+
|
|
31
|
+
export interface SqliteClient<TContract extends Contract<SqlStorage>> {
|
|
32
|
+
readonly sql: Db<TContract>;
|
|
33
|
+
readonly orm: OrmClient<TContract>;
|
|
34
|
+
readonly context: ExecutionContext<TContract>;
|
|
35
|
+
readonly stack: SqlExecutionStackWithDriver<SqliteTargetId>;
|
|
36
|
+
connect(bindingInput?: { readonly path: string }): Promise<Runtime>;
|
|
37
|
+
runtime(): Runtime;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export interface SqliteOptionsBase<TContract extends Contract<SqlStorage>> {
|
|
41
|
+
readonly extensions?: readonly SqlRuntimeExtensionDescriptor<SqliteTargetId>[];
|
|
42
|
+
readonly middleware?: readonly Middleware<TContract>[];
|
|
43
|
+
readonly verify?: RuntimeVerifyOptions;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export type SqliteOptionsWithContract<TContract extends Contract<SqlStorage>> = {
|
|
47
|
+
readonly path?: string;
|
|
48
|
+
} & SqliteOptionsBase<TContract> & {
|
|
49
|
+
readonly contract: TContract;
|
|
50
|
+
readonly contractJson?: never;
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
export type SqliteOptionsWithContractJson<TContract extends Contract<SqlStorage>> = {
|
|
54
|
+
readonly path?: string;
|
|
55
|
+
} & SqliteOptionsBase<TContract> & {
|
|
56
|
+
readonly contractJson: unknown;
|
|
57
|
+
readonly contract?: never;
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
export type SqliteOptions<TContract extends Contract<SqlStorage>> =
|
|
61
|
+
| SqliteOptionsWithContract<TContract>
|
|
62
|
+
| SqliteOptionsWithContractJson<TContract>;
|
|
63
|
+
|
|
64
|
+
function resolveContract<TContract extends Contract<SqlStorage>>(
|
|
65
|
+
options: SqliteOptions<TContract>,
|
|
66
|
+
): TContract {
|
|
67
|
+
const contractInput =
|
|
68
|
+
'contractJson' in options && options.contractJson !== undefined
|
|
69
|
+
? options.contractJson
|
|
70
|
+
: (options as SqliteOptionsWithContract<TContract>).contract;
|
|
71
|
+
return validateContract<TContract>(contractInput, emptyCodecLookup);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export default function sqlite<TContract extends Contract<SqlStorage>>(
|
|
75
|
+
options: SqliteOptionsWithContract<TContract>,
|
|
76
|
+
): SqliteClient<TContract>;
|
|
77
|
+
export default function sqlite<TContract extends Contract<SqlStorage>>(
|
|
78
|
+
options: SqliteOptionsWithContractJson<TContract>,
|
|
79
|
+
): SqliteClient<TContract>;
|
|
80
|
+
export default function sqlite<TContract extends Contract<SqlStorage>>(
|
|
81
|
+
options: SqliteOptions<TContract>,
|
|
82
|
+
): SqliteClient<TContract> {
|
|
83
|
+
const contract = resolveContract(options);
|
|
84
|
+
let binding = resolveOptionalSqliteBinding(options);
|
|
85
|
+
const stack = createSqlExecutionStack({
|
|
86
|
+
target: sqliteTarget,
|
|
87
|
+
adapter: sqliteAdapter,
|
|
88
|
+
driver: sqliteDriver,
|
|
89
|
+
extensionPacks: options.extensions ?? [],
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
const context = createExecutionContext({
|
|
93
|
+
contract,
|
|
94
|
+
stack,
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
const sql: Db<TContract> = sqlBuilder<TContract>({ context });
|
|
98
|
+
let runtimeInstance: Runtime | undefined;
|
|
99
|
+
let runtimeDriver: { connect(binding: unknown): Promise<void> } | undefined;
|
|
100
|
+
let driverConnected = false;
|
|
101
|
+
let connectPromise: Promise<void> | undefined;
|
|
102
|
+
let backgroundConnectError: unknown;
|
|
103
|
+
|
|
104
|
+
const connectDriver = async (resolvedBinding: SqliteBinding): Promise<void> => {
|
|
105
|
+
if (driverConnected) return;
|
|
106
|
+
if (!runtimeDriver) throw new Error('SQLite runtime driver missing');
|
|
107
|
+
if (connectPromise) return connectPromise;
|
|
108
|
+
connectPromise = runtimeDriver
|
|
109
|
+
.connect(resolvedBinding)
|
|
110
|
+
.then(() => {
|
|
111
|
+
driverConnected = true;
|
|
112
|
+
})
|
|
113
|
+
.catch((err) => {
|
|
114
|
+
backgroundConnectError = err;
|
|
115
|
+
connectPromise = undefined;
|
|
116
|
+
throw err;
|
|
117
|
+
});
|
|
118
|
+
return connectPromise;
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
const getRuntime = (): Runtime => {
|
|
122
|
+
if (backgroundConnectError !== undefined) {
|
|
123
|
+
throw backgroundConnectError;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
if (runtimeInstance) {
|
|
127
|
+
return runtimeInstance;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const stackInstance = instantiateExecutionStack(stack);
|
|
131
|
+
const driverDescriptor = stack.driver;
|
|
132
|
+
if (!driverDescriptor) {
|
|
133
|
+
throw new Error('Driver descriptor missing from execution stack');
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const driver = driverDescriptor.create();
|
|
137
|
+
runtimeDriver = driver;
|
|
138
|
+
if (binding !== undefined) {
|
|
139
|
+
void connectDriver(binding).catch(() => undefined);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
runtimeInstance = createRuntime({
|
|
143
|
+
stackInstance,
|
|
144
|
+
context,
|
|
145
|
+
driver,
|
|
146
|
+
verify: options.verify ?? { mode: 'onFirstUse', requireMarker: false },
|
|
147
|
+
...(options.middleware ? { middleware: options.middleware } : {}),
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
return runtimeInstance;
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
const orm: OrmClient<TContract> = ormBuilder({
|
|
154
|
+
context,
|
|
155
|
+
runtime: {
|
|
156
|
+
execute(plan) {
|
|
157
|
+
return getRuntime().execute(plan);
|
|
158
|
+
},
|
|
159
|
+
connection() {
|
|
160
|
+
return getRuntime().connection();
|
|
161
|
+
},
|
|
162
|
+
},
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
return {
|
|
166
|
+
sql,
|
|
167
|
+
orm,
|
|
168
|
+
context,
|
|
169
|
+
stack,
|
|
170
|
+
async connect(bindingInput) {
|
|
171
|
+
if (driverConnected || connectPromise) {
|
|
172
|
+
throw new Error('SQLite client already connected');
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
backgroundConnectError = undefined;
|
|
176
|
+
|
|
177
|
+
if (bindingInput !== undefined) {
|
|
178
|
+
binding = resolveSqliteBinding(bindingInput);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
if (binding === undefined) {
|
|
182
|
+
throw new Error(
|
|
183
|
+
'SQLite binding not configured. Pass path to sqlite(...) or call db.connect({ path }).',
|
|
184
|
+
);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
const runtime = getRuntime();
|
|
188
|
+
if (driverConnected) {
|
|
189
|
+
return runtime;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
await connectDriver(binding);
|
|
193
|
+
return runtime;
|
|
194
|
+
},
|
|
195
|
+
runtime() {
|
|
196
|
+
return getRuntime();
|
|
197
|
+
},
|
|
198
|
+
};
|
|
199
|
+
}
|