on-zero 0.7.2-1784530701923 → 0.7.2
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/cjs/asyncTasks.cjs +51 -0
- package/dist/cjs/asyncTasks.native.js +84 -0
- package/dist/cjs/asyncTasks.native.js.map +1 -0
- package/dist/cjs/createZeroDirectServer.cjs +269 -0
- package/dist/cjs/createZeroDirectServer.native.js +287 -0
- package/dist/cjs/createZeroDirectServer.native.js.map +1 -0
- package/dist/cjs/createZeroSQLiteServer.cjs +50 -0
- package/dist/cjs/createZeroSQLiteServer.native.js +58 -0
- package/dist/cjs/createZeroSQLiteServer.native.js.map +1 -0
- package/dist/cjs/createZeroSQLiteServer.test.cjs +595 -0
- package/dist/cjs/createZeroSQLiteServer.test.native.js +647 -0
- package/dist/cjs/createZeroSQLiteServer.test.native.js.map +1 -0
- package/dist/cjs/createZeroServer.cjs +82 -0
- package/dist/cjs/createZeroServer.native.js +93 -0
- package/dist/cjs/createZeroServer.native.js.map +1 -0
- package/dist/cjs/createZeroServer.test.cjs +378 -0
- package/dist/cjs/createZeroServer.test.native.js +448 -0
- package/dist/cjs/createZeroServer.test.native.js.map +1 -0
- package/dist/cjs/createZeroServerCore.cjs +211 -0
- package/dist/cjs/createZeroServerCore.native.js +355 -0
- package/dist/cjs/createZeroServerCore.native.js.map +1 -0
- package/dist/cjs/helpers/createMutators.cjs +3 -4
- package/dist/cjs/helpers/createMutators.native.js +3 -6
- package/dist/cjs/helpers/createMutators.native.js.map +1 -1
- package/dist/cjs/httpPull/auth.test.cjs +197 -0
- package/dist/cjs/httpPull/auth.test.native.js +279 -0
- package/dist/cjs/httpPull/auth.test.native.js.map +1 -0
- package/dist/cjs/httpPull/churn.test.cjs +132 -0
- package/dist/cjs/httpPull/churn.test.native.js +155 -0
- package/dist/cjs/httpPull/churn.test.native.js.map +1 -0
- package/dist/cjs/httpPull/completeAck.test.cjs +69 -0
- package/dist/cjs/httpPull/completeAck.test.native.js +76 -0
- package/dist/cjs/httpPull/completeAck.test.native.js.map +1 -0
- package/dist/cjs/httpPull/fixtureServer.cjs +340 -0
- package/dist/cjs/httpPull/fixtureServer.native.js +534 -0
- package/dist/cjs/httpPull/fixtureServer.native.js.map +1 -0
- package/dist/cjs/httpPull/integration.test.cjs +53 -0
- package/dist/cjs/httpPull/integration.test.native.js +60 -0
- package/dist/cjs/httpPull/integration.test.native.js.map +1 -0
- package/dist/cjs/httpPull/rebase.test.cjs +360 -0
- package/dist/cjs/httpPull/rebase.test.native.js +420 -0
- package/dist/cjs/httpPull/rebase.test.native.js.map +1 -0
- package/dist/cjs/httpPull/relations.test.cjs +107 -0
- package/dist/cjs/httpPull/relations.test.native.js +119 -0
- package/dist/cjs/httpPull/relations.test.native.js.map +1 -0
- package/dist/cjs/httpPull/testHarness.cjs +100 -0
- package/dist/cjs/httpPull/testHarness.native.js +112 -0
- package/dist/cjs/httpPull/testHarness.native.js.map +1 -0
- package/dist/cjs/index.cjs +1 -0
- package/dist/cjs/index.native.js +1 -0
- package/dist/cjs/index.native.js.map +1 -1
- package/dist/cjs/run.cjs +1 -1
- package/dist/cjs/run.native.js +1 -1
- package/dist/cjs/server.cjs +22 -0
- package/dist/cjs/server.native.js +4 -0
- package/dist/cjs/server.native.js.map +1 -0
- package/dist/cjs/sqliteRuntime.cjs +318 -0
- package/dist/cjs/sqliteRuntime.native.js +438 -0
- package/dist/cjs/sqliteRuntime.native.js.map +1 -0
- package/dist/cjs/state.cjs +1 -1
- package/dist/cjs/state.native.js +1 -1
- package/dist/cjs/syncHost.cjs +179 -0
- package/dist/cjs/syncHost.native.js +388 -0
- package/dist/cjs/syncHost.native.js.map +1 -0
- package/dist/cjs/syncHost.test.cjs +240 -0
- package/dist/cjs/syncHost.test.native.js +290 -0
- package/dist/cjs/syncHost.test.native.js.map +1 -0
- package/dist/cjs/zeroRunner.cjs +1 -1
- package/dist/cjs/zeroRunner.native.js +1 -1
- package/dist/esm/asyncTasks.mjs +26 -0
- package/dist/esm/asyncTasks.mjs.map +1 -0
- package/dist/esm/asyncTasks.native.js +56 -0
- package/dist/esm/asyncTasks.native.js.map +1 -0
- package/dist/esm/createZeroDirectServer.mjs +241 -0
- package/dist/esm/createZeroDirectServer.mjs.map +1 -0
- package/dist/esm/createZeroDirectServer.native.js +256 -0
- package/dist/esm/createZeroDirectServer.native.js.map +1 -0
- package/dist/esm/createZeroSQLiteServer.mjs +24 -0
- package/dist/esm/createZeroSQLiteServer.mjs.map +1 -0
- package/dist/esm/createZeroSQLiteServer.native.js +29 -0
- package/dist/esm/createZeroSQLiteServer.native.js.map +1 -0
- package/dist/esm/createZeroSQLiteServer.test.mjs +596 -0
- package/dist/esm/createZeroSQLiteServer.test.mjs.map +1 -0
- package/dist/esm/createZeroSQLiteServer.test.native.js +645 -0
- package/dist/esm/createZeroSQLiteServer.test.native.js.map +1 -0
- package/dist/esm/createZeroServer.mjs +57 -0
- package/dist/esm/createZeroServer.mjs.map +1 -0
- package/dist/esm/createZeroServer.native.js +65 -0
- package/dist/esm/createZeroServer.native.js.map +1 -0
- package/dist/esm/createZeroServer.test.mjs +379 -0
- package/dist/esm/createZeroServer.test.mjs.map +1 -0
- package/dist/esm/createZeroServer.test.native.js +446 -0
- package/dist/esm/createZeroServer.test.native.js.map +1 -0
- package/dist/esm/createZeroServerCore.mjs +186 -0
- package/dist/esm/createZeroServerCore.mjs.map +1 -0
- package/dist/esm/createZeroServerCore.native.js +327 -0
- package/dist/esm/createZeroServerCore.native.js.map +1 -0
- package/dist/esm/helpers/createMutators.mjs +3 -4
- package/dist/esm/helpers/createMutators.mjs.map +1 -1
- package/dist/esm/helpers/createMutators.native.js +3 -6
- package/dist/esm/helpers/createMutators.native.js.map +1 -1
- package/dist/esm/httpPull/auth.test.mjs +198 -0
- package/dist/esm/httpPull/auth.test.mjs.map +1 -0
- package/dist/esm/httpPull/auth.test.native.js +277 -0
- package/dist/esm/httpPull/auth.test.native.js.map +1 -0
- package/dist/esm/httpPull/churn.test.mjs +133 -0
- package/dist/esm/httpPull/churn.test.mjs.map +1 -0
- package/dist/esm/httpPull/churn.test.native.js +153 -0
- package/dist/esm/httpPull/churn.test.native.js.map +1 -0
- package/dist/esm/httpPull/completeAck.test.mjs +70 -0
- package/dist/esm/httpPull/completeAck.test.mjs.map +1 -0
- package/dist/esm/httpPull/completeAck.test.native.js +74 -0
- package/dist/esm/httpPull/completeAck.test.native.js.map +1 -0
- package/dist/esm/httpPull/fixtureServer.mjs +315 -0
- package/dist/esm/httpPull/fixtureServer.mjs.map +1 -0
- package/dist/esm/httpPull/fixtureServer.native.js +506 -0
- package/dist/esm/httpPull/fixtureServer.native.js.map +1 -0
- package/dist/esm/httpPull/integration.test.mjs +54 -0
- package/dist/esm/httpPull/integration.test.mjs.map +1 -0
- package/dist/esm/httpPull/integration.test.native.js +58 -0
- package/dist/esm/httpPull/integration.test.native.js.map +1 -0
- package/dist/esm/httpPull/rebase.test.mjs +361 -0
- package/dist/esm/httpPull/rebase.test.mjs.map +1 -0
- package/dist/esm/httpPull/rebase.test.native.js +418 -0
- package/dist/esm/httpPull/rebase.test.native.js.map +1 -0
- package/dist/esm/httpPull/relations.test.mjs +108 -0
- package/dist/esm/httpPull/relations.test.mjs.map +1 -0
- package/dist/esm/httpPull/relations.test.native.js +117 -0
- package/dist/esm/httpPull/relations.test.native.js.map +1 -0
- package/dist/esm/httpPull/testHarness.mjs +72 -0
- package/dist/esm/httpPull/testHarness.mjs.map +1 -0
- package/dist/esm/httpPull/testHarness.native.js +81 -0
- package/dist/esm/httpPull/testHarness.native.js.map +1 -0
- package/dist/esm/index.js +1 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/index.mjs +1 -0
- package/dist/esm/index.mjs.map +1 -1
- package/dist/esm/index.native.js +1 -0
- package/dist/esm/index.native.js.map +1 -1
- package/dist/esm/run.mjs +1 -1
- package/dist/esm/run.mjs.map +1 -1
- package/dist/esm/run.native.js +1 -1
- package/dist/esm/server.mjs +4 -0
- package/dist/esm/server.mjs.map +1 -0
- package/dist/esm/server.native.js +2 -0
- package/dist/esm/server.native.js.map +1 -0
- package/dist/esm/sqliteRuntime.mjs +289 -0
- package/dist/esm/sqliteRuntime.mjs.map +1 -0
- package/dist/esm/sqliteRuntime.native.js +406 -0
- package/dist/esm/sqliteRuntime.native.js.map +1 -0
- package/dist/esm/state.mjs +1 -1
- package/dist/esm/state.native.js +1 -1
- package/dist/esm/syncHost.mjs +153 -0
- package/dist/esm/syncHost.mjs.map +1 -0
- package/dist/esm/syncHost.native.js +359 -0
- package/dist/esm/syncHost.native.js.map +1 -0
- package/dist/esm/syncHost.test.mjs +217 -0
- package/dist/esm/syncHost.test.mjs.map +1 -0
- package/dist/esm/syncHost.test.native.js +264 -0
- package/dist/esm/syncHost.test.native.js.map +1 -0
- package/dist/esm/zeroRunner.mjs +1 -1
- package/dist/esm/zeroRunner.mjs.map +1 -1
- package/dist/esm/zeroRunner.native.js +1 -1
- package/package.json +23 -8
- package/readme.md +65 -40
- package/src/asyncTasks.ts +36 -0
- package/src/createZeroClient.tsx +1 -1
- package/src/createZeroDirectServer.ts +411 -0
- package/src/createZeroSQLiteServer.test.ts +614 -0
- package/src/createZeroSQLiteServer.ts +56 -0
- package/src/createZeroServer.test.ts +421 -0
- package/src/createZeroServer.ts +105 -0
- package/src/createZeroServerCore.ts +296 -0
- package/src/helpers/createMutators.ts +2 -6
- package/src/httpPull/auth.test.ts +208 -0
- package/src/httpPull/churn.test.ts +147 -0
- package/src/httpPull/completeAck.test.ts +80 -0
- package/src/httpPull/fixtureServer.ts +391 -0
- package/src/httpPull/integration.test.ts +57 -0
- package/src/httpPull/rebase.test.ts +368 -0
- package/src/httpPull/relations.test.ts +135 -0
- package/src/httpPull/testHarness.ts +95 -0
- package/src/index.ts +1 -0
- package/src/run.ts +1 -1
- package/src/server.native.ts +3 -0
- package/src/server.ts +4 -0
- package/src/sqliteRuntime.ts +512 -0
- package/src/state.ts +1 -1
- package/src/syncHost.test.ts +223 -0
- package/src/syncHost.ts +294 -0
- package/src/types.ts +5 -0
- package/src/zeroRunner.ts +1 -1
- package/test-fixtures/server-return-types.ts +58 -21
- package/types/asyncTasks.d.ts +11 -0
- package/types/asyncTasks.d.ts.map +1 -0
- package/types/createZeroDirectServer.d.ts +80 -0
- package/types/createZeroDirectServer.d.ts.map +1 -0
- package/types/createZeroSQLiteServer.d.ts +12 -0
- package/types/createZeroSQLiteServer.d.ts.map +1 -0
- package/types/createZeroSQLiteServer.test.d.ts +2 -0
- package/types/createZeroSQLiteServer.test.d.ts.map +1 -0
- package/types/createZeroServer.d.ts +18 -0
- package/types/createZeroServer.d.ts.map +1 -0
- package/types/createZeroServer.test.d.ts +2 -0
- package/types/createZeroServer.test.d.ts.map +1 -0
- package/types/createZeroServerCore.d.ts +256 -0
- package/types/createZeroServerCore.d.ts.map +1 -0
- package/types/helpers/createMutators.d.ts +1 -2
- package/types/helpers/createMutators.d.ts.map +1 -1
- package/types/httpPull/auth.test.d.ts +2 -0
- package/types/httpPull/auth.test.d.ts.map +1 -0
- package/types/httpPull/churn.test.d.ts +2 -0
- package/types/httpPull/churn.test.d.ts.map +1 -0
- package/types/httpPull/completeAck.test.d.ts +2 -0
- package/types/httpPull/completeAck.test.d.ts.map +1 -0
- package/types/httpPull/fixtureSchema.d.ts +1 -1
- package/types/httpPull/fixtureServer.d.ts +14 -0
- package/types/httpPull/fixtureServer.d.ts.map +1 -0
- package/types/httpPull/integration.test.d.ts +2 -0
- package/types/httpPull/integration.test.d.ts.map +1 -0
- package/types/httpPull/rebase.test.d.ts +2 -0
- package/types/httpPull/rebase.test.d.ts.map +1 -0
- package/types/httpPull/relations.test.d.ts +2 -0
- package/types/httpPull/relations.test.d.ts.map +1 -0
- package/types/httpPull/testHarness.d.ts +32 -0
- package/types/httpPull/testHarness.d.ts.map +1 -0
- package/types/index.d.ts +1 -0
- package/types/index.d.ts.map +1 -1
- package/types/server.d.ts +5 -0
- package/types/server.d.ts.map +1 -0
- package/types/server.native.d.ts +1 -0
- package/types/server.native.d.ts.map +1 -0
- package/types/sqliteRuntime.d.ts +71 -0
- package/types/sqliteRuntime.d.ts.map +1 -0
- package/types/syncHost.d.ts +42 -0
- package/types/syncHost.d.ts.map +1 -0
- package/types/syncHost.test.d.ts +2 -0
- package/types/syncHost.test.d.ts.map +1 -0
- package/types/types.d.ts +4 -0
- package/types/types.d.ts.map +1 -1
- package/dist/cjs/orez.cjs +0 -227
- package/dist/cjs/orez.native.js +0 -314
- package/dist/cjs/orez.native.js.map +0 -1
- package/dist/cjs/orez.test.cjs +0 -211
- package/dist/cjs/orez.test.native.js +0 -226
- package/dist/cjs/orez.test.native.js.map +0 -1
- package/dist/esm/orez.mjs +0 -202
- package/dist/esm/orez.mjs.map +0 -1
- package/dist/esm/orez.native.js +0 -286
- package/dist/esm/orez.native.js.map +0 -1
- package/dist/esm/orez.test.mjs +0 -188
- package/dist/esm/orez.test.mjs.map +0 -1
- package/dist/esm/orez.test.native.js +0 -200
- package/dist/esm/orez.test.native.js.map +0 -1
- package/src/orez.test.ts +0 -195
- package/src/orez.ts +0 -331
- package/types/orez.d.ts +0 -53
- package/types/orez.d.ts.map +0 -1
- package/types/orez.test.d.ts +0 -2
- package/types/orez.test.d.ts.map +0 -1
|
@@ -0,0 +1,614 @@
|
|
|
1
|
+
import { DatabaseSync, type SQLInputValue } from 'node:sqlite'
|
|
2
|
+
|
|
3
|
+
import { boolean, createSchema, json, relationships, string, table } from '@rocicorp/zero'
|
|
4
|
+
import { asQueryInternals } from '@rocicorp/zero/bindings'
|
|
5
|
+
import { afterEach, beforeEach, describe, expect, test } from 'vitest'
|
|
6
|
+
|
|
7
|
+
import { createZeroSQLiteServer } from './createZeroSQLiteServer'
|
|
8
|
+
import { zeroHttpFixtureSchema } from './httpPull/fixtureSchema'
|
|
9
|
+
import { mutations } from './mutations'
|
|
10
|
+
import { serverWhere } from './serverWhere'
|
|
11
|
+
|
|
12
|
+
import type {
|
|
13
|
+
SqlStatementMetadata,
|
|
14
|
+
SQLiteTransactionExecutor,
|
|
15
|
+
SQLiteTransactionProvider,
|
|
16
|
+
} from './createZeroSQLiteServer'
|
|
17
|
+
|
|
18
|
+
const note = table('note')
|
|
19
|
+
.from('note_records')
|
|
20
|
+
.columns({
|
|
21
|
+
id: string().from('note_id'),
|
|
22
|
+
done: boolean(),
|
|
23
|
+
data: json<{ label: string }>().optional(),
|
|
24
|
+
})
|
|
25
|
+
.primaryKey('id')
|
|
26
|
+
|
|
27
|
+
const sqliteTypesSchema = createSchema({
|
|
28
|
+
tables: [note],
|
|
29
|
+
relationships: [],
|
|
30
|
+
enableLegacyQueries: true,
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
const person = table('person').columns({ id: string() }).primaryKey('id')
|
|
34
|
+
const membership = table('membership')
|
|
35
|
+
.columns({ personId: string(), teamId: string() })
|
|
36
|
+
.primaryKey('personId', 'teamId')
|
|
37
|
+
const team = table('team')
|
|
38
|
+
.from('team_records')
|
|
39
|
+
.columns({
|
|
40
|
+
id: string().from('team_id'),
|
|
41
|
+
active: boolean().from('is_active'),
|
|
42
|
+
metadata: json<{ label: string }>().from('metadata_json'),
|
|
43
|
+
})
|
|
44
|
+
.primaryKey('id')
|
|
45
|
+
const twoHopSchema = createSchema({
|
|
46
|
+
tables: [person, membership, team],
|
|
47
|
+
relationships: [
|
|
48
|
+
relationships(person, ({ many }) => ({
|
|
49
|
+
teams: many(
|
|
50
|
+
{
|
|
51
|
+
sourceField: ['id'],
|
|
52
|
+
destSchema: membership,
|
|
53
|
+
destField: ['personId'],
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
sourceField: ['teamId'],
|
|
57
|
+
destSchema: team,
|
|
58
|
+
destField: ['id'],
|
|
59
|
+
},
|
|
60
|
+
),
|
|
61
|
+
})),
|
|
62
|
+
],
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
function pushRequest(id: number, name: string, args: unknown) {
|
|
66
|
+
return new Request('http://localhost/push?schema=zero_0&appID=zero', {
|
|
67
|
+
method: 'POST',
|
|
68
|
+
headers: { 'content-type': 'application/json' },
|
|
69
|
+
body: JSON.stringify({
|
|
70
|
+
clientGroupID: 'cg1',
|
|
71
|
+
mutations: [
|
|
72
|
+
{
|
|
73
|
+
type: 'custom',
|
|
74
|
+
id,
|
|
75
|
+
clientID: 'client-a',
|
|
76
|
+
name,
|
|
77
|
+
args: [args],
|
|
78
|
+
timestamp: 1,
|
|
79
|
+
},
|
|
80
|
+
],
|
|
81
|
+
pushVersion: 1,
|
|
82
|
+
timestamp: 1,
|
|
83
|
+
requestID: 'req-' + id,
|
|
84
|
+
}),
|
|
85
|
+
})
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function cleanupRequest() {
|
|
89
|
+
return new Request('http://localhost/push?schema=zero_0&appID=zero', {
|
|
90
|
+
method: 'POST',
|
|
91
|
+
headers: { 'content-type': 'application/json' },
|
|
92
|
+
body: JSON.stringify({
|
|
93
|
+
clientGroupID: 'cg1',
|
|
94
|
+
mutations: [
|
|
95
|
+
{
|
|
96
|
+
type: 'custom',
|
|
97
|
+
id: 2,
|
|
98
|
+
clientID: 'client-a',
|
|
99
|
+
name: '_zero_cleanupResults',
|
|
100
|
+
args: [
|
|
101
|
+
{
|
|
102
|
+
clientGroupID: 'cg1',
|
|
103
|
+
clientID: 'client-a',
|
|
104
|
+
upToMutationID: 1,
|
|
105
|
+
},
|
|
106
|
+
],
|
|
107
|
+
timestamp: 1,
|
|
108
|
+
},
|
|
109
|
+
],
|
|
110
|
+
pushVersion: 1,
|
|
111
|
+
timestamp: 1,
|
|
112
|
+
requestID: 'cleanup',
|
|
113
|
+
}),
|
|
114
|
+
})
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
describe('createZeroSQLiteServer', () => {
|
|
118
|
+
let db: DatabaseSync
|
|
119
|
+
let retryNextTransaction: boolean
|
|
120
|
+
let transactionProvider: SQLiteTransactionProvider
|
|
121
|
+
let statements: SqlStatementMetadata[]
|
|
122
|
+
|
|
123
|
+
beforeEach(() => {
|
|
124
|
+
db = new DatabaseSync(':memory:')
|
|
125
|
+
db.exec(
|
|
126
|
+
[
|
|
127
|
+
'CREATE TABLE project (id TEXT PRIMARY KEY, ownerId TEXT NOT NULL, name TEXT NOT NULL);',
|
|
128
|
+
'CREATE TABLE note_records (note_id TEXT PRIMARY KEY, done INTEGER NOT NULL, data TEXT);',
|
|
129
|
+
].join('\n'),
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
retryNextTransaction = false
|
|
133
|
+
statements = []
|
|
134
|
+
const executor: SQLiteTransactionExecutor = {
|
|
135
|
+
async exec(sql, params = [], metadata) {
|
|
136
|
+
if (metadata) statements.push(metadata)
|
|
137
|
+
const result = db.prepare(sql).run(...(params as SQLInputValue[]))
|
|
138
|
+
return { changes: Number(result.changes) }
|
|
139
|
+
},
|
|
140
|
+
async query<Row extends Record<string, unknown>>(sql, params = []) {
|
|
141
|
+
return db.prepare(sql).all(...(params as SQLInputValue[])) as Row[]
|
|
142
|
+
},
|
|
143
|
+
async queryAst<Result>(ast, format) {
|
|
144
|
+
let rows: Record<string, unknown>[]
|
|
145
|
+
if (ast.table === 'project') {
|
|
146
|
+
rows = db.prepare('SELECT * FROM project ORDER BY id').all()
|
|
147
|
+
} else if (ast.table === 'note') {
|
|
148
|
+
rows = db
|
|
149
|
+
.prepare('SELECT note_id, done, data FROM note_records ORDER BY note_id')
|
|
150
|
+
.all()
|
|
151
|
+
.map((row) => ({
|
|
152
|
+
id: row.note_id,
|
|
153
|
+
done: row.done !== 0,
|
|
154
|
+
data: typeof row.data === 'string' ? JSON.parse(row.data) : row.data,
|
|
155
|
+
}))
|
|
156
|
+
} else if (ast.table === 'person') {
|
|
157
|
+
rows = [
|
|
158
|
+
{
|
|
159
|
+
id: 'p1',
|
|
160
|
+
teams: [
|
|
161
|
+
{
|
|
162
|
+
id: 't1',
|
|
163
|
+
active: true,
|
|
164
|
+
metadata: { label: 'core' },
|
|
165
|
+
},
|
|
166
|
+
],
|
|
167
|
+
},
|
|
168
|
+
]
|
|
169
|
+
} else {
|
|
170
|
+
throw new Error('unexpected table ' + ast.table)
|
|
171
|
+
}
|
|
172
|
+
return (format.singular ? rows[0] : rows) as Result
|
|
173
|
+
},
|
|
174
|
+
}
|
|
175
|
+
const run = async <R>(
|
|
176
|
+
callback: (tx: SQLiteTransactionExecutor) => R | Promise<R>,
|
|
177
|
+
) => {
|
|
178
|
+
db.exec('BEGIN')
|
|
179
|
+
try {
|
|
180
|
+
const value = await callback(executor)
|
|
181
|
+
db.exec('COMMIT')
|
|
182
|
+
return value
|
|
183
|
+
} catch (error) {
|
|
184
|
+
db.exec('ROLLBACK')
|
|
185
|
+
throw error
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
transactionProvider = async <R>(
|
|
189
|
+
callback: (tx: SQLiteTransactionExecutor) => R | Promise<R>,
|
|
190
|
+
) => {
|
|
191
|
+
if (retryNextTransaction) {
|
|
192
|
+
retryNextTransaction = false
|
|
193
|
+
db.exec('BEGIN')
|
|
194
|
+
await callback(executor)
|
|
195
|
+
db.exec('ROLLBACK')
|
|
196
|
+
}
|
|
197
|
+
return run(callback)
|
|
198
|
+
}
|
|
199
|
+
})
|
|
200
|
+
|
|
201
|
+
afterEach(() => {
|
|
202
|
+
db.close()
|
|
203
|
+
})
|
|
204
|
+
|
|
205
|
+
test('commits CRUD, the mutation ledger, and one retry-safe async task', async () => {
|
|
206
|
+
let effectRuns = 0
|
|
207
|
+
const server = createZeroSQLiteServer({
|
|
208
|
+
schema: zeroHttpFixtureSchema,
|
|
209
|
+
models: {
|
|
210
|
+
project: {
|
|
211
|
+
mutate: {
|
|
212
|
+
create: async ({ tx, server }, value: Record<string, unknown>) => {
|
|
213
|
+
await tx.mutate.project.insert(value as never)
|
|
214
|
+
server?.enqueueTask(
|
|
215
|
+
async () => {
|
|
216
|
+
effectRuns++
|
|
217
|
+
},
|
|
218
|
+
{ barrier: true },
|
|
219
|
+
)
|
|
220
|
+
},
|
|
221
|
+
},
|
|
222
|
+
},
|
|
223
|
+
},
|
|
224
|
+
createServerActions: () => ({}),
|
|
225
|
+
transactionProvider,
|
|
226
|
+
})
|
|
227
|
+
|
|
228
|
+
retryNextTransaction = true
|
|
229
|
+
const result = await server.handleMutationRequest({
|
|
230
|
+
authData: null,
|
|
231
|
+
request: pushRequest(1, 'project.create', {
|
|
232
|
+
id: 'p1',
|
|
233
|
+
ownerId: 'u1',
|
|
234
|
+
name: 'first',
|
|
235
|
+
}),
|
|
236
|
+
skipAsyncTasks: true,
|
|
237
|
+
})
|
|
238
|
+
|
|
239
|
+
expect((result.response as any).mutations[0].result).toEqual({})
|
|
240
|
+
expect(db.prepare('SELECT * FROM project').all()).toEqual([
|
|
241
|
+
{ id: 'p1', ownerId: 'u1', name: 'first' },
|
|
242
|
+
])
|
|
243
|
+
expect(db.prepare('SELECT * FROM zero_0_clients').all()).toEqual([
|
|
244
|
+
{ clientGroupID: 'cg1', clientID: 'client-a', lastMutationID: 1 },
|
|
245
|
+
])
|
|
246
|
+
expect(result.asyncTasks).toHaveLength(1)
|
|
247
|
+
expect(result.asyncTasks[0]!.barrier).toBe(true)
|
|
248
|
+
await result.asyncTasks[0]!.task()
|
|
249
|
+
expect(effectRuns).toBe(1)
|
|
250
|
+
})
|
|
251
|
+
|
|
252
|
+
test('keeps later writes after inserting an existing primary key', async () => {
|
|
253
|
+
db.prepare('INSERT INTO project (id, ownerId, name) VALUES (?, ?, ?)').run(
|
|
254
|
+
'p1',
|
|
255
|
+
'u1',
|
|
256
|
+
'original',
|
|
257
|
+
)
|
|
258
|
+
db.prepare('INSERT INTO project (id, ownerId, name) VALUES (?, ?, ?)').run(
|
|
259
|
+
'p2',
|
|
260
|
+
'u1',
|
|
261
|
+
'before',
|
|
262
|
+
)
|
|
263
|
+
const server = createZeroSQLiteServer({
|
|
264
|
+
schema: zeroHttpFixtureSchema,
|
|
265
|
+
models: {
|
|
266
|
+
project: {
|
|
267
|
+
mutate: {
|
|
268
|
+
converge: async ({ tx }) => {
|
|
269
|
+
await tx.mutate.project.insert({
|
|
270
|
+
id: 'p1',
|
|
271
|
+
ownerId: 'u2',
|
|
272
|
+
name: 'replacement',
|
|
273
|
+
})
|
|
274
|
+
await tx.mutate.project.update({ id: 'p2', name: 'after' })
|
|
275
|
+
},
|
|
276
|
+
},
|
|
277
|
+
},
|
|
278
|
+
},
|
|
279
|
+
createServerActions: () => ({}),
|
|
280
|
+
transactionProvider,
|
|
281
|
+
})
|
|
282
|
+
|
|
283
|
+
const result = await server.handleMutationRequest({
|
|
284
|
+
authData: null,
|
|
285
|
+
request: pushRequest(1, 'project.converge', {}),
|
|
286
|
+
})
|
|
287
|
+
|
|
288
|
+
expect((result.response as any).mutations[0].result).toEqual({})
|
|
289
|
+
expect(db.prepare('SELECT * FROM project ORDER BY id').all()).toEqual([
|
|
290
|
+
{ id: 'p1', ownerId: 'u1', name: 'original' },
|
|
291
|
+
{ id: 'p2', ownerId: 'u1', name: 'after' },
|
|
292
|
+
])
|
|
293
|
+
})
|
|
294
|
+
|
|
295
|
+
test('rolls back row writes and persists an application error with its LMID', async () => {
|
|
296
|
+
const server = createZeroSQLiteServer({
|
|
297
|
+
schema: zeroHttpFixtureSchema,
|
|
298
|
+
models: {
|
|
299
|
+
project: {
|
|
300
|
+
mutate: {
|
|
301
|
+
fail: async ({ tx }, value: Record<string, unknown>) => {
|
|
302
|
+
await tx.mutate.project.insert(value as never)
|
|
303
|
+
throw new Error('rejected')
|
|
304
|
+
},
|
|
305
|
+
},
|
|
306
|
+
},
|
|
307
|
+
},
|
|
308
|
+
createServerActions: () => ({}),
|
|
309
|
+
transactionProvider,
|
|
310
|
+
})
|
|
311
|
+
|
|
312
|
+
const result = await server.handleMutationRequest({
|
|
313
|
+
authData: null,
|
|
314
|
+
request: pushRequest(1, 'project.fail', {
|
|
315
|
+
id: 'p1',
|
|
316
|
+
ownerId: 'u1',
|
|
317
|
+
name: 'first',
|
|
318
|
+
}),
|
|
319
|
+
})
|
|
320
|
+
|
|
321
|
+
expect((result.response as any).mutations[0].result).toMatchObject({
|
|
322
|
+
error: 'app',
|
|
323
|
+
message: 'rejected',
|
|
324
|
+
})
|
|
325
|
+
expect(db.prepare('SELECT * FROM project').all()).toEqual([])
|
|
326
|
+
expect(db.prepare('SELECT lastMutationID FROM zero_0_clients').get()).toEqual({
|
|
327
|
+
lastMutationID: 1,
|
|
328
|
+
})
|
|
329
|
+
const stored = db.prepare('SELECT result FROM zero_0_mutations').get() as {
|
|
330
|
+
result: string
|
|
331
|
+
}
|
|
332
|
+
expect(JSON.parse(stored.result)).toMatchObject({
|
|
333
|
+
error: 'app',
|
|
334
|
+
message: 'rejected',
|
|
335
|
+
})
|
|
336
|
+
})
|
|
337
|
+
|
|
338
|
+
test('allows a custom CRUD mutation to no-op without an automatic permission check', async () => {
|
|
339
|
+
const projectPermission = serverWhere('project', (q) => q.cmp('ownerId', 'u1'))
|
|
340
|
+
const projectMutations = mutations('project', projectPermission, {
|
|
341
|
+
insert: async () => {},
|
|
342
|
+
})
|
|
343
|
+
const server = createZeroSQLiteServer({
|
|
344
|
+
schema: zeroHttpFixtureSchema,
|
|
345
|
+
models: {
|
|
346
|
+
project: { mutate: projectMutations },
|
|
347
|
+
},
|
|
348
|
+
createServerActions: () => ({}),
|
|
349
|
+
transactionProvider,
|
|
350
|
+
})
|
|
351
|
+
|
|
352
|
+
const result = await server.handleMutationRequest({
|
|
353
|
+
authData: { id: 'u1', role: 'user' },
|
|
354
|
+
request: pushRequest(1, 'project.insert', {
|
|
355
|
+
id: 'p1',
|
|
356
|
+
ownerId: 'u1',
|
|
357
|
+
name: 'skip',
|
|
358
|
+
}),
|
|
359
|
+
})
|
|
360
|
+
|
|
361
|
+
expect((result.response as any).mutations[0].result).toEqual({})
|
|
362
|
+
expect(db.prepare('SELECT * FROM project').all()).toEqual([])
|
|
363
|
+
})
|
|
364
|
+
|
|
365
|
+
test('rolls back when a custom CRUD mutation throws', async () => {
|
|
366
|
+
const projectPermission = serverWhere('project', (q) => q.cmp('ownerId', 'u1'))
|
|
367
|
+
const projectMutations = mutations('project', projectPermission, {
|
|
368
|
+
insert: async ({ tx }, value: { id: string; ownerId: string; name: string }) => {
|
|
369
|
+
await tx.mutate.project.insert(value)
|
|
370
|
+
throw new Error('denied by custom validation')
|
|
371
|
+
},
|
|
372
|
+
})
|
|
373
|
+
const server = createZeroSQLiteServer({
|
|
374
|
+
schema: zeroHttpFixtureSchema,
|
|
375
|
+
models: {
|
|
376
|
+
project: { mutate: projectMutations },
|
|
377
|
+
},
|
|
378
|
+
createServerActions: () => ({}),
|
|
379
|
+
transactionProvider,
|
|
380
|
+
})
|
|
381
|
+
|
|
382
|
+
const result = await server.handleMutationRequest({
|
|
383
|
+
authData: { id: 'u2', role: 'user' },
|
|
384
|
+
request: pushRequest(1, 'project.insert', {
|
|
385
|
+
id: 'p2',
|
|
386
|
+
ownerId: 'u2',
|
|
387
|
+
name: 'unauthorized',
|
|
388
|
+
}),
|
|
389
|
+
})
|
|
390
|
+
|
|
391
|
+
expect((result.response as any).mutations[0].result).toMatchObject({
|
|
392
|
+
error: 'app',
|
|
393
|
+
message: 'denied by custom validation',
|
|
394
|
+
})
|
|
395
|
+
expect(db.prepare('SELECT * FROM project').all()).toEqual([])
|
|
396
|
+
})
|
|
397
|
+
|
|
398
|
+
test('permission-checks generated CRUD mutations', async () => {
|
|
399
|
+
let inserted: Record<string, unknown> | undefined
|
|
400
|
+
let permissionChecks = 0
|
|
401
|
+
const projectPermission = serverWhere('project', (q) => q.cmp('ownerId', 'u1'))
|
|
402
|
+
const projectMutations = mutations('project', projectPermission)
|
|
403
|
+
const value = { id: 'p3', ownerId: 'u2', name: 'unauthorized' }
|
|
404
|
+
|
|
405
|
+
await expect(
|
|
406
|
+
projectMutations.insert(
|
|
407
|
+
{
|
|
408
|
+
tx: {
|
|
409
|
+
mutate: {
|
|
410
|
+
project: {
|
|
411
|
+
insert: async (row: Record<string, unknown>) => {
|
|
412
|
+
inserted = row
|
|
413
|
+
},
|
|
414
|
+
},
|
|
415
|
+
},
|
|
416
|
+
},
|
|
417
|
+
can: async (_where, row) => {
|
|
418
|
+
permissionChecks++
|
|
419
|
+
expect(row).toEqual(value)
|
|
420
|
+
throw new Error('denied')
|
|
421
|
+
},
|
|
422
|
+
} as never,
|
|
423
|
+
value,
|
|
424
|
+
),
|
|
425
|
+
).rejects.toThrow('denied')
|
|
426
|
+
expect(inserted).toEqual(value)
|
|
427
|
+
expect(permissionChecks).toBe(1)
|
|
428
|
+
})
|
|
429
|
+
|
|
430
|
+
test('recovers duplicate results and deletes them through the cleanup mutation', async () => {
|
|
431
|
+
const server = createZeroSQLiteServer({
|
|
432
|
+
schema: zeroHttpFixtureSchema,
|
|
433
|
+
models: {
|
|
434
|
+
project: {
|
|
435
|
+
mutate: {
|
|
436
|
+
create: async ({ tx }, value: Record<string, unknown>) => {
|
|
437
|
+
await tx.mutate.project.insert(value as never)
|
|
438
|
+
},
|
|
439
|
+
},
|
|
440
|
+
},
|
|
441
|
+
},
|
|
442
|
+
createServerActions: () => ({}),
|
|
443
|
+
transactionProvider,
|
|
444
|
+
})
|
|
445
|
+
const value = {
|
|
446
|
+
id: 'p1',
|
|
447
|
+
ownerId: 'u1',
|
|
448
|
+
name: 'first',
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
await server.handleMutationRequest({
|
|
452
|
+
authData: null,
|
|
453
|
+
request: pushRequest(1, 'project.create', value),
|
|
454
|
+
})
|
|
455
|
+
const duplicate = await server.handleMutationRequest({
|
|
456
|
+
authData: null,
|
|
457
|
+
request: pushRequest(1, 'project.create', value),
|
|
458
|
+
})
|
|
459
|
+
|
|
460
|
+
expect((duplicate.response as any).mutations[0].result).toMatchObject({
|
|
461
|
+
error: 'alreadyProcessed',
|
|
462
|
+
})
|
|
463
|
+
expect(db.prepare('SELECT lastMutationID FROM zero_0_clients').get()).toEqual({
|
|
464
|
+
lastMutationID: 1,
|
|
465
|
+
})
|
|
466
|
+
expect(db.prepare('SELECT COUNT(*) AS count FROM zero_0_mutations').get()).toEqual({
|
|
467
|
+
count: 1,
|
|
468
|
+
})
|
|
469
|
+
|
|
470
|
+
await server.handleMutationRequest({
|
|
471
|
+
authData: null,
|
|
472
|
+
request: cleanupRequest(),
|
|
473
|
+
})
|
|
474
|
+
expect(db.prepare('SELECT COUNT(*) AS count FROM zero_0_mutations').get()).toEqual({
|
|
475
|
+
count: 0,
|
|
476
|
+
})
|
|
477
|
+
})
|
|
478
|
+
|
|
479
|
+
test('supports direct CRUD, server names, value codecs, and query AST execution', async () => {
|
|
480
|
+
const server = createZeroSQLiteServer({
|
|
481
|
+
schema: sqliteTypesSchema,
|
|
482
|
+
models: {
|
|
483
|
+
note: {
|
|
484
|
+
mutate: {
|
|
485
|
+
insert: async ({ tx }, value: Record<string, unknown>) => {
|
|
486
|
+
await tx.mutate.note.insert(value as never)
|
|
487
|
+
},
|
|
488
|
+
upsert: async ({ tx }, value: Record<string, unknown>) => {
|
|
489
|
+
await tx.mutate.note.upsert(value as never)
|
|
490
|
+
},
|
|
491
|
+
update: async ({ tx }, value: Record<string, unknown>) => {
|
|
492
|
+
await tx.mutate.note.update(value as never)
|
|
493
|
+
},
|
|
494
|
+
delete: async ({ tx }, value: Record<string, unknown>) => {
|
|
495
|
+
await tx.mutate.note.delete(value as never)
|
|
496
|
+
},
|
|
497
|
+
},
|
|
498
|
+
},
|
|
499
|
+
},
|
|
500
|
+
createServerActions: () => ({}),
|
|
501
|
+
transactionProvider,
|
|
502
|
+
})
|
|
503
|
+
|
|
504
|
+
await server.mutate.note.insert({
|
|
505
|
+
id: 'n1',
|
|
506
|
+
done: false,
|
|
507
|
+
data: { label: 'first' },
|
|
508
|
+
})
|
|
509
|
+
await server.mutate.note.upsert({
|
|
510
|
+
id: 'n1',
|
|
511
|
+
done: true,
|
|
512
|
+
data: { label: 'second' },
|
|
513
|
+
})
|
|
514
|
+
await server.mutate.note.update({
|
|
515
|
+
id: 'n1',
|
|
516
|
+
done: false,
|
|
517
|
+
})
|
|
518
|
+
|
|
519
|
+
expect(db.prepare('SELECT * FROM note_records').get()).toEqual({
|
|
520
|
+
note_id: 'n1',
|
|
521
|
+
done: 0,
|
|
522
|
+
data: JSON.stringify({ label: 'second' }),
|
|
523
|
+
})
|
|
524
|
+
await expect(server.query((q) => q.note)).resolves.toEqual([
|
|
525
|
+
{
|
|
526
|
+
id: 'n1',
|
|
527
|
+
done: false,
|
|
528
|
+
data: { label: 'second' },
|
|
529
|
+
},
|
|
530
|
+
])
|
|
531
|
+
await server.transaction(async (tx) => {
|
|
532
|
+
if (tx.location !== 'server') throw new Error('expected server transaction')
|
|
533
|
+
await expect((tx.query as any).note.one().run()).resolves.toEqual({
|
|
534
|
+
id: 'n1',
|
|
535
|
+
done: false,
|
|
536
|
+
data: { label: 'second' },
|
|
537
|
+
})
|
|
538
|
+
await expect(
|
|
539
|
+
tx.dbTransaction.query('SELECT * FROM note_records', []),
|
|
540
|
+
).resolves.toEqual([
|
|
541
|
+
{
|
|
542
|
+
note_id: 'n1',
|
|
543
|
+
done: 0,
|
|
544
|
+
data: JSON.stringify({ label: 'second' }),
|
|
545
|
+
},
|
|
546
|
+
])
|
|
547
|
+
})
|
|
548
|
+
|
|
549
|
+
await server.mutate.note.delete({ id: 'n1' })
|
|
550
|
+
expect(db.prepare('SELECT * FROM note_records').all()).toEqual([])
|
|
551
|
+
expect(statements).toEqual([
|
|
552
|
+
{ table: 'note_records', publicTable: 'note', kind: 'insert' },
|
|
553
|
+
{ table: 'note_records', publicTable: 'note', kind: 'upsert' },
|
|
554
|
+
{ table: 'note_records', publicTable: 'note', kind: 'update' },
|
|
555
|
+
{ table: 'note_records', publicTable: 'note', kind: 'delete' },
|
|
556
|
+
])
|
|
557
|
+
})
|
|
558
|
+
|
|
559
|
+
test('decodes destination rows through a hidden two-hop junction', async () => {
|
|
560
|
+
const server = createZeroSQLiteServer({
|
|
561
|
+
schema: twoHopSchema,
|
|
562
|
+
models: {},
|
|
563
|
+
createServerActions: () => ({}),
|
|
564
|
+
transactionProvider,
|
|
565
|
+
})
|
|
566
|
+
|
|
567
|
+
await expect(server.query((q: any) => q.person.related('teams'))).resolves.toEqual([
|
|
568
|
+
{
|
|
569
|
+
id: 'p1',
|
|
570
|
+
teams: [
|
|
571
|
+
{
|
|
572
|
+
id: 't1',
|
|
573
|
+
active: true,
|
|
574
|
+
metadata: { label: 'core' },
|
|
575
|
+
},
|
|
576
|
+
],
|
|
577
|
+
},
|
|
578
|
+
])
|
|
579
|
+
})
|
|
580
|
+
|
|
581
|
+
test('accepts a hydrated singular query result from the transaction executor', async () => {
|
|
582
|
+
const hydrated = {
|
|
583
|
+
id: 'n1',
|
|
584
|
+
done: false,
|
|
585
|
+
data: { label: 'already decoded' },
|
|
586
|
+
}
|
|
587
|
+
let receivedQueryName: string | undefined
|
|
588
|
+
const hydratedExecutor = {
|
|
589
|
+
async exec() {
|
|
590
|
+
return { changes: 0 }
|
|
591
|
+
},
|
|
592
|
+
async query() {
|
|
593
|
+
return []
|
|
594
|
+
},
|
|
595
|
+
async queryAst(_ast: unknown, _format: unknown, queryName?: string) {
|
|
596
|
+
receivedQueryName = queryName
|
|
597
|
+
return hydrated
|
|
598
|
+
},
|
|
599
|
+
} as unknown as SQLiteTransactionExecutor
|
|
600
|
+
const hydratedProvider: SQLiteTransactionProvider = async (callback) =>
|
|
601
|
+
callback(hydratedExecutor)
|
|
602
|
+
const server = createZeroSQLiteServer({
|
|
603
|
+
schema: sqliteTypesSchema,
|
|
604
|
+
models: {},
|
|
605
|
+
createServerActions: () => ({}),
|
|
606
|
+
transactionProvider: hydratedProvider,
|
|
607
|
+
})
|
|
608
|
+
|
|
609
|
+
await expect(
|
|
610
|
+
server.query((q) => asQueryInternals(q.note.one()).nameAndArgs('noteByID', ['n1'])),
|
|
611
|
+
).resolves.toEqual(hydrated)
|
|
612
|
+
expect(receivedQueryName).toBe('noteByID')
|
|
613
|
+
})
|
|
614
|
+
})
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { createZeroServerCore } from './createZeroServerCore'
|
|
2
|
+
import {
|
|
3
|
+
createSQLiteDatabase,
|
|
4
|
+
defaultLedgerTables,
|
|
5
|
+
encodeSQLiteValue,
|
|
6
|
+
persistAlreadyProcessedMutationResults,
|
|
7
|
+
type SQLiteLedgerTables,
|
|
8
|
+
type SQLiteTransactionProvider,
|
|
9
|
+
type SQLiteValueContext,
|
|
10
|
+
} from './sqliteRuntime'
|
|
11
|
+
|
|
12
|
+
import type { ZeroServer, ZeroServerCommonOptions } from './createZeroServerCore'
|
|
13
|
+
import type { GenericModels } from './types'
|
|
14
|
+
import type { Schema as ZeroSchema } from '@rocicorp/zero'
|
|
15
|
+
|
|
16
|
+
export type CreateZeroSQLiteServerOptions<
|
|
17
|
+
Schema extends ZeroSchema,
|
|
18
|
+
Models extends GenericModels,
|
|
19
|
+
ServerActions extends Record<string, unknown>,
|
|
20
|
+
> = ZeroServerCommonOptions<Schema, Models, ServerActions> & {
|
|
21
|
+
transactionProvider: SQLiteTransactionProvider
|
|
22
|
+
ledgerTables?: (upstreamSchema: string) => SQLiteLedgerTables
|
|
23
|
+
encodeValue?: (value: unknown, context: SQLiteValueContext) => unknown
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function createZeroSQLiteServer<
|
|
27
|
+
Schema extends ZeroSchema,
|
|
28
|
+
Models extends GenericModels,
|
|
29
|
+
ServerActions extends Record<string, unknown>,
|
|
30
|
+
>({
|
|
31
|
+
encodeValue = encodeSQLiteValue,
|
|
32
|
+
ledgerTables = defaultLedgerTables,
|
|
33
|
+
transactionProvider,
|
|
34
|
+
...options
|
|
35
|
+
}: CreateZeroSQLiteServerOptions<Schema, Models, ServerActions>): ZeroServer<
|
|
36
|
+
Schema,
|
|
37
|
+
Models,
|
|
38
|
+
ServerActions
|
|
39
|
+
> {
|
|
40
|
+
const databaseOptions = {
|
|
41
|
+
encodeValue,
|
|
42
|
+
initializedLedgers: new Set<string>(),
|
|
43
|
+
ledgerTables,
|
|
44
|
+
schema: options.schema,
|
|
45
|
+
transactionProvider,
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return createZeroServerCore({
|
|
49
|
+
...options,
|
|
50
|
+
createDatabase: () => createSQLiteDatabase(databaseOptions),
|
|
51
|
+
persistAlreadyProcessed: (args) =>
|
|
52
|
+
persistAlreadyProcessedMutationResults(databaseOptions, args),
|
|
53
|
+
})
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export * from './sqliteRuntime'
|