spacetimedb 2.4.1 → 2.6.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.txt +759 -759
- package/README.md +211 -120
- package/dist/angular/index.cjs.map +1 -1
- package/dist/angular/index.mjs.map +1 -1
- package/dist/browser/angular/index.mjs.map +1 -1
- package/dist/browser/react/index.mjs +129 -57
- package/dist/browser/react/index.mjs.map +1 -1
- package/dist/browser/solid/index.mjs +1933 -0
- package/dist/browser/solid/index.mjs.map +1 -0
- package/dist/browser/svelte/index.mjs.map +1 -1
- package/dist/browser/vue/index.mjs.map +1 -1
- package/dist/index.browser.mjs +10 -2
- package/dist/index.browser.mjs.map +1 -1
- package/dist/index.cjs +10 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +10 -2
- package/dist/index.mjs.map +1 -1
- package/dist/min/index.browser.mjs +1 -1
- package/dist/min/index.browser.mjs.map +1 -1
- package/dist/min/react/index.mjs +1 -1
- package/dist/min/react/index.mjs.map +1 -1
- package/dist/min/sdk/index.browser.mjs +1 -1
- package/dist/min/sdk/index.browser.mjs.map +1 -1
- package/dist/react/index.cjs +129 -57
- package/dist/react/index.cjs.map +1 -1
- package/dist/react/index.mjs +129 -57
- package/dist/react/index.mjs.map +1 -1
- package/dist/react/useTable.d.ts.map +1 -1
- package/dist/sdk/connection_manager.d.ts +8 -0
- package/dist/sdk/connection_manager.d.ts.map +1 -1
- package/dist/sdk/db_connection_impl.d.ts +7 -0
- package/dist/sdk/db_connection_impl.d.ts.map +1 -1
- package/dist/sdk/index.browser.mjs +10 -2
- package/dist/sdk/index.browser.mjs.map +1 -1
- package/dist/sdk/index.cjs +10 -2
- package/dist/sdk/index.cjs.map +1 -1
- package/dist/sdk/index.mjs +10 -2
- package/dist/sdk/index.mjs.map +1 -1
- package/dist/sdk/websocket_test_adapter.d.ts +2 -1
- package/dist/sdk/websocket_test_adapter.d.ts.map +1 -1
- package/dist/server/index.mjs.map +1 -1
- package/dist/server/runtime.d.ts.map +1 -1
- package/dist/solid/SpacetimeDBProvider.d.ts +7 -0
- package/dist/solid/SpacetimeDBProvider.d.ts.map +1 -0
- package/dist/solid/connection_state.d.ts +6 -0
- package/dist/solid/connection_state.d.ts.map +1 -0
- package/dist/solid/index.cjs +1939 -0
- package/dist/solid/index.cjs.map +1 -0
- package/dist/solid/index.d.ts +6 -0
- package/dist/solid/index.d.ts.map +1 -0
- package/dist/solid/index.mjs +1933 -0
- package/dist/solid/index.mjs.map +1 -0
- package/dist/solid/useProcedure.d.ts +4 -0
- package/dist/solid/useProcedure.d.ts.map +1 -0
- package/dist/solid/useReducer.d.ts +4 -0
- package/dist/solid/useReducer.d.ts.map +1 -0
- package/dist/solid/useSpacetimeDB.d.ts +4 -0
- package/dist/solid/useSpacetimeDB.d.ts.map +1 -0
- package/dist/solid/useTable.d.ts +32 -0
- package/dist/solid/useTable.d.ts.map +1 -0
- package/dist/svelte/index.cjs.map +1 -1
- package/dist/svelte/index.mjs.map +1 -1
- package/dist/tanstack/index.cjs +120 -50
- package/dist/tanstack/index.cjs.map +1 -1
- package/dist/tanstack/index.mjs +120 -50
- package/dist/tanstack/index.mjs.map +1 -1
- package/dist/vue/index.cjs.map +1 -1
- package/dist/vue/index.mjs.map +1 -1
- package/package.json +13 -3
- package/src/angular/connection_state.ts +19 -19
- package/src/angular/index.ts +3 -3
- package/src/angular/injectors/index.ts +4 -4
- package/src/angular/injectors/inject-reducer.ts +62 -62
- package/src/angular/injectors/inject-spacetimedb-connected.ts +13 -13
- package/src/angular/injectors/inject-spacetimedb.ts +10 -10
- package/src/angular/injectors/inject-table.ts +234 -234
- package/src/angular/providers/index.ts +1 -1
- package/src/angular/providers/provide-spacetimedb.ts +96 -96
- package/src/index.ts +16 -16
- package/src/lib/algebraic_type.ts +819 -819
- package/src/lib/algebraic_type_variants.ts +26 -26
- package/src/lib/algebraic_value.ts +10 -10
- package/src/lib/autogen/types.ts +746 -746
- package/src/lib/binary_reader.ts +188 -188
- package/src/lib/binary_writer.ts +213 -213
- package/src/lib/connection_id.ts +102 -102
- package/src/lib/constraints.ts +48 -48
- package/src/lib/errors.ts +26 -26
- package/src/lib/filter.ts +195 -195
- package/src/lib/identity.ts +83 -83
- package/src/lib/indexes.ts +251 -251
- package/src/lib/option.ts +34 -34
- package/src/lib/query.ts +1019 -1019
- package/src/lib/reducer_schema.ts +38 -38
- package/src/lib/reducers.ts +116 -116
- package/src/lib/result.ts +36 -36
- package/src/lib/schedule_at.ts +86 -86
- package/src/lib/schema.ts +420 -420
- package/src/lib/table.ts +548 -548
- package/src/lib/table_schema.ts +64 -64
- package/src/lib/time_duration.ts +77 -77
- package/src/lib/timestamp.ts +148 -148
- package/src/lib/type_builders.test-d.ts +128 -128
- package/src/lib/type_builders.ts +4014 -4014
- package/src/lib/type_util.ts +124 -124
- package/src/lib/util.ts +196 -196
- package/src/lib/uuid.ts +337 -337
- package/src/react/SpacetimeDBProvider.ts +84 -84
- package/src/react/connection_state.ts +6 -6
- package/src/react/index.ts +5 -5
- package/src/react/useProcedure.ts +60 -60
- package/src/react/useReducer.ts +53 -53
- package/src/react/useSpacetimeDB.ts +18 -18
- package/src/react/useTable.ts +256 -251
- package/src/sdk/client_api/index.ts +114 -114
- package/src/sdk/client_api/types/procedures.ts +8 -8
- package/src/sdk/client_api/types/reducers.ts +8 -8
- package/src/sdk/client_api/types.ts +288 -288
- package/src/sdk/client_cache.ts +129 -129
- package/src/sdk/client_table.ts +179 -179
- package/src/sdk/connection_manager.ts +352 -237
- package/src/sdk/db_connection_builder.ts +290 -290
- package/src/sdk/db_connection_impl.ts +1356 -1347
- package/src/sdk/db_context.ts +28 -28
- package/src/sdk/db_view.ts +12 -12
- package/src/sdk/decompress.ts +51 -51
- package/src/sdk/event.ts +18 -18
- package/src/sdk/event_context.ts +51 -51
- package/src/sdk/event_emitter.ts +32 -32
- package/src/sdk/index.ts +14 -14
- package/src/sdk/internal.ts +2 -2
- package/src/sdk/json_api.ts +46 -46
- package/src/sdk/logger.ts +134 -134
- package/src/sdk/message_types.ts +46 -46
- package/src/sdk/procedures.ts +83 -83
- package/src/sdk/reducer_event.ts +20 -20
- package/src/sdk/reducer_handle.ts +12 -12
- package/src/sdk/reducers.ts +159 -159
- package/src/sdk/schema.ts +45 -45
- package/src/sdk/spacetime_module.ts +28 -28
- package/src/sdk/subscription_builder_impl.ts +275 -275
- package/src/sdk/table_cache.ts +581 -581
- package/src/sdk/type_utils.ts +19 -19
- package/src/sdk/version.ts +133 -133
- package/src/sdk/websocket_decompress_adapter.ts +63 -63
- package/src/sdk/websocket_protocols.ts +25 -25
- package/src/sdk/websocket_test_adapter.ts +107 -100
- package/src/sdk/websocket_v3_frames.ts +126 -126
- package/src/sdk/ws.ts +105 -105
- package/src/server/console.ts +81 -81
- package/src/server/db_view.ts +21 -21
- package/src/server/errors.ts +138 -138
- package/src/server/http.test-d.ts +80 -80
- package/src/server/http.ts +14 -14
- package/src/server/http_handlers.ts +413 -413
- package/src/server/http_internal.ts +79 -79
- package/src/server/http_shared.ts +186 -186
- package/src/server/index.ts +37 -37
- package/src/server/polyfills.ts +4 -4
- package/src/server/procedures.ts +239 -239
- package/src/server/query.ts +1 -1
- package/src/server/range.ts +53 -53
- package/src/server/reducers.ts +113 -113
- package/src/server/rng.ts +113 -113
- package/src/server/runtime.ts +1102 -1102
- package/src/server/schema.test-d.ts +99 -99
- package/src/server/schema.ts +663 -663
- package/src/server/sys.d.ts +125 -125
- package/src/server/view.test-d.ts +194 -194
- package/src/server/views.ts +340 -340
- package/src/solid/SpacetimeDBProvider.ts +97 -0
- package/src/solid/connection_state.ts +6 -0
- package/src/solid/index.ts +5 -0
- package/src/solid/useProcedure.ts +57 -0
- package/src/solid/useReducer.ts +50 -0
- package/src/solid/useSpacetimeDB.ts +18 -0
- package/src/solid/useTable.ts +203 -0
- package/src/svelte/SpacetimeDBProvider.ts +101 -101
- package/src/svelte/connection_state.ts +16 -16
- package/src/svelte/index.ts +4 -4
- package/src/svelte/useReducer.ts +61 -61
- package/src/svelte/useSpacetimeDB.ts +22 -22
- package/src/svelte/useTable.ts +218 -218
- package/src/tanstack/SpacetimeDBQueryClient.ts +330 -330
- package/src/tanstack/hooks.ts +83 -83
- package/src/tanstack/index.ts +16 -16
- package/src/util-stub.ts +1 -1
- package/src/vue/SpacetimeDBProvider.ts +157 -157
- package/src/vue/connection_state.ts +19 -19
- package/src/vue/index.ts +5 -5
- package/src/vue/useProcedure.ts +62 -62
- package/src/vue/useReducer.ts +55 -55
- package/src/vue/useSpacetimeDB.ts +18 -18
- package/src/vue/useTable.ts +229 -229
package/src/server/views.ts
CHANGED
|
@@ -1,340 +1,340 @@
|
|
|
1
|
-
import {
|
|
2
|
-
AlgebraicType,
|
|
3
|
-
ProductType,
|
|
4
|
-
type AlgebraicTypeVariants,
|
|
5
|
-
type Deserializer,
|
|
6
|
-
type Serializer,
|
|
7
|
-
} from '../lib/algebraic_type';
|
|
8
|
-
import type { Identity } from '../lib/identity';
|
|
9
|
-
import type { OptionAlgebraicType } from '../lib/option';
|
|
10
|
-
import type { ParamsObj } from '../lib/reducers';
|
|
11
|
-
import { type UntypedSchemaDef } from '../lib/schema';
|
|
12
|
-
import {
|
|
13
|
-
ArrayBuilder,
|
|
14
|
-
OptionBuilder,
|
|
15
|
-
RowBuilder,
|
|
16
|
-
type ColumnBuilder,
|
|
17
|
-
type ColumnMetadata,
|
|
18
|
-
type Infer,
|
|
19
|
-
type InferSpacetimeTypeOfTypeBuilder,
|
|
20
|
-
type InferTypeOfRow,
|
|
21
|
-
type RowObj,
|
|
22
|
-
type TypeBuilder,
|
|
23
|
-
} from '../lib/type_builders';
|
|
24
|
-
import { bsatnBaseSize, toPascalCase } from '../lib/util';
|
|
25
|
-
import type { ReadonlyDbView } from './db_view';
|
|
26
|
-
import { type QueryBuilder, type RowTypedQuery } from './query';
|
|
27
|
-
import {
|
|
28
|
-
exportContext,
|
|
29
|
-
registerExport,
|
|
30
|
-
type ModuleExport,
|
|
31
|
-
type SchemaInner,
|
|
32
|
-
} from './schema';
|
|
33
|
-
|
|
34
|
-
export type ViewExport<ViewFn> = ViewFn & ModuleExport;
|
|
35
|
-
|
|
36
|
-
export function makeViewExport<
|
|
37
|
-
S extends UntypedSchemaDef,
|
|
38
|
-
Params extends ParamsObj,
|
|
39
|
-
Ret extends ViewReturnTypeBuilder,
|
|
40
|
-
F extends ViewFn<S, Params, Ret>,
|
|
41
|
-
>(
|
|
42
|
-
ctx: SchemaInner,
|
|
43
|
-
opts: ViewOpts,
|
|
44
|
-
params: Params,
|
|
45
|
-
ret: Ret,
|
|
46
|
-
fn: F
|
|
47
|
-
): ViewExport<F> {
|
|
48
|
-
const viewExport =
|
|
49
|
-
// @ts-expect-error typescript incorrectly says Function#bind requires an argument.
|
|
50
|
-
fn.bind() as ViewExport<F>;
|
|
51
|
-
viewExport[exportContext] = ctx;
|
|
52
|
-
viewExport[registerExport] = (ctx, exportName) => {
|
|
53
|
-
registerView(ctx, opts, exportName, false, params, ret, fn);
|
|
54
|
-
};
|
|
55
|
-
return viewExport;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
export function makeAnonViewExport<
|
|
59
|
-
S extends UntypedSchemaDef,
|
|
60
|
-
Params extends ParamsObj,
|
|
61
|
-
Ret extends ViewReturnTypeBuilder,
|
|
62
|
-
F extends AnonymousViewFn<S, Params, Ret>,
|
|
63
|
-
>(
|
|
64
|
-
ctx: SchemaInner,
|
|
65
|
-
opts: ViewOpts,
|
|
66
|
-
params: Params,
|
|
67
|
-
ret: Ret,
|
|
68
|
-
fn: F
|
|
69
|
-
): ViewExport<F> {
|
|
70
|
-
const viewExport =
|
|
71
|
-
// @ts-expect-error typescript incorrectly says Function#bind requires an argument.
|
|
72
|
-
fn.bind() as ViewExport<F>;
|
|
73
|
-
viewExport[exportContext] = ctx;
|
|
74
|
-
viewExport[registerExport] = (ctx, exportName) => {
|
|
75
|
-
registerView(ctx, opts, exportName, true, params, ret, fn);
|
|
76
|
-
};
|
|
77
|
-
return viewExport;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
export type ViewCtx<S extends UntypedSchemaDef> = Readonly<{
|
|
81
|
-
sender: Identity;
|
|
82
|
-
db: ReadonlyDbView<S>;
|
|
83
|
-
from: QueryBuilder<S>;
|
|
84
|
-
}>;
|
|
85
|
-
|
|
86
|
-
export type AnonymousViewCtx<S extends UntypedSchemaDef> = Readonly<{
|
|
87
|
-
db: ReadonlyDbView<S>;
|
|
88
|
-
from: QueryBuilder<S>;
|
|
89
|
-
}>;
|
|
90
|
-
|
|
91
|
-
export type ViewOpts = {
|
|
92
|
-
name?: string;
|
|
93
|
-
public: true;
|
|
94
|
-
};
|
|
95
|
-
|
|
96
|
-
type FlattenedArray<T> = T extends readonly (infer E)[] ? E : never;
|
|
97
|
-
|
|
98
|
-
// Compile-time mirror of `viewReturnRow` below. Views currently return either
|
|
99
|
-
// `array(row(...))` or `option(row(...))`; this extracts the row object type
|
|
100
|
-
// from those builders so we can inspect column metadata at the type level.
|
|
101
|
-
// Non-row returns collapse to `never`, which makes the primary-key validation
|
|
102
|
-
// below a no-op for unsupported shapes.
|
|
103
|
-
type ViewReturnRow<Ret extends ViewReturnTypeBuilder> =
|
|
104
|
-
Ret extends ArrayBuilder<infer Element>
|
|
105
|
-
? Element extends RowBuilder<infer Row>
|
|
106
|
-
? Row
|
|
107
|
-
: never
|
|
108
|
-
: Ret extends OptionBuilder<infer Value>
|
|
109
|
-
? Value extends RowBuilder<infer Row>
|
|
110
|
-
? Row
|
|
111
|
-
: never
|
|
112
|
-
: never;
|
|
113
|
-
|
|
114
|
-
// Produces a union of the returned row's column names marked with
|
|
115
|
-
// `.primaryKey()`. For example, `{ id: t.u32().primaryKey(), name: t.string() }`
|
|
116
|
-
// becomes `"id"`, while two marked columns becomes `"id" | "name"`.
|
|
117
|
-
type PrimaryKeyColumnNames<Row extends RowObj> = {
|
|
118
|
-
[K in keyof Row & string]: Row[K] extends ColumnBuilder<any, any, infer M>
|
|
119
|
-
? M extends { isPrimaryKey: true }
|
|
120
|
-
? K
|
|
121
|
-
: never
|
|
122
|
-
: never;
|
|
123
|
-
}[keyof Row & string];
|
|
124
|
-
|
|
125
|
-
// Standard conditional-type trick for distinguishing a single type from a
|
|
126
|
-
// union. We use it because zero or one primary-key column is valid, but a union
|
|
127
|
-
// of two or more column names means the row builder marked multiple primary
|
|
128
|
-
// keys.
|
|
129
|
-
type IsUnion<T, U = T> = [T] extends [never]
|
|
130
|
-
? false
|
|
131
|
-
: T extends any
|
|
132
|
-
? [U] extends [T]
|
|
133
|
-
? false
|
|
134
|
-
: true
|
|
135
|
-
: false;
|
|
136
|
-
|
|
137
|
-
// In generic code, row keys may widen from literal names like "id" | "name"
|
|
138
|
-
// to plain `string`. That means "unknown column name", not "multiple primary
|
|
139
|
-
// keys", so avoid a false-positive type error and rely on the runtime check.
|
|
140
|
-
type HasMultiplePrimaryKeys<Row extends RowObj> =
|
|
141
|
-
string extends PrimaryKeyColumnNames<Row>
|
|
142
|
-
? false
|
|
143
|
-
: IsUnion<PrimaryKeyColumnNames<Row>>;
|
|
144
|
-
|
|
145
|
-
type MultiplePrimaryKeyColumns<Ret extends ViewReturnTypeBuilder> =
|
|
146
|
-
PrimaryKeyColumnNames<ViewReturnRow<Ret>>;
|
|
147
|
-
|
|
148
|
-
type ERROR_view_return_type_can_have_at_most_one_primaryKey<
|
|
149
|
-
Columns extends string,
|
|
150
|
-
> = {
|
|
151
|
-
_primaryKeyColumns: Columns;
|
|
152
|
-
_fix: 'Remove primaryKey() from all but one column on the returned row type';
|
|
153
|
-
};
|
|
154
|
-
|
|
155
|
-
// Used as a rest parameter type on `Schema.view` and `Schema.anonymousView`.
|
|
156
|
-
// Valid return builders produce `[]`, so callers pass no extra arguments. If
|
|
157
|
-
// the returned row has multiple `.primaryKey()` columns, this becomes a
|
|
158
|
-
// one-element tuple containing an explanatory error type, which makes the
|
|
159
|
-
// normal three-argument call fail to type-check.
|
|
160
|
-
export type ValidateViewPrimaryKey<Ret extends ViewReturnTypeBuilder> =
|
|
161
|
-
HasMultiplePrimaryKeys<ViewReturnRow<Ret>> extends true
|
|
162
|
-
? [
|
|
163
|
-
error: ERROR_view_return_type_can_have_at_most_one_primaryKey<
|
|
164
|
-
MultiplePrimaryKeyColumns<Ret>
|
|
165
|
-
>,
|
|
166
|
-
]
|
|
167
|
-
: [];
|
|
168
|
-
|
|
169
|
-
// // If we allowed functions to return either.
|
|
170
|
-
// type ViewReturn<Ret extends ViewReturnTypeBuilder> =
|
|
171
|
-
// | Infer<Ret>
|
|
172
|
-
// | RowTypedQuery<FlattenedArray<Infer<Ret>>>;
|
|
173
|
-
|
|
174
|
-
export type ViewFn<
|
|
175
|
-
S extends UntypedSchemaDef,
|
|
176
|
-
Params extends ParamsObj,
|
|
177
|
-
Ret extends ViewReturnTypeBuilder,
|
|
178
|
-
> =
|
|
179
|
-
| ((ctx: ViewCtx<S>, params: InferTypeOfRow<Params>) => Infer<Ret>)
|
|
180
|
-
| ((
|
|
181
|
-
ctx: ViewCtx<S>,
|
|
182
|
-
params: InferTypeOfRow<Params>
|
|
183
|
-
) => RowTypedQuery<FlattenedArray<Infer<Ret>>, ExtractArrayProduct<Ret>>);
|
|
184
|
-
|
|
185
|
-
export type AnonymousViewFn<
|
|
186
|
-
S extends UntypedSchemaDef,
|
|
187
|
-
Params extends ParamsObj,
|
|
188
|
-
Ret extends ViewReturnTypeBuilder,
|
|
189
|
-
> =
|
|
190
|
-
| ((ctx: AnonymousViewCtx<S>, params: InferTypeOfRow<Params>) => Infer<Ret>)
|
|
191
|
-
| ((
|
|
192
|
-
ctx: AnonymousViewCtx<S>,
|
|
193
|
-
params: InferTypeOfRow<Params>
|
|
194
|
-
) => RowTypedQuery<FlattenedArray<Infer<Ret>>, ExtractArrayProduct<Ret>>);
|
|
195
|
-
|
|
196
|
-
export type ViewReturnTypeBuilder =
|
|
197
|
-
| TypeBuilder<
|
|
198
|
-
readonly object[],
|
|
199
|
-
{ tag: 'Array'; value: AlgebraicTypeVariants.Product }
|
|
200
|
-
>
|
|
201
|
-
| TypeBuilder<
|
|
202
|
-
object | undefined,
|
|
203
|
-
OptionAlgebraicType<AlgebraicTypeVariants.Product>
|
|
204
|
-
>;
|
|
205
|
-
|
|
206
|
-
export function registerView<
|
|
207
|
-
S extends UntypedSchemaDef,
|
|
208
|
-
const Anonymous extends boolean,
|
|
209
|
-
Params extends ParamsObj,
|
|
210
|
-
Ret extends ViewReturnTypeBuilder,
|
|
211
|
-
>(
|
|
212
|
-
ctx: SchemaInner,
|
|
213
|
-
opts: ViewOpts,
|
|
214
|
-
exportName: string,
|
|
215
|
-
anon: Anonymous,
|
|
216
|
-
params: Params,
|
|
217
|
-
ret: Ret,
|
|
218
|
-
fn: Anonymous extends true
|
|
219
|
-
? AnonymousViewFn<S, Params, Ret>
|
|
220
|
-
: ViewFn<S, Params, Ret>
|
|
221
|
-
) {
|
|
222
|
-
ctx.defineFunction(exportName);
|
|
223
|
-
const paramsBuilder = new RowBuilder(params, toPascalCase(exportName));
|
|
224
|
-
|
|
225
|
-
// Register return types if they are product types
|
|
226
|
-
let returnType = ctx.registerTypesRecursively(ret).algebraicType;
|
|
227
|
-
|
|
228
|
-
const { typespace } = ctx;
|
|
229
|
-
|
|
230
|
-
const { value: paramType } = ctx.resolveType(
|
|
231
|
-
ctx.registerTypesRecursively(paramsBuilder)
|
|
232
|
-
);
|
|
233
|
-
|
|
234
|
-
ctx.moduleDef.views.push({
|
|
235
|
-
sourceName: exportName,
|
|
236
|
-
index: (anon ? ctx.anonViews : ctx.views).length,
|
|
237
|
-
isPublic: opts.public,
|
|
238
|
-
isAnonymous: anon,
|
|
239
|
-
params: paramType,
|
|
240
|
-
returnType,
|
|
241
|
-
});
|
|
242
|
-
|
|
243
|
-
// Runtime counterpart to `ValidateViewPrimaryKey`: the type-level check gives
|
|
244
|
-
// users an early diagnostic in normal code, but this still protects dynamic
|
|
245
|
-
// or widened builders and is the source of the raw module-def metadata.
|
|
246
|
-
const primaryKeyColumns = viewPrimaryKeyColumns(ret);
|
|
247
|
-
if (primaryKeyColumns.length > 1) {
|
|
248
|
-
throw new TypeError(
|
|
249
|
-
`View '${exportName}' can have at most one primaryKey() column on its returned row type; found ${primaryKeyColumns.join(', ')}`
|
|
250
|
-
);
|
|
251
|
-
}
|
|
252
|
-
if (primaryKeyColumns.length === 1) {
|
|
253
|
-
ctx.moduleDef.viewPrimaryKeys.push({
|
|
254
|
-
viewSourceName: exportName,
|
|
255
|
-
columns: primaryKeyColumns,
|
|
256
|
-
});
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
if (opts.name != null) {
|
|
260
|
-
ctx.moduleDef.explicitNames.entries.push({
|
|
261
|
-
tag: 'Function',
|
|
262
|
-
value: {
|
|
263
|
-
sourceName: exportName,
|
|
264
|
-
canonicalName: opts.name,
|
|
265
|
-
},
|
|
266
|
-
});
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
// If it is an option, we wrap the function to make the return look like an array.
|
|
270
|
-
if (returnType.tag == 'Sum') {
|
|
271
|
-
const originalFn = fn;
|
|
272
|
-
fn = ((ctx: ViewCtx<S>, args: InferTypeOfRow<Params>) => {
|
|
273
|
-
const ret = originalFn(ctx, args);
|
|
274
|
-
return ret == null ? [] : [ret];
|
|
275
|
-
}) as any;
|
|
276
|
-
returnType = AlgebraicType.Array(
|
|
277
|
-
returnType.value.variants[0].algebraicType
|
|
278
|
-
);
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
(anon ? ctx.anonViews : ctx.views).push({
|
|
282
|
-
fn,
|
|
283
|
-
deserializeParams: ProductType.makeDeserializer(paramType, typespace),
|
|
284
|
-
serializeReturn: AlgebraicType.makeSerializer(returnType, typespace),
|
|
285
|
-
returnTypeBaseSize: bsatnBaseSize(typespace, returnType),
|
|
286
|
-
});
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
// Inspect the returned row builder and collect the column property names marked
|
|
290
|
-
// with `.primaryKey()`. These names are the TypeScript row-builder keys, which
|
|
291
|
-
// are also the raw column names in the module definition emitted by the TS SDK.
|
|
292
|
-
function viewPrimaryKeyColumns(ret: ViewReturnTypeBuilder): string[] {
|
|
293
|
-
const row = viewReturnRow(ret);
|
|
294
|
-
if (row == null) {
|
|
295
|
-
return [];
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
return Object.entries(row.row)
|
|
299
|
-
.filter(
|
|
300
|
-
(
|
|
301
|
-
entry
|
|
302
|
-
): entry is [string, ColumnBuilder<any, any, ColumnMetadata<any>>] =>
|
|
303
|
-
entry[1].columnMetadata.isPrimaryKey === true
|
|
304
|
-
)
|
|
305
|
-
.map(([name]) => name);
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
// Views can return either `array(row(...))` or `option(row(...))`. The primary
|
|
309
|
-
// key marker lives on the inner `RowBuilder`, so unwrap those two supported
|
|
310
|
-
// shapes and ignore anything else.
|
|
311
|
-
function viewReturnRow(
|
|
312
|
-
ret: ViewReturnTypeBuilder
|
|
313
|
-
): RowBuilder<any> | undefined {
|
|
314
|
-
if (ret instanceof ArrayBuilder && ret.element instanceof RowBuilder) {
|
|
315
|
-
return ret.element;
|
|
316
|
-
}
|
|
317
|
-
if (ret instanceof OptionBuilder && ret.value instanceof RowBuilder) {
|
|
318
|
-
return ret.value;
|
|
319
|
-
}
|
|
320
|
-
return undefined;
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
type ViewInfo<F> = {
|
|
324
|
-
fn: F;
|
|
325
|
-
deserializeParams: Deserializer<any>;
|
|
326
|
-
serializeReturn: Serializer<any>;
|
|
327
|
-
returnTypeBaseSize: number;
|
|
328
|
-
};
|
|
329
|
-
|
|
330
|
-
export type Views = ViewInfo<ViewFn<any, any, any>>[];
|
|
331
|
-
export type AnonViews = ViewInfo<AnonymousViewFn<any, any, any>>[];
|
|
332
|
-
|
|
333
|
-
// A helper to get the product type out of a type builder.
|
|
334
|
-
// This is only non-never if the type builder is an array.
|
|
335
|
-
type ExtractArrayProduct<T extends TypeBuilder<any, any>> =
|
|
336
|
-
InferSpacetimeTypeOfTypeBuilder<T> extends { tag: 'Array'; value: infer V }
|
|
337
|
-
? V extends { tag: 'Product'; value: infer P }
|
|
338
|
-
? P
|
|
339
|
-
: never
|
|
340
|
-
: never;
|
|
1
|
+
import {
|
|
2
|
+
AlgebraicType,
|
|
3
|
+
ProductType,
|
|
4
|
+
type AlgebraicTypeVariants,
|
|
5
|
+
type Deserializer,
|
|
6
|
+
type Serializer,
|
|
7
|
+
} from '../lib/algebraic_type';
|
|
8
|
+
import type { Identity } from '../lib/identity';
|
|
9
|
+
import type { OptionAlgebraicType } from '../lib/option';
|
|
10
|
+
import type { ParamsObj } from '../lib/reducers';
|
|
11
|
+
import { type UntypedSchemaDef } from '../lib/schema';
|
|
12
|
+
import {
|
|
13
|
+
ArrayBuilder,
|
|
14
|
+
OptionBuilder,
|
|
15
|
+
RowBuilder,
|
|
16
|
+
type ColumnBuilder,
|
|
17
|
+
type ColumnMetadata,
|
|
18
|
+
type Infer,
|
|
19
|
+
type InferSpacetimeTypeOfTypeBuilder,
|
|
20
|
+
type InferTypeOfRow,
|
|
21
|
+
type RowObj,
|
|
22
|
+
type TypeBuilder,
|
|
23
|
+
} from '../lib/type_builders';
|
|
24
|
+
import { bsatnBaseSize, toPascalCase } from '../lib/util';
|
|
25
|
+
import type { ReadonlyDbView } from './db_view';
|
|
26
|
+
import { type QueryBuilder, type RowTypedQuery } from './query';
|
|
27
|
+
import {
|
|
28
|
+
exportContext,
|
|
29
|
+
registerExport,
|
|
30
|
+
type ModuleExport,
|
|
31
|
+
type SchemaInner,
|
|
32
|
+
} from './schema';
|
|
33
|
+
|
|
34
|
+
export type ViewExport<ViewFn> = ViewFn & ModuleExport;
|
|
35
|
+
|
|
36
|
+
export function makeViewExport<
|
|
37
|
+
S extends UntypedSchemaDef,
|
|
38
|
+
Params extends ParamsObj,
|
|
39
|
+
Ret extends ViewReturnTypeBuilder,
|
|
40
|
+
F extends ViewFn<S, Params, Ret>,
|
|
41
|
+
>(
|
|
42
|
+
ctx: SchemaInner,
|
|
43
|
+
opts: ViewOpts,
|
|
44
|
+
params: Params,
|
|
45
|
+
ret: Ret,
|
|
46
|
+
fn: F
|
|
47
|
+
): ViewExport<F> {
|
|
48
|
+
const viewExport =
|
|
49
|
+
// @ts-expect-error typescript incorrectly says Function#bind requires an argument.
|
|
50
|
+
fn.bind() as ViewExport<F>;
|
|
51
|
+
viewExport[exportContext] = ctx;
|
|
52
|
+
viewExport[registerExport] = (ctx, exportName) => {
|
|
53
|
+
registerView(ctx, opts, exportName, false, params, ret, fn);
|
|
54
|
+
};
|
|
55
|
+
return viewExport;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export function makeAnonViewExport<
|
|
59
|
+
S extends UntypedSchemaDef,
|
|
60
|
+
Params extends ParamsObj,
|
|
61
|
+
Ret extends ViewReturnTypeBuilder,
|
|
62
|
+
F extends AnonymousViewFn<S, Params, Ret>,
|
|
63
|
+
>(
|
|
64
|
+
ctx: SchemaInner,
|
|
65
|
+
opts: ViewOpts,
|
|
66
|
+
params: Params,
|
|
67
|
+
ret: Ret,
|
|
68
|
+
fn: F
|
|
69
|
+
): ViewExport<F> {
|
|
70
|
+
const viewExport =
|
|
71
|
+
// @ts-expect-error typescript incorrectly says Function#bind requires an argument.
|
|
72
|
+
fn.bind() as ViewExport<F>;
|
|
73
|
+
viewExport[exportContext] = ctx;
|
|
74
|
+
viewExport[registerExport] = (ctx, exportName) => {
|
|
75
|
+
registerView(ctx, opts, exportName, true, params, ret, fn);
|
|
76
|
+
};
|
|
77
|
+
return viewExport;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export type ViewCtx<S extends UntypedSchemaDef> = Readonly<{
|
|
81
|
+
sender: Identity;
|
|
82
|
+
db: ReadonlyDbView<S>;
|
|
83
|
+
from: QueryBuilder<S>;
|
|
84
|
+
}>;
|
|
85
|
+
|
|
86
|
+
export type AnonymousViewCtx<S extends UntypedSchemaDef> = Readonly<{
|
|
87
|
+
db: ReadonlyDbView<S>;
|
|
88
|
+
from: QueryBuilder<S>;
|
|
89
|
+
}>;
|
|
90
|
+
|
|
91
|
+
export type ViewOpts = {
|
|
92
|
+
name?: string;
|
|
93
|
+
public: true;
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
type FlattenedArray<T> = T extends readonly (infer E)[] ? E : never;
|
|
97
|
+
|
|
98
|
+
// Compile-time mirror of `viewReturnRow` below. Views currently return either
|
|
99
|
+
// `array(row(...))` or `option(row(...))`; this extracts the row object type
|
|
100
|
+
// from those builders so we can inspect column metadata at the type level.
|
|
101
|
+
// Non-row returns collapse to `never`, which makes the primary-key validation
|
|
102
|
+
// below a no-op for unsupported shapes.
|
|
103
|
+
type ViewReturnRow<Ret extends ViewReturnTypeBuilder> =
|
|
104
|
+
Ret extends ArrayBuilder<infer Element>
|
|
105
|
+
? Element extends RowBuilder<infer Row>
|
|
106
|
+
? Row
|
|
107
|
+
: never
|
|
108
|
+
: Ret extends OptionBuilder<infer Value>
|
|
109
|
+
? Value extends RowBuilder<infer Row>
|
|
110
|
+
? Row
|
|
111
|
+
: never
|
|
112
|
+
: never;
|
|
113
|
+
|
|
114
|
+
// Produces a union of the returned row's column names marked with
|
|
115
|
+
// `.primaryKey()`. For example, `{ id: t.u32().primaryKey(), name: t.string() }`
|
|
116
|
+
// becomes `"id"`, while two marked columns becomes `"id" | "name"`.
|
|
117
|
+
type PrimaryKeyColumnNames<Row extends RowObj> = {
|
|
118
|
+
[K in keyof Row & string]: Row[K] extends ColumnBuilder<any, any, infer M>
|
|
119
|
+
? M extends { isPrimaryKey: true }
|
|
120
|
+
? K
|
|
121
|
+
: never
|
|
122
|
+
: never;
|
|
123
|
+
}[keyof Row & string];
|
|
124
|
+
|
|
125
|
+
// Standard conditional-type trick for distinguishing a single type from a
|
|
126
|
+
// union. We use it because zero or one primary-key column is valid, but a union
|
|
127
|
+
// of two or more column names means the row builder marked multiple primary
|
|
128
|
+
// keys.
|
|
129
|
+
type IsUnion<T, U = T> = [T] extends [never]
|
|
130
|
+
? false
|
|
131
|
+
: T extends any
|
|
132
|
+
? [U] extends [T]
|
|
133
|
+
? false
|
|
134
|
+
: true
|
|
135
|
+
: false;
|
|
136
|
+
|
|
137
|
+
// In generic code, row keys may widen from literal names like "id" | "name"
|
|
138
|
+
// to plain `string`. That means "unknown column name", not "multiple primary
|
|
139
|
+
// keys", so avoid a false-positive type error and rely on the runtime check.
|
|
140
|
+
type HasMultiplePrimaryKeys<Row extends RowObj> =
|
|
141
|
+
string extends PrimaryKeyColumnNames<Row>
|
|
142
|
+
? false
|
|
143
|
+
: IsUnion<PrimaryKeyColumnNames<Row>>;
|
|
144
|
+
|
|
145
|
+
type MultiplePrimaryKeyColumns<Ret extends ViewReturnTypeBuilder> =
|
|
146
|
+
PrimaryKeyColumnNames<ViewReturnRow<Ret>>;
|
|
147
|
+
|
|
148
|
+
type ERROR_view_return_type_can_have_at_most_one_primaryKey<
|
|
149
|
+
Columns extends string,
|
|
150
|
+
> = {
|
|
151
|
+
_primaryKeyColumns: Columns;
|
|
152
|
+
_fix: 'Remove primaryKey() from all but one column on the returned row type';
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
// Used as a rest parameter type on `Schema.view` and `Schema.anonymousView`.
|
|
156
|
+
// Valid return builders produce `[]`, so callers pass no extra arguments. If
|
|
157
|
+
// the returned row has multiple `.primaryKey()` columns, this becomes a
|
|
158
|
+
// one-element tuple containing an explanatory error type, which makes the
|
|
159
|
+
// normal three-argument call fail to type-check.
|
|
160
|
+
export type ValidateViewPrimaryKey<Ret extends ViewReturnTypeBuilder> =
|
|
161
|
+
HasMultiplePrimaryKeys<ViewReturnRow<Ret>> extends true
|
|
162
|
+
? [
|
|
163
|
+
error: ERROR_view_return_type_can_have_at_most_one_primaryKey<
|
|
164
|
+
MultiplePrimaryKeyColumns<Ret>
|
|
165
|
+
>,
|
|
166
|
+
]
|
|
167
|
+
: [];
|
|
168
|
+
|
|
169
|
+
// // If we allowed functions to return either.
|
|
170
|
+
// type ViewReturn<Ret extends ViewReturnTypeBuilder> =
|
|
171
|
+
// | Infer<Ret>
|
|
172
|
+
// | RowTypedQuery<FlattenedArray<Infer<Ret>>>;
|
|
173
|
+
|
|
174
|
+
export type ViewFn<
|
|
175
|
+
S extends UntypedSchemaDef,
|
|
176
|
+
Params extends ParamsObj,
|
|
177
|
+
Ret extends ViewReturnTypeBuilder,
|
|
178
|
+
> =
|
|
179
|
+
| ((ctx: ViewCtx<S>, params: InferTypeOfRow<Params>) => Infer<Ret>)
|
|
180
|
+
| ((
|
|
181
|
+
ctx: ViewCtx<S>,
|
|
182
|
+
params: InferTypeOfRow<Params>
|
|
183
|
+
) => RowTypedQuery<FlattenedArray<Infer<Ret>>, ExtractArrayProduct<Ret>>);
|
|
184
|
+
|
|
185
|
+
export type AnonymousViewFn<
|
|
186
|
+
S extends UntypedSchemaDef,
|
|
187
|
+
Params extends ParamsObj,
|
|
188
|
+
Ret extends ViewReturnTypeBuilder,
|
|
189
|
+
> =
|
|
190
|
+
| ((ctx: AnonymousViewCtx<S>, params: InferTypeOfRow<Params>) => Infer<Ret>)
|
|
191
|
+
| ((
|
|
192
|
+
ctx: AnonymousViewCtx<S>,
|
|
193
|
+
params: InferTypeOfRow<Params>
|
|
194
|
+
) => RowTypedQuery<FlattenedArray<Infer<Ret>>, ExtractArrayProduct<Ret>>);
|
|
195
|
+
|
|
196
|
+
export type ViewReturnTypeBuilder =
|
|
197
|
+
| TypeBuilder<
|
|
198
|
+
readonly object[],
|
|
199
|
+
{ tag: 'Array'; value: AlgebraicTypeVariants.Product }
|
|
200
|
+
>
|
|
201
|
+
| TypeBuilder<
|
|
202
|
+
object | undefined,
|
|
203
|
+
OptionAlgebraicType<AlgebraicTypeVariants.Product>
|
|
204
|
+
>;
|
|
205
|
+
|
|
206
|
+
export function registerView<
|
|
207
|
+
S extends UntypedSchemaDef,
|
|
208
|
+
const Anonymous extends boolean,
|
|
209
|
+
Params extends ParamsObj,
|
|
210
|
+
Ret extends ViewReturnTypeBuilder,
|
|
211
|
+
>(
|
|
212
|
+
ctx: SchemaInner,
|
|
213
|
+
opts: ViewOpts,
|
|
214
|
+
exportName: string,
|
|
215
|
+
anon: Anonymous,
|
|
216
|
+
params: Params,
|
|
217
|
+
ret: Ret,
|
|
218
|
+
fn: Anonymous extends true
|
|
219
|
+
? AnonymousViewFn<S, Params, Ret>
|
|
220
|
+
: ViewFn<S, Params, Ret>
|
|
221
|
+
) {
|
|
222
|
+
ctx.defineFunction(exportName);
|
|
223
|
+
const paramsBuilder = new RowBuilder(params, toPascalCase(exportName));
|
|
224
|
+
|
|
225
|
+
// Register return types if they are product types
|
|
226
|
+
let returnType = ctx.registerTypesRecursively(ret).algebraicType;
|
|
227
|
+
|
|
228
|
+
const { typespace } = ctx;
|
|
229
|
+
|
|
230
|
+
const { value: paramType } = ctx.resolveType(
|
|
231
|
+
ctx.registerTypesRecursively(paramsBuilder)
|
|
232
|
+
);
|
|
233
|
+
|
|
234
|
+
ctx.moduleDef.views.push({
|
|
235
|
+
sourceName: exportName,
|
|
236
|
+
index: (anon ? ctx.anonViews : ctx.views).length,
|
|
237
|
+
isPublic: opts.public,
|
|
238
|
+
isAnonymous: anon,
|
|
239
|
+
params: paramType,
|
|
240
|
+
returnType,
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
// Runtime counterpart to `ValidateViewPrimaryKey`: the type-level check gives
|
|
244
|
+
// users an early diagnostic in normal code, but this still protects dynamic
|
|
245
|
+
// or widened builders and is the source of the raw module-def metadata.
|
|
246
|
+
const primaryKeyColumns = viewPrimaryKeyColumns(ret);
|
|
247
|
+
if (primaryKeyColumns.length > 1) {
|
|
248
|
+
throw new TypeError(
|
|
249
|
+
`View '${exportName}' can have at most one primaryKey() column on its returned row type; found ${primaryKeyColumns.join(', ')}`
|
|
250
|
+
);
|
|
251
|
+
}
|
|
252
|
+
if (primaryKeyColumns.length === 1) {
|
|
253
|
+
ctx.moduleDef.viewPrimaryKeys.push({
|
|
254
|
+
viewSourceName: exportName,
|
|
255
|
+
columns: primaryKeyColumns,
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
if (opts.name != null) {
|
|
260
|
+
ctx.moduleDef.explicitNames.entries.push({
|
|
261
|
+
tag: 'Function',
|
|
262
|
+
value: {
|
|
263
|
+
sourceName: exportName,
|
|
264
|
+
canonicalName: opts.name,
|
|
265
|
+
},
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// If it is an option, we wrap the function to make the return look like an array.
|
|
270
|
+
if (returnType.tag == 'Sum') {
|
|
271
|
+
const originalFn = fn;
|
|
272
|
+
fn = ((ctx: ViewCtx<S>, args: InferTypeOfRow<Params>) => {
|
|
273
|
+
const ret = originalFn(ctx, args);
|
|
274
|
+
return ret == null ? [] : [ret];
|
|
275
|
+
}) as any;
|
|
276
|
+
returnType = AlgebraicType.Array(
|
|
277
|
+
returnType.value.variants[0].algebraicType
|
|
278
|
+
);
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
(anon ? ctx.anonViews : ctx.views).push({
|
|
282
|
+
fn,
|
|
283
|
+
deserializeParams: ProductType.makeDeserializer(paramType, typespace),
|
|
284
|
+
serializeReturn: AlgebraicType.makeSerializer(returnType, typespace),
|
|
285
|
+
returnTypeBaseSize: bsatnBaseSize(typespace, returnType),
|
|
286
|
+
});
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
// Inspect the returned row builder and collect the column property names marked
|
|
290
|
+
// with `.primaryKey()`. These names are the TypeScript row-builder keys, which
|
|
291
|
+
// are also the raw column names in the module definition emitted by the TS SDK.
|
|
292
|
+
function viewPrimaryKeyColumns(ret: ViewReturnTypeBuilder): string[] {
|
|
293
|
+
const row = viewReturnRow(ret);
|
|
294
|
+
if (row == null) {
|
|
295
|
+
return [];
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
return Object.entries(row.row)
|
|
299
|
+
.filter(
|
|
300
|
+
(
|
|
301
|
+
entry
|
|
302
|
+
): entry is [string, ColumnBuilder<any, any, ColumnMetadata<any>>] =>
|
|
303
|
+
entry[1].columnMetadata.isPrimaryKey === true
|
|
304
|
+
)
|
|
305
|
+
.map(([name]) => name);
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
// Views can return either `array(row(...))` or `option(row(...))`. The primary
|
|
309
|
+
// key marker lives on the inner `RowBuilder`, so unwrap those two supported
|
|
310
|
+
// shapes and ignore anything else.
|
|
311
|
+
function viewReturnRow(
|
|
312
|
+
ret: ViewReturnTypeBuilder
|
|
313
|
+
): RowBuilder<any> | undefined {
|
|
314
|
+
if (ret instanceof ArrayBuilder && ret.element instanceof RowBuilder) {
|
|
315
|
+
return ret.element;
|
|
316
|
+
}
|
|
317
|
+
if (ret instanceof OptionBuilder && ret.value instanceof RowBuilder) {
|
|
318
|
+
return ret.value;
|
|
319
|
+
}
|
|
320
|
+
return undefined;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
type ViewInfo<F> = {
|
|
324
|
+
fn: F;
|
|
325
|
+
deserializeParams: Deserializer<any>;
|
|
326
|
+
serializeReturn: Serializer<any>;
|
|
327
|
+
returnTypeBaseSize: number;
|
|
328
|
+
};
|
|
329
|
+
|
|
330
|
+
export type Views = ViewInfo<ViewFn<any, any, any>>[];
|
|
331
|
+
export type AnonViews = ViewInfo<AnonymousViewFn<any, any, any>>[];
|
|
332
|
+
|
|
333
|
+
// A helper to get the product type out of a type builder.
|
|
334
|
+
// This is only non-never if the type builder is an array.
|
|
335
|
+
type ExtractArrayProduct<T extends TypeBuilder<any, any>> =
|
|
336
|
+
InferSpacetimeTypeOfTypeBuilder<T> extends { tag: 'Array'; value: infer V }
|
|
337
|
+
? V extends { tag: 'Product'; value: infer P }
|
|
338
|
+
? P
|
|
339
|
+
: never
|
|
340
|
+
: never;
|