@haverstack/record-adapter-do-sqlite 0.1.0
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/LICENSE +7 -0
- package/dist/index.d.ts +134 -0
- package/dist/index.js +1174 -0
- package/dist/index.js.map +1 -0
- package/package.json +55 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
CC0 1.0 Universal (CC0 1.0) Public Domain Dedication
|
|
2
|
+
|
|
3
|
+
To the extent possible under law, the Haverstack contributors have waived all
|
|
4
|
+
copyright and related or neighboring rights to Haverstack. This work is
|
|
5
|
+
published from the United States.
|
|
6
|
+
|
|
7
|
+
https://creativecommons.org/publicdomain/zero/1.0/
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { StackRecord, RecordVersion, ActorOptions, Permission, TypeId, StackQuery, QueryResult, FileId, StackType, Association } from '@haverstack/core';
|
|
2
|
+
import { StackRecordAdapter, AdapterCapabilities } from '@haverstack/core/adapter';
|
|
3
|
+
import { SqlExecutor } from '@haverstack/sqlite-shared/record';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Normalizes a Durable Object's ctx.storage.sql to SqlExecutor.
|
|
7
|
+
*
|
|
8
|
+
* Two things don't map onto node:sqlite's shape the way the rest of this
|
|
9
|
+
* interface does:
|
|
10
|
+
*
|
|
11
|
+
* - There is no get/all/run split — sql.exec() always returns a cursor.
|
|
12
|
+
* get()/all() read it via .toArray(); run() reads .rowsWritten for the
|
|
13
|
+
* affected-row count run()'s contract promises.
|
|
14
|
+
* - Raw BEGIN/COMMIT/ROLLBACK are rejected outright by DO SQLite (verified
|
|
15
|
+
* against the real Workers runtime, not assumed) — its storage has no
|
|
16
|
+
* notion of a transaction left open across separate exec() calls, and
|
|
17
|
+
* each statement auto-commits the instant it runs, so no-op'ing those
|
|
18
|
+
* three strings would silently break atomicity, not preserve it. The
|
|
19
|
+
* platform's real primitive is ctx.storage.transactionSync(fn), which
|
|
20
|
+
* SqlExecutor.transaction() reaches directly — see docs/spec/adapters.md
|
|
21
|
+
* § Concurrency & storage ownership.
|
|
22
|
+
*/
|
|
23
|
+
declare class DurableObjectSqliteExecutor implements SqlExecutor {
|
|
24
|
+
private readonly storage;
|
|
25
|
+
constructor(storage: DurableObjectStorage);
|
|
26
|
+
private get sql();
|
|
27
|
+
exec(sql: string): void;
|
|
28
|
+
run(sql: string, params?: readonly unknown[]): number;
|
|
29
|
+
get<T = Record<string, unknown>>(sql: string, params?: readonly unknown[]): T | undefined;
|
|
30
|
+
all<T = Record<string, unknown>>(sql: string, params?: readonly unknown[]): T[];
|
|
31
|
+
transaction<T>(fn: () => T): T;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Haverstack — Durable Object SQLite Record Adapter
|
|
36
|
+
* -------------------------------------------------------
|
|
37
|
+
* Implements StackRecordAdapter over a Cloudflare Durable Object's SQLite
|
|
38
|
+
* storage (ctx.storage.sql). Full-text search uses FTS5, same as
|
|
39
|
+
* record-adapter-sqlite — DO's SQLite build ships it.
|
|
40
|
+
*
|
|
41
|
+
* Ownership and durability come from the platform, not from anything this
|
|
42
|
+
* class does: a Durable Object id maps to exactly one running instance,
|
|
43
|
+
* so there is no separate lock file the way record-adapter-sqlite needs
|
|
44
|
+
* one for real files (see docs/spec/adapters.md § Concurrency & storage
|
|
45
|
+
* ownership) — the DO *is* the lock. There is likewise no persist/flush
|
|
46
|
+
* step: every write through ctx.storage.sql is durable by the time the
|
|
47
|
+
* call returns, so flush()/close() are no-ops kept only to satisfy the
|
|
48
|
+
* optional StackRecordAdapter methods.
|
|
49
|
+
*
|
|
50
|
+
* This class itself is a thin binding: schema setup and the one piece of
|
|
51
|
+
* genuinely engine-specific wiring — SqlExecutor.transaction() reaching
|
|
52
|
+
* ctx.storage.transactionSync() instead of raw SQL BEGIN/COMMIT/ROLLBACK,
|
|
53
|
+
* which DO SQLite rejects outright — live here (see executor.ts). The
|
|
54
|
+
* actual StackRecordAdapter logic lives in @haverstack/sqlite-shared's
|
|
55
|
+
* SharedSqlRecordLogic, exactly as it does for record-adapter-sqlite.
|
|
56
|
+
*/
|
|
57
|
+
|
|
58
|
+
type DoRecordCreateOptions = {
|
|
59
|
+
/** Entity ID of the stack owner. Ignored if the DO's storage already has a config record. */
|
|
60
|
+
entityId: string;
|
|
61
|
+
/** IANA timezone string e.g. "America/New_York". Optional passthrough app metadata — no default. */
|
|
62
|
+
timezone?: string;
|
|
63
|
+
};
|
|
64
|
+
declare class DoSQLiteRecordAdapter implements StackRecordAdapter {
|
|
65
|
+
private readonly exec;
|
|
66
|
+
readonly capabilities: AdapterCapabilities;
|
|
67
|
+
ownerEntityId: string;
|
|
68
|
+
timezone: string | undefined;
|
|
69
|
+
private readonly record;
|
|
70
|
+
private constructor();
|
|
71
|
+
/**
|
|
72
|
+
* Create (or reattach to) the adapter for a DO instance. There is no
|
|
73
|
+
* initialize()/open() split the way file-based adapters need one: a DO
|
|
74
|
+
* id either already has a config record (a previous call created it —
|
|
75
|
+
* reattach, opts.entityId/timezone ignored in favor of what's stored)
|
|
76
|
+
* or it doesn't (first call — opts.entityId/timezone become the config).
|
|
77
|
+
* Schema DDL is `CREATE TABLE IF NOT EXISTS`, so running it every call
|
|
78
|
+
* is idempotent and cheap.
|
|
79
|
+
*/
|
|
80
|
+
static create(storage: DurableObjectStorage, opts: DoRecordCreateOptions): Promise<DoSQLiteRecordAdapter>;
|
|
81
|
+
createRecord(record: StackRecord): Promise<StackRecord>;
|
|
82
|
+
getRecord(id: string): Promise<StackRecord | null>;
|
|
83
|
+
patchContent(id: string, patch: Record<string, unknown | null>, opts?: {
|
|
84
|
+
expectedVersion?: number;
|
|
85
|
+
snapshot?: RecordVersion;
|
|
86
|
+
} & ActorOptions): Promise<StackRecord>;
|
|
87
|
+
deleteRecord(id: string, opts?: {
|
|
88
|
+
hard?: boolean;
|
|
89
|
+
expectedVersion?: number;
|
|
90
|
+
snapshot?: RecordVersion;
|
|
91
|
+
} & ActorOptions): Promise<StackRecord | null>;
|
|
92
|
+
undeleteRecord(id: string, opts?: {
|
|
93
|
+
expectedVersion?: number;
|
|
94
|
+
snapshot?: RecordVersion;
|
|
95
|
+
} & ActorOptions): Promise<StackRecord>;
|
|
96
|
+
setPermissions(id: string, permissions: Permission[], opts?: {
|
|
97
|
+
expectedVersion?: number;
|
|
98
|
+
snapshot?: RecordVersion;
|
|
99
|
+
} & ActorOptions): Promise<StackRecord>;
|
|
100
|
+
setUnlisted(id: string, unlisted: boolean, opts?: {
|
|
101
|
+
expectedVersion?: number;
|
|
102
|
+
snapshot?: RecordVersion;
|
|
103
|
+
} & ActorOptions): Promise<StackRecord>;
|
|
104
|
+
restoreVersion(id: string, version: number, opts?: {
|
|
105
|
+
expectedVersion?: number;
|
|
106
|
+
snapshot?: RecordVersion;
|
|
107
|
+
} & ActorOptions): Promise<StackRecord>;
|
|
108
|
+
commitMigration(id: string, toTypeId: TypeId, content: Record<string, unknown>, opts?: {
|
|
109
|
+
expectedVersion?: number;
|
|
110
|
+
snapshot?: RecordVersion;
|
|
111
|
+
} & ActorOptions): Promise<StackRecord>;
|
|
112
|
+
queryRecords(query: StackQuery): Promise<QueryResult>;
|
|
113
|
+
deleteUnreferencedAttachmentRecords(fileId: FileId, metadataTypeId: TypeId): Promise<StackRecord[]>;
|
|
114
|
+
getVersions(id: string): Promise<RecordVersion[]>;
|
|
115
|
+
getVersion(id: string, version: number): Promise<RecordVersion | null>;
|
|
116
|
+
saveVersion(id: string, version: RecordVersion): Promise<void>;
|
|
117
|
+
saveType(type: StackType): Promise<void>;
|
|
118
|
+
getType(id: TypeId): Promise<StackType | null>;
|
|
119
|
+
listTypes(): Promise<StackType[]>;
|
|
120
|
+
associate(recordId: string, association: Association, opts?: {
|
|
121
|
+
expectedVersion?: number;
|
|
122
|
+
snapshot?: RecordVersion;
|
|
123
|
+
} & ActorOptions): Promise<StackRecord>;
|
|
124
|
+
dissociate(recordId: string, association: Association, opts?: {
|
|
125
|
+
expectedVersion?: number;
|
|
126
|
+
snapshot?: RecordVersion;
|
|
127
|
+
} & ActorOptions): Promise<StackRecord>;
|
|
128
|
+
/** No-op: every write through ctx.storage.sql is already durable. */
|
|
129
|
+
flush(): Promise<void>;
|
|
130
|
+
/** No-op: no lock file, no connection to release — the DO's own lifecycle governs storage. */
|
|
131
|
+
close(): Promise<void>;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
export { type DoRecordCreateOptions, DoSQLiteRecordAdapter, DurableObjectSqliteExecutor };
|