on-zero 0.6.13 → 0.6.15
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/createSchemaFromDrizzle.cjs +4 -4
- package/dist/cjs/createSchemaFromDrizzle.native.js +4 -4
- package/dist/cjs/createSchemaFromDrizzle.native.js.map +1 -1
- package/dist/cjs/createZeroDirectServer.cjs +279 -0
- package/dist/cjs/createZeroDirectServer.native.js +292 -0
- package/dist/cjs/createZeroDirectServer.native.js.map +1 -0
- package/dist/cjs/createZeroSQLiteServer.cjs +8 -277
- package/dist/cjs/createZeroSQLiteServer.native.js +8 -390
- package/dist/cjs/createZeroSQLiteServer.native.js.map +1 -1
- package/dist/cjs/createZeroSQLiteServer.test.cjs +30 -3
- package/dist/cjs/createZeroSQLiteServer.test.native.js +31 -3
- package/dist/cjs/createZeroSQLiteServer.test.native.js.map +1 -1
- package/dist/cjs/createZeroServerCore.cjs +20 -205
- package/dist/cjs/createZeroServerCore.native.js +19 -213
- package/dist/cjs/createZeroServerCore.native.js.map +1 -1
- package/dist/cjs/generate.cjs +10 -3
- package/dist/cjs/generate.native.js +10 -3
- package/dist/cjs/generate.native.js.map +1 -1
- package/dist/cjs/generate.test.cjs +39 -0
- package/dist/cjs/generate.test.native.js +39 -0
- package/dist/cjs/generate.test.native.js.map +1 -1
- 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/syncHost.cjs +16 -9
- package/dist/cjs/syncHost.native.js +21 -12
- package/dist/cjs/syncHost.native.js.map +1 -1
- package/dist/cjs/syncHost.test.cjs +13 -2
- package/dist/cjs/syncHost.test.native.js +14 -2
- package/dist/cjs/syncHost.test.native.js.map +1 -1
- package/dist/esm/createSchemaFromDrizzle.mjs +2 -2
- package/dist/esm/createSchemaFromDrizzle.native.js +2 -2
- package/dist/esm/createZeroDirectServer.mjs +251 -0
- package/dist/esm/createZeroDirectServer.mjs.map +1 -0
- package/dist/esm/createZeroDirectServer.native.js +261 -0
- package/dist/esm/createZeroDirectServer.native.js.map +1 -0
- package/dist/esm/createZeroSQLiteServer.mjs +3 -272
- package/dist/esm/createZeroSQLiteServer.mjs.map +1 -1
- package/dist/esm/createZeroSQLiteServer.native.js +3 -385
- package/dist/esm/createZeroSQLiteServer.native.js.map +1 -1
- package/dist/esm/createZeroSQLiteServer.test.mjs +30 -3
- package/dist/esm/createZeroSQLiteServer.test.mjs.map +1 -1
- package/dist/esm/createZeroSQLiteServer.test.native.js +31 -3
- package/dist/esm/createZeroSQLiteServer.test.native.js.map +1 -1
- package/dist/esm/createZeroServerCore.mjs +18 -202
- package/dist/esm/createZeroServerCore.mjs.map +1 -1
- package/dist/esm/createZeroServerCore.native.js +18 -211
- package/dist/esm/createZeroServerCore.native.js.map +1 -1
- package/dist/esm/generate.mjs +10 -3
- package/dist/esm/generate.mjs.map +1 -1
- package/dist/esm/generate.native.js +10 -3
- package/dist/esm/generate.native.js.map +1 -1
- package/dist/esm/generate.test.mjs +39 -1
- package/dist/esm/generate.test.mjs.map +1 -1
- package/dist/esm/generate.test.native.js +39 -1
- package/dist/esm/generate.test.native.js.map +1 -1
- 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/syncHost.mjs +14 -7
- package/dist/esm/syncHost.mjs.map +1 -1
- package/dist/esm/syncHost.native.js +19 -10
- package/dist/esm/syncHost.native.js.map +1 -1
- package/dist/esm/syncHost.test.mjs +13 -2
- package/dist/esm/syncHost.test.mjs.map +1 -1
- package/dist/esm/syncHost.test.native.js +14 -2
- package/dist/esm/syncHost.test.native.js.map +1 -1
- package/package.json +5 -6
- package/src/createSchemaFromDrizzle.ts +2 -2
- package/src/createZeroDirectServer.ts +427 -0
- package/src/createZeroSQLiteServer.test.ts +20 -5
- package/src/createZeroSQLiteServer.ts +14 -481
- package/src/createZeroServerCore.ts +32 -337
- package/src/generate.test.ts +57 -1
- package/src/generate.ts +23 -3
- package/src/sqliteRuntime.ts +512 -0
- package/src/syncHost.test.ts +10 -3
- package/src/syncHost.ts +49 -12
- package/test-fixtures/server-return-types.ts +8 -1
- package/types/createSchemaFromDrizzle.d.ts +2 -2
- package/types/createSchemaFromDrizzle.d.ts.map +1 -1
- package/types/createZeroDirectServer.d.ts +80 -0
- package/types/createZeroDirectServer.d.ts.map +1 -0
- package/types/createZeroSQLiteServer.d.ts +5 -30
- package/types/createZeroSQLiteServer.d.ts.map +1 -1
- package/types/createZeroServerCore.d.ts +30 -87
- package/types/createZeroServerCore.d.ts.map +1 -1
- package/types/generate.d.ts.map +1 -1
- package/types/sqliteRuntime.d.ts +71 -0
- package/types/sqliteRuntime.d.ts.map +1 -0
- package/types/syncHost.d.ts +10 -19
- package/types/syncHost.d.ts.map +1 -1
|
@@ -1,47 +1,22 @@
|
|
|
1
|
-
import { mustGetQuery } from '@rocicorp/zero'
|
|
2
1
|
import {
|
|
3
2
|
PushProcessor,
|
|
4
3
|
handleQueryRequest as zeroHandleQueryRequest,
|
|
5
4
|
} from '@rocicorp/zero/server'
|
|
6
5
|
|
|
7
|
-
import { createPermissions } from './createPermissions'
|
|
8
|
-
import { createMutators } from './helpers/createMutators'
|
|
9
6
|
import {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
7
|
+
createAsyncTaskCollector,
|
|
8
|
+
createZeroDirectServerRuntime,
|
|
9
|
+
resolveServerQuery,
|
|
10
|
+
type TransactionAttemptLifecycle,
|
|
11
|
+
type ZeroServerCommonOptions,
|
|
12
|
+
type ZeroServerDatabase,
|
|
13
|
+
} from './createZeroDirectServer'
|
|
14
|
+
import { createMutators } from './helpers/createMutators'
|
|
15
|
+
import { runWithAuthScope } from './helpers/mutatorContext'
|
|
15
16
|
import { runWithQueryContext } from './helpers/queryContext'
|
|
16
|
-
import { getMutationsPermissions } from './modelRegistry'
|
|
17
|
-
import { setCustomQueries } from './run'
|
|
18
|
-
import { getZQL, setEnvironment, setSchema } from './state'
|
|
19
|
-
import { setEvaluatingPermission } from './where'
|
|
20
|
-
import { setRunner } from './zeroRunner'
|
|
21
17
|
|
|
22
|
-
import type {
|
|
23
|
-
|
|
24
|
-
AsyncAction,
|
|
25
|
-
AuthData,
|
|
26
|
-
GenericModels,
|
|
27
|
-
MutatorContext,
|
|
28
|
-
QueryBuilder,
|
|
29
|
-
Transaction,
|
|
30
|
-
} from './types'
|
|
31
|
-
import type {
|
|
32
|
-
AnyQueryRegistry,
|
|
33
|
-
HumanReadable,
|
|
34
|
-
Query,
|
|
35
|
-
Schema as ZeroSchema,
|
|
36
|
-
} from '@rocicorp/zero'
|
|
37
|
-
import type { Database, TransactionProviderInput } from '@rocicorp/zero/server'
|
|
38
|
-
|
|
39
|
-
type MutateAuthData = Pick<AuthData, 'email' | 'id'> & Partial<AuthData>
|
|
40
|
-
|
|
41
|
-
type MutateOptions = {
|
|
42
|
-
authData?: MutateAuthData
|
|
43
|
-
awaitEffects?: boolean
|
|
44
|
-
}
|
|
18
|
+
import type { AuthData, GenericModels } from './types'
|
|
19
|
+
import type { Schema as ZeroSchema } from '@rocicorp/zero'
|
|
45
20
|
|
|
46
21
|
type AlreadyProcessedMutation = {
|
|
47
22
|
id: {
|
|
@@ -58,122 +33,12 @@ type PushRequestBody = {
|
|
|
58
33
|
clientGroupID?: unknown
|
|
59
34
|
}
|
|
60
35
|
|
|
61
|
-
type ServerMutate<Models extends GenericModels> = {
|
|
62
|
-
[Key in keyof Models]: {
|
|
63
|
-
[K in keyof Models[Key]['mutate']]: Models[Key]['mutate'][K] extends (
|
|
64
|
-
ctx: MutatorContext,
|
|
65
|
-
arg: infer Arg,
|
|
66
|
-
) => any
|
|
67
|
-
? (arg: Arg, options?: MutateOptions) => Promise<void>
|
|
68
|
-
: (options?: MutateOptions) => Promise<void>
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
export type ValidateQueryArgs = {
|
|
73
|
-
authData: AuthData | null
|
|
74
|
-
queryName: string
|
|
75
|
-
params: unknown
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
export type ValidateMutationArgs = {
|
|
79
|
-
authData: AuthData | null
|
|
80
|
-
mutatorName: string
|
|
81
|
-
tableName: string
|
|
82
|
-
args: unknown
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
export type ValidateQueryFn = (args: ValidateQueryArgs) => void
|
|
86
|
-
export type ValidateMutationFn = (args: ValidateMutationArgs) => void | Promise<void>
|
|
87
|
-
|
|
88
|
-
export type ServerQueryResolverOptions = {
|
|
89
|
-
authData: AuthData | null
|
|
90
|
-
name: string
|
|
91
|
-
args: unknown
|
|
92
|
-
queries: AnyQueryRegistry
|
|
93
|
-
permissions: ReturnType<typeof createPermissions>
|
|
94
|
-
validateQuery?: ValidateQueryFn
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
export function resolveServerQuery({
|
|
98
|
-
authData,
|
|
99
|
-
name,
|
|
100
|
-
args,
|
|
101
|
-
queries,
|
|
102
|
-
permissions,
|
|
103
|
-
validateQuery,
|
|
104
|
-
}: ServerQueryResolverOptions) {
|
|
105
|
-
if (name.startsWith('permission.')) {
|
|
106
|
-
const table = name.slice('permission.'.length)
|
|
107
|
-
const { objOrId } = args as {
|
|
108
|
-
objOrId: string | Record<string, any>
|
|
109
|
-
}
|
|
110
|
-
const permission = getMutationsPermissions(table)
|
|
111
|
-
if (!permission) {
|
|
112
|
-
throw new Error(`[permission] no permission defined for table: ${table}`)
|
|
113
|
-
}
|
|
114
|
-
setEvaluatingPermission(true)
|
|
115
|
-
try {
|
|
116
|
-
return (getZQL() as any)[table]
|
|
117
|
-
.where((eb: any) => {
|
|
118
|
-
return permissions.buildPermissionQuery(
|
|
119
|
-
authData,
|
|
120
|
-
eb,
|
|
121
|
-
permission,
|
|
122
|
-
objOrId,
|
|
123
|
-
table,
|
|
124
|
-
)
|
|
125
|
-
})
|
|
126
|
-
.one()
|
|
127
|
-
} finally {
|
|
128
|
-
setEvaluatingPermission(false)
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
if (validateQuery) {
|
|
133
|
-
validateQuery({ authData, queryName: name, params: args })
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
const query = (mustGetQuery as any)(queries, name)
|
|
137
|
-
return query.fn({ args, ctx: authData })
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
export type TransactionAttemptLifecycle = {
|
|
141
|
-
beginAttempt(): void
|
|
142
|
-
completeAttempt(): void
|
|
143
|
-
rollbackAttempt(): void
|
|
144
|
-
commitTransaction(): void
|
|
145
|
-
rollbackTransaction(): void
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
export type ZeroServerDatabase = Database<Transaction>
|
|
149
|
-
|
|
150
36
|
export type PersistAlreadyProcessedArgs = {
|
|
151
37
|
clientGroupID: string
|
|
152
38
|
mutations: AlreadyProcessedMutation[]
|
|
153
39
|
upstreamSchema: string
|
|
154
40
|
}
|
|
155
41
|
|
|
156
|
-
export type ZeroServerCommonOptions<
|
|
157
|
-
Schema extends ZeroSchema,
|
|
158
|
-
Models extends GenericModels,
|
|
159
|
-
ServerActions extends Record<string, unknown>,
|
|
160
|
-
> = {
|
|
161
|
-
schema: Schema
|
|
162
|
-
models: Models
|
|
163
|
-
createServerActions: () => ServerActions
|
|
164
|
-
queries?: AnyQueryRegistry
|
|
165
|
-
/** generated validators keyed by model and mutation name */
|
|
166
|
-
mutations?: Record<string, Record<string, any>>
|
|
167
|
-
/** synchronous query authorization hook; throw to reject */
|
|
168
|
-
validateQuery?: ValidateQueryFn
|
|
169
|
-
/** mutation authorization hook; throw to reject */
|
|
170
|
-
validateMutation?: ValidateMutationFn
|
|
171
|
-
/** controls which operations the admin role bypasses */
|
|
172
|
-
defaultAllowAdminRole?: AdminRoleMode
|
|
173
|
-
/** auth data used by direct server mutations when no scope provides it */
|
|
174
|
-
defaultMutateAuthData?: MutateAuthData
|
|
175
|
-
}
|
|
176
|
-
|
|
177
42
|
type ZeroServerCoreOptions<
|
|
178
43
|
Schema extends ZeroSchema,
|
|
179
44
|
Models extends GenericModels,
|
|
@@ -183,60 +48,6 @@ type ZeroServerCoreOptions<
|
|
|
183
48
|
persistAlreadyProcessed?: (args: PersistAlreadyProcessedArgs) => Promise<void>
|
|
184
49
|
}
|
|
185
50
|
|
|
186
|
-
function createAsyncTaskCollector() {
|
|
187
|
-
const committed: AsyncAction[] = []
|
|
188
|
-
let attempt: AsyncAction[] | undefined
|
|
189
|
-
let completedAttempt: AsyncAction[] | undefined
|
|
190
|
-
const current = () => attempt ?? committed
|
|
191
|
-
const queue = new Proxy([] as AsyncAction[], {
|
|
192
|
-
deleteProperty(_target, property) {
|
|
193
|
-
return Reflect.deleteProperty(current(), property)
|
|
194
|
-
},
|
|
195
|
-
get(_target, property) {
|
|
196
|
-
const target = current()
|
|
197
|
-
const value = Reflect.get(target, property, target)
|
|
198
|
-
return typeof value === 'function' ? value.bind(target) : value
|
|
199
|
-
},
|
|
200
|
-
getOwnPropertyDescriptor(_target, property) {
|
|
201
|
-
return Reflect.getOwnPropertyDescriptor(current(), property)
|
|
202
|
-
},
|
|
203
|
-
has(_target, property) {
|
|
204
|
-
return Reflect.has(current(), property)
|
|
205
|
-
},
|
|
206
|
-
ownKeys() {
|
|
207
|
-
return Reflect.ownKeys(current())
|
|
208
|
-
},
|
|
209
|
-
set(_target, property, value) {
|
|
210
|
-
return Reflect.set(current(), property, value)
|
|
211
|
-
},
|
|
212
|
-
})
|
|
213
|
-
|
|
214
|
-
const lifecycle: TransactionAttemptLifecycle = {
|
|
215
|
-
beginAttempt() {
|
|
216
|
-
attempt = []
|
|
217
|
-
completedAttempt = undefined
|
|
218
|
-
},
|
|
219
|
-
completeAttempt() {
|
|
220
|
-
completedAttempt = attempt
|
|
221
|
-
attempt = undefined
|
|
222
|
-
},
|
|
223
|
-
rollbackAttempt() {
|
|
224
|
-
attempt = undefined
|
|
225
|
-
completedAttempt = undefined
|
|
226
|
-
},
|
|
227
|
-
commitTransaction() {
|
|
228
|
-
if (completedAttempt) committed.push(...completedAttempt)
|
|
229
|
-
completedAttempt = undefined
|
|
230
|
-
},
|
|
231
|
-
rollbackTransaction() {
|
|
232
|
-
attempt = undefined
|
|
233
|
-
completedAttempt = undefined
|
|
234
|
-
},
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
return { committed, lifecycle, queue }
|
|
238
|
-
}
|
|
239
|
-
|
|
240
51
|
export function createZeroServerCore<
|
|
241
52
|
Schema extends ZeroSchema,
|
|
242
53
|
Models extends GenericModels,
|
|
@@ -245,7 +56,7 @@ export function createZeroServerCore<
|
|
|
245
56
|
createDatabase,
|
|
246
57
|
createServerActions,
|
|
247
58
|
defaultAllowAdminRole = 'all',
|
|
248
|
-
defaultMutateAuthData
|
|
59
|
+
defaultMutateAuthData,
|
|
249
60
|
models,
|
|
250
61
|
mutations: mutationValidators,
|
|
251
62
|
persistAlreadyProcessed,
|
|
@@ -254,13 +65,17 @@ export function createZeroServerCore<
|
|
|
254
65
|
validateMutation,
|
|
255
66
|
validateQuery,
|
|
256
67
|
}: ZeroServerCoreOptions<Schema, Models, ServerActions>) {
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
68
|
+
const { permissions, server } = createZeroDirectServerRuntime({
|
|
69
|
+
createDatabase,
|
|
70
|
+
createServerActions,
|
|
71
|
+
defaultAllowAdminRole,
|
|
72
|
+
defaultMutateAuthData,
|
|
73
|
+
models,
|
|
74
|
+
mutations: mutationValidators,
|
|
75
|
+
queries,
|
|
262
76
|
schema,
|
|
263
|
-
|
|
77
|
+
validateMutation,
|
|
78
|
+
validateQuery,
|
|
264
79
|
})
|
|
265
80
|
|
|
266
81
|
const handleMutationRequest = async ({
|
|
@@ -342,135 +157,13 @@ export function createZeroServerCore<
|
|
|
342
157
|
: zeroHandleQueryRequest({ handler, schema, request, userID }),
|
|
343
158
|
)
|
|
344
159
|
|
|
345
|
-
return {
|
|
346
|
-
response,
|
|
347
|
-
}
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
async function runTransaction<
|
|
351
|
-
CB extends (tx: Transaction) => Promise<any>,
|
|
352
|
-
Returns extends CB extends (tx: Transaction) => Promise<infer X> ? X : never,
|
|
353
|
-
>(database: ZeroServerDatabase, query: CB): Promise<Returns> {
|
|
354
|
-
try {
|
|
355
|
-
if (isInZeroMutation()) {
|
|
356
|
-
const { tx } = mutatorContext()
|
|
357
|
-
return await query(tx)
|
|
358
|
-
}
|
|
359
|
-
return (await database.transaction(query, dummyTransactionInput)) as Returns
|
|
360
|
-
} catch (err) {
|
|
361
|
-
if ((err as any)?.name !== 'PermissionError') {
|
|
362
|
-
console.error(`Error running transaction(): ${err}`)
|
|
363
|
-
}
|
|
364
|
-
throw err
|
|
365
|
-
}
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
async function transaction<
|
|
369
|
-
CB extends (tx: Transaction) => Promise<any>,
|
|
370
|
-
Returns extends CB extends (tx: Transaction) => Promise<infer X> ? X : never,
|
|
371
|
-
>(query: CB): Promise<Returns> {
|
|
372
|
-
return runTransaction(createDatabase(), query)
|
|
160
|
+
return { response }
|
|
373
161
|
}
|
|
374
162
|
|
|
375
|
-
async function runMutate(
|
|
376
|
-
modelName: string,
|
|
377
|
-
mutatorName: string,
|
|
378
|
-
mutatorArg: unknown,
|
|
379
|
-
options?: MutateOptions,
|
|
380
|
-
) {
|
|
381
|
-
let authData = options?.authData
|
|
382
|
-
if (!authData) {
|
|
383
|
-
const scoped = getScopedAuthData()
|
|
384
|
-
if (scoped) authData = scoped as MutateAuthData
|
|
385
|
-
}
|
|
386
|
-
|
|
387
|
-
const tasks = createAsyncTaskCollector()
|
|
388
|
-
const mutators = createMutators({
|
|
389
|
-
models,
|
|
390
|
-
environment: 'server',
|
|
391
|
-
asyncTasks: tasks.queue,
|
|
392
|
-
authData: {
|
|
393
|
-
...defaultMutateAuthData,
|
|
394
|
-
...authData,
|
|
395
|
-
},
|
|
396
|
-
createServerActions,
|
|
397
|
-
can: permissions.can,
|
|
398
|
-
validateMutation,
|
|
399
|
-
mutationValidators,
|
|
400
|
-
})
|
|
401
|
-
const modelMutators = mutators[modelName as keyof typeof mutators] as Record<
|
|
402
|
-
string,
|
|
403
|
-
(tx: Transaction, arg?: unknown) => Promise<void>
|
|
404
|
-
>
|
|
405
|
-
const mutator = modelMutators[mutatorName]
|
|
406
|
-
|
|
407
|
-
await runTransaction(
|
|
408
|
-
withTransactionLifecycle(createDatabase(), tasks.lifecycle),
|
|
409
|
-
async (tx) => {
|
|
410
|
-
await mutator(tx, mutatorArg)
|
|
411
|
-
},
|
|
412
|
-
)
|
|
413
|
-
|
|
414
|
-
if (tasks.committed.length) {
|
|
415
|
-
const resolvedAuth = authData ?? null
|
|
416
|
-
const promise = Promise.all(
|
|
417
|
-
tasks.committed.map((task) => runWithAuthScope(resolvedAuth, task)),
|
|
418
|
-
)
|
|
419
|
-
if (options?.awaitEffects) {
|
|
420
|
-
await promise
|
|
421
|
-
} else {
|
|
422
|
-
promise.catch((err: unknown) => {
|
|
423
|
-
console.error('[mutate] async tasks failed', err)
|
|
424
|
-
})
|
|
425
|
-
}
|
|
426
|
-
}
|
|
427
|
-
}
|
|
428
|
-
|
|
429
|
-
const mutate = new Proxy({} as ServerMutate<Models>, {
|
|
430
|
-
get(_, modelName: string) {
|
|
431
|
-
return new Proxy(
|
|
432
|
-
{},
|
|
433
|
-
{
|
|
434
|
-
get(_, mutatorName: string) {
|
|
435
|
-
return (arg: unknown, options?: MutateOptions) =>
|
|
436
|
-
runMutate(modelName, mutatorName, arg, options)
|
|
437
|
-
},
|
|
438
|
-
},
|
|
439
|
-
)
|
|
440
|
-
},
|
|
441
|
-
})
|
|
442
|
-
|
|
443
|
-
function query<R>(
|
|
444
|
-
cb: (q: QueryBuilder) => Query<any, Schema, R>,
|
|
445
|
-
authData?: AuthData | null,
|
|
446
|
-
): Promise<HumanReadable<R>> {
|
|
447
|
-
const run = () =>
|
|
448
|
-
transaction(async (tx) => {
|
|
449
|
-
return tx.run(cb(getZQL()))
|
|
450
|
-
}) as any
|
|
451
|
-
|
|
452
|
-
if (authData !== undefined) {
|
|
453
|
-
return runWithQueryContext({ authData }, run)
|
|
454
|
-
}
|
|
455
|
-
return run()
|
|
456
|
-
}
|
|
457
|
-
|
|
458
|
-
if (queries) {
|
|
459
|
-
setCustomQueries(queries)
|
|
460
|
-
}
|
|
461
|
-
|
|
462
|
-
setRunner((queryObj) => {
|
|
463
|
-
return transaction(async (tx) => {
|
|
464
|
-
return tx.run(queryObj)
|
|
465
|
-
})
|
|
466
|
-
})
|
|
467
|
-
|
|
468
163
|
return {
|
|
469
164
|
handleMutationRequest,
|
|
470
165
|
handleQueryRequest,
|
|
471
|
-
|
|
472
|
-
mutate,
|
|
473
|
-
query,
|
|
166
|
+
...server,
|
|
474
167
|
}
|
|
475
168
|
}
|
|
476
169
|
|
|
@@ -549,9 +242,11 @@ function alreadyProcessedMutations(response: unknown): AlreadyProcessedMutation[
|
|
|
549
242
|
})
|
|
550
243
|
}
|
|
551
244
|
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
245
|
+
export type {
|
|
246
|
+
ValidateMutationArgs,
|
|
247
|
+
ValidateMutationFn,
|
|
248
|
+
ValidateQueryArgs,
|
|
249
|
+
ValidateQueryFn,
|
|
250
|
+
ZeroServerCommonOptions,
|
|
251
|
+
ZeroServerDatabase,
|
|
252
|
+
} from './createZeroDirectServer'
|
package/src/generate.test.ts
CHANGED
|
@@ -1,4 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
existsSync,
|
|
3
|
+
mkdirSync,
|
|
4
|
+
readFileSync,
|
|
5
|
+
rmSync,
|
|
6
|
+
symlinkSync,
|
|
7
|
+
writeFileSync,
|
|
8
|
+
} from 'node:fs'
|
|
2
9
|
import { tmpdir } from 'node:os'
|
|
3
10
|
import { join } from 'node:path'
|
|
4
11
|
import { runInNewContext } from 'node:vm'
|
|
@@ -617,6 +624,55 @@ export const mutate = mutations(schema, perm, {
|
|
|
617
624
|
expect(content).not.toMatch(/rename:[\s\S]*count/)
|
|
618
625
|
})
|
|
619
626
|
|
|
627
|
+
test('resolves instantiated Zero row fields through Partial and Omit', async () => {
|
|
628
|
+
symlinkSync(
|
|
629
|
+
join(import.meta.dirname, '../../../node_modules'),
|
|
630
|
+
join(testDir, 'node_modules'),
|
|
631
|
+
'dir',
|
|
632
|
+
)
|
|
633
|
+
writeFileSync(
|
|
634
|
+
join(testDir, 'models/types.ts'),
|
|
635
|
+
`
|
|
636
|
+
import type { Row } from '@rocicorp/zero'
|
|
637
|
+
import { drizzleZeroConfig } from 'drizzle-zero-sqlite'
|
|
638
|
+
import { sqliteTable, text } from 'drizzle-orm/sqlite-core'
|
|
639
|
+
|
|
640
|
+
const item = sqliteTable('item', {
|
|
641
|
+
id: text().primaryKey(),
|
|
642
|
+
name: text().notNull(),
|
|
643
|
+
description: text().notNull(),
|
|
644
|
+
})
|
|
645
|
+
const schema = drizzleZeroConfig({ item })
|
|
646
|
+
|
|
647
|
+
export type Item = Row<(typeof schema)['tables']['item']>
|
|
648
|
+
`,
|
|
649
|
+
)
|
|
650
|
+
|
|
651
|
+
writeFileSync(
|
|
652
|
+
join(testDir, 'models/item.ts'),
|
|
653
|
+
`
|
|
654
|
+
import { mutations } from 'on-zero'
|
|
655
|
+
import type { Item } from './types'
|
|
656
|
+
|
|
657
|
+
type ItemUpdate = { id: string } & Partial<Omit<Item, 'id'>>
|
|
658
|
+
|
|
659
|
+
export const mutate = mutations('item', {
|
|
660
|
+
update: async ({ tx }, props: ItemUpdate) => {
|
|
661
|
+
await tx.mutate.item.update(props)
|
|
662
|
+
},
|
|
663
|
+
})
|
|
664
|
+
`,
|
|
665
|
+
)
|
|
666
|
+
|
|
667
|
+
await generate({ dir: testDir, silent: true })
|
|
668
|
+
|
|
669
|
+
const content = readFileSync(join(testDir, 'generated/syncedMutations.ts'), 'utf-8')
|
|
670
|
+
expect(content).toContain('name: v.optional(v.string())')
|
|
671
|
+
expect(content).toContain('description: v.optional(v.string())')
|
|
672
|
+
expect(content).not.toContain('name: v.optional(v.unknown())')
|
|
673
|
+
expect(content).not.toContain('description: v.optional(v.unknown())')
|
|
674
|
+
})
|
|
675
|
+
|
|
620
676
|
test('skips symbol-keyed properties when resolving imported mutation param types', async () => {
|
|
621
677
|
writeFileSync(
|
|
622
678
|
join(testDir, 'models/types.ts'),
|
package/src/generate.ts
CHANGED
|
@@ -442,6 +442,19 @@ function extractSchemaColumns(
|
|
|
442
442
|
visit(sourceFile)
|
|
443
443
|
}
|
|
444
444
|
|
|
445
|
+
function getInstantiatedPropertyType(
|
|
446
|
+
checker: import('typescript').TypeChecker,
|
|
447
|
+
parent: import('typescript').Type,
|
|
448
|
+
name: string,
|
|
449
|
+
) {
|
|
450
|
+
const resolveProperty: unknown = Reflect.get(checker, 'getTypeOfPropertyOfType')
|
|
451
|
+
if (typeof resolveProperty !== 'function') return undefined
|
|
452
|
+
// typescript exposes this runtime method but omits it from TypeChecker.
|
|
453
|
+
return Reflect.apply(resolveProperty, checker, [parent, name]) as
|
|
454
|
+
| import('typescript').Type
|
|
455
|
+
| undefined
|
|
456
|
+
}
|
|
457
|
+
|
|
445
458
|
// convert a ts.Type to valibot code by walking the type checker AST
|
|
446
459
|
function tsTypeToValibot(
|
|
447
460
|
ts: typeof import('typescript'),
|
|
@@ -528,7 +541,14 @@ function tsTypeToValibot(
|
|
|
528
541
|
}
|
|
529
542
|
|
|
530
543
|
// resolve symbol property type with fallbacks
|
|
531
|
-
const resolveSymbolType = (
|
|
544
|
+
const resolveSymbolType = (
|
|
545
|
+
parent: import('typescript').Type,
|
|
546
|
+
prop: import('typescript').Symbol,
|
|
547
|
+
) => {
|
|
548
|
+
// mapped and conditional types can expose transient symbols with no
|
|
549
|
+
// declaration, so resolve each property against its concrete parent.
|
|
550
|
+
const instantiated = getInstantiatedPropertyType(checker, parent, prop.getName())
|
|
551
|
+
if (instantiated) return instantiated
|
|
532
552
|
if (prop.valueDeclaration)
|
|
533
553
|
return checker.getTypeOfSymbolAtLocation(prop, prop.valueDeclaration)
|
|
534
554
|
if ((prop as any).declarations?.[0])
|
|
@@ -544,7 +564,7 @@ function tsTypeToValibot(
|
|
|
544
564
|
for (const prop of props) {
|
|
545
565
|
const name = prop.getName()
|
|
546
566
|
if (shouldSkipObjectKey(name)) continue
|
|
547
|
-
const propType = resolveSymbolType(prop)
|
|
567
|
+
const propType = resolveSymbolType(type, prop)
|
|
548
568
|
const isOptional = !!(prop.getFlags() & ts.SymbolFlags.Optional)
|
|
549
569
|
let val = recurse(propType)
|
|
550
570
|
if (isOptional && !val.startsWith('v.optional(')) {
|
|
@@ -589,7 +609,7 @@ function tsTypeToValibot(
|
|
|
589
609
|
for (const prop of props) {
|
|
590
610
|
const name = prop.getName()
|
|
591
611
|
if (shouldSkipObjectKey(name)) continue
|
|
592
|
-
const propType = resolveSymbolType(prop)
|
|
612
|
+
const propType = resolveSymbolType(type, prop)
|
|
593
613
|
const isOptional = !!(prop.getFlags() & ts.SymbolFlags.Optional)
|
|
594
614
|
let val = recurse(propType)
|
|
595
615
|
if (isOptional && !val.startsWith('v.optional(')) {
|