@effect/sql-sqlite-do 4.0.0-beta.87 → 4.0.0-beta.88
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/dist/SqliteClient.d.ts +21 -9
- package/dist/SqliteClient.d.ts.map +1 -1
- package/dist/SqliteClient.js +53 -8
- package/dist/SqliteClient.js.map +1 -1
- package/dist/SqliteMigrator.d.ts +19 -4
- package/dist/SqliteMigrator.d.ts.map +1 -1
- package/dist/SqliteMigrator.js.map +1 -1
- package/package.json +3 -3
- package/src/SqliteClient.ts +119 -30
- package/src/SqliteMigrator.ts +19 -4
package/dist/SqliteClient.d.ts
CHANGED
|
@@ -1,15 +1,26 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Connects Effect SQL to SQLite storage inside Cloudflare Durable Objects.
|
|
3
3
|
*
|
|
4
|
-
* This module
|
|
5
|
-
* `SqliteClient` and the generic Effect
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
4
|
+
* This module adapts a Durable Object `SqlStorage` handle into both the
|
|
5
|
+
* Durable Object-specific `SqliteClient` service and the generic Effect
|
|
6
|
+
* `SqlClient` service. Use it from inside a Durable Object to run local
|
|
7
|
+
* per-object queries, repositories, migrations, transactional read/write
|
|
8
|
+
* workflows, and tests that exercise Cloudflare's SQLite-backed storage API.
|
|
9
|
+
*
|
|
10
|
+
* Durable Object SQLite storage is scoped to one object id, so each object
|
|
11
|
+
* instance has its own database. Callers can pass the `SqlStorage` handle for
|
|
12
|
+
* normal queries, or the full `DurableObjectStorage` when `withTransaction` or
|
|
13
|
+
* migrations need Cloudflare-managed transactions. This adapter serializes
|
|
14
|
+
* Effect SQL access through one connection; a transaction holds that permit for
|
|
15
|
+
* the lifetime of its scope, so keep transactions short, avoid suspending them
|
|
16
|
+
* across unrelated work, and use them when multi-statement writes must commit
|
|
17
|
+
* atomically. `SqlStorage.exec` returns `ArrayBuffer` values
|
|
18
|
+
* for SQLite blobs, which this client normalizes to `Uint8Array`, and SQLite
|
|
19
|
+
* does not support `updateValues`.
|
|
9
20
|
*
|
|
10
21
|
* @since 4.0.0
|
|
11
22
|
*/
|
|
12
|
-
import type { SqlStorage } from "@cloudflare/workers-types";
|
|
23
|
+
import type { DurableObjectStorage, SqlStorage } from "@cloudflare/workers-types";
|
|
13
24
|
import * as Config from "effect/Config";
|
|
14
25
|
import * as Context from "effect/Context";
|
|
15
26
|
import * as Effect from "effect/Effect";
|
|
@@ -56,19 +67,20 @@ export interface SqliteClient extends Client.SqlClient {
|
|
|
56
67
|
*/
|
|
57
68
|
export declare const SqliteClient: Context.Service<SqliteClient, SqliteClient>;
|
|
58
69
|
/**
|
|
59
|
-
* Configuration for a Cloudflare Durable Object SQLite client, including
|
|
70
|
+
* Configuration for a Cloudflare Durable Object SQLite client, including either a `SqlStorage` handle or the full `DurableObjectStorage` for transaction support, span attributes, and query/result name transforms.
|
|
60
71
|
*
|
|
61
72
|
* @category models
|
|
62
73
|
* @since 4.0.0
|
|
63
74
|
*/
|
|
64
75
|
export interface SqliteClientConfig {
|
|
65
|
-
readonly db
|
|
76
|
+
readonly db?: SqlStorage | undefined;
|
|
77
|
+
readonly storage?: DurableObjectStorage | undefined;
|
|
66
78
|
readonly spanAttributes?: Record<string, unknown> | undefined;
|
|
67
79
|
readonly transformResultNames?: ((str: string) => string) | undefined;
|
|
68
80
|
readonly transformQueryNames?: ((str: string) => string) | undefined;
|
|
69
81
|
}
|
|
70
82
|
/**
|
|
71
|
-
* Creates a scoped Cloudflare Durable Object SQLite client around
|
|
83
|
+
* Creates a scoped Cloudflare Durable Object SQLite client around Durable Object SQLite storage, serializing access and converting returned `ArrayBuffer` values to `Uint8Array`.
|
|
72
84
|
*
|
|
73
85
|
* @category constructors
|
|
74
86
|
* @since 4.0.0
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SqliteClient.d.ts","sourceRoot":"","sources":["../src/SqliteClient.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"SqliteClient.d.ts","sourceRoot":"","sources":["../src/SqliteClient.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,OAAO,KAAK,EAAE,oBAAoB,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAA;AACjF,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AACvC,OAAO,KAAK,OAAO,MAAM,gBAAgB,CAAA;AACzC,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AAIvC,OAAO,KAAK,KAAK,MAAM,cAAc,CAAA;AACrC,OAAO,KAAK,KAAK,MAAM,cAAc,CAAA;AAGrC,OAAO,KAAK,UAAU,MAAM,uCAAuC,CAAA;AACnE,OAAO,KAAK,MAAM,MAAM,+BAA+B,CAAA;AAUvD;;;;;GAKG;AACH,eAAO,MAAM,MAAM,EAAE,MAA8C,CAAA;AAEnE;;;;;GAKG;AACH,MAAM,MAAM,MAAM,GAAG,qCAAqC,CAAA;AAE1D;;;;;GAKG;AACH,MAAM,WAAW,YAAa,SAAQ,MAAM,CAAC,SAAS;IACpD,QAAQ,CAAC,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;IACzB,QAAQ,CAAC,MAAM,EAAE,kBAAkB,CAAA;IAEnC,8BAA8B;IAC9B,QAAQ,CAAC,YAAY,EAAE,KAAK,CAAA;CAC7B;AAED;;;;;;;;;;GAUG;AACH,eAAO,MAAM,YAAY,6CAAsE,CAAA;AAM/F;;;;;GAKG;AACH,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,EAAE,CAAC,EAAE,UAAU,GAAG,SAAS,CAAA;IACpC,QAAQ,CAAC,OAAO,CAAC,EAAE,oBAAoB,GAAG,SAAS,CAAA;IACnD,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAAA;IAE7D,QAAQ,CAAC,oBAAoB,CAAC,EAAE,CAAC,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,CAAC,GAAG,SAAS,CAAA;IACrE,QAAQ,CAAC,mBAAmB,CAAC,EAAE,CAAC,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,CAAC,GAAG,SAAS,CAAA;CACrE;AAiED;;;;;GAKG;AACH,eAAO,MAAM,IAAI,GACf,SAAS,kBAAkB,KAC1B,MAAM,CAAC,MAAM,CAAC,YAAY,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,GAAG,UAAU,CAAC,UAAU,CA+HrE,CAAA;AAEJ;;;;;GAKG;AACH,eAAO,MAAM,WAAW,GACtB,QAAQ,MAAM,CAAC,IAAI,CAAC,kBAAkB,CAAC,KACtC,KAAK,CAAC,KAAK,CAAC,YAAY,GAAG,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,WAAW,CAUzB,CAAA;AAEzC;;;;;GAKG;AACH,eAAO,MAAM,KAAK,GAChB,QAAQ,kBAAkB,KACzB,KAAK,CAAC,KAAK,CAAC,YAAY,GAAG,MAAM,CAAC,SAAS,CAML,CAAA"}
|
package/dist/SqliteClient.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as Config from "effect/Config";
|
|
2
2
|
import * as Context from "effect/Context";
|
|
3
3
|
import * as Effect from "effect/Effect";
|
|
4
|
+
import * as Exit from "effect/Exit";
|
|
4
5
|
import * as Fiber from "effect/Fiber";
|
|
5
6
|
import { identity } from "effect/Function";
|
|
6
7
|
import * as Layer from "effect/Layer";
|
|
@@ -9,7 +10,7 @@ import * as Semaphore from "effect/Semaphore";
|
|
|
9
10
|
import * as Stream from "effect/Stream";
|
|
10
11
|
import * as Reactivity from "effect/unstable/reactivity/Reactivity";
|
|
11
12
|
import * as Client from "effect/unstable/sql/SqlClient";
|
|
12
|
-
import { classifySqliteError, SqlError } from "effect/unstable/sql/SqlError";
|
|
13
|
+
import { classifySqliteError, SqlError, UnknownError } from "effect/unstable/sql/SqlError";
|
|
13
14
|
import * as Statement from "effect/unstable/sql/Statement";
|
|
14
15
|
const ATTR_DB_SYSTEM_NAME = "db.system.name";
|
|
15
16
|
const classifyError = (cause, message, operation) => classifySqliteError(cause, {
|
|
@@ -35,8 +36,45 @@ export const TypeId = "~@effect/sql-sqlite-do/SqliteClient";
|
|
|
35
36
|
* @since 4.0.0
|
|
36
37
|
*/
|
|
37
38
|
export const SqliteClient = /*#__PURE__*/Context.Service("@effect/sql-sqlite-do/SqliteClient");
|
|
39
|
+
const SqliteTransaction = /*#__PURE__*/Context.Service("@effect/sql-sqlite-do/SqliteClient/SqliteTransaction");
|
|
40
|
+
const unsupportedTransaction = (message, operation) => new SqlError({
|
|
41
|
+
reason: new UnknownError({
|
|
42
|
+
cause: new Error(message),
|
|
43
|
+
message,
|
|
44
|
+
operation
|
|
45
|
+
})
|
|
46
|
+
});
|
|
47
|
+
const makeUnsupportedWithTransaction = message => _effect => Effect.fail(unsupportedTransaction(message, "transaction"));
|
|
48
|
+
const makeStorageBackedWithTransaction = (storage, connection, semaphore) => effect => Effect.withFiber(fiber => {
|
|
49
|
+
const services = fiber.context;
|
|
50
|
+
const connOption = Context.getOption(services, SqliteTransaction);
|
|
51
|
+
if (connOption._tag === "Some") {
|
|
52
|
+
return Effect.fail(unsupportedTransaction("Nested transactions are not supported by Cloudflare Durable Object SQLite storage", "transaction"));
|
|
53
|
+
}
|
|
54
|
+
const effectWithTxn = Effect.provideContext(effect, Context.add(services, SqliteTransaction, [connection, 0]));
|
|
55
|
+
return semaphore.withPermits(1)(Effect.callback(resume => {
|
|
56
|
+
let interrupted = false;
|
|
57
|
+
const promise = storage.transaction(txn => new Promise(resolve => {
|
|
58
|
+
if (interrupted) return resolve();
|
|
59
|
+
resume(Effect.onExit(effectWithTxn, exit => {
|
|
60
|
+
if (Exit.isFailure(exit)) {
|
|
61
|
+
txn.rollback();
|
|
62
|
+
}
|
|
63
|
+
resolve();
|
|
64
|
+
// wait for the transaction to complete
|
|
65
|
+
return Effect.promise(() => promise);
|
|
66
|
+
}));
|
|
67
|
+
})).catch(cause => resume(Effect.fail(new SqlError({
|
|
68
|
+
reason: classifyError(cause, "Failed transaction", "transaction")
|
|
69
|
+
}))));
|
|
70
|
+
return Effect.suspend(() => {
|
|
71
|
+
interrupted = true;
|
|
72
|
+
return Effect.promise(() => promise);
|
|
73
|
+
});
|
|
74
|
+
}));
|
|
75
|
+
});
|
|
38
76
|
/**
|
|
39
|
-
* Creates a scoped Cloudflare Durable Object SQLite client around
|
|
77
|
+
* Creates a scoped Cloudflare Durable Object SQLite client around Durable Object SQLite storage, serializing access and converting returned `ArrayBuffer` values to `Uint8Array`.
|
|
40
78
|
*
|
|
41
79
|
* @category constructors
|
|
42
80
|
* @since 4.0.0
|
|
@@ -44,10 +82,14 @@ export const SqliteClient = /*#__PURE__*/Context.Service("@effect/sql-sqlite-do/
|
|
|
44
82
|
export const make = options => Effect.gen(function* () {
|
|
45
83
|
const compiler = Statement.makeCompilerSqlite(options.transformQueryNames);
|
|
46
84
|
const transformRows = options.transformResultNames ? Statement.defaultTransforms(options.transformResultNames).array : undefined;
|
|
85
|
+
const db = options.storage?.sql ?? options.db;
|
|
86
|
+
if (db === undefined) {
|
|
87
|
+
return yield* Effect.die("SqliteClient.make requires either a Durable Object storage or sql storage");
|
|
88
|
+
}
|
|
89
|
+
const sqlStorage = db;
|
|
47
90
|
const makeConnection = Effect.gen(function* () {
|
|
48
|
-
const db = options.db;
|
|
49
91
|
function* runIterator(sql, params = []) {
|
|
50
|
-
const cursor =
|
|
92
|
+
const cursor = sqlStorage.exec(sql, ...params);
|
|
51
93
|
const columns = cursor.columnNames;
|
|
52
94
|
for (const result of cursor.raw()) {
|
|
53
95
|
const obj = {};
|
|
@@ -65,7 +107,7 @@ export const make = options => Effect.gen(function* () {
|
|
|
65
107
|
})
|
|
66
108
|
});
|
|
67
109
|
const runValues = (sql, params = []) => Effect.try({
|
|
68
|
-
try: () => Array.from(
|
|
110
|
+
try: () => Array.from(sqlStorage.exec(sql, ...params).raw(), row => {
|
|
69
111
|
for (let i = 0; i < row.length; i++) {
|
|
70
112
|
const value = row[i];
|
|
71
113
|
if (value instanceof ArrayBuffer) {
|
|
@@ -110,15 +152,18 @@ export const make = options => Effect.gen(function* () {
|
|
|
110
152
|
const scope = Context.getUnsafe(fiber.context, Scope.Scope);
|
|
111
153
|
return Effect.as(Effect.tap(restore(semaphore.take(1)), () => Scope.addFinalizer(scope, semaphore.release(1))), connection);
|
|
112
154
|
});
|
|
113
|
-
|
|
155
|
+
const client = yield* Client.make({
|
|
114
156
|
acquirer,
|
|
115
157
|
compiler,
|
|
116
158
|
transactionAcquirer,
|
|
159
|
+
transactionService: SqliteTransaction,
|
|
117
160
|
spanAttributes: [...(options.spanAttributes ? Object.entries(options.spanAttributes) : []), [ATTR_DB_SYSTEM_NAME, "sqlite"]],
|
|
118
161
|
transformRows
|
|
119
|
-
})
|
|
162
|
+
});
|
|
163
|
+
return Object.assign(client, {
|
|
120
164
|
[TypeId]: TypeId,
|
|
121
|
-
config: options
|
|
165
|
+
config: options,
|
|
166
|
+
withTransaction: options.storage ? makeStorageBackedWithTransaction(options.storage, connection, semaphore) : makeUnsupportedWithTransaction("Transactions require Durable Object storage; pass ctx.storage as the storage option")
|
|
122
167
|
});
|
|
123
168
|
});
|
|
124
169
|
/**
|
package/dist/SqliteClient.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SqliteClient.js","names":["Config","Context","Effect","Fiber","identity","Layer","Scope","Semaphore","Stream","Reactivity","Client","classifySqliteError","SqlError","Statement","ATTR_DB_SYSTEM_NAME","classifyError","cause","message","operation","TypeId","SqliteClient","Service","make","options","gen","compiler","makeCompilerSqlite","transformQueryNames","transformRows","transformResultNames","defaultTransforms","array","undefined","
|
|
1
|
+
{"version":3,"file":"SqliteClient.js","names":["Config","Context","Effect","Exit","Fiber","identity","Layer","Scope","Semaphore","Stream","Reactivity","Client","classifySqliteError","SqlError","UnknownError","Statement","ATTR_DB_SYSTEM_NAME","classifyError","cause","message","operation","TypeId","SqliteClient","Service","SqliteTransaction","unsupportedTransaction","reason","Error","makeUnsupportedWithTransaction","_effect","fail","makeStorageBackedWithTransaction","storage","connection","semaphore","effect","withFiber","fiber","services","context","connOption","getOption","_tag","effectWithTxn","provideContext","add","withPermits","callback","resume","interrupted","promise","transaction","txn","Promise","resolve","onExit","exit","isFailure","rollback","catch","suspend","make","options","gen","compiler","makeCompilerSqlite","transformQueryNames","transformRows","transformResultNames","defaultTransforms","array","undefined","db","sql","die","sqlStorage","makeConnection","runIterator","params","cursor","exec","columns","columnNames","result","raw","obj","i","length","value","ArrayBuffer","Uint8Array","runStatement","try","Array","from","runValues","row","execute","map","executeRaw","executeValues","executeValuesUnprepared","executeUnprepared","executeStream","iterator","fromIteratorSucceed","pipe","mapArray","chunk","acquirer","succeed","transactionAcquirer","uninterruptibleMask","restore","getCurrent","scope","getUnsafe","as","tap","take","addFinalizer","release","client","transactionService","spanAttributes","Object","entries","assign","config","withTransaction","layerConfig","effectContext","unwrap","flatMap","SqlClient","provide","layer"],"sources":["../src/SqliteClient.ts"],"sourcesContent":[null],"mappings":"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","ignoreList":[]}
|
package/dist/SqliteMigrator.d.ts
CHANGED
|
@@ -2,10 +2,25 @@
|
|
|
2
2
|
* Runs database migrations for Durable Object SQLite storage that uses Effect
|
|
3
3
|
* SQL.
|
|
4
4
|
*
|
|
5
|
-
* This module re-exports the shared
|
|
6
|
-
* `run` and `layer` helpers that
|
|
7
|
-
* `SqlClient`.
|
|
8
|
-
*
|
|
5
|
+
* This module re-exports the shared `Migrator` loaders and error types, then
|
|
6
|
+
* provides `run` and `layer` helpers that execute ordered migrations through the
|
|
7
|
+
* current Durable Object SQLite `SqlClient`. Use it when a Durable
|
|
8
|
+
* Object needs to create or upgrade its local schema during construction, before
|
|
9
|
+
* repositories or request handlers use the object storage, or in tests that
|
|
10
|
+
* exercise Durable Object persistence.
|
|
11
|
+
*
|
|
12
|
+
* Migrations are recorded in `effect_sql_migrations` by default and are loaded
|
|
13
|
+
* using the shared `<id>_<name>` file or record-key convention. The underlying
|
|
14
|
+
* storage is scoped to a Durable Object id, so running migrations for one object
|
|
15
|
+
* does not update any other object instance; run the migrator against the same
|
|
16
|
+
* `DurableObjectStorage`-backed client that the object uses for normal queries
|
|
17
|
+
* so migrations can run in Cloudflare-managed transactions. These SQL
|
|
18
|
+
* migrations are separate from Cloudflare's Durable Object class migrations, and
|
|
19
|
+
* the Durable Object must already be configured with SQLite storage before this
|
|
20
|
+
* module can apply schema changes. Repeated startup runs are expected and are
|
|
21
|
+
* guarded by the migrations table, but request handling should wait until the
|
|
22
|
+
* migration layer has finished. This adapter does not currently write SQLite
|
|
23
|
+
* schema dumps for `schemaDirectory`.
|
|
9
24
|
*
|
|
10
25
|
* @since 4.0.0
|
|
11
26
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SqliteMigrator.d.ts","sourceRoot":"","sources":["../src/SqliteMigrator.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"SqliteMigrator.d.ts","sourceRoot":"","sources":["../src/SqliteMigrator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,OAAO,KAAK,KAAK,MAAM,MAAM,eAAe,CAAA;AAC5C,OAAO,KAAK,KAAK,MAAM,cAAc,CAAA;AACrC,OAAO,KAAK,QAAQ,MAAM,8BAA8B,CAAA;AACxD,OAAO,KAAK,KAAK,MAAM,MAAM,+BAA+B,CAAA;AAC5D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,8BAA8B,CAAA;AAE5D;;GAEG;AACH,cAAc,8BAA8B,CAAA;AAE5C;;;;;GAKG;AACH,eAAO,MAAM,GAAG,EAAE,CAAC,EAAE,GAAG,KAAK,EAC3B,EAAE,MAAM,EAAE,eAAe,EAAE,KAAK,EAAE,EAAE,QAAQ,CAAC,eAAe,CAAC,EAAE,CAAC,KAC7D,MAAM,CAAC,MAAM,CAChB,aAAa,CAAC,SAAS,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC,EAClD,QAAQ,CAAC,cAAc,GAAG,QAAQ,EAClC,MAAM,CAAC,SAAS,GAAG,EAAE,CACF,CAAA;AAErB;;;;;GAKG;AACH,eAAO,MAAM,KAAK,GAAI,CAAC,EACrB,SAAS,QAAQ,CAAC,eAAe,CAAC,CAAC,CAAC,KACnC,KAAK,CAAC,KAAK,CAAC,KAAK,EAAE,QAAQ,CAAC,cAAc,GAAG,QAAQ,EAAE,MAAM,CAAC,SAAS,GAAG,CAAC,CAAsC,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SqliteMigrator.js","names":["Layer","Migrator","run","make","layer","options","effectDiscard"],"sources":["../src/SqliteMigrator.ts"],"sourcesContent":[null],"mappings":"
|
|
1
|
+
{"version":3,"file":"SqliteMigrator.js","names":["Layer","Migrator","run","make","layer","options","effectDiscard"],"sources":["../src/SqliteMigrator.ts"],"sourcesContent":[null],"mappings":"AA2BA,OAAO,KAAKA,KAAK,MAAM,cAAc;AACrC,OAAO,KAAKC,QAAQ,MAAM,8BAA8B;AAIxD;;;AAGA,cAAc,8BAA8B;AAE5C;;;;;;AAMA,OAAO,MAAMC,GAAG,gBAMZD,QAAQ,CAACE,IAAI,CAAC,EAAE,CAAC;AAErB;;;;;;AAMA,OAAO,MAAMC,KAAK,GAChBC,OAAoC,IAC6CL,KAAK,CAACM,aAAa,CAACJ,GAAG,CAACG,OAAO,CAAC,CAAC","ignoreList":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@effect/sql-sqlite-do",
|
|
3
|
-
"version": "4.0.0-beta.
|
|
3
|
+
"version": "4.0.0-beta.88",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"description": "A SQLite toolkit for Effect",
|
|
@@ -44,10 +44,10 @@
|
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
46
|
"@cloudflare/workers-types": "^4.20260511.1",
|
|
47
|
-
"effect": "^4.0.0-beta.
|
|
47
|
+
"effect": "^4.0.0-beta.88"
|
|
48
48
|
},
|
|
49
49
|
"peerDependencies": {
|
|
50
|
-
"effect": "^4.0.0-beta.
|
|
50
|
+
"effect": "^4.0.0-beta.88"
|
|
51
51
|
},
|
|
52
52
|
"scripts": {
|
|
53
53
|
"codegen": "effect-utils codegen",
|
package/src/SqliteClient.ts
CHANGED
|
@@ -1,18 +1,30 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Connects Effect SQL to SQLite storage inside Cloudflare Durable Objects.
|
|
3
3
|
*
|
|
4
|
-
* This module
|
|
5
|
-
* `SqliteClient` and the generic Effect
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
4
|
+
* This module adapts a Durable Object `SqlStorage` handle into both the
|
|
5
|
+
* Durable Object-specific `SqliteClient` service and the generic Effect
|
|
6
|
+
* `SqlClient` service. Use it from inside a Durable Object to run local
|
|
7
|
+
* per-object queries, repositories, migrations, transactional read/write
|
|
8
|
+
* workflows, and tests that exercise Cloudflare's SQLite-backed storage API.
|
|
9
|
+
*
|
|
10
|
+
* Durable Object SQLite storage is scoped to one object id, so each object
|
|
11
|
+
* instance has its own database. Callers can pass the `SqlStorage` handle for
|
|
12
|
+
* normal queries, or the full `DurableObjectStorage` when `withTransaction` or
|
|
13
|
+
* migrations need Cloudflare-managed transactions. This adapter serializes
|
|
14
|
+
* Effect SQL access through one connection; a transaction holds that permit for
|
|
15
|
+
* the lifetime of its scope, so keep transactions short, avoid suspending them
|
|
16
|
+
* across unrelated work, and use them when multi-statement writes must commit
|
|
17
|
+
* atomically. `SqlStorage.exec` returns `ArrayBuffer` values
|
|
18
|
+
* for SQLite blobs, which this client normalizes to `Uint8Array`, and SQLite
|
|
19
|
+
* does not support `updateValues`.
|
|
9
20
|
*
|
|
10
21
|
* @since 4.0.0
|
|
11
22
|
*/
|
|
12
|
-
import type { SqlStorage } from "@cloudflare/workers-types"
|
|
23
|
+
import type { DurableObjectStorage, SqlStorage } from "@cloudflare/workers-types"
|
|
13
24
|
import * as Config from "effect/Config"
|
|
14
25
|
import * as Context from "effect/Context"
|
|
15
26
|
import * as Effect from "effect/Effect"
|
|
27
|
+
import * as Exit from "effect/Exit"
|
|
16
28
|
import * as Fiber from "effect/Fiber"
|
|
17
29
|
import { identity } from "effect/Function"
|
|
18
30
|
import * as Layer from "effect/Layer"
|
|
@@ -22,7 +34,7 @@ import * as Stream from "effect/Stream"
|
|
|
22
34
|
import * as Reactivity from "effect/unstable/reactivity/Reactivity"
|
|
23
35
|
import * as Client from "effect/unstable/sql/SqlClient"
|
|
24
36
|
import type { Connection } from "effect/unstable/sql/SqlConnection"
|
|
25
|
-
import { classifySqliteError, SqlError } from "effect/unstable/sql/SqlError"
|
|
37
|
+
import { classifySqliteError, SqlError, UnknownError } from "effect/unstable/sql/SqlError"
|
|
26
38
|
import * as Statement from "effect/unstable/sql/Statement"
|
|
27
39
|
|
|
28
40
|
const ATTR_DB_SYSTEM_NAME = "db.system.name"
|
|
@@ -73,22 +85,90 @@ export interface SqliteClient extends Client.SqlClient {
|
|
|
73
85
|
*/
|
|
74
86
|
export const SqliteClient = Context.Service<SqliteClient>("@effect/sql-sqlite-do/SqliteClient")
|
|
75
87
|
|
|
88
|
+
const SqliteTransaction = Context.Service<Client.TransactionConnection, Client.TransactionConnection.Service>(
|
|
89
|
+
"@effect/sql-sqlite-do/SqliteClient/SqliteTransaction"
|
|
90
|
+
)
|
|
91
|
+
|
|
76
92
|
/**
|
|
77
|
-
* Configuration for a Cloudflare Durable Object SQLite client, including
|
|
93
|
+
* Configuration for a Cloudflare Durable Object SQLite client, including either a `SqlStorage` handle or the full `DurableObjectStorage` for transaction support, span attributes, and query/result name transforms.
|
|
78
94
|
*
|
|
79
95
|
* @category models
|
|
80
96
|
* @since 4.0.0
|
|
81
97
|
*/
|
|
82
98
|
export interface SqliteClientConfig {
|
|
83
|
-
readonly db
|
|
99
|
+
readonly db?: SqlStorage | undefined
|
|
100
|
+
readonly storage?: DurableObjectStorage | undefined
|
|
84
101
|
readonly spanAttributes?: Record<string, unknown> | undefined
|
|
85
102
|
|
|
86
103
|
readonly transformResultNames?: ((str: string) => string) | undefined
|
|
87
104
|
readonly transformQueryNames?: ((str: string) => string) | undefined
|
|
88
105
|
}
|
|
89
106
|
|
|
107
|
+
const unsupportedTransaction = (message: string, operation: string) =>
|
|
108
|
+
new SqlError({
|
|
109
|
+
reason: new UnknownError({
|
|
110
|
+
cause: new Error(message),
|
|
111
|
+
message,
|
|
112
|
+
operation
|
|
113
|
+
})
|
|
114
|
+
})
|
|
115
|
+
|
|
116
|
+
const makeUnsupportedWithTransaction =
|
|
117
|
+
(message: string): Client.SqlClient["withTransaction"] =>
|
|
118
|
+
<R, E, A>(_effect: Effect.Effect<A, E, R>): Effect.Effect<A, E | SqlError, R> =>
|
|
119
|
+
Effect.fail(unsupportedTransaction(message, "transaction"))
|
|
120
|
+
|
|
121
|
+
const makeStorageBackedWithTransaction = (
|
|
122
|
+
storage: DurableObjectStorage,
|
|
123
|
+
connection: Connection,
|
|
124
|
+
semaphore: Semaphore.Semaphore
|
|
125
|
+
): Client.SqlClient["withTransaction"] =>
|
|
126
|
+
<R, E, A>(effect: Effect.Effect<A, E, R>): Effect.Effect<A, E | SqlError, R> =>
|
|
127
|
+
Effect.withFiber((fiber) => {
|
|
128
|
+
const services = fiber.context
|
|
129
|
+
const connOption = Context.getOption(services, SqliteTransaction)
|
|
130
|
+
if (connOption._tag === "Some") {
|
|
131
|
+
return Effect.fail(
|
|
132
|
+
unsupportedTransaction(
|
|
133
|
+
"Nested transactions are not supported by Cloudflare Durable Object SQLite storage",
|
|
134
|
+
"transaction"
|
|
135
|
+
)
|
|
136
|
+
)
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const effectWithTxn = Effect.provideContext(
|
|
140
|
+
effect,
|
|
141
|
+
Context.add(services, SqliteTransaction, [connection, 0] as const)
|
|
142
|
+
)
|
|
143
|
+
|
|
144
|
+
return semaphore.withPermits(1)(
|
|
145
|
+
Effect.callback((resume) => {
|
|
146
|
+
let interrupted = false
|
|
147
|
+
const promise = storage.transaction((txn) =>
|
|
148
|
+
new Promise<void>((resolve) => {
|
|
149
|
+
if (interrupted) return resolve()
|
|
150
|
+
resume(Effect.onExit(effectWithTxn, (exit) => {
|
|
151
|
+
if (Exit.isFailure(exit)) {
|
|
152
|
+
txn.rollback()
|
|
153
|
+
}
|
|
154
|
+
resolve()
|
|
155
|
+
// wait for the transaction to complete
|
|
156
|
+
return Effect.promise(() => promise)
|
|
157
|
+
}))
|
|
158
|
+
})
|
|
159
|
+
).catch((cause) =>
|
|
160
|
+
resume(Effect.fail(new SqlError({ reason: classifyError(cause, "Failed transaction", "transaction") })))
|
|
161
|
+
)
|
|
162
|
+
return Effect.suspend(() => {
|
|
163
|
+
interrupted = true
|
|
164
|
+
return Effect.promise(() => promise)
|
|
165
|
+
})
|
|
166
|
+
})
|
|
167
|
+
)
|
|
168
|
+
})
|
|
169
|
+
|
|
90
170
|
/**
|
|
91
|
-
* Creates a scoped Cloudflare Durable Object SQLite client around
|
|
171
|
+
* Creates a scoped Cloudflare Durable Object SQLite client around Durable Object SQLite storage, serializing access and converting returned `ArrayBuffer` values to `Uint8Array`.
|
|
92
172
|
*
|
|
93
173
|
* @category constructors
|
|
94
174
|
* @since 4.0.0
|
|
@@ -101,15 +181,19 @@ export const make = (
|
|
|
101
181
|
const transformRows = options.transformResultNames
|
|
102
182
|
? Statement.defaultTransforms(options.transformResultNames).array
|
|
103
183
|
: undefined
|
|
184
|
+
const db = options.storage?.sql ?? options.db
|
|
104
185
|
|
|
105
|
-
|
|
106
|
-
|
|
186
|
+
if (db === undefined) {
|
|
187
|
+
return yield* Effect.die("SqliteClient.make requires either a Durable Object storage or sql storage")
|
|
188
|
+
}
|
|
189
|
+
const sqlStorage = db
|
|
107
190
|
|
|
191
|
+
const makeConnection = Effect.gen(function*() {
|
|
108
192
|
function* runIterator(
|
|
109
193
|
sql: string,
|
|
110
194
|
params: ReadonlyArray<unknown> = []
|
|
111
195
|
) {
|
|
112
|
-
const cursor =
|
|
196
|
+
const cursor = sqlStorage.exec(sql, ...params)
|
|
113
197
|
const columns = cursor.columnNames
|
|
114
198
|
for (const result of cursor.raw()) {
|
|
115
199
|
const obj: any = {}
|
|
@@ -136,7 +220,7 @@ export const make = (
|
|
|
136
220
|
): Effect.Effect<ReadonlyArray<any>, SqlError, never> =>
|
|
137
221
|
Effect.try({
|
|
138
222
|
try: () =>
|
|
139
|
-
Array.from(
|
|
223
|
+
Array.from(sqlStorage.exec(sql, ...params).raw(), (row) => {
|
|
140
224
|
for (let i = 0; i < row.length; i++) {
|
|
141
225
|
const value = row[i]
|
|
142
226
|
if (value instanceof ArrayBuffer) {
|
|
@@ -197,22 +281,27 @@ export const make = (
|
|
|
197
281
|
)
|
|
198
282
|
})
|
|
199
283
|
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
284
|
+
const client = (yield* Client.make({
|
|
285
|
+
acquirer,
|
|
286
|
+
compiler,
|
|
287
|
+
transactionAcquirer,
|
|
288
|
+
transactionService: SqliteTransaction,
|
|
289
|
+
spanAttributes: [
|
|
290
|
+
...(options.spanAttributes ? Object.entries(options.spanAttributes) : []),
|
|
291
|
+
[ATTR_DB_SYSTEM_NAME, "sqlite"]
|
|
292
|
+
],
|
|
293
|
+
transformRows
|
|
294
|
+
})) as SqliteClient
|
|
295
|
+
|
|
296
|
+
return Object.assign(client, {
|
|
297
|
+
[TypeId]: TypeId as TypeId,
|
|
298
|
+
config: options,
|
|
299
|
+
withTransaction: options.storage
|
|
300
|
+
? makeStorageBackedWithTransaction(options.storage, connection, semaphore)
|
|
301
|
+
: makeUnsupportedWithTransaction(
|
|
302
|
+
"Transactions require Durable Object storage; pass ctx.storage as the storage option"
|
|
303
|
+
)
|
|
304
|
+
})
|
|
216
305
|
})
|
|
217
306
|
|
|
218
307
|
/**
|
package/src/SqliteMigrator.ts
CHANGED
|
@@ -2,10 +2,25 @@
|
|
|
2
2
|
* Runs database migrations for Durable Object SQLite storage that uses Effect
|
|
3
3
|
* SQL.
|
|
4
4
|
*
|
|
5
|
-
* This module re-exports the shared
|
|
6
|
-
* `run` and `layer` helpers that
|
|
7
|
-
* `SqlClient`.
|
|
8
|
-
*
|
|
5
|
+
* This module re-exports the shared `Migrator` loaders and error types, then
|
|
6
|
+
* provides `run` and `layer` helpers that execute ordered migrations through the
|
|
7
|
+
* current Durable Object SQLite `SqlClient`. Use it when a Durable
|
|
8
|
+
* Object needs to create or upgrade its local schema during construction, before
|
|
9
|
+
* repositories or request handlers use the object storage, or in tests that
|
|
10
|
+
* exercise Durable Object persistence.
|
|
11
|
+
*
|
|
12
|
+
* Migrations are recorded in `effect_sql_migrations` by default and are loaded
|
|
13
|
+
* using the shared `<id>_<name>` file or record-key convention. The underlying
|
|
14
|
+
* storage is scoped to a Durable Object id, so running migrations for one object
|
|
15
|
+
* does not update any other object instance; run the migrator against the same
|
|
16
|
+
* `DurableObjectStorage`-backed client that the object uses for normal queries
|
|
17
|
+
* so migrations can run in Cloudflare-managed transactions. These SQL
|
|
18
|
+
* migrations are separate from Cloudflare's Durable Object class migrations, and
|
|
19
|
+
* the Durable Object must already be configured with SQLite storage before this
|
|
20
|
+
* module can apply schema changes. Repeated startup runs are expected and are
|
|
21
|
+
* guarded by the migrations table, but request handling should wait until the
|
|
22
|
+
* migration layer has finished. This adapter does not currently write SQLite
|
|
23
|
+
* schema dumps for `schemaDirectory`.
|
|
9
24
|
*
|
|
10
25
|
* @since 4.0.0
|
|
11
26
|
*/
|