From 652982712640a33e8dddfbe8a2e137630d23f460 Mon Sep 17 00:00:00 2001 From: = Date: Sun, 2 Nov 2025 21:00:43 -0500 Subject: [PATCH 01/49] Big prototype --- .../examples/quickstart-chat/src/App.tsx | 3 +- .../src/module_bindings/index.ts | 6 +- .../src/module_bindings/user_table.ts | 8 +- .../src/react/SpacetimeDBProvider.ts | 96 +++- .../src/react/connection_state.ts | 12 + crates/bindings-typescript/src/react/index.ts | 1 + .../src/react/useReducer.ts | 17 + .../src/react/useSpacetimeDB.ts | 14 +- .../bindings-typescript/src/react/useTable.ts | 34 +- .../src/sdk/client_api/index.ts | 2 +- .../src/sdk/client_cache.ts | 105 +++- .../src/sdk/db_connection_builder.ts | 48 +- .../src/sdk/db_connection_impl.ts | 276 ++++++---- .../bindings-typescript/src/sdk/db_context.ts | 24 +- crates/bindings-typescript/src/sdk/db_view.ts | 14 + crates/bindings-typescript/src/sdk/event.ts | 5 +- .../src/sdk/event_context.ts | 40 +- crates/bindings-typescript/src/sdk/index.ts | 4 +- .../src/sdk/reducer_event.ts | 5 +- .../src/sdk/reducer_handle.ts | 12 + .../bindings-typescript/src/sdk/reducers.ts | 25 + .../src/sdk/set_reducer_flags.ts | 3 + .../src/sdk/spacetime_module.ts | 19 +- .../src/sdk/subscription_builder_impl.ts | 57 +-- .../src/sdk/table_cache.ts | 113 +++-- .../src/sdk/table_handle.ts | 80 ++- .../bindings-typescript/src/server/db_view.ts | 25 + .../bindings-typescript/src/server/index.ts | 2 + .../bindings-typescript/src/server/indexes.ts | 53 +- .../src/server/reducers.ts | 122 ++++- .../bindings-typescript/src/server/runtime.ts | 44 +- .../bindings-typescript/src/server/schema.ts | 30 +- .../bindings-typescript/src/server/table.ts | 37 +- .../src/server/type_util.ts | 12 + .../bindings-typescript/test-app/src/App.tsx | 4 +- .../test-app/src/module_bindings/index.ts | 473 +++++++++++------- .../src/module_bindings/player_table.ts | 10 +- .../src/module_bindings/user_table.ts | 6 +- .../src/module_bindings/counter_table.ts | 6 +- .../src/module_bindings/offline_user_table.ts | 6 +- .../src/module_bindings/user_table.ts | 6 +- crates/codegen/src/typescript.rs | 13 +- 42 files changed, 1276 insertions(+), 596 deletions(-) create mode 100644 crates/bindings-typescript/src/react/connection_state.ts create mode 100644 crates/bindings-typescript/src/react/useReducer.ts create mode 100644 crates/bindings-typescript/src/sdk/db_view.ts create mode 100644 crates/bindings-typescript/src/sdk/reducer_handle.ts create mode 100644 crates/bindings-typescript/src/sdk/reducers.ts create mode 100644 crates/bindings-typescript/src/sdk/set_reducer_flags.ts create mode 100644 crates/bindings-typescript/src/server/db_view.ts diff --git a/crates/bindings-typescript/examples/quickstart-chat/src/App.tsx b/crates/bindings-typescript/examples/quickstart-chat/src/App.tsx index 78ae2da57a0..0fa172b20ab 100644 --- a/crates/bindings-typescript/examples/quickstart-chat/src/App.tsx +++ b/crates/bindings-typescript/examples/quickstart-chat/src/App.tsx @@ -16,8 +16,9 @@ function App() { const [settingName, setSettingName] = useState(false); const [systemMessages, setSystemMessages] = useState([] as Message[]); const [newMessage, setNewMessage] = useState(''); - const conn = useSpacetimeDB(); + + conn.setReducerFlags() const { identity, isActive: connected } = conn; // Subscribe to all messages in the chat diff --git a/crates/bindings-typescript/examples/quickstart-chat/src/module_bindings/index.ts b/crates/bindings-typescript/examples/quickstart-chat/src/module_bindings/index.ts index f30b1c1253b..b104c9eced0 100644 --- a/crates/bindings-typescript/examples/quickstart-chat/src/module_bindings/index.ts +++ b/crates/bindings-typescript/examples/quickstart-chat/src/module_bindings/index.ts @@ -61,9 +61,9 @@ const REMOTE_MODULE = { user: { tableName: 'user' as const, rowType: User.getTypeScriptAlgebraicType(), - primaryKey: 'identity', + primaryKey: 'identity' as const, primaryKeyInfo: { - colName: 'identity', + colName: 'identity' as const, colType: ( User.getTypeScriptAlgebraicType() as __AlgebraicTypeVariants.Product ).value.elements[0].algebraicType, @@ -119,7 +119,7 @@ const REMOTE_MODULE = { setReducerFlagsConstructor: () => { return new SetReducerFlags(); }, -}; +} satisfies RemoteModule; // A type representing all the possible variants of a reducer. export type Reducer = diff --git a/crates/bindings-typescript/examples/quickstart-chat/src/module_bindings/user_table.ts b/crates/bindings-typescript/examples/quickstart-chat/src/module_bindings/user_table.ts index 85687a99eff..9b35746a2ab 100644 --- a/crates/bindings-typescript/examples/quickstart-chat/src/module_bindings/user_table.ts +++ b/crates/bindings-typescript/examples/quickstart-chat/src/module_bindings/user_table.ts @@ -47,7 +47,7 @@ declare type __keep = [EventContext, Reducer, RemoteReducers, RemoteTables]; * like `ctx.db.user.on_insert(...)`. */ export class UserTableHandle - implements __TableHandle + extends ClientTable { // phantom type to track the table name readonly tableName!: TableName; @@ -76,11 +76,11 @@ export class UserTableHandle * Get a handle on the `identity` unique index on the table `user`. */ identity = { - // Find the subscribed row whose `identity` column value is equal to `col_val`, + // Find the subscribed row whose `identity` column value is equal to `colVal`, // if such a row is present in the client cache. - find: (col_val: __Identity): User | undefined => { + find: (colVal: __Identity): User | undefined => { for (let row of this.tableCache.iter()) { - if (__deepEqual(row.identity, col_val)) { + if (__deepEqual(row.identity, colVal)) { return row; } } diff --git a/crates/bindings-typescript/src/react/SpacetimeDBProvider.ts b/crates/bindings-typescript/src/react/SpacetimeDBProvider.ts index 0af29acf067..6899bed3610 100644 --- a/crates/bindings-typescript/src/react/SpacetimeDBProvider.ts +++ b/crates/bindings-typescript/src/react/SpacetimeDBProvider.ts @@ -1,38 +1,96 @@ import { DbConnectionBuilder, type DbConnectionImpl, + type ErrorContextInterface, + type SubscriptionEventContextInterface, } from '../sdk/db_connection_impl'; import * as React from 'react'; import { SpacetimeDBContext } from './useSpacetimeDB'; +import type { ConnectionState } from './connection_state'; +import { ConnectionId } from '../lib/connection_id'; export interface SpacetimeDBProviderProps< DbConnection extends DbConnectionImpl, - ErrorContext, - SubscriptionEventContext, + ErrorContext extends ErrorContextInterface, + SubscriptionEventContext extends SubscriptionEventContextInterface, > { - connectionBuilder: DbConnectionBuilder< - DbConnection, - ErrorContext, - SubscriptionEventContext - >; + connectionBuilder: DbConnectionBuilder; children?: React.ReactNode; } export function SpacetimeDBProvider< DbConnection extends DbConnectionImpl, - ErrorContext, - SubscriptionEventContext, ->({ - connectionBuilder, - children, -}: SpacetimeDBProviderProps< - DbConnection, - ErrorContext, - SubscriptionEventContext ->): React.JSX.Element { + ErrorContext extends ErrorContextInterface, + SubscriptionEventContext extends SubscriptionEventContextInterface, +>({ connectionBuilder, children }: SpacetimeDBProviderProps) { + // Holds the imperative connection instance when (and only when) we’re on the client. + const connRef = React.useRef(null); + const getConnection = React.useCallback(() => connRef.current, []); + + const [state, setState] = React.useState>({ + isActive: false, + identity: undefined, + token: undefined, + connectionId: ConnectionId.random(), + connectionError: undefined, + getConnection, + }); + + // Build on the client only; useEffect won't run during SSR. + React.useEffect(() => { + // Register callback for onConnect to update state + const onConnect = (conn: DbConnectionImpl) => { + setState(s => ({ + ...s, + isActive: conn.isActive, + identity: conn.identity, + token: conn.token, + connectionId: conn.connectionId, + })); + }; + const onDisconnect = (ctx: ErrorContextInterface) => { + setState(s => ({ + ...s, + isActive: ctx.isActive, + })); + }; + const onConnectError = (ctx: ErrorContextInterface, err: Error) => { + setState(s => ({ + ...s, + isActive: ctx.isActive, + connectionError: err, + })); + }; + connectionBuilder.onConnect(onConnect); + connectionBuilder.onDisconnect(onDisconnect); + connectionBuilder.onConnectError(onConnectError); + + const conn = connRef.current!; + setState(s => ({ + ...s, + isActive: conn.isActive, + identity: conn.identity, + token: conn.token, + connectionId: conn.connectionId, + })); + + // Lazily build once + if (!connRef.current) { + connRef.current = connectionBuilder.build(); + } + + return () => { + connRef.current?.removeOnConnect(onConnect); + connRef.current?.removeOnDisconnect(onDisconnect); + connRef.current?.removeOnConnectError(onConnectError); + connRef.current?.disconnect(); + connRef.current = null; + }; + }, [connectionBuilder]); + return React.createElement( SpacetimeDBContext.Provider, - { value: connectionBuilder.build() }, // May need to modify this to do it lazily in server-side rendering + { value: state }, children ); -} + } \ No newline at end of file diff --git a/crates/bindings-typescript/src/react/connection_state.ts b/crates/bindings-typescript/src/react/connection_state.ts new file mode 100644 index 00000000000..4f45c6b902e --- /dev/null +++ b/crates/bindings-typescript/src/react/connection_state.ts @@ -0,0 +1,12 @@ +import type { ConnectionId } from "../lib/connection_id"; +import type { Identity } from "../lib/identity"; +import type { DbConnectionImpl } from "../sdk/db_connection_impl"; + +export type ConnectionState = { + isActive: boolean; + identity?: Identity; + token?: string; + connectionId: ConnectionId; + connectionError?: Error; + getConnection(): DbConnection | null; +}; diff --git a/crates/bindings-typescript/src/react/index.ts b/crates/bindings-typescript/src/react/index.ts index b99fe7f78f4..6bcf01a6a28 100644 --- a/crates/bindings-typescript/src/react/index.ts +++ b/crates/bindings-typescript/src/react/index.ts @@ -1,3 +1,4 @@ export * from './SpacetimeDBProvider.ts'; export { useSpacetimeDB } from './useSpacetimeDB.ts'; export { useTable, where, eq } from './useTable.ts'; +export { useReducer } from './useReducer.ts'; diff --git a/crates/bindings-typescript/src/react/useReducer.ts b/crates/bindings-typescript/src/react/useReducer.ts new file mode 100644 index 00000000000..dab84320ed2 --- /dev/null +++ b/crates/bindings-typescript/src/react/useReducer.ts @@ -0,0 +1,17 @@ +import type { DbConnectionImpl } from "../sdk/db_connection_impl"; +import type { ReducerNamesFromReducers } from "../sdk/reducer_handle"; +import { useSpacetimeDB } from "./useSpacetimeDB"; + +// export function useReducer< +// DbConnection extends DbConnectionImpl, +// ReducerName extends ReducerNamesFromReducers = ReducerNamesFromReducers< +// DbConnection['reducers'] +// >, +// ReducerType = DbConnection['reducers'][ReducerName & keyof DbConnection['reducers']] +// >( +// reducerName: ReducerName, +// ): ReducerType { +// const connectionState = useSpacetimeDB(); +// const connection = connectionState.getConnection()!; +// return connection.reducers[reducerName as keyof typeof connection.reducers]; +// } \ No newline at end of file diff --git a/crates/bindings-typescript/src/react/useSpacetimeDB.ts b/crates/bindings-typescript/src/react/useSpacetimeDB.ts index 505c8143742..17f180b9878 100644 --- a/crates/bindings-typescript/src/react/useSpacetimeDB.ts +++ b/crates/bindings-typescript/src/react/useSpacetimeDB.ts @@ -1,19 +1,17 @@ -import { createContext, useContext, type Context } from 'react'; +import { createContext, useContext } from 'react'; import type { DbConnectionImpl } from '../sdk/db_connection_impl'; +import type { ConnectionState } from './connection_state'; -export const SpacetimeDBContext: Context = - createContext(undefined); +export const SpacetimeDBContext = createContext | undefined>(undefined); // Throws an error if used outside of a SpacetimeDBProvider // Error is caught by other hooks like useTable so they can provide better error messages -export function useSpacetimeDB< - DbConnection extends DbConnectionImpl, ->(): DbConnection { - const context = useContext(SpacetimeDBContext) as DbConnection | undefined; +export function useSpacetimeDB(): ConnectionState { + const context = useContext(SpacetimeDBContext) as ConnectionState | undefined; if (!context) { throw new Error( 'useSpacetimeDB must be used within a SpacetimeDBProvider component. Did you forget to add a `SpacetimeDBProvider` to your component tree?' ); } return context; -} +} \ No newline at end of file diff --git a/crates/bindings-typescript/src/react/useTable.ts b/crates/bindings-typescript/src/react/useTable.ts index 78f675f6e31..5c81fdf2ed4 100644 --- a/crates/bindings-typescript/src/react/useTable.ts +++ b/crates/bindings-typescript/src/react/useTable.ts @@ -8,6 +8,7 @@ import { import { useSpacetimeDB } from './useSpacetimeDB'; import { DbConnectionImpl, TableCache } from '../sdk/db_connection_impl'; import type { TableNamesFromDb } from '../sdk/table_handle'; +import type { ConnectionState } from './connection_state'; export interface UseQueryCallbacks { onInsert?: (row: RowType) => void; @@ -292,9 +293,9 @@ export function useTable< | undefined; } const [subscribeApplied, setSubscribeApplied] = useState(false); - let spacetime: DbConnection | undefined; + let connectionState: ConnectionState | undefined; try { - spacetime = useSpacetimeDB(); + connectionState = useSpacetimeDB(); } catch { throw new Error( 'Could not find SpacetimeDB client! Did you forget to add a ' + @@ -302,7 +303,6 @@ export function useTable< 'under a `SpacetimeDBProvider` component.' ); } - const client = spacetime; const query = `SELECT * FROM ${tableName}` + @@ -314,8 +314,12 @@ export function useTable< const whereKey = whereClause ? toString(whereClause) : ''; const computeSnapshot = useCallback((): Snapshot => { - const table = client.db[ - tableName as keyof typeof client.db + const connection = connectionState.getConnection(); + if (!connection) { + return { rows: [], state: 'loading' }; + } + const table = connection.db[ + tableName as keyof typeof connection.db ] as unknown as TableCache; const result: readonly RowType[] = whereClause ? table.iter().filter(row => evaluate(whereClause, row)) @@ -325,11 +329,12 @@ export function useTable< state: subscribeApplied ? 'ready' : 'loading', }; // eslint-disable-next-line react-hooks/exhaustive-deps - }, [client, tableName, whereKey, subscribeApplied]); + }, [connectionState, tableName, whereKey, subscribeApplied]); useEffect(() => { - if (client.isActive) { - const cancel = client + const connection = connectionState.getConnection()!; + if (connectionState.isActive && connection) { + const cancel = connection .subscriptionBuilder() .onApplied(() => { setSubscribeApplied(true); @@ -339,7 +344,7 @@ export function useTable< cancel.unsubscribe(); }; } - }, [query, client.isActive, client]); + }, [query, connectionState.isActive, connectionState]); const subscribe = useCallback( (onStoreChange: () => void) => { @@ -400,8 +405,13 @@ export function useTable< } }; - const table = client.db[ - tableName as keyof typeof client.db + const connection = connectionState.getConnection(); + if (!connection) { + return () => {}; + } + + const table = connection.db[ + tableName as keyof typeof connection.db ] as unknown as TableCache; table.onInsert(onInsert); table.onDelete(onDelete); @@ -415,7 +425,7 @@ export function useTable< }, // eslint-disable-next-line react-hooks/exhaustive-deps [ - client, + connectionState, tableName, whereKey, callbacks?.onDelete, diff --git a/crates/bindings-typescript/src/sdk/client_api/index.ts b/crates/bindings-typescript/src/sdk/client_api/index.ts index 5e3cc809133..2441d1d8732 100644 --- a/crates/bindings-typescript/src/sdk/client_api/index.ts +++ b/crates/bindings-typescript/src/sdk/client_api/index.ts @@ -112,7 +112,7 @@ const REMOTE_MODULE = { // SDK, but if in the future we wanted to create a class this would be // necessary because classes have methods, so we'll keep it. eventContextConstructor: ( - imp: __DbConnectionImpl, + imp: __DbConnectionImpl ) => { return { diff --git a/crates/bindings-typescript/src/sdk/client_cache.ts b/crates/bindings-typescript/src/sdk/client_cache.ts index 81beec64ba5..40b8c98bc08 100644 --- a/crates/bindings-typescript/src/sdk/client_cache.ts +++ b/crates/bindings-typescript/src/sdk/client_cache.ts @@ -1,47 +1,100 @@ -import type { TableRuntimeTypeInfo } from './spacetime_module.ts'; +import type { UntypedSchemaDef } from '../server/schema.ts'; +import type { UntypedTableDef } from '../server/table.ts'; +import type { UntypedReducersDef } from './reducers.ts'; import { TableCache } from './table_cache.ts'; -export class ClientCache { +type TableName = + [SchemaDef] extends [UntypedSchemaDef] ? SchemaDef['tables'][number]['name'] : string; + +export type TableDefForTableName = + [SchemaDef] extends [UntypedSchemaDef] + ? Extract + : UntypedTableDef; + +type TableCacheForTableName< + SchemaDef extends UntypedSchemaDef, + Reducers extends UntypedReducersDef, + N +> = TableCache>; + +/** + * This is a helper class that provides a mapping from table names to their corresponding TableCache instances + * while preserving the correspondence between the key and value type. + */ +class TableMap { + private readonly map: Map>> = new Map(); + + get>(key: K): TableCacheForTableName | undefined { + // Cast required: a Map can't refine the union to the exact K-specific member on get(key: K). + return this.map.get(key) as TableCacheForTableName | undefined; + } + + set>(key: K, value: TableCacheForTableName): this { + this.map.set(key, value); + return this; + } + + has(key: TableName): boolean { + return this.map.has(key); + } + + delete(key: TableName): boolean { + return this.map.delete(key); + } + + // optional: iteration stays broadly typed (cannot express per-key relation here) + keys(): IterableIterator { return this.map.keys(); } + values(): IterableIterator>> { return this.map.values(); } + entries(): IterableIterator<[string, TableCacheForTableName>]> { return this.map.entries(); } + [Symbol.iterator]() { return this.entries(); } +} + +/** + * ClientCache maintains a cache of TableCache instances for each table in the database. + * It provides methods to get or create TableCache instances by table name, + * ensuring type safety based on the provided SchemaDef. + */ +export class ClientCache { /** * The tables in the database. */ - tables: Map>; - - constructor() { - this.tables = new Map(); - } + readonly tables = new TableMap(); /** * Returns the table with the given name. - * @param name The name of the table. - * @returns The table + * - If SchemaDef is a concrete schema, `name` is constrained to known table names, + * and the return type matches that table. + * - If SchemaDef is undefined, `name` is string and the return type is untyped. */ - getTable>( - name: string - ): TableCache { + getTable>(name: N): TableCacheForTableName { const table = this.tables.get(name); - - // ! This should not happen as the table should be available but an exception is thrown just in case. if (!table) { console.error( 'The table has not been registered for this client. Please register the table before using it. If you have registered global tables using the SpacetimeDBClient.registerTables() or `registerTable()` method, please make sure that is executed first!' ); - throw new Error(`Table ${name} does not exist`); + throw new Error(`Table ${String(name)} does not exist`); } - return table; } - getOrCreateTable>( - tableTypeInfo: TableRuntimeTypeInfo - ): TableCache { - let table: TableCache; - if (!this.tables.has(tableTypeInfo.tableName)) { - table = new TableCache(tableTypeInfo); - this.tables.set(tableTypeInfo.tableName, table); - } else { - table = this.tables.get(tableTypeInfo.tableName)!; + /** + * Returns the table with the given name, creating it if needed. + * - Typed mode: `tableTypeInfo.tableName` is constrained to known names and + * the return type matches that table. + * - Untyped mode: accepts any string and returns an untyped TableCache. + */ + getOrCreateTable>( + tableDef: TableDefForTableName + ): TableCacheForTableName { + const name = tableDef.name as N; + + let table = this.tables.get(name); + if (table) { + return table; } - return table; + + const newTable = new TableCache>(tableDef); + this.tables.set(name, newTable); + return newTable; } } diff --git a/crates/bindings-typescript/src/sdk/db_connection_builder.ts b/crates/bindings-typescript/src/sdk/db_connection_builder.ts index a891dd3cb6b..b585cf35564 100644 --- a/crates/bindings-typescript/src/sdk/db_connection_builder.ts +++ b/crates/bindings-typescript/src/sdk/db_connection_builder.ts @@ -1,17 +1,19 @@ import { DbConnectionImpl, type ConnectionEvent } from './db_connection_impl'; import { EventEmitter } from './event_emitter'; -import type { Identity } from '../'; -import type RemoteModule from './spacetime_module'; +import type { DbConnectionConfig, ErrorContextInterface, Identity, SubscriptionEventContextInterface } from '../'; +import { type RemoteModule, type RemoteModule2 } from './spacetime_module'; import { ensureMinimumVersionOrThrow } from './version'; import { WebsocketDecompressAdapter } from './websocket_decompress_adapter'; +import type { UntypedSchemaDef } from '../server/schema'; +import type { UntypedReducersDef } from './reducers'; /** * The database client connection to a SpacetimeDB server. */ export class DbConnectionBuilder< - DbConnection, - ErrorContext, - _SubscriptionEventContext, + SchemaDef extends UntypedSchemaDef, + Reducers extends UntypedReducersDef, + DbConnection extends DbConnectionImpl, > { #uri?: URL; #nameOrAddress?: string; @@ -32,8 +34,8 @@ export class DbConnectionBuilder< * @param dbConnectionConstructor The constructor to use to create a new `DbConnection`. */ constructor( - private remoteModule: RemoteModule, - private dbConnectionConstructor: (imp: DbConnectionImpl) => DbConnection + private remoteModule: RemoteModule2, + private dbConnectionCtor: (config: DbConnectionConfig) => DbConnection ) { this.#createWSFn = WebsocketDecompressAdapter.createWebSocketFn; } @@ -179,7 +181,7 @@ export class DbConnectionBuilder< * }); * ``` */ - onConnectError(callback: (ctx: ErrorContext, error: Error) => void): this { + onConnectError(callback: (ctx: ErrorContextInterface, error: Error) => void): this { this.#emitter.on('connectError', callback); return this; } @@ -211,7 +213,7 @@ export class DbConnectionBuilder< * @throws {Error} Throws an error if called multiple times on the same `DbConnectionBuilder`. */ onDisconnect( - callback: (ctx: ErrorContext, error?: Error | undefined) => void + callback: (ctx: ErrorContextInterface, error?: Error | undefined) => void ): this { this.#emitter.on('disconnect', callback); return this; @@ -231,7 +233,7 @@ export class DbConnectionBuilder< * DbConnection.builder().withUri(host).withModuleName(name_or_address).withToken(auth_token).build(); * ``` */ - build(): DbConnection { + build(): DbConnectionImpl { if (!this.#uri) { throw new Error('URI is required to connect to SpacetimeDB'); } @@ -245,19 +247,17 @@ export class DbConnectionBuilder< // Ideally, it would be a compile time error, but I'm not sure how to accomplish that. ensureMinimumVersionOrThrow(this.remoteModule.versionInfo?.cliVersion); - return this.dbConnectionConstructor( - new DbConnectionImpl({ - uri: this.#uri, - nameOrAddress: this.#nameOrAddress, - identity: this.#identity, - token: this.#token, - emitter: this.#emitter, - compression: this.#compression, - lightMode: this.#lightMode, - confirmedReads: this.#confirmedReads, - createWSFn: this.#createWSFn, - remoteModule: this.remoteModule, - }) - ); + return this.dbConnectionCtor({ + uri: this.#uri, + nameOrAddress: this.#nameOrAddress, + identity: this.#identity, + token: this.#token, + emitter: this.#emitter, + compression: this.#compression, + lightMode: this.#lightMode, + confirmedReads: this.#confirmedReads, + createWSFn: this.#createWSFn, + remoteModule: this.remoteModule, + }) } } diff --git a/crates/bindings-typescript/src/sdk/db_connection_impl.ts b/crates/bindings-typescript/src/sdk/db_connection_impl.ts index 16720d8837b..64c7b435554 100644 --- a/crates/bindings-typescript/src/sdk/db_connection_impl.ts +++ b/crates/bindings-typescript/src/sdk/db_connection_impl.ts @@ -1,4 +1,4 @@ -import { ConnectionId } from '../'; +import { ConnectionId, ProductType } from '../'; import { AlgebraicType, type AlgebraicTypeVariants, @@ -22,6 +22,7 @@ import { type EventContextInterface, type ReducerEventContextInterface, type SubscriptionEventContextInterface, + type UntypedEventContext, } from './event_context.ts'; import { EventEmitter } from './event_emitter.ts'; import { decompress } from './decompress.ts'; @@ -33,7 +34,7 @@ import type { UnsubscribeAppliedMessage, } from './message_types.ts'; import type { ReducerEvent } from './reducer_event.ts'; -import type RemoteModule from './spacetime_module.ts'; +import { type RemoteModule, type RemoteModule2 } from './spacetime_module.ts'; import { TableCache, type Operation, @@ -49,8 +50,13 @@ import { type SubscribeEvent, } from './subscription_builder_impl.ts'; import { stdbLogger } from './logger.ts'; -import { type ReducerRuntimeTypeInfo } from './spacetime_module.ts'; import { fromByteArray } from 'base64-js'; +import type { ReducersView, SetReducerFlags, UntypedReducersDef } from './reducers.ts'; +import type { UntypedSchemaDef } from '../server/schema.ts'; +import type { DbView } from '../server/db_view.ts'; +import type { RowType, UntypedTableDef } from '../server/table.ts'; +import type { CamelCase } from '../server/type_util.ts'; +import { toCamelCase } from '../server/runtime.ts'; export { DbConnectionBuilder, SubscriptionBuilderImpl, TableCache, type Event }; @@ -66,12 +72,13 @@ export type { export type ConnectionEvent = 'connect' | 'disconnect' | 'connectError'; export type CallReducerFlags = 'FullUpdate' | 'NoSuccessNotify'; -type ReducerEventCallback = ( - ctx: ReducerEventContextInterface, +type ReducerEventCallback = ( + ctx: ReducerEventContextInterface, ...args: ReducerArgs ) => void; -type SubscriptionEventCallback = ( - ctx: SubscriptionEventContextInterface + +type SubscriptionEventCallback = ( + ctx: SubscriptionEventContextInterface, ) => void; function callReducerFlagsToNumber(flags: CallReducerFlags): number { @@ -83,25 +90,23 @@ function callReducerFlagsToNumber(flags: CallReducerFlags): number { } } -type DbConnectionConfig = { +export type DbConnectionConfig = { uri: URL; nameOrAddress: string; identity?: Identity; token?: string; emitter: EventEmitter; - remoteModule: RemoteModule; createWSFn: typeof WebsocketDecompressAdapter.createWebSocketFn; compression: 'gzip' | 'none'; lightMode: boolean; confirmedReads?: boolean; + remoteModule: RemoteModule2; }; export class DbConnectionImpl< - DBView = any, - Reducers = any, - SetReducerFlags = any, -> implements DbContext -{ + SchemaDef extends UntypedSchemaDef, + ReducersDef extends UntypedReducersDef, +> implements DbContext { /** * Whether or not the connection is active. */ @@ -121,20 +126,20 @@ export class DbConnectionImpl< * The accessor field to access the tables in the database and associated * callback functions. */ - db: DBView; + db: DbView; /** * The accessor field to access the reducers in the database and associated * callback functions. */ - reducers: Reducers; + reducers: ReducersView; /** * The accessor field to access functions related to setting flags on * reducers regarding how the server should handle the reducer call and * the events that it sends back to the client. */ - setReducerFlags: SetReducerFlags; + setReducerFlags: SetReducerFlags; /** * The `ConnectionId` of the connection to to the database. @@ -144,18 +149,19 @@ export class DbConnectionImpl< // These fields are meant to be strictly private. #queryId = 0; #emitter: EventEmitter; - #reducerEmitter: EventEmitter = + #reducerEmitter: EventEmitter> = new EventEmitter(); - #onApplied?: SubscriptionEventCallback; - #remoteModule: RemoteModule; + #onApplied?: SubscriptionEventCallback; #messageQueue = Promise.resolve(); - #subscriptionManager = new SubscriptionManager(); + #subscriptionManager = new SubscriptionManager(); + #remoteModule: RemoteModule2; + #callReducerFlags = new Map(); // These fields are not part of the public API, but in a pinch you // could use JavaScript to access them by bypassing TypeScript's // private fields. // We use them in testing. - private clientCache: ClientCache; + private clientCache: ClientCache; private ws?: WebsocketDecompressAdapter | WebsocketTestAdapter; private wsPromise: Promise< WebsocketDecompressAdapter | WebsocketTestAdapter | undefined @@ -172,7 +178,7 @@ export class DbConnectionImpl< compression, lightMode, confirmedReads, - }: DbConnectionConfig) { + }: DbConnectionConfig) { stdbLogger('info', 'Connecting to SpacetimeDB WS...'); // We use .toString() here because some versions of React Native contain a bug where the URL constructor @@ -192,13 +198,10 @@ export class DbConnectionImpl< const connectionId = this.connectionId.toHexString(); url.searchParams.set('connection_id', connectionId); - this.clientCache = new ClientCache(); - this.db = this.#remoteModule.dbViewConstructor(this); - this.setReducerFlags = this.#remoteModule.setReducerFlagsConstructor(); - this.reducers = this.#remoteModule.reducersConstructor( - this, - this.setReducerFlags - ); + this.clientCache = new ClientCache(); + this.db = this.#makeDbView(remoteModule.tables); + this.reducers = this.#makeReducers(remoteModule.reducers); + this.setReducerFlags = this.#makeSetReducerFlags(remoteModule.reducers); this.wsPromise = createWSFn({ url, @@ -236,6 +239,74 @@ export class DbConnectionImpl< return queryId; }; + #makeDbView(def: SchemaDef): DbView { + const view = Object.create(null) as DbView; + + for (const tbl of def.tables) { + // DbView uses this name verbatim + const key = tbl.accessorName; + Object.defineProperty(view, key, { + enumerable: true, + configurable: false, + get: () => { + return this.clientCache.getOrCreateTable(tbl); + }, + }); + } + + return view; + } + + #makeReducers(def: ReducersDef): ReducersView { + const out: Record = {}; + + for (const reducer of def.reducers) { + const key = toCamelCase(reducer.name); + + (out as any)[key] = (params: typeof reducer.params) => { + const flags = this.#callReducerFlags.get(reducer.name) ?? 'FullUpdate'; + this.callReducerWithParams( + reducer.name, + reducer.paramsSpacetimeType, + params, + flags + ); + }; + } + + return out as ReducersView; + } + + #makeSetReducerFlags(defs: ReducersDef): SetReducerFlags { + const out = Object.create(null) as SetReducerFlags; + for (const r of defs.reducers) { + const key = toCamelCase(r.name); + Object.defineProperty(out, key, { + enumerable: true, + configurable: false, + value: (flags: CallReducerFlags) => { + this.#callReducerFlags.set(r.name, flags); + }, + }); + } + return out; + } + + #makeEventContext( + event: Event + ): EventContextInterface { + // Bind methods to preserve `this` (#private fields safe) + return { + db: this.db, + reducers: this.reducers, + setReducerFlags: this.setReducerFlags, + isActive: this.isActive, + subscriptionBuilder: this.subscriptionBuilder.bind(this), + disconnect: this.disconnect.bind(this), + event, + }; + } + // NOTE: This is very important!!! This is the actual function that // gets called when you call `connection.subscriptionBuilder()`. // The `subscriptionBuilder` function which is generated, just shadows @@ -243,13 +314,13 @@ export class DbConnectionImpl< // Do not remove this function, or shoot yourself in the foot please. // It's not clear what would be a better way to do this at this exact // moment. - subscriptionBuilder = (): SubscriptionBuilderImpl => { + subscriptionBuilder = (): SubscriptionBuilderImpl => { return new SubscriptionBuilderImpl(this); }; registerSubscription( - handle: SubscriptionHandleImpl, - handleEmitter: EventEmitter, + handle: SubscriptionHandleImpl, + handleEmitter: EventEmitter>, querySql: string[] ): number { const queryId = this.#getNextQueryId(); @@ -292,16 +363,21 @@ export class DbConnectionImpl< const buffer = rowList.rowsData; const reader = new BinaryReader(buffer); const rows: Operation[] = []; - const rowType = this.#remoteModule.tables[tableName]!.rowType; - const primaryKeyInfo = - this.#remoteModule.tables[tableName]!.primaryKeyInfo; + + // TODO: performance + const table = this.#remoteModule.tables.tables.find(t => t.name === tableName); + const rowType = table!.rowType; + const columnsArray = Object.entries(table!.columns); + const primaryKeyColumnEntry = columnsArray.find(col => col[1].columnMetadata.isPrimaryKey); while (reader.remaining > 0) { - const row = AlgebraicType.deserializeValue(reader, rowType); + const row = ProductType.deserializeValue(reader, rowType); let rowId: ComparablePrimitive | undefined = undefined; - if (primaryKeyInfo !== undefined) { + if (primaryKeyColumnEntry !== undefined) { + const primaryKeyColName = primaryKeyColumnEntry[0]; + const primaryKeyColType = primaryKeyColumnEntry[1].typeBuilder.algebraicType; rowId = AlgebraicType.intoMapKey( - primaryKeyInfo.colType, - row[primaryKeyInfo.colName] + primaryKeyColType, + row[primaryKeyColName] ); } else { // Get a view of the bytes for this row. @@ -322,7 +398,7 @@ export class DbConnectionImpl< const parseTableUpdate = async ( rawTableUpdate: RawTableUpdate - ): Promise => { + ): Promise> => { const tableName = rawTableUpdate.tableName; let operations: Operation[] = []; for (const update of rawTableUpdate.updates) { @@ -354,8 +430,8 @@ export class DbConnectionImpl< const parseDatabaseUpdate = async ( dbUpdate: DatabaseUpdate - ): Promise => { - const tableUpdates: CacheTableUpdate[] = []; + ): Promise[]> => { + const tableUpdates: CacheTableUpdate[] = []; for (const rawTableUpdate of dbUpdate.tables) { tableUpdates.push(await parseTableUpdate(rawTableUpdate)); } @@ -393,7 +469,7 @@ export class DbConnectionImpl< const args = txUpdate.reducerCall.args; const energyQuantaUsed = txUpdate.energyQuantaUsed; - let tableUpdates: CacheTableUpdate[] = []; + let tableUpdates: CacheTableUpdate[] = []; let errMessage = ''; switch (txUpdate.status.tag) { case 'Committed': @@ -418,9 +494,9 @@ export class DbConnectionImpl< let reducerInfo: | { - reducerName: string; - args: Uint8Array; - } + reducerName: string; + args: Uint8Array; + } | undefined; if (reducerName !== '') { reducerInfo = { @@ -516,15 +592,16 @@ export class DbConnectionImpl< } #applyTableUpdates( - tableUpdates: CacheTableUpdate[], - eventContext: EventContextInterface + tableUpdates: CacheTableUpdate[], + eventContext: EventContextInterface ): PendingCallback[] { const pendingCallbacks: PendingCallback[] = []; for (const tableUpdate of tableUpdates) { // Get table information for the table being updated const tableName = tableUpdate.tableName; - const tableTypeInfo = this.#remoteModule.tables[tableName]!; - const table = this.clientCache.getOrCreateTable(tableTypeInfo); + // TODO: performance + const tableDef = this.#remoteModule.tables.tables.find(t => t.name === tableName)!; + const table = this.clientCache.getOrCreateTable(tableDef); const newCallbacks = table.applyOperations( tableUpdate.operations, eventContext @@ -545,11 +622,7 @@ export class DbConnectionImpl< switch (message.tag) { case 'InitialSubscription': { const event: Event = { tag: 'SubscribeApplied' }; - - const eventContext = this.#remoteModule.eventContextConstructor( - this, - event - ); + const eventContext = this.#makeEventContext(event); // Remove the event from the subscription event context // It is not a field in the type narrowed SubscriptionEventContext const { event: _, ...subscriptionEventContext } = eventContext; @@ -568,10 +641,7 @@ export class DbConnectionImpl< } case 'TransactionUpdateLight': { const event: Event = { tag: 'UnknownTransaction' }; - const eventContext = this.#remoteModule.eventContextConstructor( - this, - event - ); + const eventContext = this.#makeEventContext(event); const callbacks = this.#applyTableUpdates( message.tableUpdates, eventContext @@ -585,17 +655,16 @@ export class DbConnectionImpl< let reducerInfo = message.reducerInfo; let unknownTransaction = false; let reducerArgs: any | undefined; - let reducerTypeInfo: ReducerRuntimeTypeInfo | undefined; + const reducer = this.#remoteModule.reducers.reducers.find(t => t.name === reducerInfo!.reducerName)!; if (!reducerInfo) { unknownTransaction = true; } else { - reducerTypeInfo = - this.#remoteModule.reducers[reducerInfo.reducerName]; + // TODO: performance try { const reader = new BinaryReader(reducerInfo.args as Uint8Array); - reducerArgs = AlgebraicType.deserializeValue( + reducerArgs = ProductType.deserializeValue( reader, - reducerTypeInfo.argsType + reducer?.paramsSpacetimeType ); } catch { // This should only be printed in development, since it's @@ -608,10 +677,7 @@ export class DbConnectionImpl< if (unknownTransaction) { const event: Event = { tag: 'UnknownTransaction' }; - const eventContext = this.#remoteModule.eventContextConstructor( - this, - event - ); + const eventContext = this.#makeEventContext(event); const callbacks = this.#applyTableUpdates( message.tableUpdates, eventContext @@ -626,7 +692,6 @@ export class DbConnectionImpl< // At this point, we know that `reducerInfo` is not null because // we return if `unknownTransaction` is true. reducerInfo = reducerInfo!; - reducerTypeInfo = reducerTypeInfo!; // Thus this must be a reducer event create it and emit it. const reducerEvent = { @@ -637,17 +702,16 @@ export class DbConnectionImpl< energyConsumed: message.energyConsumed, reducer: { name: reducerInfo.reducerName, - args: reducerArgs, + // TODO(cloutiertyler): rename back to args to maintain API compatibility + params: reducerArgs, + paramsSpacetimeType: reducer.paramsSpacetimeType, }, }; const event: Event = { tag: 'Reducer', value: reducerEvent, }; - const eventContext = this.#remoteModule.eventContextConstructor( - this, - event - ); + const eventContext = this.#makeEventContext(event); const reducerEventContext = { ...eventContext, event: reducerEvent, @@ -660,8 +724,8 @@ export class DbConnectionImpl< const argsArray: any[] = []; ( - reducerTypeInfo.argsType as AlgebraicTypeVariants.Product - ).value.elements.forEach(element => { + reducer.paramsSpacetimeType + ).elements.forEach(element => { argsArray.push(reducerArgs[element.name!]); }); this.#reducerEmitter.emit( @@ -696,10 +760,7 @@ export class DbConnectionImpl< break; } const event: Event = { tag: 'SubscribeApplied' }; - const eventContext = this.#remoteModule.eventContextConstructor( - this, - event - ); + const eventContext = this.#makeEventContext(event); const { event: _, ...subscriptionEventContext } = eventContext; const callbacks = this.#applyTableUpdates( message.tableUpdates, @@ -724,10 +785,7 @@ export class DbConnectionImpl< break; } const event: Event = { tag: 'UnsubscribeApplied' }; - const eventContext = this.#remoteModule.eventContextConstructor( - this, - event - ); + const eventContext = this.#makeEventContext(event); const { event: _, ...subscriptionEventContext } = eventContext; const callbacks = this.#applyTableUpdates( message.tableUpdates, @@ -743,10 +801,7 @@ export class DbConnectionImpl< case 'SubscriptionError': { const error = Error(message.error); const event: Event = { tag: 'Error', value: error }; - const eventContext = this.#remoteModule.eventContextConstructor( - this, - event - ); + const eventContext = this.#makeEventContext(event); const errorContext = { ...eventContext, event: error, @@ -807,6 +862,23 @@ export class DbConnectionImpl< this.#sendMessage(message); } + /** + * Call a reducer on your SpacetimeDB module with typed arguments. + * @param reducerSchema The schema of the reducer to call + * @param callReducerFlags The flags for the reducer call + * @param params The arguments to pass to the reducer + */ + callReducerWithParams(reducerName: string, paramsType: ProductType, params: object, flags: CallReducerFlags) { + let writer = new BinaryWriter(1024); + ProductType.serializeValue(writer, paramsType, params); + let argsBuffer = writer.getBuffer(); + this.callReducer( + reducerName, + argsBuffer, + flags + ); + } + /** * Close the current connection. * @@ -827,63 +899,63 @@ export class DbConnectionImpl< private on( eventName: ConnectionEvent, - callback: (ctx: DbConnectionImpl, ...args: any[]) => void + callback: (ctx: DbConnectionImpl, ...args: any[]) => void ): void { this.#emitter.on(eventName, callback); } private off( eventName: ConnectionEvent, - callback: (ctx: DbConnectionImpl, ...args: any[]) => void + callback: (ctx: DbConnectionImpl, ...args: any[]) => void ): void { this.#emitter.off(eventName, callback); } private onConnect( - callback: (ctx: DbConnectionImpl, ...args: any[]) => void + callback: (ctx: DbConnectionImpl, ...args: any[]) => void ): void { this.#emitter.on('connect', callback); } private onDisconnect( - callback: (ctx: DbConnectionImpl, ...args: any[]) => void + callback: (ctx: DbConnectionImpl, ...args: any[]) => void ): void { this.#emitter.on('disconnect', callback); } private onConnectError( - callback: (ctx: DbConnectionImpl, ...args: any[]) => void + callback: (ctx: DbConnectionImpl, ...args: any[]) => void ): void { this.#emitter.on('connectError', callback); } - private removeOnConnect( - callback: (ctx: DbConnectionImpl, ...args: any[]) => void + removeOnConnect( + callback: (ctx: DbConnectionImpl, ...args: any[]) => void ): void { this.#emitter.off('connect', callback); } - private removeOnDisconnect( - callback: (ctx: DbConnectionImpl, ...args: any[]) => void + removeOnDisconnect( + callback: (ctx: DbConnectionImpl, ...args: any[]) => void ): void { this.#emitter.off('disconnect', callback); } - private removeOnConnectError( - callback: (ctx: DbConnectionImpl, ...args: any[]) => void + removeOnConnectError( + callback: (ctx: DbConnectionImpl, ...args: any[]) => void ): void { this.#emitter.off('connectError', callback); } // Note: This is required to be public because it needs to be // called from the `RemoteReducers` class. - onReducer(reducerName: string, callback: ReducerEventCallback): void { + onReducer(reducerName: string, callback: ReducerEventCallback): void { this.#reducerEmitter.on(reducerName, callback); } // Note: This is required to be public because it needs to be // called from the `RemoteReducers` class. - offReducer(reducerName: string, callback: ReducerEventCallback): void { + offReducer(reducerName: string, callback: ReducerEventCallback): void { this.#reducerEmitter.off(reducerName, callback); } } diff --git a/crates/bindings-typescript/src/sdk/db_context.ts b/crates/bindings-typescript/src/sdk/db_context.ts index 533ce32e923..7d5d0da464c 100644 --- a/crates/bindings-typescript/src/sdk/db_context.ts +++ b/crates/bindings-typescript/src/sdk/db_context.ts @@ -1,20 +1,19 @@ +import type { DbView } from '../server/db_view'; +import type { UntypedSchemaDef } from '../server/schema'; +import type { ReducersView, SetReducerFlags, UntypedReducersDef } from './reducers'; import type { SubscriptionBuilderImpl } from './subscription_builder_impl'; /** * Interface representing a database context. * - * @template DBView - Type representing the database view. - * @template Reducers - Type representing the reducers. + * @template DbView - Type representing the database view. + * @template ReducersDef - Type representing the reducers. * @template SetReducerFlags - Type representing the reducer flags collection. */ -export interface DbContext< - DBView = any, - Reducers = any, - SetReducerFlags = any, -> { - db: DBView; - reducers: Reducers; - setReducerFlags: SetReducerFlags; +export interface DbContext { + db: DbView; + reducers: ReducersView; + setReducerFlags: SetReducerFlags; isActive: boolean; /** @@ -23,9 +22,8 @@ export interface DbContext< * @returns The subscription builder. */ subscriptionBuilder(): SubscriptionBuilderImpl< - DBView, - Reducers, - SetReducerFlags + SchemaDef, + ReducersDef >; /** diff --git a/crates/bindings-typescript/src/sdk/db_view.ts b/crates/bindings-typescript/src/sdk/db_view.ts new file mode 100644 index 00000000000..664fcbe2483 --- /dev/null +++ b/crates/bindings-typescript/src/sdk/db_view.ts @@ -0,0 +1,14 @@ +import type { DbView } from "../server/db_view"; +import type { UntypedSchemaDef } from "../server/schema"; + +/** + * An untyped database view, where the table names and row types are not known. + * Each key is a camelCased version of the table name, and each value is an untyped table handle. + * + * For example, a database with tables "user_profile" and "game_stats" would have the type: + * { + * userProfile: TableHandle<"user_profile", any>; + * gameStats: TableHandle<"game_stats", any>; + * } + */ +export type UntypedDbView = DbView; \ No newline at end of file diff --git a/crates/bindings-typescript/src/sdk/event.ts b/crates/bindings-typescript/src/sdk/event.ts index 8be677e47ab..98254af3ca5 100644 --- a/crates/bindings-typescript/src/sdk/event.ts +++ b/crates/bindings-typescript/src/sdk/event.ts @@ -1,6 +1,7 @@ -import type { ReducerEvent, ReducerInfoType } from './reducer_event'; +import type { ReducerEvent } from './reducer_event'; +import type { UntypedReducerDef } from './reducers'; -export type Event = +export type Event = | { tag: 'Reducer'; value: ReducerEvent } | { tag: 'SubscribeApplied' } | { tag: 'UnsubscribeApplied' } diff --git a/crates/bindings-typescript/src/sdk/event_context.ts b/crates/bindings-typescript/src/sdk/event_context.ts index 2ed7112d431..459cfbfeaf0 100644 --- a/crates/bindings-typescript/src/sdk/event_context.ts +++ b/crates/bindings-typescript/src/sdk/event_context.ts @@ -1,41 +1,39 @@ +import type { UntypedSchemaDef } from '../server/schema.ts'; import type { DbContext } from './db_context'; import type { Event } from './event.ts'; -import type { ReducerEvent, ReducerInfoType } from './reducer_event.ts'; +import type { ReducerEvent } from './reducer_event.ts'; +import type { UntypedReducersDef } from './reducers.ts'; + +export type UntypedEventContext = EventContextInterface; export interface EventContextInterface< - DBView = any, - Reducers = any, - SetReducerFlags = any, - Reducer extends ReducerInfoType = never, -> extends DbContext { + SchemaDef extends UntypedSchemaDef, + Reducers extends UntypedReducersDef, +> extends DbContext { /** Enum with variants for all possible events. */ - event: Event; + event: Event; } export interface ReducerEventContextInterface< - DBView = any, - Reducers = any, - SetReducerFlags = any, - Reducer extends ReducerInfoType = never, -> extends DbContext { + SchemaDef extends UntypedSchemaDef, + Reducers extends UntypedReducersDef, +> extends DbContext { /** Enum with variants for all possible events. */ - event: ReducerEvent; + event: ReducerEvent; } // eslint-disable-next-line @typescript-eslint/no-empty-object-type export interface SubscriptionEventContextInterface< - DBView = any, - Reducers = any, - SetReducerFlags = any, -> extends DbContext { + SchemaDef extends UntypedSchemaDef, + Reducers extends UntypedReducersDef, +> extends DbContext { /** No event is provided **/ } export interface ErrorContextInterface< - DBView = any, - Reducers = any, - SetReducerFlags = any, -> extends DbContext { + SchemaDef extends UntypedSchemaDef, + Reducers extends UntypedReducersDef, +> extends DbContext { /** Enum with variants for all possible events. */ event?: Error; } diff --git a/crates/bindings-typescript/src/sdk/index.ts b/crates/bindings-typescript/src/sdk/index.ts index 814bc67a54e..568e04bd5b5 100644 --- a/crates/bindings-typescript/src/sdk/index.ts +++ b/crates/bindings-typescript/src/sdk/index.ts @@ -2,4 +2,6 @@ export * from './db_connection_impl.ts'; export * from './client_cache.ts'; export * from './message_types.ts'; -export { type TableHandle } from './table_handle.ts'; +export { type ClientTable } from './table_handle.ts'; +export { type RemoteModule } from './spacetime_module.ts'; +export { type SetReducerFlags } from './reducers.ts'; diff --git a/crates/bindings-typescript/src/sdk/reducer_event.ts b/crates/bindings-typescript/src/sdk/reducer_event.ts index aaebd27fabb..1ffe5c79177 100644 --- a/crates/bindings-typescript/src/sdk/reducer_event.ts +++ b/crates/bindings-typescript/src/sdk/reducer_event.ts @@ -2,10 +2,9 @@ import { ConnectionId } from '../'; import { Timestamp } from '../'; import type { UpdateStatus } from './client_api/index.ts'; import { Identity } from '../'; +import type { UntypedReducerDef } from './reducers.ts'; -export type ReducerInfoType = { name: string; args?: any } | never; - -export type ReducerEvent = { +export type ReducerEvent = { /** * The time when the reducer started running. * diff --git a/crates/bindings-typescript/src/sdk/reducer_handle.ts b/crates/bindings-typescript/src/sdk/reducer_handle.ts new file mode 100644 index 00000000000..a4e76eda4a4 --- /dev/null +++ b/crates/bindings-typescript/src/sdk/reducer_handle.ts @@ -0,0 +1,12 @@ +export type ReducerHandle = { + /** Phantom reducer name */ + readonly reducerName?: ReducerName; +}; + +export type ReducerNamesFromReducers = R extends object + ? { + [K in keyof R]: R[K] extends ReducerHandle + ? ReducerName + : never; + }[keyof R] + : never; diff --git a/crates/bindings-typescript/src/sdk/reducers.ts b/crates/bindings-typescript/src/sdk/reducers.ts new file mode 100644 index 00000000000..e25b805c97f --- /dev/null +++ b/crates/bindings-typescript/src/sdk/reducers.ts @@ -0,0 +1,25 @@ +import type { ProductType } from "../lib/algebraic_type"; +import type { ParamsObj } from "../server/reducers"; +import type { CamelCase } from "../server/type_util"; +import type { CallReducerFlags } from "./db_connection_impl"; + +export type ReducersView = { + [I in keyof R['reducers'] as CamelCase]: + (params: R['reducers'][number]['params']) => void +}; + +export type UntypedReducers = Record void>; + +export type UntypedReducerDef = { + name: string; + params: ParamsObj; + paramsSpacetimeType: ProductType; +}; + +export type UntypedReducersDef = { + reducers: readonly UntypedReducerDef[]; +}; + +export type SetReducerFlags = { + [K in keyof R['reducers'] as CamelCase]: (flags: CallReducerFlags) => void; +}; \ No newline at end of file diff --git a/crates/bindings-typescript/src/sdk/set_reducer_flags.ts b/crates/bindings-typescript/src/sdk/set_reducer_flags.ts new file mode 100644 index 00000000000..a5648b67d36 --- /dev/null +++ b/crates/bindings-typescript/src/sdk/set_reducer_flags.ts @@ -0,0 +1,3 @@ +import type { CallReducerFlags } from "./db_connection_impl"; + +export type UntypedSetReducerFlags = Record void>; \ No newline at end of file diff --git a/crates/bindings-typescript/src/sdk/spacetime_module.ts b/crates/bindings-typescript/src/sdk/spacetime_module.ts index 4a76006f93f..72ad623703e 100644 --- a/crates/bindings-typescript/src/sdk/spacetime_module.ts +++ b/crates/bindings-typescript/src/sdk/spacetime_module.ts @@ -1,9 +1,12 @@ import type { AlgebraicType } from '../'; +import type { UntypedSchemaDef } from '../server/schema'; import type { DbConnectionImpl } from './db_connection_impl'; +import type { UntypedReducersDef } from './reducers'; export interface TableRuntimeTypeInfo { tableName: string; rowType: AlgebraicType; + primaryKey?: string; primaryKeyInfo?: PrimaryKeyInfo; } @@ -17,13 +20,21 @@ export interface ReducerRuntimeTypeInfo { argsType: AlgebraicType; } -export default interface RemoteModule { +export type RemoteModule2 = { + versionInfo: { + cliVersion: CLI; + }; + tables: SchemaDef; + reducers: ReducersDef; +} + +export interface RemoteModule { tables: { [name: string]: TableRuntimeTypeInfo }; reducers: { [name: string]: ReducerRuntimeTypeInfo }; - eventContextConstructor: (imp: DbConnectionImpl, event: any) => any; - dbViewConstructor: (connection: DbConnectionImpl) => any; + eventContextConstructor: (imp: DbConnectionImpl, event: any) => any; + dbViewConstructor: (connection: DbConnectionImpl) => any; reducersConstructor: ( - connection: DbConnectionImpl, + connection: DbConnectionImpl, setReducerFlags: any ) => any; setReducerFlagsConstructor: () => any; diff --git a/crates/bindings-typescript/src/sdk/subscription_builder_impl.ts b/crates/bindings-typescript/src/sdk/subscription_builder_impl.ts index 5fffd581237..a0856367b7b 100644 --- a/crates/bindings-typescript/src/sdk/subscription_builder_impl.ts +++ b/crates/bindings-typescript/src/sdk/subscription_builder_impl.ts @@ -1,23 +1,24 @@ +import type { UntypedSchemaDef } from '../server/schema'; import type { DbConnectionImpl } from './db_connection_impl'; import type { ErrorContextInterface, SubscriptionEventContextInterface, } from './event_context'; import { EventEmitter } from './event_emitter'; +import type { UntypedReducersDef } from './reducers'; export class SubscriptionBuilderImpl< - DBView = any, - Reducers = any, - SetReducerFlags = any, + SchemaDef extends UntypedSchemaDef, + Reducers extends UntypedReducersDef, > { #onApplied?: ( - ctx: SubscriptionEventContextInterface + ctx: SubscriptionEventContextInterface ) => void = undefined; #onError?: ( - ctx: ErrorContextInterface + ctx: ErrorContextInterface ) => void = undefined; constructor( - private db: DbConnectionImpl + private db: DbConnectionImpl ) {} /** @@ -37,9 +38,9 @@ export class SubscriptionBuilderImpl< */ onApplied( cb: ( - ctx: SubscriptionEventContextInterface + ctx: SubscriptionEventContextInterface ) => void - ): SubscriptionBuilderImpl { + ): SubscriptionBuilderImpl { this.#onApplied = cb; return this; } @@ -65,8 +66,8 @@ export class SubscriptionBuilderImpl< * @returns The current `SubscriptionBuilder` instance. */ onError( - cb: (ctx: ErrorContextInterface) => void - ): SubscriptionBuilderImpl { + cb: (ctx: ErrorContextInterface) => void + ): SubscriptionBuilderImpl { this.#onError = cb; return this; } @@ -89,7 +90,7 @@ export class SubscriptionBuilderImpl< */ subscribe( query_sql: string | string[] - ): SubscriptionHandleImpl { + ): SubscriptionHandleImpl { const queries = Array.isArray(query_sql) ? query_sql : [query_sql]; if (queries.length === 0) { throw new Error('Subscriptions must have at least one query'); @@ -126,17 +127,16 @@ export class SubscriptionBuilderImpl< export type SubscribeEvent = 'applied' | 'error' | 'end'; -export class SubscriptionManager { +export class SubscriptionManager { subscriptions: Map< number, - { handle: SubscriptionHandleImpl; emitter: EventEmitter } + { handle: SubscriptionHandleImpl; emitter: EventEmitter } > = new Map(); } export class SubscriptionHandleImpl< - DBView = any, - Reducers = any, - SetReducerFlags = any, + SchemaDef extends UntypedSchemaDef, + Reducers extends UntypedReducersDef, > { #queryId: number; #unsubscribeCalled: boolean = false; @@ -146,13 +146,13 @@ export class SubscriptionHandleImpl< new EventEmitter(); constructor( - private db: DbConnectionImpl, + private db: DbConnectionImpl, querySql: string[], onApplied?: ( - ctx: SubscriptionEventContextInterface + ctx: SubscriptionEventContextInterface ) => void, onError?: ( - ctx: ErrorContextInterface, + ctx: ErrorContextInterface, error: Error ) => void ) { @@ -160,9 +160,8 @@ export class SubscriptionHandleImpl< 'applied', ( ctx: SubscriptionEventContextInterface< - DBView, - Reducers, - SetReducerFlags + SchemaDef, + Reducers > ) => { this.#activeState = true; @@ -174,7 +173,7 @@ export class SubscriptionHandleImpl< this.#emitter.on( 'error', ( - ctx: ErrorContextInterface, + ctx: ErrorContextInterface, error: Error ) => { this.#activeState = false; @@ -202,9 +201,8 @@ export class SubscriptionHandleImpl< 'end', ( _ctx: SubscriptionEventContextInterface< - DBView, - Reducers, - SetReducerFlags + SchemaDef, + Reducers > ) => { this.#endedState = true; @@ -225,7 +223,7 @@ export class SubscriptionHandleImpl< */ unsubscribeThen( onEnd: ( - ctx: SubscriptionEventContextInterface + ctx: SubscriptionEventContextInterface ) => void ): void { if (this.#endedState) { @@ -240,9 +238,8 @@ export class SubscriptionHandleImpl< 'end', ( ctx: SubscriptionEventContextInterface< - DBView, - Reducers, - SetReducerFlags + SchemaDef, + Reducers > ) => { this.#endedState = true; diff --git a/crates/bindings-typescript/src/sdk/table_cache.ts b/crates/bindings-typescript/src/sdk/table_cache.ts index dc9fce02431..cd79debf72e 100644 --- a/crates/bindings-typescript/src/sdk/table_cache.ts +++ b/crates/bindings-typescript/src/sdk/table_cache.ts @@ -3,7 +3,11 @@ import type { TableRuntimeTypeInfo } from './spacetime_module.ts'; import { stdbLogger } from './logger.ts'; import type { ComparablePrimitive } from '../'; -import type { EventContextInterface } from './index.ts'; +import type { EventContextInterface, ClientTable } from './index.ts'; +import type { RowType, Table, UntypedTableDef } from '../server/table.ts'; +import type { UntypedSchemaDef } from '../server/schema.ts'; +import type { UntypedReducersDef } from './reducers.ts'; +import type { ClientTableCore } from './table_handle.ts'; export type Operation< RowType extends Record = Record, @@ -16,10 +20,10 @@ export type Operation< }; export type TableUpdate< - RowType extends Record = Record, + TableDef extends UntypedTableDef, > = { tableName: string; - operations: Operation[]; + operations: Operation>[]; }; export type PendingCallback = { @@ -31,10 +35,12 @@ export type PendingCallback = { * Builder to generate calls to query a `table` in the database */ export class TableCache< - RowType extends Record = Record, -> { - private rows: Map; - private tableTypeInfo: TableRuntimeTypeInfo; + SchemaDef extends UntypedSchemaDef, + Reducers extends UntypedReducersDef, + TableDef extends UntypedTableDef, +> implements ClientTableCore { + private rows: Map, number]>; + private tableDef: TableDef; private emitter: EventEmitter<'insert' | 'delete' | 'update'>; /** @@ -43,8 +49,8 @@ export class TableCache< * @param primaryKey column name designated as `#[primarykey]` * @param entityClass the entityClass */ - constructor(tableTypeInfo: TableRuntimeTypeInfo) { - this.tableTypeInfo = tableTypeInfo; + constructor(tableDef: TableDef) { + this.tableDef = tableDef; this.rows = new Map(); this.emitter = new EventEmitter(); } @@ -52,30 +58,45 @@ export class TableCache< /** * @returns number of rows in the table */ - count(): number { - return this.rows.size; + count(): bigint { + return BigInt(this.rows.size); } /** * @returns The values of the rows in the table */ - iter(): RowType[] { - return Array.from(this.rows.values()).map(([row]) => row); + iter(): IterableIterator> { + function* generator(rows: Map, number]>): IterableIterator> { + for (const [row] of rows.values()) { + yield row; + } + } + return generator(this.rows); + } + + /** + * Allows iteration over the rows in the table + * @returns An iterator over the rows in the table + */ + [Symbol.iterator](): IterableIterator> { + return this.iter(); } applyOperations = ( - operations: Operation[], - ctx: EventContextInterface + operations: Operation>[], + ctx: EventContextInterface ): PendingCallback[] => { const pendingCallbacks: PendingCallback[] = []; - if (this.tableTypeInfo.primaryKeyInfo !== undefined) { + // TODO: performance + const hasPrimaryKey = Object.values(this.tableDef.columns).some(col => col.columnMetadata.isPrimaryKey === true); + if (hasPrimaryKey) { const insertMap = new Map< ComparablePrimitive, - [Operation, number] + [Operation>, number] >(); const deleteMap = new Map< ComparablePrimitive, - [Operation, number] + [Operation>, number] >(); for (const op of operations) { if (op.type === 'insert') { @@ -136,9 +157,9 @@ export class TableCache< }; update = ( - ctx: EventContextInterface, + ctx: EventContextInterface, rowId: ComparablePrimitive, - newRow: RowType, + newRow: RowType, refCountDelta: number = 0 ): PendingCallback | undefined => { const existingEntry = this.rows.get(rowId); @@ -146,7 +167,7 @@ export class TableCache< // TODO: this should throw an error and kill the connection. stdbLogger( 'error', - `Updating a row that was not present in the cache. Table: ${this.tableTypeInfo.tableName}, RowId: ${rowId}` + `Updating a row that was not present in the cache. Table: ${this.tableDef.name}, RowId: ${rowId}` ); return undefined; } @@ -155,7 +176,7 @@ export class TableCache< if (previousCount + refCountDelta <= 0) { stdbLogger( 'error', - `Negative reference count for in table ${this.tableTypeInfo.tableName} row ${rowId} (${previousCount} + ${refCountDelta})` + `Negative reference count for in table ${this.tableDef.name} row ${rowId} (${previousCount} + ${refCountDelta})` ); return undefined; } @@ -164,11 +185,11 @@ export class TableCache< if (previousCount === 0) { stdbLogger( 'error', - `Updating a row id in table ${this.tableTypeInfo.tableName} which was not present in the cache (rowId: ${rowId})` + `Updating a row id in table ${this.tableDef.name} which was not present in the cache (rowId: ${rowId})` ); return { type: 'insert', - table: this.tableTypeInfo.tableName, + table: this.tableDef.name, cb: () => { this.emitter.emit('insert', ctx, newRow); }, @@ -176,7 +197,7 @@ export class TableCache< } return { type: 'update', - table: this.tableTypeInfo.tableName, + table: this.tableDef.name, cb: () => { this.emitter.emit('update', ctx, oldRow, newRow); }, @@ -184,8 +205,8 @@ export class TableCache< }; insert = ( - ctx: EventContextInterface, - operation: Operation, + ctx: EventContextInterface, + operation: Operation>, count: number = 1 ): PendingCallback | undefined => { const [_, previousCount] = this.rows.get(operation.rowId) || [ @@ -196,7 +217,7 @@ export class TableCache< if (previousCount === 0) { return { type: 'insert', - table: this.tableTypeInfo.tableName, + table: this.tableDef.name, cb: () => { this.emitter.emit('insert', ctx, operation.row); }, @@ -207,8 +228,8 @@ export class TableCache< }; delete = ( - ctx: EventContextInterface, - operation: Operation, + ctx: EventContextInterface, + operation: Operation>, count: number = 1 ): PendingCallback | undefined => { const [_, previousCount] = this.rows.get(operation.rowId) || [ @@ -226,7 +247,7 @@ export class TableCache< this.rows.delete(operation.rowId); return { type: 'delete', - table: this.tableTypeInfo.tableName, + table: this.tableDef.name, cb: () => { this.emitter.emit('delete', ctx, operation.row); }, @@ -240,7 +261,7 @@ export class TableCache< * Register a callback for when a row is newly inserted into the database. * * ```ts - * User.onInsert((user, reducerEvent) => { + * ctx.db.user.onInsert((reducerEvent, user) => { * if (reducerEvent) { * console.log("New user on reducer", reducerEvent, user); * } else { @@ -251,8 +272,8 @@ export class TableCache< * * @param cb Callback to be called when a new row is inserted */ - onInsert = ( - cb: (ctx: EventContext, row: RowType) => void + onInsert = ( + cb: (ctx: EventContextInterface, row: RowType) => void ): void => { this.emitter.on('insert', cb); }; @@ -261,7 +282,7 @@ export class TableCache< * Register a callback for when a row is deleted from the database. * * ```ts - * User.onDelete((user, reducerEvent) => { + * ctx.db.user.onDelete((reducerEvent, user) => { * if (reducerEvent) { * console.log("Deleted user on reducer", reducerEvent, user); * } else { @@ -272,8 +293,8 @@ export class TableCache< * * @param cb Callback to be called when a new row is inserted */ - onDelete = ( - cb: (ctx: EventContext, row: RowType) => void + onDelete = ( + cb: (ctx: EventContextInterface, row: RowType) => void ): void => { this.emitter.on('delete', cb); }; @@ -282,7 +303,7 @@ export class TableCache< * Register a callback for when a row is updated into the database. * * ```ts - * User.onInsert((user, reducerEvent) => { + * ctx.db.user.onInsert((reducerEvent, oldUser, user) => { * if (reducerEvent) { * console.log("Updated user on reducer", reducerEvent, user); * } else { @@ -293,8 +314,8 @@ export class TableCache< * * @param cb Callback to be called when a new row is inserted */ - onUpdate = ( - cb: (ctx: EventContext, oldRow: RowType, row: RowType) => void + onUpdate = ( + cb: (ctx: EventContextInterface, oldRow: RowType, row: RowType) => void ): void => { this.emitter.on('update', cb); }; @@ -304,8 +325,8 @@ export class TableCache< * * @param cb Callback to be removed */ - removeOnInsert = ( - cb: (ctx: EventContext, row: RowType) => void + removeOnInsert = ( + cb: (ctx: EventContextInterface, row: RowType) => void ): void => { this.emitter.off('insert', cb); }; @@ -315,8 +336,8 @@ export class TableCache< * * @param cb Callback to be removed */ - removeOnDelete = ( - cb: (ctx: EventContext, row: RowType) => void + removeOnDelete = ( + cb: (ctx: EventContextInterface, row: RowType) => void ): void => { this.emitter.off('delete', cb); }; @@ -326,8 +347,8 @@ export class TableCache< * * @param cb Callback to be removed */ - removeOnUpdate = ( - cb: (ctx: EventContext, oldRow: RowType, row: RowType) => void + removeOnUpdate = ( + cb: (ctx: EventContextInterface, oldRow: RowType, row: RowType) => void ): void => { this.emitter.off('update', cb); }; diff --git a/crates/bindings-typescript/src/sdk/table_handle.ts b/crates/bindings-typescript/src/sdk/table_handle.ts index a648be11325..757caae4e80 100644 --- a/crates/bindings-typescript/src/sdk/table_handle.ts +++ b/crates/bindings-typescript/src/sdk/table_handle.ts @@ -1,12 +1,72 @@ -export type TableHandle = { - /** Phantom table name */ - readonly tableName?: TableName; +import type { ReadonlyIndexes } from "../server/indexes"; +import type { UntypedSchemaDef } from "../server/schema"; +import type { ReadonlyTableMethods, RowType, TableIndexes, UntypedTableDef } from "../server/table"; +import type { Prettify } from "../server/type_util"; +import type { EventContextInterface } from "./event_context"; +import type { UntypedReducersDef } from "./reducers"; + +export type ClientTableMethods< + SchemaDef extends UntypedSchemaDef, + Reducers extends UntypedReducersDef, + TableDef extends UntypedTableDef, +> = { + /** + * Registers a callback to be invoked when a row is inserted into the table. + */ + onInsert(cb: (ctx: EventContextInterface, row: RowType) => void): void; + + /** + * Removes a previously registered insert event listener. + * @param cb The callback to remove from the insert event listeners. + */ + removeOnInsert(cb: (ctx: EventContextInterface, row: RowType) => void): void; + + /** + * Registers a callback to be invoked when a row is deleted from the table. + */ + onDelete(cb: (ctx: EventContextInterface, row: RowType) => void): void; + + /** + * Removes a previously registered delete event listener. + * @param cb The callback to remove from the delete event listeners. + */ + removeOnDelete(cb: (ctx: EventContextInterface, row: RowType) => void): void; }; -export type TableNamesFromDb = Db extends object - ? { - [K in keyof Db]: Db[K] extends TableHandle - ? TableName - : never; - }[keyof Db] - : never; +/** + * Table + * + * - Row: row shape + * - UCV: unique-constraint violation error type (never if none) + * - AIO: auto-increment overflow error type (never if none) + */ +export type ClientTable< + SchemaDef extends UntypedSchemaDef, + Reducers extends UntypedReducersDef, + TableDef extends UntypedTableDef +> = Prettify< + ClientTableCore & + ReadonlyIndexes> +>; + +/** + * Core methods of ClientTable, without the indexes mixed in. + * Includes only staticly known methods. + */ +export type ClientTableCore< + SchemaDef extends UntypedSchemaDef, + Reducers extends UntypedReducersDef, + TableDef extends UntypedTableDef, +> = + ReadonlyTableMethods & + ClientTableMethods; + +/** + * Client database view, mapping table names to their corresponding ClientTable handles. + */ +export type ClientDbView< + SchemaDef extends UntypedSchemaDef, + Reducers extends UntypedReducersDef, +> = { + readonly [Tbl in SchemaDef['tables'][number] as Tbl['name']]: ClientTable; +}; \ No newline at end of file diff --git a/crates/bindings-typescript/src/server/db_view.ts b/crates/bindings-typescript/src/server/db_view.ts new file mode 100644 index 00000000000..3ba53c0da55 --- /dev/null +++ b/crates/bindings-typescript/src/server/db_view.ts @@ -0,0 +1,25 @@ +import type { ClientTable } from "../sdk"; +import type { UntypedReducersDef } from "../sdk/reducers"; +import type { UntypedSchemaDef } from "./schema"; +import type { ReadonlyTable, Table } from "./table"; + +/** + * A type representing a read-only database view, mapping table names to their corresponding read-only Table handles. + */ +export type ReadonlyDbView = { + readonly [Tbl in SchemaDef['tables'][number] as Tbl['accessorName']]: ReadonlyTable; +}; + +/** + * A type representing a client-side database view, mapping table names to their corresponding client Table handles. + */ +export type ClientDbView = { + readonly [Tbl in SchemaDef['tables'][number] as Tbl['accessorName']]: ClientTable; +}; + +/** + * A type representing the database view, mapping table names to their corresponding Table handles. + */ +export type DbView = { + readonly [Tbl in SchemaDef['tables'][number] as Tbl['accessorName']]: Table; +}; \ No newline at end of file diff --git a/crates/bindings-typescript/src/server/index.ts b/crates/bindings-typescript/src/server/index.ts index c602d704184..6db590d7d07 100644 --- a/crates/bindings-typescript/src/server/index.ts +++ b/crates/bindings-typescript/src/server/index.ts @@ -1,9 +1,11 @@ export * from './type_builders'; export { schema, type InferSchema } from './schema'; export { table } from './table'; +export { reducers } from './reducers'; export * as errors from './errors'; export { SenderError } from './errors'; export { type Reducer, type ReducerCtx } from './reducers'; +export { type DbView } from './db_view'; import './polyfills'; // Ensure polyfills are loaded import './register_hooks'; // Ensure module hooks are registered diff --git a/crates/bindings-typescript/src/server/indexes.ts b/crates/bindings-typescript/src/server/indexes.ts index 7af552012f6..f85bd92cbe2 100644 --- a/crates/bindings-typescript/src/server/indexes.ts +++ b/crates/bindings-typescript/src/server/indexes.ts @@ -56,6 +56,37 @@ export type Index< ? UniqueIndex : RangedIndex; +/** + * A type representing a collection of read-only indexes defined on a table. + */ +export type ReadonlyIndexes< + TableDef extends UntypedTableDef, + I extends Record>, +> = { + [k in keyof I]: ReadonlyIndex; +}; + +/** + * A type representing a read-only database index, which can be either unique or ranged. + * This type only exposes read-only operations. + */ +export type ReadonlyIndex< + TableDef extends UntypedTableDef, + I extends UntypedIndex, +> = I['unique'] extends true + ? ReadonlyUniqueIndex + : ReadonlyRangedIndex; + +/** + * A type representing a read-only unique index on a database table. + */ +export type ReadonlyUniqueIndex< + TableDef extends UntypedTableDef, + I extends UntypedIndex, +> = { + find(colVal: IndexVal): RowType | null; +}; + /** * A type representing a unique index on a database table. * Unique indexes enforce that the indexed columns contain unique values. @@ -63,23 +94,31 @@ export type Index< export type UniqueIndex< TableDef extends UntypedTableDef, I extends UntypedIndex, -> = { - find(col_val: IndexVal): RowType | null; - delete(col_val: IndexVal): boolean; - update(col_val: RowType): RowType; +> = ReadonlyUniqueIndex & { + delete(colVal: IndexVal): boolean; + update(colVal: RowType): RowType; }; /** - * A type representing a ranged index on a database table. - * Ranged indexes allow for range queries on the indexed columns. + * A type representing a read-only ranged index on a database table. */ -export type RangedIndex< +export type ReadonlyRangedIndex< TableDef extends UntypedTableDef, I extends UntypedIndex, > = { filter( range: IndexScanRangeBounds ): IterableIterator>; +}; + +/** + * A type representing a ranged index on a database table. + * Ranged indexes allow for range queries on the indexed columns. + */ +export type RangedIndex< + TableDef extends UntypedTableDef, + I extends UntypedIndex, +> = ReadonlyRangedIndex & { delete(range: IndexScanRangeBounds): number; }; diff --git a/crates/bindings-typescript/src/server/reducers.ts b/crates/bindings-typescript/src/server/reducers.ts index 0735cc004c1..55233d5a5b1 100644 --- a/crates/bindings-typescript/src/server/reducers.ts +++ b/crates/bindings-typescript/src/server/reducers.ts @@ -4,12 +4,14 @@ import type RawReducerDefV9 from '../lib/autogen/raw_reducer_def_v_9_type'; import type { ConnectionId } from '../lib/connection_id'; import type { Identity } from '../lib/identity'; import type { Timestamp } from '../lib/timestamp'; +import type { UntypedReducersDef } from '../sdk/reducers'; +import type { DbView } from './db_view'; import { MODULE_DEF, type UntypedSchemaDef } from './schema'; -import type { Table } from './table'; import type { InferTypeOfRow, RowBuilder, RowObj, + StringBuilder, TypeBuilder, } from './type_builders'; @@ -58,13 +60,6 @@ export type Reducer< payload: ParamsAsObject ) => void | { tag: 'ok' } | { tag: 'err'; value: string }; -/** - * A type representing the database view, mapping table names to their corresponding Table handles. - */ -export type DbView = { - readonly [Tbl in SchemaDef['tables'][number] as Tbl['name']]: Table; -}; - /** * Authentication information for the caller of a reducer. */ @@ -133,8 +128,9 @@ export function pushReducer( fn: Reducer, lifecycle?: RawReducerDefV9['lifecycle'] ): void { - if (existingReducers.has(name)) + if (existingReducers.has(name)) { throw new TypeError(`There is already a reducer with the name '${name}'`); + } existingReducers.add(name); const paramType: ProductType = { @@ -263,3 +259,111 @@ export function clientDisconnected< >(name: string, params: Params, fn: Reducer): void { pushReducer(name, params, fn, Lifecycle.OnDisconnect); } + +/** + * Represents a handle to a database reducer, including its name and argument type. + */ +export type ReducerSchema< + ReducerName extends string, + Params extends ParamsObj, +> = { + /** + * The name of the reducer. + */ + readonly reducerName: ReducerName; + + /** + * The type of the parameters object expected by the reducer. + */ + readonly paramsType: Params; + + /** + * + */ + readonly paramsSpacetimeType: ProductType; + + /** + * The {@link RawReducerDefV9} of the configured reducer. + */ + readonly reducerDef: RawReducerDefV9; +}; + +class Reducers { + /** + * Phantom type to track the reducers definition + */ + reducersType!: ReducersDef; +} + +/** + * Helper type to convert an array of TableSchema into a schema definition + */ +type ReducersToSchema[]> = { + reducers: { + /** @type {UntypedReducerDef} */ + readonly [i in keyof T]: { + name: T[i]['reducerName']; + params: T[i]['paramsType']; + paramsSpacetimeType: T[i]['paramsSpacetimeType']; + }; + }; +}; + +/** + * Creates a schema from table definitions + * @param handles - Array of table handles created by table() function + * @returns ColumnBuilder representing the complete database schema + * @example + * ```ts + * const s = schema( + * table({ name: 'user' }, userType), + * table({ name: 'post' }, postType) + * ); + * ``` + */ +export function reducers[]>( + ...handles: H +): Reducers>; + +/** + * Creates a schema from table definitions (array overload) + * @param handles - Array of table handles created by table() function + * @returns ColumnBuilder representing the complete database schema + */ +export function reducers[]>( + handles: H +): Reducers>; + +export function reducers( + ...args: + | [readonly ReducerSchema[]] + | readonly ReducerSchema[] +): Reducers { + return new Reducers(); +} + +export function reducerSchema< + ReducerName extends string, + Params extends ParamsObj, +>( + name: ReducerName, + params: Params +): ReducerSchema { + const paramType: ProductType = { + elements: Object.entries(params).map(([n, c]) => ({ + name: n, + algebraicType: c.algebraicType, + })), + }; + return { + reducerName: name, + paramsType: params, + paramsSpacetimeType: paramType, + reducerDef: { + name, + params: paramType, + lifecycle: undefined, + }, + }; +} + diff --git a/crates/bindings-typescript/src/server/runtime.ts b/crates/bindings-typescript/src/server/runtime.ts index e9d1ecff775..74533661373 100644 --- a/crates/bindings-typescript/src/server/runtime.ts +++ b/crates/bindings-typescript/src/server/runtime.ts @@ -18,7 +18,6 @@ import { } from './indexes'; import { type RowType, type Table, type TableMethods } from './table'; import { - type DbView, type ReducerCtx, REDUCERS, type JwtClaims, @@ -29,9 +28,20 @@ import { MODULE_DEF } from './schema'; import * as _syscalls from 'spacetime:sys@1.0'; import type { u16, u32, ModuleHooks } from 'spacetime:sys@1.0'; +import type { DbView } from './db_view'; +import type { CamelCase } from './type_util'; const { freeze } = Object; +/** + * Type safe conversion from a string like "some_identifier-name" to "someIdentifierName". + * @param str The string to convert + * @returns The converted string + */ +export function toCamelCase(str: T): CamelCase { + return str.replace(/[-_]+(\w)/g, (_, c) => c.toUpperCase()) as CamelCase; +} + const sys: typeof _syscalls = freeze( Object.fromEntries( Object.entries(_syscalls).map(([name, syscall]) => [ @@ -218,12 +228,12 @@ function getDbView() { return DB_VIEW; } -function makeDbView(module_def: RawModuleDefV9): DbView { +function makeDbView(moduleDef: RawModuleDefV9): DbView { return freeze( Object.fromEntries( - module_def.tables.map(table => [ - table.name, - makeTableView(module_def.typespace, table), + moduleDef.tables.map(table => [ + toCamelCase(table.name), + makeTableView(moduleDef.typespace, table), ]) ) ); @@ -232,7 +242,9 @@ function makeDbView(module_def: RawModuleDefV9): DbView { function makeTableView(typespace: Typespace, table: RawTableDefV9): Table { const table_id = sys.table_id_from_name(table.name); const rowType = typespace.types[table.productTypeRef]; - if (rowType.tag !== 'Product') throw 'impossible'; + if (rowType.tag !== 'Product') { + throw 'impossible'; + } const baseSize = bsatnBaseSize(typespace, rowType); @@ -339,19 +351,19 @@ function makeTableView(typespace: Typespace, table: RawTableDefV9): Table { let index: Index; if (isUnique) { - const serializeBound = (col_val: any[]): IndexScanArgs => { - if (col_val.length !== numColumns) + const serializeBound = (colVal: any[]): IndexScanArgs => { + if (colVal.length !== numColumns) throw new TypeError('wrong number of elements'); const writer = new BinaryWriter(baseSize + 1); const prefix_elems = numColumns - 1; - serializePrefix(writer, col_val, prefix_elems); + serializePrefix(writer, colVal, prefix_elems); const rstartOffset = writer.offset; writer.writeU8(0); AlgebraicType.serializeValue( writer, indexType.value.elements[numColumns - 1].algebraicType, - col_val[numColumns - 1], + colVal[numColumns - 1], typespace ); const buffer = writer.getBuffer(); @@ -360,9 +372,9 @@ function makeTableView(typespace: Typespace, table: RawTableDefV9): Table { return [prefix, prefix_elems, rstart, rstart]; }; index = { - find: (col_val: IndexVal): RowType | null => { - if (numColumns === 1) col_val = [col_val]; - const args = serializeBound(col_val); + find: (colVal: IndexVal): RowType | null => { + if (numColumns === 1) colVal = [colVal]; + const args = serializeBound(colVal); const iter = new TableIterator( sys.datastore_index_scan_range_bsatn(index_id, ...args), rowType @@ -375,9 +387,9 @@ function makeTableView(typespace: Typespace, table: RawTableDefV9): Table { ); return value; }, - delete: (col_val: IndexVal): boolean => { - if (numColumns === 1) col_val = [col_val]; - const args = serializeBound(col_val); + delete: (colVal: IndexVal): boolean => { + if (numColumns === 1) colVal = [colVal]; + const args = serializeBound(colVal); const num = sys.datastore_delete_by_index_scan_range_bsatn( index_id, ...args diff --git a/crates/bindings-typescript/src/server/schema.ts b/crates/bindings-typescript/src/server/schema.ts index 6684091b788..a8b775121e7 100644 --- a/crates/bindings-typescript/src/server/schema.ts +++ b/crates/bindings-typescript/src/server/schema.ts @@ -22,6 +22,7 @@ import { type AlgebraicTypeVariants, } from '../lib/algebraic_type'; import type RawScopedTypeNameV9 from '../lib/autogen/raw_scoped_type_name_v_9_type'; +import type { CamelCase } from './type_util'; /** * The global module definition that gets populated by calls to `reducer()` and lifecycle hooks. @@ -86,7 +87,9 @@ type TablesToSchema[]> = { /** @type {UntypedTableDef} */ readonly [i in keyof T]: { name: T[i]['tableName']; + accessorName: CamelCase; columns: T[i]['rowType']['row']; + rowType: T[i]['rowSpacetimeType']; indexes: T[i]['idxs']; }; }; @@ -314,22 +317,6 @@ export function schema[]>( ...handles: H ): Schema>; -/** - * Creates a schema from table definitions - * @param handles - Array of table handles created by table() function - * @returns ColumnBuilder representing the complete database schema - * @example - * ```ts - * const s = schema( - * table({ name: 'user' }, userType), - * table({ name: 'post' }, postType) - * ); - * ``` - */ -export function schema[]>( - ...handles: H -): Schema>; - /** * Creates a schema from table definitions (array overload) * @param handles - Array of table handles created by table() function @@ -351,13 +338,12 @@ export function schema[]>( * ); * ``` */ -export function schema( +export function schema[]>( ...args: - | [readonly TableSchema[]] - | readonly TableSchema[] -): Schema { - const handles: readonly TableSchema[] = - args.length === 1 && Array.isArray(args[0]) ? args[0] : args; + | [H] + | H +): Schema> { + const handles = (args.length === 1 && Array.isArray(args[0]) ? args[0] : args) as H; const tableDefs = handles.map(h => h.tableDef); diff --git a/crates/bindings-typescript/src/server/table.ts b/crates/bindings-typescript/src/server/table.ts index 8c78488433b..96803cc1646 100644 --- a/crates/bindings-typescript/src/server/table.ts +++ b/crates/bindings-typescript/src/server/table.ts @@ -1,11 +1,11 @@ -import { AlgebraicType } from '../lib/algebraic_type'; +import { AlgebraicType, ProductType } from '../lib/algebraic_type'; import type RawConstraintDefV9 from '../lib/autogen/raw_constraint_def_v_9_type'; import RawIndexAlgorithm from '../lib/autogen/raw_index_algorithm_type'; import type RawIndexDefV9 from '../lib/autogen/raw_index_def_v_9_type'; import type RawSequenceDefV9 from '../lib/autogen/raw_sequence_def_v_9_type'; import type RawTableDefV9 from '../lib/autogen/raw_table_def_v_9_type'; import type { AllUnique } from './constraints'; -import type { ColumnIndex, IndexColumns, Indexes, IndexOpts } from './indexes'; +import type { ColumnIndex, IndexColumns, Indexes, IndexOpts, ReadonlyIndexes } from './indexes'; import { MODULE_DEF, splitName } from './schema'; import { RowBuilder, @@ -53,7 +53,9 @@ type CoerceArray[]> = X; */ export type UntypedTableDef = { name: string; + accessorName: string; columns: Record>>; + rowType: ProductType; indexes: IndexOpts[]; }; @@ -108,17 +110,30 @@ export type Table = Prettify< TableMethods & Indexes> >; -/** - * A type representing the methods available on a table. - */ -export type TableMethods = { +export type ReadonlyTable = Prettify< + ReadonlyTableMethods & + ReadonlyIndexes> +>; + +export type ReadonlyTableMethods = { /** Returns the number of rows in the TX state. */ count(): bigint; - /** Iterate over all rows in the TX state. Rust Iterator → TS IterableIterator. */ + /** + * Insert and return the inserted row (auto-increment fields filled). + * + * May throw on error: + * * If there are any unique or primary key columns in this table, may throw {@link UniqueAlreadyExists}. + * * If there are any auto-incrementing columns in this table, may throw {@link AutoIncOverflow}. + * */ iter(): IterableIterator>; [Symbol.iterator](): IterableIterator>; +}; +/** + * A type representing the methods available on a table. + */ +export type TableMethods = ReadonlyTableMethods & { /** * Insert and return the inserted row (auto-increment fields filled). * @@ -148,9 +163,9 @@ export type TableSchema< readonly tableName: TableName; /** - * The {@link AlgebraicType} representing the structure of a row in the table. + * The {@link ProductType} representing the structure of a row in the table. */ - readonly rowSpacetimeType: AlgebraicType; + readonly rowSpacetimeType: ProductType; /** * The {@link RawTableDefV9} of the configured table @@ -319,11 +334,11 @@ export function table>( }); } - const productType = AlgebraicType.Product({ + const productType = { elements: row.resolveType().value.elements.map(elem => { return { name: elem.name, algebraicType: elem.algebraicType }; }), - }); + }; return { rowType: row as RowBuilder>, diff --git a/crates/bindings-typescript/src/server/type_util.ts b/crates/bindings-typescript/src/server/type_util.ts index 4febb2c11c8..ae9e978c7e9 100644 --- a/crates/bindings-typescript/src/server/type_util.ts +++ b/crates/bindings-typescript/src/server/type_util.ts @@ -32,3 +32,15 @@ export type Values = T[keyof T]; * A helper type to collapse a tuple into a single type if it has only one element. */ export type CollapseTuple = A extends [infer T] ? T : A; + +type CamelCaseImpl = + S extends `${infer Head}_${infer Tail}` ? `${Head}${Capitalize>}` : + S extends `${infer Head}-${infer Tail}` ? `${Head}${Capitalize>}` : + S; + +/** + * Convert "Some_identifier-name" -> "someIdentifierName" + * - No spaces; allowed separators: "_" and "-" + * - Normalizes the *first* character to lowercase (e.g. "User_Name" -> "userName") + */ +export type CamelCase = Uncapitalize>; \ No newline at end of file diff --git a/crates/bindings-typescript/test-app/src/App.tsx b/crates/bindings-typescript/test-app/src/App.tsx index b8ee5f08b50..894e49b9239 100644 --- a/crates/bindings-typescript/test-app/src/App.tsx +++ b/crates/bindings-typescript/test-app/src/App.tsx @@ -1,9 +1,11 @@ import { DbConnection, Player } from './module_bindings'; import { useEffect } from 'react'; import './App.css'; -import { useSpacetimeDB, useTable } from '../../src/react'; +import { useReducer, useSpacetimeDB, useTable } from '../../src/react'; function App() { + const x = useReducer; + const createPlayer = useReducer('createPlayer'); const connection = useSpacetimeDB(); const players = useTable('player', { onInsert: player => { diff --git a/crates/bindings-typescript/test-app/src/module_bindings/index.ts b/crates/bindings-typescript/test-app/src/module_bindings/index.ts index 104b8f6c14c..908c9243607 100644 --- a/crates/bindings-typescript/test-app/src/module_bindings/index.ts +++ b/crates/bindings-typescript/test-app/src/module_bindings/index.ts @@ -27,7 +27,10 @@ import { type EventContextInterface as __EventContextInterface, type ReducerEventContextInterface as __ReducerEventContextInterface, type SubscriptionEventContextInterface as __SubscriptionEventContextInterface, - type TableHandle as __TableHandle, + type ClientTable as __ClientTable, + type RemoteModule as __RemoteModule, + type SetReducerFlags as __SetReducerFlags, + DbConnectionConfig, } from '../../../src/index'; // Import and reexport all reducer arg types @@ -50,196 +53,312 @@ export { Point }; import { UnindexedPlayer } from './unindexed_player_type.ts'; export { UnindexedPlayer }; import { User } from './user_type.ts'; +import { schema } from '../../../src/server/schema.ts'; +import t from '../../../src/server/type_builders.ts'; +import { table } from '../../../src/server/table.ts'; +import { reducerSchema, reducers } from '../../../src/server/reducers.ts'; +import { RemoteModule2 } from '../../../src/sdk/spacetime_module.ts'; export { User }; +const pointType = t.object('Point', { + x: t.number(), + y: t.number(), +}); + +const tablesSchema = schema( + table({ name: 'player', }, t.row({ + ownerId: t.string(), + name: t.string(), + location: pointType, + })), + table({ name: 'unindexed_player', }, t.row({ + ownerId: t.string(), + name: t.string(), + location: pointType, + })), + table({ name: 'user', primaryKey: 'identity', }, t.row({ + identity: t.string(), + name: t.string(), + })), +); + +const reducersSchema = reducers( + reducerSchema('create_player', { + name: t.string(), + location: pointType, + }), + reducerSchema('foo_bar', { + name: t.string(), + location: pointType, + }), +); + const REMOTE_MODULE = { - tables: { - player: { - tableName: 'player' as const, - rowType: Player.getTypeScriptAlgebraicType(), - primaryKey: 'ownerId', - primaryKeyInfo: { - colName: 'ownerId', - colType: ( - Player.getTypeScriptAlgebraicType() as __AlgebraicTypeVariants.Product - ).value.elements[0].algebraicType, - }, - }, - unindexed_player: { - tableName: 'unindexed_player' as const, - rowType: UnindexedPlayer.getTypeScriptAlgebraicType(), - }, - user: { - tableName: 'user' as const, - rowType: User.getTypeScriptAlgebraicType(), - primaryKey: 'identity', - primaryKeyInfo: { - colName: 'identity', - colType: ( - User.getTypeScriptAlgebraicType() as __AlgebraicTypeVariants.Product - ).value.elements[0].algebraicType, - }, - }, - }, - reducers: { - create_player: { - reducerName: 'create_player', - argsType: CreatePlayer.getTypeScriptAlgebraicType(), - }, - }, versionInfo: { - cliVersion: '1.5.0', - }, - // Constructors which are used by the DbConnectionImpl to - // extract type information from the generated RemoteModule. - // - // NOTE: This is not strictly necessary for `eventContextConstructor` because - // all we do is build a TypeScript object which we could have done inside the - // SDK, but if in the future we wanted to create a class this would be - // necessary because classes have methods, so we'll keep it. - eventContextConstructor: ( - imp: __DbConnectionImpl, - event: __Event - ) => { - return { - ...(imp as DbConnection), - event, - }; - }, - dbViewConstructor: (imp: __DbConnectionImpl) => { - return new RemoteTables(imp); + cliVersion: '1.6.0' as const, }, - reducersConstructor: ( - imp: __DbConnectionImpl, - setReducerFlags: SetReducerFlags - ) => { - return new RemoteReducers(imp, setReducerFlags); - }, - setReducerFlagsConstructor: () => { - return new SetReducerFlags(); - }, -}; - -// A type representing all the possible variants of a reducer. -export type Reducer = never | { name: 'CreatePlayer'; args: CreatePlayer }; - -export class RemoteReducers { - constructor( - private connection: __DbConnectionImpl, - private setCallReducerFlags: SetReducerFlags - ) {} - - createPlayer(name: string, location: Point) { - const __args = { name, location }; - let __writer = new __BinaryWriter(1024); - CreatePlayer.serialize(__writer, __args); - let __argsBuffer = __writer.getBuffer(); - this.connection.callReducer( - 'create_player', - __argsBuffer, - this.setCallReducerFlags.createPlayerFlags - ); - } - - onCreatePlayer( - callback: (ctx: ReducerEventContext, name: string, location: Point) => void - ) { - this.connection.onReducer('create_player', callback); - } - - removeOnCreatePlayer( - callback: (ctx: ReducerEventContext, name: string, location: Point) => void - ) { - this.connection.offReducer('create_player', callback); - } -} + tables: tablesSchema.schemaType, + reducers: reducersSchema.reducersType, +} satisfies RemoteModule2< + typeof tablesSchema.schemaType, + typeof reducersSchema.reducersType +>; -export class SetReducerFlags { - createPlayerFlags: __CallReducerFlags = 'FullUpdate'; - createPlayer(flags: __CallReducerFlags) { - this.createPlayerFlags = flags; - } -} +export type EventContext = __EventContextInterface< + typeof tablesSchema.schemaType, + typeof reducersSchema.reducersType +>; -export class RemoteTables { - constructor(private connection: __DbConnectionImpl) {} - - get player(): PlayerTableHandle<'player'> { - // clientCache is a private property - return new PlayerTableHandle( - ( - this.connection as unknown as { clientCache: __ClientCache } - ).clientCache.getOrCreateTable(REMOTE_MODULE.tables.player) - ); - } - - get unindexedPlayer(): UnindexedPlayerTableHandle<'unindexed_player'> { - // clientCache is a private property - return new UnindexedPlayerTableHandle( - ( - this.connection as unknown as { clientCache: __ClientCache } - ).clientCache.getOrCreateTable( - REMOTE_MODULE.tables.unindexed_player - ) - ); - } - - get user(): UserTableHandle<'user'> { - // clientCache is a private property - return new UserTableHandle( - ( - this.connection as unknown as { clientCache: __ClientCache } - ).clientCache.getOrCreateTable(REMOTE_MODULE.tables.user) - ); - } -} +export type ReducerEventContext = __ReducerEventContextInterface< + typeof tablesSchema.schemaType, + typeof reducersSchema.reducersType +>; + +export type SubscriptionEventContext = __SubscriptionEventContextInterface< + typeof tablesSchema.schemaType, + typeof reducersSchema.reducersType +>; + +export type ErrorContext = __ErrorContextInterface< + typeof tablesSchema.schemaType, + typeof reducersSchema.reducersType +>; export class SubscriptionBuilder extends __SubscriptionBuilderImpl< - RemoteTables, - RemoteReducers, - SetReducerFlags + typeof tablesSchema.schemaType, + typeof reducersSchema.reducersType > {} -export class DbConnection extends __DbConnectionImpl< - RemoteTables, - RemoteReducers, - SetReducerFlags -> { - static builder = (): __DbConnectionBuilder< - DbConnection, - ErrorContext, - SubscriptionEventContext - > => { - return new __DbConnectionBuilder< - DbConnection, - ErrorContext, - SubscriptionEventContext - >(REMOTE_MODULE, (imp: __DbConnectionImpl) => imp as DbConnection); +export class DbConnectionBuilder extends __DbConnectionBuilder< + typeof tablesSchema.schemaType, + typeof reducersSchema.reducersType, + DbConnection +> {}; + +export class DbConnection extends __DbConnectionImpl { + static builder = (): DbConnectionBuilder => { + return new DbConnectionBuilder(REMOTE_MODULE, (config: DbConnectionConfig) => new DbConnection(config)); }; subscriptionBuilder = (): SubscriptionBuilder => { return new SubscriptionBuilder(this); }; } -export type EventContext = __EventContextInterface< - RemoteTables, - RemoteReducers, - SetReducerFlags, - Reducer ->; -export type ReducerEventContext = __ReducerEventContextInterface< - RemoteTables, - RemoteReducers, - SetReducerFlags, - Reducer ->; -export type SubscriptionEventContext = __SubscriptionEventContextInterface< - RemoteTables, - RemoteReducers, - SetReducerFlags ->; -export type ErrorContext = __ErrorContextInterface< - RemoteTables, - RemoteReducers, - SetReducerFlags ->; + +// // --- factory returning a well-typed object --- +// function makeReducersObj( +// r: { reducersType: R }, +// call: (name: string, spacetime: R['reducers'][number]['paramsSpacetimeType'], params: R['reducers'][number]['params']) => void +// ): Readonly> { +// const obj: Record = {}; +// for (const red of Object.values(r.reducersType.reducers)) { +// const key = toCamelCase(red.name as string); +// obj[key] = (params: any) => call(red.name as string, red.paramsSpacetimeType, params); +// } +// return Object.freeze(obj) as Readonly>; +// } + +// const reducersObj: UntypedReducers = {} +// for (const reducer of Object.values(reducersSchema.reducersType.reducers)) { +// reducersObj[toCamelCase(reducer.name)] = function(...args: Args) { +// this.#connection.callReducerWithParams( +// reducersSchema.reducersType.reducers[0].name, +// reducersSchema.reducersType.reducers[0].paramsSpacetimeType, +// args, +// "FullUpdate", +// ); +// }; +// } +// Object.freeze(reducersObj); + +// export class RemoteReducers implements UntypedReducersDef { +// [key: string]: (...args: any[]) => void; + +// #connection: __DbConnectionImpl; +// #setCallReducerFlags: SetReducerFlags; + +// constructor( +// connection: __DbConnectionImpl, +// setCallReducerFlags: SetReducerFlags +// ) { +// this.#connection = connection; +// this.#setCallReducerFlags = setCallReducerFlags; +// } + +// createPlayer(name: string, location: Point) { +// this.#connection.callReducerWithParams( +// r.reducersType.reducers[0].name, +// r.reducersType.reducers[0].paramsSpacetimeType, +// [name, location], +// this.#setCallReducerFlags.createPlayerFlags, +// ); +// } + +// // onCreatePlayer( +// // callback: (ctx: ReducerEventContext, name: string, location: Point) => void +// // ) { +// // this.#connection.onReducer('create_player', callback); +// // } + +// // removeOnCreatePlayer( +// // callback: (ctx: ReducerEventContext, name: string, location: Point) => void +// // ) { +// // this.#connection.offReducer('create_player', callback); +// // } +// } + +// export class SetReducerFlags implements __SetReducerFlags { +// createPlayerFlags: __CallReducerFlags = 'FullUpdate'; +// createPlayer(flags: __CallReducerFlags) { +// this.createPlayerFlags = flags; +// } +// } + +// export class RemoteTables implements ClientDbView { +// constructor(private connection: __DbConnectionImpl) {} + +// get player(): PlayerTableHandle { +// // clientCache is a private property +// return new PlayerTableHandle( +// ( +// this.connection as unknown as { clientCache: __ClientCache } +// ).clientCache.getOrCreateTable<"player">(spacetimedb.tablesDef.tables[0]) +// ); +// } + +// get unindexedPlayer(): UnindexedPlayerTableHandle<'unindexed_player'> { +// // clientCache is a private property +// return new UnindexedPlayerTableHandle( +// ( +// this.connection as unknown as { clientCache: __ClientCache } +// ).clientCache.getOrCreateTable<"unindexed_player">( +// REMOTE_MODULE.tables.unindexed_player +// ) +// ); +// } + +// get user(): UserTableHandle<'user'> { +// // clientCache is a private property +// return new UserTableHandle( +// ( +// this.connection as unknown as { clientCache: __ClientCache } +// ).clientCache.getOrCreateTable<"user">(REMOTE_MODULE.tables.user) +// ); +// } +// } + +// export class SubscriptionBuilder extends __SubscriptionBuilderImpl< +// SchemaDef, +// RemoteReducers +// > {} + +// export class DbConnection extends __DbConnectionImpl< +// SchemaDef, +// RemoteReducers, +// > { +// static builder = (): __DbConnectionBuilder< +// DbConnection, +// ErrorContext, +// SubscriptionEventContext +// > => { +// return new __DbConnectionBuilder< +// DbConnection, +// ErrorContext, +// SubscriptionEventContext +// >(REMOTE_MODULE, (imp: __DbConnectionImpl) => imp as DbConnection); +// }; +// subscriptionBuilder = (): SubscriptionBuilder => { +// return new SubscriptionBuilder(this); +// }; +// } + +// export type EventContext = __EventContextInterface< +// RemoteTables, +// RemoteReducers, +// SetReducerFlags, +// Reducer +// >; +// export type ReducerEventContext = __ReducerEventContextInterface< +// RemoteTables, +// RemoteReducers, +// SetReducerFlags, +// Reducer +// >; +// export type SubscriptionEventContext = __SubscriptionEventContextInterface< +// RemoteTables, +// RemoteReducers, +// SetReducerFlags +// >; +// export type ErrorContext = __ErrorContextInterface< +// RemoteTables, +// RemoteReducers, +// SetReducerFlags +// >; + +// const REMOTE_MODULE = { +// tables: { +// player: { +// name: 'player' as const, +// rowType: Player.getTypeScriptAlgebraicType(), +// primaryKey: 'ownerId', +// primaryKeyInfo: { +// colName: 'ownerId', +// colType: ( +// Player.getTypeScriptAlgebraicType() as __AlgebraicTypeVariants.Product +// ).value.elements[0].algebraicType, +// }, +// }, +// unindexed_player: { +// tableName: 'unindexed_player' as const, +// rowType: UnindexedPlayer.getTypeScriptAlgebraicType(), +// }, +// user: { +// tableName: 'user' as const, +// rowType: User.getTypeScriptAlgebraicType(), +// primaryKey: 'identity', +// primaryKeyInfo: { +// colName: 'identity', +// colType: ( +// User.getTypeScriptAlgebraicType() as __AlgebraicTypeVariants.Product +// ).value.elements[0].algebraicType, +// }, +// }, +// }, +// reducers: { +// create_player: { +// reducerName: 'create_player', +// argsType: CreatePlayer.getTypeScriptAlgebraicType(), +// }, +// }, +// versionInfo: { +// cliVersion: '1.5.0', +// }, +// // Constructors which are used by the DbConnectionImpl to +// // extract type information from the generated RemoteModule. +// // +// // NOTE: This is not strictly necessary for `eventContextConstructor` because +// // all we do is build a TypeScript object which we could have done inside the +// // SDK, but if in the future we wanted to create a class this would be +// // necessary because classes have methods, so we'll keep it. +// eventContextConstructor: ( +// imp: __DbConnectionImpl, +// event: __Event +// ) => { +// return { +// ...(imp as DbConnection), +// event, +// }; +// }, +// dbViewConstructor: (imp: __DbConnectionImpl) => { +// return new RemoteTables(imp); +// }, +// reducersConstructor: ( +// imp: __DbConnectionImpl, +// setReducerFlags: SetReducerFlags +// ) => { +// return new RemoteReducers(imp, setReducerFlags); +// }, +// setReducerFlagsConstructor: () => { +// return new SetReducerFlags(); +// }, +// } satisfies __RemoteModule; \ No newline at end of file diff --git a/crates/bindings-typescript/test-app/src/module_bindings/player_table.ts b/crates/bindings-typescript/test-app/src/module_bindings/player_table.ts index 63a846fa7f6..53444fbc677 100644 --- a/crates/bindings-typescript/test-app/src/module_bindings/player_table.ts +++ b/crates/bindings-typescript/test-app/src/module_bindings/player_table.ts @@ -25,7 +25,7 @@ import { type EventContextInterface as __EventContextInterface, type ReducerEventContextInterface as __ReducerEventContextInterface, type SubscriptionEventContextInterface as __SubscriptionEventContextInterface, - type TableHandle as __TableHandle, + type ClientTable as __ClientTable, } from '../../../src/index'; import { Player } from './player_type'; import { Point } from './point_type'; @@ -51,7 +51,7 @@ declare type __keep = [EventContext, Reducer, RemoteReducers, RemoteTables]; * like `ctx.db.player.on_insert(...)`. */ export class PlayerTableHandle - implements __TableHandle + implements __ClientTable { // phantom type to track the table name readonly tableName!: TableName; @@ -80,11 +80,11 @@ export class PlayerTableHandle * Get a handle on the `ownerId` unique index on the table `player`. */ ownerId = { - // Find the subscribed row whose `ownerId` column value is equal to `col_val`, + // Find the subscribed row whose `ownerId` column value is equal to `colVal`, // if such a row is present in the client cache. - find: (col_val: string): Player | undefined => { + find: (colVal: string): Player | undefined => { for (let row of this.tableCache.iter()) { - if (__deepEqual(row.ownerId, col_val)) { + if (__deepEqual(row.ownerId, colVal)) { return row; } } diff --git a/crates/bindings-typescript/test-app/src/module_bindings/user_table.ts b/crates/bindings-typescript/test-app/src/module_bindings/user_table.ts index 21275ac19c1..e8364a92e8f 100644 --- a/crates/bindings-typescript/test-app/src/module_bindings/user_table.ts +++ b/crates/bindings-typescript/test-app/src/module_bindings/user_table.ts @@ -76,11 +76,11 @@ export class UserTableHandle * Get a handle on the `identity` unique index on the table `user`. */ identity = { - // Find the subscribed row whose `identity` column value is equal to `col_val`, + // Find the subscribed row whose `identity` column value is equal to `colVal`, // if such a row is present in the client cache. - find: (col_val: __Identity): User | undefined => { + find: (colVal: __Identity): User | undefined => { for (let row of this.tableCache.iter()) { - if (__deepEqual(row.identity, col_val)) { + if (__deepEqual(row.identity, colVal)) { return row; } } diff --git a/crates/bindings-typescript/test-react-router-app/src/module_bindings/counter_table.ts b/crates/bindings-typescript/test-react-router-app/src/module_bindings/counter_table.ts index 6d99cb4b7c6..9ffbf83d2c4 100644 --- a/crates/bindings-typescript/test-react-router-app/src/module_bindings/counter_table.ts +++ b/crates/bindings-typescript/test-react-router-app/src/module_bindings/counter_table.ts @@ -76,11 +76,11 @@ export class CounterTableHandle * Get a handle on the `id` unique index on the table `counter`. */ id = { - // Find the subscribed row whose `id` column value is equal to `col_val`, + // Find the subscribed row whose `id` column value is equal to `colVal`, // if such a row is present in the client cache. - find: (col_val: number): Counter | undefined => { + find: (colVal: number): Counter | undefined => { for (let row of this.tableCache.iter()) { - if (__deepEqual(row.id, col_val)) { + if (__deepEqual(row.id, colVal)) { return row; } } diff --git a/crates/bindings-typescript/test-react-router-app/src/module_bindings/offline_user_table.ts b/crates/bindings-typescript/test-react-router-app/src/module_bindings/offline_user_table.ts index 47537ef2c6a..cb526e2dee8 100644 --- a/crates/bindings-typescript/test-react-router-app/src/module_bindings/offline_user_table.ts +++ b/crates/bindings-typescript/test-react-router-app/src/module_bindings/offline_user_table.ts @@ -76,11 +76,11 @@ export class OfflineUserTableHandle * Get a handle on the `identity` unique index on the table `offline_user`. */ identity = { - // Find the subscribed row whose `identity` column value is equal to `col_val`, + // Find the subscribed row whose `identity` column value is equal to `colVal`, // if such a row is present in the client cache. - find: (col_val: __Identity): User | undefined => { + find: (colVal: __Identity): User | undefined => { for (let row of this.tableCache.iter()) { - if (__deepEqual(row.identity, col_val)) { + if (__deepEqual(row.identity, colVal)) { return row; } } diff --git a/crates/bindings-typescript/test-react-router-app/src/module_bindings/user_table.ts b/crates/bindings-typescript/test-react-router-app/src/module_bindings/user_table.ts index 21275ac19c1..e8364a92e8f 100644 --- a/crates/bindings-typescript/test-react-router-app/src/module_bindings/user_table.ts +++ b/crates/bindings-typescript/test-react-router-app/src/module_bindings/user_table.ts @@ -76,11 +76,11 @@ export class UserTableHandle * Get a handle on the `identity` unique index on the table `user`. */ identity = { - // Find the subscribed row whose `identity` column value is equal to `col_val`, + // Find the subscribed row whose `identity` column value is equal to `colVal`, // if such a row is present in the client cache. - find: (col_val: __Identity): User | undefined => { + find: (colVal: __Identity): User | undefined => { for (let row of this.tableCache.iter()) { - if (__deepEqual(row.identity, col_val)) { + if (__deepEqual(row.identity, colVal)) { return row; } } diff --git a/crates/codegen/src/typescript.rs b/crates/codegen/src/typescript.rs index e8c793be5b8..2770fc4d6ab 100644 --- a/crates/codegen/src/typescript.rs +++ b/crates/codegen/src/typescript.rs @@ -167,7 +167,7 @@ impl Lang for TypeScript { * but to directly chain method calls, * like `ctx.db.{accessor_method}.on_insert(...)`. */ -export class {table_handle} implements __TableHandle {{ +export class {table_handle} extends __TableCache {{ " ); out.indent(1); @@ -373,11 +373,11 @@ removeOnUpdate = (cb: (ctx: EventContext, onRow: {row_type}, newRow: {row_type}) // version of the SDK. // // Eventually we can remove this and only generate use the `primaryKeyInfo` field. - writeln!(out, "primaryKey: \"{}\",", pk.col_name.to_string().to_case(Case::Camel)); + writeln!(out, "primaryKey: \"{}\" as const,", pk.col_name.to_string().to_case(Case::Camel)); writeln!(out, "primaryKeyInfo: {{"); out.indent(1); - writeln!(out, "colName: \"{}\",", pk.col_name.to_string().to_case(Case::Camel)); + writeln!(out, "colName: \"{}\" as const,", pk.col_name.to_string().to_case(Case::Camel)); writeln!( out, "colType: ({row_type}.getTypeScriptAlgebraicType() as __AlgebraicTypeVariants.Product).value.elements[{}].algebraicType,", @@ -396,7 +396,7 @@ removeOnUpdate = (cb: (ctx: EventContext, onRow: {row_type}, newRow: {row_type}) for reducer in iter_reducers(module) { writeln!(out, "{}: {{", reducer.name); out.indent(1); - writeln!(out, "reducerName: \"{}\",", reducer.name); + writeln!(out, "reducerName: \"{}\" as const,", reducer.name); writeln!( out, "argsType: {args_type}.getTypeScriptAlgebraicType(),", @@ -409,7 +409,7 @@ removeOnUpdate = (cb: (ctx: EventContext, onRow: {row_type}, newRow: {row_type}) writeln!(out, "}},"); writeln!(out, "versionInfo: {{"); out.indent(1); - writeln!(out, "cliVersion: \"{}\",", spacetimedb_lib_version()); + writeln!(out, "cliVersion: \"{}\" as const,", spacetimedb_lib_version()); out.dedent(1); writeln!(out, "}},"); writeln!( @@ -438,7 +438,7 @@ setReducerFlagsConstructor: () => {{ }}" ); out.dedent(1); - writeln!(out, "}}"); + writeln!(out, "}} satisfies __RemoteModule;"); // Define `type Reducer` enum. writeln!(out); @@ -693,6 +693,7 @@ fn print_spacetimedb_imports(out: &mut Indenter) { "type CallReducerFlags as __CallReducerFlags", "type EventContextInterface as __EventContextInterface", "type ReducerEventContextInterface as __ReducerEventContextInterface", + "type RemoteModule as __RemoteModule", "type SubscriptionEventContextInterface as __SubscriptionEventContextInterface", "type ErrorContextInterface as __ErrorContextInterface", "SubscriptionBuilderImpl as __SubscriptionBuilderImpl", From e9c0a6fe35f20f5219852b5fdd3b51c605c1c9de Mon Sep 17 00:00:00 2001 From: = Date: Sun, 2 Nov 2025 21:34:37 -0500 Subject: [PATCH 02/49] RemoteModule-ify --- .../src/sdk/client_cache.ts | 39 ++++---- .../src/sdk/db_connection_builder.ts | 19 ++-- .../src/sdk/db_connection_impl.ts | 99 +++++++++---------- .../bindings-typescript/src/sdk/db_context.ts | 13 ++- .../src/sdk/event_context.ts | 29 +++--- .../src/sdk/spacetime_module.ts | 46 ++------- .../src/sdk/subscription_builder_impl.ts | 54 ++++------ .../src/sdk/table_cache.ts | 29 +++--- .../src/sdk/table_handle.ts | 29 +++--- .../bindings-typescript/src/server/db_view.ts | 6 +- .../test-app/src/module_bindings/index.ts | 30 +++--- .../tests/table_cache.test.ts | 1 - 12 files changed, 164 insertions(+), 230 deletions(-) diff --git a/crates/bindings-typescript/src/sdk/client_cache.ts b/crates/bindings-typescript/src/sdk/client_cache.ts index 40b8c98bc08..f410911c454 100644 --- a/crates/bindings-typescript/src/sdk/client_cache.ts +++ b/crates/bindings-typescript/src/sdk/client_cache.ts @@ -1,6 +1,6 @@ import type { UntypedSchemaDef } from '../server/schema.ts'; import type { UntypedTableDef } from '../server/table.ts'; -import type { UntypedReducersDef } from './reducers.ts'; +import type { UntypedRemoteModule } from './spacetime_module.ts'; import { TableCache } from './table_cache.ts'; type TableName = @@ -12,40 +12,39 @@ export type TableDefForTableName = : UntypedTableDef; type TableCacheForTableName< - SchemaDef extends UntypedSchemaDef, - Reducers extends UntypedReducersDef, + RemoteModule extends UntypedRemoteModule, N -> = TableCache>; +> = TableCache>; /** * This is a helper class that provides a mapping from table names to their corresponding TableCache instances * while preserving the correspondence between the key and value type. */ -class TableMap { - private readonly map: Map>> = new Map(); +class TableMap { + private readonly map: Map>> = new Map(); - get>(key: K): TableCacheForTableName | undefined { + get>(key: K): TableCacheForTableName | undefined { // Cast required: a Map can't refine the union to the exact K-specific member on get(key: K). - return this.map.get(key) as TableCacheForTableName | undefined; + return this.map.get(key) as TableCacheForTableName | undefined; } - set>(key: K, value: TableCacheForTableName): this { + set>(key: K, value: TableCacheForTableName): this { this.map.set(key, value); return this; } - has(key: TableName): boolean { + has(key: TableName): boolean { return this.map.has(key); } - delete(key: TableName): boolean { + delete(key: TableName): boolean { return this.map.delete(key); } // optional: iteration stays broadly typed (cannot express per-key relation here) keys(): IterableIterator { return this.map.keys(); } - values(): IterableIterator>> { return this.map.values(); } - entries(): IterableIterator<[string, TableCacheForTableName>]> { return this.map.entries(); } + values(): IterableIterator>> { return this.map.values(); } + entries(): IterableIterator<[string, TableCacheForTableName>]> { return this.map.entries(); } [Symbol.iterator]() { return this.entries(); } } @@ -54,11 +53,11 @@ class TableMap { +export class ClientCache { /** * The tables in the database. */ - readonly tables = new TableMap(); + readonly tables = new TableMap(); /** * Returns the table with the given name. @@ -66,7 +65,7 @@ export class ClientCache>(name: N): TableCacheForTableName { + getTable>(name: N): TableCacheForTableName { const table = this.tables.get(name); if (!table) { console.error( @@ -83,9 +82,9 @@ export class ClientCache>( - tableDef: TableDefForTableName - ): TableCacheForTableName { + getOrCreateTable>( + tableDef: TableDefForTableName + ): TableCacheForTableName { const name = tableDef.name as N; let table = this.tables.get(name); @@ -93,7 +92,7 @@ export class ClientCache>(tableDef); + const newTable = new TableCache>(tableDef); this.tables.set(name, newTable); return newTable; } diff --git a/crates/bindings-typescript/src/sdk/db_connection_builder.ts b/crates/bindings-typescript/src/sdk/db_connection_builder.ts index b585cf35564..4eec420dd97 100644 --- a/crates/bindings-typescript/src/sdk/db_connection_builder.ts +++ b/crates/bindings-typescript/src/sdk/db_connection_builder.ts @@ -1,19 +1,16 @@ import { DbConnectionImpl, type ConnectionEvent } from './db_connection_impl'; import { EventEmitter } from './event_emitter'; import type { DbConnectionConfig, ErrorContextInterface, Identity, SubscriptionEventContextInterface } from '../'; -import { type RemoteModule, type RemoteModule2 } from './spacetime_module'; +import { type UntypedRemoteModule } from './spacetime_module'; import { ensureMinimumVersionOrThrow } from './version'; import { WebsocketDecompressAdapter } from './websocket_decompress_adapter'; -import type { UntypedSchemaDef } from '../server/schema'; -import type { UntypedReducersDef } from './reducers'; /** * The database client connection to a SpacetimeDB server. */ export class DbConnectionBuilder< - SchemaDef extends UntypedSchemaDef, - Reducers extends UntypedReducersDef, - DbConnection extends DbConnectionImpl, + RemoteModule extends UntypedRemoteModule, + DbConnection extends DbConnectionImpl, > { #uri?: URL; #nameOrAddress?: string; @@ -34,8 +31,8 @@ export class DbConnectionBuilder< * @param dbConnectionConstructor The constructor to use to create a new `DbConnection`. */ constructor( - private remoteModule: RemoteModule2, - private dbConnectionCtor: (config: DbConnectionConfig) => DbConnection + private remoteModule: RemoteModule, + private dbConnectionCtor: (config: DbConnectionConfig) => DbConnection ) { this.#createWSFn = WebsocketDecompressAdapter.createWebSocketFn; } @@ -181,7 +178,7 @@ export class DbConnectionBuilder< * }); * ``` */ - onConnectError(callback: (ctx: ErrorContextInterface, error: Error) => void): this { + onConnectError(callback: (ctx: ErrorContextInterface, error: Error) => void): this { this.#emitter.on('connectError', callback); return this; } @@ -213,7 +210,7 @@ export class DbConnectionBuilder< * @throws {Error} Throws an error if called multiple times on the same `DbConnectionBuilder`. */ onDisconnect( - callback: (ctx: ErrorContextInterface, error?: Error | undefined) => void + callback: (ctx: ErrorContextInterface, error?: Error | undefined) => void ): this { this.#emitter.on('disconnect', callback); return this; @@ -233,7 +230,7 @@ export class DbConnectionBuilder< * DbConnection.builder().withUri(host).withModuleName(name_or_address).withToken(auth_token).build(); * ``` */ - build(): DbConnectionImpl { + build(): DbConnectionImpl { if (!this.#uri) { throw new Error('URI is required to connect to SpacetimeDB'); } diff --git a/crates/bindings-typescript/src/sdk/db_connection_impl.ts b/crates/bindings-typescript/src/sdk/db_connection_impl.ts index 64c7b435554..fc270ac69ef 100644 --- a/crates/bindings-typescript/src/sdk/db_connection_impl.ts +++ b/crates/bindings-typescript/src/sdk/db_connection_impl.ts @@ -34,7 +34,7 @@ import type { UnsubscribeAppliedMessage, } from './message_types.ts'; import type { ReducerEvent } from './reducer_event.ts'; -import { type RemoteModule, type RemoteModule2 } from './spacetime_module.ts'; +import { type RemoteModule, type UntypedRemoteModule } from './spacetime_module.ts'; import { TableCache, type Operation, @@ -52,10 +52,8 @@ import { import { stdbLogger } from './logger.ts'; import { fromByteArray } from 'base64-js'; import type { ReducersView, SetReducerFlags, UntypedReducersDef } from './reducers.ts'; -import type { UntypedSchemaDef } from '../server/schema.ts'; import type { DbView } from '../server/db_view.ts'; -import type { RowType, UntypedTableDef } from '../server/table.ts'; -import type { CamelCase } from '../server/type_util.ts'; +import type { UntypedTableDef } from '../server/table.ts'; import { toCamelCase } from '../server/runtime.ts'; export { DbConnectionBuilder, SubscriptionBuilderImpl, TableCache, type Event }; @@ -72,13 +70,13 @@ export type { export type ConnectionEvent = 'connect' | 'disconnect' | 'connectError'; export type CallReducerFlags = 'FullUpdate' | 'NoSuccessNotify'; -type ReducerEventCallback = ( - ctx: ReducerEventContextInterface, +type ReducerEventCallback = ( + ctx: ReducerEventContextInterface, ...args: ReducerArgs ) => void; -type SubscriptionEventCallback = ( - ctx: SubscriptionEventContextInterface, +type SubscriptionEventCallback = ( + ctx: SubscriptionEventContextInterface, ) => void; function callReducerFlagsToNumber(flags: CallReducerFlags): number { @@ -90,7 +88,7 @@ function callReducerFlagsToNumber(flags: CallReducerFlags): number { } } -export type DbConnectionConfig = { +export type DbConnectionConfig = { uri: URL; nameOrAddress: string; identity?: Identity; @@ -100,13 +98,12 @@ export type DbConnectionConfig; + remoteModule: RemoteModule; }; export class DbConnectionImpl< - SchemaDef extends UntypedSchemaDef, - ReducersDef extends UntypedReducersDef, -> implements DbContext { + RemoteModule extends UntypedRemoteModule, +> implements DbContext { /** * Whether or not the connection is active. */ @@ -126,20 +123,20 @@ export class DbConnectionImpl< * The accessor field to access the tables in the database and associated * callback functions. */ - db: DbView; + db: DbView; /** * The accessor field to access the reducers in the database and associated * callback functions. */ - reducers: ReducersView; + reducers: ReducersView; /** * The accessor field to access functions related to setting flags on * reducers regarding how the server should handle the reducer call and * the events that it sends back to the client. */ - setReducerFlags: SetReducerFlags; + setReducerFlags: SetReducerFlags; /** * The `ConnectionId` of the connection to to the database. @@ -149,19 +146,19 @@ export class DbConnectionImpl< // These fields are meant to be strictly private. #queryId = 0; #emitter: EventEmitter; - #reducerEmitter: EventEmitter> = + #reducerEmitter: EventEmitter> = new EventEmitter(); - #onApplied?: SubscriptionEventCallback; + #onApplied?: SubscriptionEventCallback; #messageQueue = Promise.resolve(); - #subscriptionManager = new SubscriptionManager(); - #remoteModule: RemoteModule2; + #subscriptionManager = new SubscriptionManager(); + #remoteModule: RemoteModule; #callReducerFlags = new Map(); // These fields are not part of the public API, but in a pinch you // could use JavaScript to access them by bypassing TypeScript's // private fields. // We use them in testing. - private clientCache: ClientCache; + private clientCache: ClientCache; private ws?: WebsocketDecompressAdapter | WebsocketTestAdapter; private wsPromise: Promise< WebsocketDecompressAdapter | WebsocketTestAdapter | undefined @@ -178,7 +175,7 @@ export class DbConnectionImpl< compression, lightMode, confirmedReads, - }: DbConnectionConfig) { + }: DbConnectionConfig) { stdbLogger('info', 'Connecting to SpacetimeDB WS...'); // We use .toString() here because some versions of React Native contain a bug where the URL constructor @@ -198,10 +195,10 @@ export class DbConnectionImpl< const connectionId = this.connectionId.toHexString(); url.searchParams.set('connection_id', connectionId); - this.clientCache = new ClientCache(); - this.db = this.#makeDbView(remoteModule.tables); - this.reducers = this.#makeReducers(remoteModule.reducers); - this.setReducerFlags = this.#makeSetReducerFlags(remoteModule.reducers); + this.clientCache = new ClientCache(); + this.db = this.#makeDbView(remoteModule); + this.reducers = this.#makeReducers(remoteModule); + this.setReducerFlags = this.#makeSetReducerFlags(remoteModule); this.wsPromise = createWSFn({ url, @@ -239,8 +236,8 @@ export class DbConnectionImpl< return queryId; }; - #makeDbView(def: SchemaDef): DbView { - const view = Object.create(null) as DbView; + #makeDbView(def: RemoteModule): DbView { + const view = Object.create(null) as DbView; for (const tbl of def.tables) { // DbView uses this name verbatim @@ -257,7 +254,7 @@ export class DbConnectionImpl< return view; } - #makeReducers(def: ReducersDef): ReducersView { + #makeReducers(def: RemoteModule): ReducersView { const out: Record = {}; for (const reducer of def.reducers) { @@ -274,11 +271,11 @@ export class DbConnectionImpl< }; } - return out as ReducersView; + return out as ReducersView; } - #makeSetReducerFlags(defs: ReducersDef): SetReducerFlags { - const out = Object.create(null) as SetReducerFlags; + #makeSetReducerFlags(defs: RemoteModule): SetReducerFlags { + const out = Object.create(null) as SetReducerFlags; for (const r of defs.reducers) { const key = toCamelCase(r.name); Object.defineProperty(out, key, { @@ -293,8 +290,8 @@ export class DbConnectionImpl< } #makeEventContext( - event: Event - ): EventContextInterface { + event: Event + ): EventContextInterface { // Bind methods to preserve `this` (#private fields safe) return { db: this.db, @@ -314,13 +311,13 @@ export class DbConnectionImpl< // Do not remove this function, or shoot yourself in the foot please. // It's not clear what would be a better way to do this at this exact // moment. - subscriptionBuilder = (): SubscriptionBuilderImpl => { + subscriptionBuilder = (): SubscriptionBuilderImpl => { return new SubscriptionBuilderImpl(this); }; registerSubscription( - handle: SubscriptionHandleImpl, - handleEmitter: EventEmitter>, + handle: SubscriptionHandleImpl, + handleEmitter: EventEmitter>, querySql: string[] ): number { const queryId = this.#getNextQueryId(); @@ -365,7 +362,7 @@ export class DbConnectionImpl< const rows: Operation[] = []; // TODO: performance - const table = this.#remoteModule.tables.tables.find(t => t.name === tableName); + const table = this.#remoteModule.tables.find(t => t.name === tableName); const rowType = table!.rowType; const columnsArray = Object.entries(table!.columns); const primaryKeyColumnEntry = columnsArray.find(col => col[1].columnMetadata.isPrimaryKey); @@ -593,14 +590,14 @@ export class DbConnectionImpl< #applyTableUpdates( tableUpdates: CacheTableUpdate[], - eventContext: EventContextInterface + eventContext: EventContextInterface ): PendingCallback[] { const pendingCallbacks: PendingCallback[] = []; for (const tableUpdate of tableUpdates) { // Get table information for the table being updated const tableName = tableUpdate.tableName; // TODO: performance - const tableDef = this.#remoteModule.tables.tables.find(t => t.name === tableName)!; + const tableDef = this.#remoteModule.tables.find(t => t.name === tableName)!; const table = this.clientCache.getOrCreateTable(tableDef); const newCallbacks = table.applyOperations( tableUpdate.operations, @@ -655,7 +652,7 @@ export class DbConnectionImpl< let reducerInfo = message.reducerInfo; let unknownTransaction = false; let reducerArgs: any | undefined; - const reducer = this.#remoteModule.reducers.reducers.find(t => t.name === reducerInfo!.reducerName)!; + const reducer = this.#remoteModule.reducers.find(t => t.name === reducerInfo!.reducerName)!; if (!reducerInfo) { unknownTransaction = true; } else { @@ -899,63 +896,63 @@ export class DbConnectionImpl< private on( eventName: ConnectionEvent, - callback: (ctx: DbConnectionImpl, ...args: any[]) => void + callback: (ctx: DbConnectionImpl, ...args: any[]) => void ): void { this.#emitter.on(eventName, callback); } private off( eventName: ConnectionEvent, - callback: (ctx: DbConnectionImpl, ...args: any[]) => void + callback: (ctx: DbConnectionImpl, ...args: any[]) => void ): void { this.#emitter.off(eventName, callback); } private onConnect( - callback: (ctx: DbConnectionImpl, ...args: any[]) => void + callback: (ctx: DbConnectionImpl, ...args: any[]) => void ): void { this.#emitter.on('connect', callback); } private onDisconnect( - callback: (ctx: DbConnectionImpl, ...args: any[]) => void + callback: (ctx: DbConnectionImpl, ...args: any[]) => void ): void { this.#emitter.on('disconnect', callback); } private onConnectError( - callback: (ctx: DbConnectionImpl, ...args: any[]) => void + callback: (ctx: DbConnectionImpl, ...args: any[]) => void ): void { this.#emitter.on('connectError', callback); } removeOnConnect( - callback: (ctx: DbConnectionImpl, ...args: any[]) => void + callback: (ctx: DbConnectionImpl, ...args: any[]) => void ): void { this.#emitter.off('connect', callback); } removeOnDisconnect( - callback: (ctx: DbConnectionImpl, ...args: any[]) => void + callback: (ctx: DbConnectionImpl, ...args: any[]) => void ): void { this.#emitter.off('disconnect', callback); } removeOnConnectError( - callback: (ctx: DbConnectionImpl, ...args: any[]) => void + callback: (ctx: DbConnectionImpl, ...args: any[]) => void ): void { this.#emitter.off('connectError', callback); } // Note: This is required to be public because it needs to be // called from the `RemoteReducers` class. - onReducer(reducerName: string, callback: ReducerEventCallback): void { + onReducer(reducerName: string, callback: ReducerEventCallback): void { this.#reducerEmitter.on(reducerName, callback); } // Note: This is required to be public because it needs to be // called from the `RemoteReducers` class. - offReducer(reducerName: string, callback: ReducerEventCallback): void { + offReducer(reducerName: string, callback: ReducerEventCallback): void { this.#reducerEmitter.off(reducerName, callback); } } diff --git a/crates/bindings-typescript/src/sdk/db_context.ts b/crates/bindings-typescript/src/sdk/db_context.ts index 7d5d0da464c..cb7f76579a1 100644 --- a/crates/bindings-typescript/src/sdk/db_context.ts +++ b/crates/bindings-typescript/src/sdk/db_context.ts @@ -1,6 +1,6 @@ import type { DbView } from '../server/db_view'; -import type { UntypedSchemaDef } from '../server/schema'; import type { ReducersView, SetReducerFlags, UntypedReducersDef } from './reducers'; +import type { SchemaDef, UntypedRemoteModule } from './spacetime_module'; import type { SubscriptionBuilderImpl } from './subscription_builder_impl'; /** @@ -10,10 +10,10 @@ import type { SubscriptionBuilderImpl } from './subscription_builder_impl'; * @template ReducersDef - Type representing the reducers. * @template SetReducerFlags - Type representing the reducer flags collection. */ -export interface DbContext { - db: DbView; - reducers: ReducersView; - setReducerFlags: SetReducerFlags; +export interface DbContext { + db: DbView; + reducers: ReducersView; + setReducerFlags: SetReducerFlags; isActive: boolean; /** @@ -22,8 +22,7 @@ export interface DbContext; /** diff --git a/crates/bindings-typescript/src/sdk/event_context.ts b/crates/bindings-typescript/src/sdk/event_context.ts index 459cfbfeaf0..1a69b4c2a3c 100644 --- a/crates/bindings-typescript/src/sdk/event_context.ts +++ b/crates/bindings-typescript/src/sdk/event_context.ts @@ -1,39 +1,34 @@ -import type { UntypedSchemaDef } from '../server/schema.ts'; import type { DbContext } from './db_context'; import type { Event } from './event.ts'; import type { ReducerEvent } from './reducer_event.ts'; -import type { UntypedReducersDef } from './reducers.ts'; +import type { UntypedRemoteModule } from './spacetime_module.ts'; -export type UntypedEventContext = EventContextInterface; +export type UntypedEventContext = EventContextInterface; export interface EventContextInterface< - SchemaDef extends UntypedSchemaDef, - Reducers extends UntypedReducersDef, -> extends DbContext { + RemoteModule extends UntypedRemoteModule, +> extends DbContext { /** Enum with variants for all possible events. */ - event: Event; + event: Event; } export interface ReducerEventContextInterface< - SchemaDef extends UntypedSchemaDef, - Reducers extends UntypedReducersDef, -> extends DbContext { + RemoteModule extends UntypedRemoteModule, +> extends DbContext { /** Enum with variants for all possible events. */ - event: ReducerEvent; + event: ReducerEvent; } // eslint-disable-next-line @typescript-eslint/no-empty-object-type export interface SubscriptionEventContextInterface< - SchemaDef extends UntypedSchemaDef, - Reducers extends UntypedReducersDef, -> extends DbContext { + RemoteModule extends UntypedRemoteModule, +> extends DbContext { /** No event is provided **/ } export interface ErrorContextInterface< - SchemaDef extends UntypedSchemaDef, - Reducers extends UntypedReducersDef, -> extends DbContext { + RemoteModule extends UntypedRemoteModule, +> extends DbContext { /** Enum with variants for all possible events. */ event?: Error; } diff --git a/crates/bindings-typescript/src/sdk/spacetime_module.ts b/crates/bindings-typescript/src/sdk/spacetime_module.ts index 72ad623703e..f9326331198 100644 --- a/crates/bindings-typescript/src/sdk/spacetime_module.ts +++ b/crates/bindings-typescript/src/sdk/spacetime_module.ts @@ -1,44 +1,18 @@ -import type { AlgebraicType } from '../'; import type { UntypedSchemaDef } from '../server/schema'; -import type { DbConnectionImpl } from './db_connection_impl'; import type { UntypedReducersDef } from './reducers'; -export interface TableRuntimeTypeInfo { - tableName: string; - rowType: AlgebraicType; - primaryKey?: string; - primaryKeyInfo?: PrimaryKeyInfo; -} - -export interface PrimaryKeyInfo { - colName: string; - colType: AlgebraicType; -} - -export interface ReducerRuntimeTypeInfo { - reducerName: string; - argsType: AlgebraicType; -} - -export type RemoteModule2 = { +export type RemoteModule< + SchemaDef extends UntypedSchemaDef, + ReducersDef extends UntypedReducersDef, + CLI extends string = string +> = SchemaDef & ReducersDef & { versionInfo: { cliVersion: CLI; }; - tables: SchemaDef; - reducers: ReducersDef; } -export interface RemoteModule { - tables: { [name: string]: TableRuntimeTypeInfo }; - reducers: { [name: string]: ReducerRuntimeTypeInfo }; - eventContextConstructor: (imp: DbConnectionImpl, event: any) => any; - dbViewConstructor: (connection: DbConnectionImpl) => any; - reducersConstructor: ( - connection: DbConnectionImpl, - setReducerFlags: any - ) => any; - setReducerFlagsConstructor: () => any; - versionInfo?: { - cliVersion: string; - }; -} +export type UntypedRemoteModule = RemoteModule; + +export type SchemaDef = RemoteModule['tables']; + +export type ReducersDef = RemoteModule['reducers']; \ No newline at end of file diff --git a/crates/bindings-typescript/src/sdk/subscription_builder_impl.ts b/crates/bindings-typescript/src/sdk/subscription_builder_impl.ts index a0856367b7b..842e055b791 100644 --- a/crates/bindings-typescript/src/sdk/subscription_builder_impl.ts +++ b/crates/bindings-typescript/src/sdk/subscription_builder_impl.ts @@ -1,24 +1,22 @@ -import type { UntypedSchemaDef } from '../server/schema'; import type { DbConnectionImpl } from './db_connection_impl'; import type { ErrorContextInterface, SubscriptionEventContextInterface, } from './event_context'; import { EventEmitter } from './event_emitter'; -import type { UntypedReducersDef } from './reducers'; +import type { UntypedRemoteModule } from './spacetime_module'; export class SubscriptionBuilderImpl< - SchemaDef extends UntypedSchemaDef, - Reducers extends UntypedReducersDef, + RemoteModule extends UntypedRemoteModule, > { #onApplied?: ( - ctx: SubscriptionEventContextInterface + ctx: SubscriptionEventContextInterface ) => void = undefined; #onError?: ( - ctx: ErrorContextInterface + ctx: ErrorContextInterface ) => void = undefined; constructor( - private db: DbConnectionImpl + private db: DbConnectionImpl ) {} /** @@ -38,9 +36,9 @@ export class SubscriptionBuilderImpl< */ onApplied( cb: ( - ctx: SubscriptionEventContextInterface + ctx: SubscriptionEventContextInterface ) => void - ): SubscriptionBuilderImpl { + ): SubscriptionBuilderImpl { this.#onApplied = cb; return this; } @@ -66,8 +64,8 @@ export class SubscriptionBuilderImpl< * @returns The current `SubscriptionBuilder` instance. */ onError( - cb: (ctx: ErrorContextInterface) => void - ): SubscriptionBuilderImpl { + cb: (ctx: ErrorContextInterface) => void + ): SubscriptionBuilderImpl { this.#onError = cb; return this; } @@ -90,7 +88,7 @@ export class SubscriptionBuilderImpl< */ subscribe( query_sql: string | string[] - ): SubscriptionHandleImpl { + ): SubscriptionHandleImpl { const queries = Array.isArray(query_sql) ? query_sql : [query_sql]; if (queries.length === 0) { throw new Error('Subscriptions must have at least one query'); @@ -127,16 +125,15 @@ export class SubscriptionBuilderImpl< export type SubscribeEvent = 'applied' | 'error' | 'end'; -export class SubscriptionManager { +export class SubscriptionManager { subscriptions: Map< number, - { handle: SubscriptionHandleImpl; emitter: EventEmitter } + { handle: SubscriptionHandleImpl; emitter: EventEmitter } > = new Map(); } export class SubscriptionHandleImpl< - SchemaDef extends UntypedSchemaDef, - Reducers extends UntypedReducersDef, + RemoteModule extends UntypedRemoteModule, > { #queryId: number; #unsubscribeCalled: boolean = false; @@ -146,23 +143,20 @@ export class SubscriptionHandleImpl< new EventEmitter(); constructor( - private db: DbConnectionImpl, + private db: DbConnectionImpl, querySql: string[], onApplied?: ( - ctx: SubscriptionEventContextInterface + ctx: SubscriptionEventContextInterface ) => void, onError?: ( - ctx: ErrorContextInterface, + ctx: ErrorContextInterface, error: Error ) => void ) { this.#emitter.on( 'applied', ( - ctx: SubscriptionEventContextInterface< - SchemaDef, - Reducers - > + ctx: SubscriptionEventContextInterface ) => { this.#activeState = true; if (onApplied) { @@ -173,7 +167,7 @@ export class SubscriptionHandleImpl< this.#emitter.on( 'error', ( - ctx: ErrorContextInterface, + ctx: ErrorContextInterface, error: Error ) => { this.#activeState = false; @@ -200,10 +194,7 @@ export class SubscriptionHandleImpl< this.#emitter.on( 'end', ( - _ctx: SubscriptionEventContextInterface< - SchemaDef, - Reducers - > + _ctx: SubscriptionEventContextInterface ) => { this.#endedState = true; this.#activeState = false; @@ -223,7 +214,7 @@ export class SubscriptionHandleImpl< */ unsubscribeThen( onEnd: ( - ctx: SubscriptionEventContextInterface + ctx: SubscriptionEventContextInterface ) => void ): void { if (this.#endedState) { @@ -237,10 +228,7 @@ export class SubscriptionHandleImpl< this.#emitter.on( 'end', ( - ctx: SubscriptionEventContextInterface< - SchemaDef, - Reducers - > + ctx: SubscriptionEventContextInterface ) => { this.#endedState = true; this.#activeState = false; diff --git a/crates/bindings-typescript/src/sdk/table_cache.ts b/crates/bindings-typescript/src/sdk/table_cache.ts index cd79debf72e..53521530beb 100644 --- a/crates/bindings-typescript/src/sdk/table_cache.ts +++ b/crates/bindings-typescript/src/sdk/table_cache.ts @@ -1,13 +1,11 @@ import { EventEmitter } from './event_emitter.ts'; -import type { TableRuntimeTypeInfo } from './spacetime_module.ts'; import { stdbLogger } from './logger.ts'; import type { ComparablePrimitive } from '../'; import type { EventContextInterface, ClientTable } from './index.ts'; import type { RowType, Table, UntypedTableDef } from '../server/table.ts'; -import type { UntypedSchemaDef } from '../server/schema.ts'; -import type { UntypedReducersDef } from './reducers.ts'; import type { ClientTableCore } from './table_handle.ts'; +import type { UntypedRemoteModule } from './spacetime_module.ts'; export type Operation< RowType extends Record = Record, @@ -35,10 +33,9 @@ export type PendingCallback = { * Builder to generate calls to query a `table` in the database */ export class TableCache< - SchemaDef extends UntypedSchemaDef, - Reducers extends UntypedReducersDef, + RemoteModule extends UntypedRemoteModule, TableDef extends UntypedTableDef, -> implements ClientTableCore { +> implements ClientTableCore { private rows: Map, number]>; private tableDef: TableDef; private emitter: EventEmitter<'insert' | 'delete' | 'update'>; @@ -84,7 +81,7 @@ export class TableCache< applyOperations = ( operations: Operation>[], - ctx: EventContextInterface + ctx: EventContextInterface ): PendingCallback[] => { const pendingCallbacks: PendingCallback[] = []; // TODO: performance @@ -157,7 +154,7 @@ export class TableCache< }; update = ( - ctx: EventContextInterface, + ctx: EventContextInterface, rowId: ComparablePrimitive, newRow: RowType, refCountDelta: number = 0 @@ -205,7 +202,7 @@ export class TableCache< }; insert = ( - ctx: EventContextInterface, + ctx: EventContextInterface, operation: Operation>, count: number = 1 ): PendingCallback | undefined => { @@ -228,7 +225,7 @@ export class TableCache< }; delete = ( - ctx: EventContextInterface, + ctx: EventContextInterface, operation: Operation>, count: number = 1 ): PendingCallback | undefined => { @@ -273,7 +270,7 @@ export class TableCache< * @param cb Callback to be called when a new row is inserted */ onInsert = ( - cb: (ctx: EventContextInterface, row: RowType) => void + cb: (ctx: EventContextInterface, row: RowType) => void ): void => { this.emitter.on('insert', cb); }; @@ -294,7 +291,7 @@ export class TableCache< * @param cb Callback to be called when a new row is inserted */ onDelete = ( - cb: (ctx: EventContextInterface, row: RowType) => void + cb: (ctx: EventContextInterface, row: RowType) => void ): void => { this.emitter.on('delete', cb); }; @@ -315,7 +312,7 @@ export class TableCache< * @param cb Callback to be called when a new row is inserted */ onUpdate = ( - cb: (ctx: EventContextInterface, oldRow: RowType, row: RowType) => void + cb: (ctx: EventContextInterface, oldRow: RowType, row: RowType) => void ): void => { this.emitter.on('update', cb); }; @@ -326,7 +323,7 @@ export class TableCache< * @param cb Callback to be removed */ removeOnInsert = ( - cb: (ctx: EventContextInterface, row: RowType) => void + cb: (ctx: EventContextInterface, row: RowType) => void ): void => { this.emitter.off('insert', cb); }; @@ -337,7 +334,7 @@ export class TableCache< * @param cb Callback to be removed */ removeOnDelete = ( - cb: (ctx: EventContextInterface, row: RowType) => void + cb: (ctx: EventContextInterface, row: RowType) => void ): void => { this.emitter.off('delete', cb); }; @@ -348,7 +345,7 @@ export class TableCache< * @param cb Callback to be removed */ removeOnUpdate = ( - cb: (ctx: EventContextInterface, oldRow: RowType, row: RowType) => void + cb: (ctx: EventContextInterface, oldRow: RowType, row: RowType) => void ): void => { this.emitter.off('update', cb); }; diff --git a/crates/bindings-typescript/src/sdk/table_handle.ts b/crates/bindings-typescript/src/sdk/table_handle.ts index 757caae4e80..9751d8edc96 100644 --- a/crates/bindings-typescript/src/sdk/table_handle.ts +++ b/crates/bindings-typescript/src/sdk/table_handle.ts @@ -1,36 +1,34 @@ import type { ReadonlyIndexes } from "../server/indexes"; -import type { UntypedSchemaDef } from "../server/schema"; import type { ReadonlyTableMethods, RowType, TableIndexes, UntypedTableDef } from "../server/table"; import type { Prettify } from "../server/type_util"; import type { EventContextInterface } from "./event_context"; -import type { UntypedReducersDef } from "./reducers"; +import type { UntypedRemoteModule } from "./spacetime_module"; export type ClientTableMethods< - SchemaDef extends UntypedSchemaDef, - Reducers extends UntypedReducersDef, + RemoteModule extends UntypedRemoteModule, TableDef extends UntypedTableDef, > = { /** * Registers a callback to be invoked when a row is inserted into the table. */ - onInsert(cb: (ctx: EventContextInterface, row: RowType) => void): void; + onInsert(cb: (ctx: EventContextInterface, row: RowType) => void): void; /** * Removes a previously registered insert event listener. * @param cb The callback to remove from the insert event listeners. */ - removeOnInsert(cb: (ctx: EventContextInterface, row: RowType) => void): void; + removeOnInsert(cb: (ctx: EventContextInterface, row: RowType) => void): void; /** * Registers a callback to be invoked when a row is deleted from the table. */ - onDelete(cb: (ctx: EventContextInterface, row: RowType) => void): void; + onDelete(cb: (ctx: EventContextInterface, row: RowType) => void): void; /** * Removes a previously registered delete event listener. * @param cb The callback to remove from the delete event listeners. */ - removeOnDelete(cb: (ctx: EventContextInterface, row: RowType) => void): void; + removeOnDelete(cb: (ctx: EventContextInterface, row: RowType) => void): void; }; /** @@ -41,11 +39,10 @@ export type ClientTableMethods< * - AIO: auto-increment overflow error type (never if none) */ export type ClientTable< - SchemaDef extends UntypedSchemaDef, - Reducers extends UntypedReducersDef, + RemoteModule extends UntypedRemoteModule, TableDef extends UntypedTableDef > = Prettify< - ClientTableCore & + ClientTableCore & ReadonlyIndexes> >; @@ -54,19 +51,17 @@ export type ClientTable< * Includes only staticly known methods. */ export type ClientTableCore< - SchemaDef extends UntypedSchemaDef, - Reducers extends UntypedReducersDef, + RemoteModule extends UntypedRemoteModule, TableDef extends UntypedTableDef, > = ReadonlyTableMethods & - ClientTableMethods; + ClientTableMethods; /** * Client database view, mapping table names to their corresponding ClientTable handles. */ export type ClientDbView< - SchemaDef extends UntypedSchemaDef, - Reducers extends UntypedReducersDef, + RemoteModule extends UntypedRemoteModule, > = { - readonly [Tbl in SchemaDef['tables'][number] as Tbl['name']]: ClientTable; + readonly [Tbl in RemoteModule['tables'][number] as Tbl['name']]: ClientTable; }; \ No newline at end of file diff --git a/crates/bindings-typescript/src/server/db_view.ts b/crates/bindings-typescript/src/server/db_view.ts index 3ba53c0da55..ad8e540d192 100644 --- a/crates/bindings-typescript/src/server/db_view.ts +++ b/crates/bindings-typescript/src/server/db_view.ts @@ -1,5 +1,5 @@ import type { ClientTable } from "../sdk"; -import type { UntypedReducersDef } from "../sdk/reducers"; +import type { UntypedRemoteModule } from "../sdk/spacetime_module"; import type { UntypedSchemaDef } from "./schema"; import type { ReadonlyTable, Table } from "./table"; @@ -13,8 +13,8 @@ export type ReadonlyDbView = { /** * A type representing a client-side database view, mapping table names to their corresponding client Table handles. */ -export type ClientDbView = { - readonly [Tbl in SchemaDef['tables'][number] as Tbl['accessorName']]: ClientTable; +export type ClientDbView = { + readonly [Tbl in RemoteModule['tables'][number] as Tbl['accessorName']]: ClientTable; }; /** diff --git a/crates/bindings-typescript/test-app/src/module_bindings/index.ts b/crates/bindings-typescript/test-app/src/module_bindings/index.ts index 908c9243607..09683ccc7fa 100644 --- a/crates/bindings-typescript/test-app/src/module_bindings/index.ts +++ b/crates/bindings-typescript/test-app/src/module_bindings/index.ts @@ -57,7 +57,7 @@ import { schema } from '../../../src/server/schema.ts'; import t from '../../../src/server/type_builders.ts'; import { table } from '../../../src/server/table.ts'; import { reducerSchema, reducers } from '../../../src/server/reducers.ts'; -import { RemoteModule2 } from '../../../src/sdk/spacetime_module.ts'; +import { RemoteModule } from '../../../src/sdk/spacetime_module.ts'; export { User }; const pointType = t.object('Point', { @@ -97,47 +97,41 @@ const REMOTE_MODULE = { versionInfo: { cliVersion: '1.6.0' as const, }, - tables: tablesSchema.schemaType, - reducers: reducersSchema.reducersType, -} satisfies RemoteModule2< + tables: tablesSchema.schemaType.tables, + reducers: reducersSchema.reducersType.reducers, +} satisfies RemoteModule< typeof tablesSchema.schemaType, typeof reducersSchema.reducersType >; export type EventContext = __EventContextInterface< - typeof tablesSchema.schemaType, - typeof reducersSchema.reducersType + typeof REMOTE_MODULE >; export type ReducerEventContext = __ReducerEventContextInterface< - typeof tablesSchema.schemaType, - typeof reducersSchema.reducersType + typeof REMOTE_MODULE >; export type SubscriptionEventContext = __SubscriptionEventContextInterface< - typeof tablesSchema.schemaType, - typeof reducersSchema.reducersType + typeof REMOTE_MODULE >; export type ErrorContext = __ErrorContextInterface< - typeof tablesSchema.schemaType, - typeof reducersSchema.reducersType + typeof REMOTE_MODULE >; export class SubscriptionBuilder extends __SubscriptionBuilderImpl< - typeof tablesSchema.schemaType, - typeof reducersSchema.reducersType + typeof REMOTE_MODULE > {} export class DbConnectionBuilder extends __DbConnectionBuilder< - typeof tablesSchema.schemaType, - typeof reducersSchema.reducersType, + typeof REMOTE_MODULE, DbConnection > {}; -export class DbConnection extends __DbConnectionImpl { +export class DbConnection extends __DbConnectionImpl { static builder = (): DbConnectionBuilder => { - return new DbConnectionBuilder(REMOTE_MODULE, (config: DbConnectionConfig) => new DbConnection(config)); + return new DbConnectionBuilder(REMOTE_MODULE, (config: DbConnectionConfig) => new DbConnection(config)); }; subscriptionBuilder = (): SubscriptionBuilder => { return new SubscriptionBuilder(this); diff --git a/crates/bindings-typescript/tests/table_cache.test.ts b/crates/bindings-typescript/tests/table_cache.test.ts index eef948ba6be..f5961e9a4fd 100644 --- a/crates/bindings-typescript/tests/table_cache.test.ts +++ b/crates/bindings-typescript/tests/table_cache.test.ts @@ -1,5 +1,4 @@ import { type Operation, TableCache } from '../src/sdk/table_cache'; -import type { TableRuntimeTypeInfo } from '../src/sdk/spacetime_module'; import { describe, expect, test } from 'vitest'; import { Player } from '../test-app/src/module_bindings/player_type.ts'; From 541f493fb18da5c93c321b410785042f2cbfe463 Mon Sep 17 00:00:00 2001 From: = Date: Sun, 2 Nov 2025 22:09:01 -0500 Subject: [PATCH 03/49] Smaller fixes --- .../src/react/SpacetimeDBProvider.ts | 25 ++++++++--------- .../src/react/connection_state.ts | 3 +- .../src/react/useReducer.ts | 28 ++++++++++--------- .../src/react/useSpacetimeDB.ts | 7 +++-- .../bindings-typescript/src/react/useTable.ts | 16 +++++------ .../src/sdk/db_connection_impl.ts | 10 +++---- .../bindings-typescript/src/sdk/db_context.ts | 6 ++-- 7 files changed, 49 insertions(+), 46 deletions(-) diff --git a/crates/bindings-typescript/src/react/SpacetimeDBProvider.ts b/crates/bindings-typescript/src/react/SpacetimeDBProvider.ts index 6899bed3610..7ddd5b95981 100644 --- a/crates/bindings-typescript/src/react/SpacetimeDBProvider.ts +++ b/crates/bindings-typescript/src/react/SpacetimeDBProvider.ts @@ -8,26 +8,25 @@ import * as React from 'react'; import { SpacetimeDBContext } from './useSpacetimeDB'; import type { ConnectionState } from './connection_state'; import { ConnectionId } from '../lib/connection_id'; +import type { UntypedRemoteModule } from '../sdk/spacetime_module'; export interface SpacetimeDBProviderProps< - DbConnection extends DbConnectionImpl, - ErrorContext extends ErrorContextInterface, - SubscriptionEventContext extends SubscriptionEventContextInterface, + RemoteModule extends UntypedRemoteModule, + DbConnection extends DbConnectionImpl, > { - connectionBuilder: DbConnectionBuilder; + connectionBuilder: DbConnectionBuilder; children?: React.ReactNode; } export function SpacetimeDBProvider< - DbConnection extends DbConnectionImpl, - ErrorContext extends ErrorContextInterface, - SubscriptionEventContext extends SubscriptionEventContextInterface, ->({ connectionBuilder, children }: SpacetimeDBProviderProps) { + RemoteModule extends UntypedRemoteModule, + DbConnection extends DbConnectionImpl, +>({ connectionBuilder, children }: SpacetimeDBProviderProps) { // Holds the imperative connection instance when (and only when) we’re on the client. const connRef = React.useRef(null); const getConnection = React.useCallback(() => connRef.current, []); - const [state, setState] = React.useState>({ + const [state, setState] = React.useState>({ isActive: false, identity: undefined, token: undefined, @@ -39,7 +38,7 @@ export function SpacetimeDBProvider< // Build on the client only; useEffect won't run during SSR. React.useEffect(() => { // Register callback for onConnect to update state - const onConnect = (conn: DbConnectionImpl) => { + const onConnect = (conn: DbConnectionImpl) => { setState(s => ({ ...s, isActive: conn.isActive, @@ -48,13 +47,13 @@ export function SpacetimeDBProvider< connectionId: conn.connectionId, })); }; - const onDisconnect = (ctx: ErrorContextInterface) => { + const onDisconnect = (ctx: ErrorContextInterface) => { setState(s => ({ ...s, isActive: ctx.isActive, })); }; - const onConnectError = (ctx: ErrorContextInterface, err: Error) => { + const onConnectError = (ctx: ErrorContextInterface, err: Error) => { setState(s => ({ ...s, isActive: ctx.isActive, @@ -76,7 +75,7 @@ export function SpacetimeDBProvider< // Lazily build once if (!connRef.current) { - connRef.current = connectionBuilder.build(); + connRef.current = connectionBuilder.build() as DbConnection; } return () => { diff --git a/crates/bindings-typescript/src/react/connection_state.ts b/crates/bindings-typescript/src/react/connection_state.ts index 4f45c6b902e..6d63e91d693 100644 --- a/crates/bindings-typescript/src/react/connection_state.ts +++ b/crates/bindings-typescript/src/react/connection_state.ts @@ -1,8 +1,9 @@ import type { ConnectionId } from "../lib/connection_id"; import type { Identity } from "../lib/identity"; import type { DbConnectionImpl } from "../sdk/db_connection_impl"; +import type { UntypedRemoteModule } from "../sdk/spacetime_module"; -export type ConnectionState = { +export type ConnectionState> = { isActive: boolean; identity?: Identity; token?: string; diff --git a/crates/bindings-typescript/src/react/useReducer.ts b/crates/bindings-typescript/src/react/useReducer.ts index dab84320ed2..b7684234b46 100644 --- a/crates/bindings-typescript/src/react/useReducer.ts +++ b/crates/bindings-typescript/src/react/useReducer.ts @@ -1,17 +1,19 @@ import type { DbConnectionImpl } from "../sdk/db_connection_impl"; import type { ReducerNamesFromReducers } from "../sdk/reducer_handle"; +import type { UntypedRemoteModule } from "../sdk/spacetime_module"; import { useSpacetimeDB } from "./useSpacetimeDB"; -// export function useReducer< -// DbConnection extends DbConnectionImpl, -// ReducerName extends ReducerNamesFromReducers = ReducerNamesFromReducers< -// DbConnection['reducers'] -// >, -// ReducerType = DbConnection['reducers'][ReducerName & keyof DbConnection['reducers']] -// >( -// reducerName: ReducerName, -// ): ReducerType { -// const connectionState = useSpacetimeDB(); -// const connection = connectionState.getConnection()!; -// return connection.reducers[reducerName as keyof typeof connection.reducers]; -// } \ No newline at end of file +export function useReducer< + RemoteModule extends UntypedRemoteModule, + DbConnection extends DbConnectionImpl, + ReducerName extends ReducerNamesFromReducers = ReducerNamesFromReducers< + DbConnection['reducers'] + >, + ReducerType = DbConnection['reducers'][ReducerName & keyof DbConnection['reducers']] +>( + reducerName: ReducerName, +): ReducerType { + const connectionState = useSpacetimeDB(); + const connection = connectionState.getConnection()!; + return connection.reducers[reducerName as keyof typeof connection.reducers]; +} \ No newline at end of file diff --git a/crates/bindings-typescript/src/react/useSpacetimeDB.ts b/crates/bindings-typescript/src/react/useSpacetimeDB.ts index 17f180b9878..c0421a2ffd2 100644 --- a/crates/bindings-typescript/src/react/useSpacetimeDB.ts +++ b/crates/bindings-typescript/src/react/useSpacetimeDB.ts @@ -1,13 +1,14 @@ import { createContext, useContext } from 'react'; import type { DbConnectionImpl } from '../sdk/db_connection_impl'; import type { ConnectionState } from './connection_state'; +import type { UntypedRemoteModule } from '../sdk/spacetime_module'; -export const SpacetimeDBContext = createContext | undefined>(undefined); +export const SpacetimeDBContext = createContext> | undefined>(undefined); // Throws an error if used outside of a SpacetimeDBProvider // Error is caught by other hooks like useTable so they can provide better error messages -export function useSpacetimeDB(): ConnectionState { - const context = useContext(SpacetimeDBContext) as ConnectionState | undefined; +export function useSpacetimeDB>(): ConnectionState { + const context = useContext(SpacetimeDBContext) as ConnectionState | undefined; if (!context) { throw new Error( 'useSpacetimeDB must be used within a SpacetimeDBProvider component. Did you forget to add a `SpacetimeDBProvider` to your component tree?' diff --git a/crates/bindings-typescript/src/react/useTable.ts b/crates/bindings-typescript/src/react/useTable.ts index 5c81fdf2ed4..6a7f0f48782 100644 --- a/crates/bindings-typescript/src/react/useTable.ts +++ b/crates/bindings-typescript/src/react/useTable.ts @@ -9,6 +9,7 @@ import { useSpacetimeDB } from './useSpacetimeDB'; import { DbConnectionImpl, TableCache } from '../sdk/db_connection_impl'; import type { TableNamesFromDb } from '../sdk/table_handle'; import type { ConnectionState } from './connection_state'; +import type { UntypedRemoteModule } from '../sdk/spacetime_module'; export interface UseQueryCallbacks { onInsert?: (row: RowType) => void; @@ -212,7 +213,7 @@ type ColumnsFromRow = { * ``` */ export function useTable< - DbConnection extends DbConnectionImpl, + DbConnection extends DbConnectionImpl, RowType extends Record, TableName extends TableNamesFromDb = TableNamesFromDb< DbConnection['db'] @@ -257,7 +258,7 @@ export function useTable< * ``` */ export function useTable< - DbConnection extends DbConnectionImpl, + DbConnection extends DbConnectionImpl, RowType extends Record, TableName extends TableNamesFromDb = TableNamesFromDb< DbConnection['db'] @@ -268,8 +269,7 @@ export function useTable< ): Snapshot; export function useTable< - DbConnection extends DbConnectionImpl, - RowType extends Record, + DbConnection extends DbConnectionImpl, TableName extends TableNamesFromDb = TableNamesFromDb< DbConnection['db'] >, @@ -320,10 +320,10 @@ export function useTable< } const table = connection.db[ tableName as keyof typeof connection.db - ] as unknown as TableCache; + ]; const result: readonly RowType[] = whereClause - ? table.iter().filter(row => evaluate(whereClause, row)) - : table.iter(); + ? Array.from(table.iter()).filter(row => evaluate(whereClause, row)) + : Array.from(table.iter()); return { rows: result, state: subscribeApplied ? 'ready' : 'loading', @@ -412,7 +412,7 @@ export function useTable< const table = connection.db[ tableName as keyof typeof connection.db - ] as unknown as TableCache; + ]; table.onInsert(onInsert); table.onDelete(onDelete); table.onUpdate?.(onUpdate); diff --git a/crates/bindings-typescript/src/sdk/db_connection_impl.ts b/crates/bindings-typescript/src/sdk/db_connection_impl.ts index fc270ac69ef..12bf41202f7 100644 --- a/crates/bindings-typescript/src/sdk/db_connection_impl.ts +++ b/crates/bindings-typescript/src/sdk/db_connection_impl.ts @@ -52,7 +52,7 @@ import { import { stdbLogger } from './logger.ts'; import { fromByteArray } from 'base64-js'; import type { ReducersView, SetReducerFlags, UntypedReducersDef } from './reducers.ts'; -import type { DbView } from '../server/db_view.ts'; +import type { ClientDbView, DbView } from '../server/db_view.ts'; import type { UntypedTableDef } from '../server/table.ts'; import { toCamelCase } from '../server/runtime.ts'; @@ -123,7 +123,7 @@ export class DbConnectionImpl< * The accessor field to access the tables in the database and associated * callback functions. */ - db: DbView; + db: ClientDbView; /** * The accessor field to access the reducers in the database and associated @@ -236,11 +236,11 @@ export class DbConnectionImpl< return queryId; }; - #makeDbView(def: RemoteModule): DbView { - const view = Object.create(null) as DbView; + #makeDbView(def: RemoteModule): ClientDbView { + const view = Object.create(null) as ClientDbView; for (const tbl of def.tables) { - // DbView uses this name verbatim + // ClientDbView uses this name verbatim const key = tbl.accessorName; Object.defineProperty(view, key, { enumerable: true, diff --git a/crates/bindings-typescript/src/sdk/db_context.ts b/crates/bindings-typescript/src/sdk/db_context.ts index cb7f76579a1..2816b76b8d4 100644 --- a/crates/bindings-typescript/src/sdk/db_context.ts +++ b/crates/bindings-typescript/src/sdk/db_context.ts @@ -1,6 +1,6 @@ -import type { DbView } from '../server/db_view'; +import type { ClientDbView } from '../server/db_view'; import type { ReducersView, SetReducerFlags, UntypedReducersDef } from './reducers'; -import type { SchemaDef, UntypedRemoteModule } from './spacetime_module'; +import type { UntypedRemoteModule } from './spacetime_module'; import type { SubscriptionBuilderImpl } from './subscription_builder_impl'; /** @@ -11,7 +11,7 @@ import type { SubscriptionBuilderImpl } from './subscription_builder_impl'; * @template SetReducerFlags - Type representing the reducer flags collection. */ export interface DbContext { - db: DbView; + db: ClientDbView; reducers: ReducersView; setReducerFlags: SetReducerFlags; isActive: boolean; From 5da15d8dc4eb20998ce93b5fa25ba34bea9ce954 Mon Sep 17 00:00:00 2001 From: = Date: Mon, 3 Nov 2025 09:33:56 -0500 Subject: [PATCH 04/49] Cleaning up where code lives --- .../src/{server => lib}/constraints.ts | 0 .../src/{server => lib}/indexes.ts | 2 +- .../src/{server => lib}/reducers.ts | 14 +- .../src/{server => lib}/schema.ts | 56 +++---- .../src/{server => lib}/table.ts | 12 +- .../{server => lib}/type_builders.test-d.ts | 0 .../src/{server => lib}/type_builders.ts | 4 +- .../src/{server => lib}/type_util.ts | 0 crates/bindings-typescript/src/lib/utils.ts | 10 ++ .../src/sdk/client_cache.ts | 4 +- .../sdk/{table_handle.ts => client_table.ts} | 6 +- .../src/sdk/db_connection_impl.ts | 7 +- .../bindings-typescript/src/sdk/db_context.ts | 2 +- crates/bindings-typescript/src/sdk/db_view.ts | 17 +-- .../bindings-typescript/src/sdk/reducers.ts | 4 +- .../src/sdk/spacetime_module.ts | 2 +- .../src/sdk/table_cache.ts | 5 +- .../bindings-typescript/src/server/db_view.ts | 13 +- .../bindings-typescript/src/server/index.ts | 10 +- .../bindings-typescript/src/server/runtime.ts | 19 +-- .../test-app/src/module_bindings/index.ts | 6 +- .../src/module_bindings/player_type.ts | 8 + .../bindings-typescript/tests/index.test.ts | 2 +- crates/codegen/src/typescript.rs | 141 ++++++++++++++++++ 24 files changed, 240 insertions(+), 104 deletions(-) rename crates/bindings-typescript/src/{server => lib}/constraints.ts (100%) rename crates/bindings-typescript/src/{server => lib}/indexes.ts (99%) rename crates/bindings-typescript/src/{server => lib}/reducers.ts (96%) rename crates/bindings-typescript/src/{server => lib}/schema.ts (97%) rename crates/bindings-typescript/src/{server => lib}/table.ts (95%) rename crates/bindings-typescript/src/{server => lib}/type_builders.test-d.ts (100%) rename crates/bindings-typescript/src/{server => lib}/type_builders.ts (99%) rename crates/bindings-typescript/src/{server => lib}/type_util.ts (100%) rename crates/bindings-typescript/src/sdk/{table_handle.ts => client_table.ts} (93%) diff --git a/crates/bindings-typescript/src/server/constraints.ts b/crates/bindings-typescript/src/lib/constraints.ts similarity index 100% rename from crates/bindings-typescript/src/server/constraints.ts rename to crates/bindings-typescript/src/lib/constraints.ts diff --git a/crates/bindings-typescript/src/server/indexes.ts b/crates/bindings-typescript/src/lib/indexes.ts similarity index 99% rename from crates/bindings-typescript/src/server/indexes.ts rename to crates/bindings-typescript/src/lib/indexes.ts index f85bd92cbe2..5c93c9aac9b 100644 --- a/crates/bindings-typescript/src/server/indexes.ts +++ b/crates/bindings-typescript/src/lib/indexes.ts @@ -1,7 +1,7 @@ import type { RowType, UntypedTableDef } from './table'; import type { ColumnMetadata, IndexTypes } from './type_builders'; import type { CollapseTuple, Prettify } from './type_util'; -import { Range } from './range'; +import { Range } from '../server/range'; import type { ColumnIsUnique } from './constraints'; /** diff --git a/crates/bindings-typescript/src/server/reducers.ts b/crates/bindings-typescript/src/lib/reducers.ts similarity index 96% rename from crates/bindings-typescript/src/server/reducers.ts rename to crates/bindings-typescript/src/lib/reducers.ts index 55233d5a5b1..e6c1b767a04 100644 --- a/crates/bindings-typescript/src/server/reducers.ts +++ b/crates/bindings-typescript/src/lib/reducers.ts @@ -1,11 +1,11 @@ -import type { ProductType } from '../lib/algebraic_type'; -import Lifecycle from '../lib/autogen/lifecycle_type'; -import type RawReducerDefV9 from '../lib/autogen/raw_reducer_def_v_9_type'; -import type { ConnectionId } from '../lib/connection_id'; -import type { Identity } from '../lib/identity'; -import type { Timestamp } from '../lib/timestamp'; +import type { ProductType } from './algebraic_type'; +import Lifecycle from './autogen/lifecycle_type'; +import type RawReducerDefV9 from './autogen/raw_reducer_def_v_9_type'; +import type { ConnectionId } from './connection_id'; +import type { Identity } from './identity'; +import type { Timestamp } from './timestamp'; import type { UntypedReducersDef } from '../sdk/reducers'; -import type { DbView } from './db_view'; +import type { DbView } from '../server/db_view'; import { MODULE_DEF, type UntypedSchemaDef } from './schema'; import type { InferTypeOfRow, diff --git a/crates/bindings-typescript/src/server/schema.ts b/crates/bindings-typescript/src/lib/schema.ts similarity index 97% rename from crates/bindings-typescript/src/server/schema.ts rename to crates/bindings-typescript/src/lib/schema.ts index a8b775121e7..1a33c11473d 100644 --- a/crates/bindings-typescript/src/server/schema.ts +++ b/crates/bindings-typescript/src/lib/schema.ts @@ -1,5 +1,5 @@ -import type RawTableDefV9 from '../lib/autogen/raw_table_def_v_9_type'; -import type Typespace from '../lib/autogen/typespace_type'; +import type RawTableDefV9 from './autogen/raw_table_def_v_9_type'; +import type Typespace from './autogen/typespace_type'; import { // eslint-disable-next-line @typescript-eslint/no-unused-vars type ColumnBuilder, @@ -16,14 +16,37 @@ import { type ParamsObj, type Reducer, } from './reducers'; -import type RawModuleDefV9 from '../lib/autogen/raw_module_def_v_9_type'; +import type RawModuleDefV9 from './autogen/raw_module_def_v_9_type'; import { AlgebraicType, type AlgebraicTypeVariants, -} from '../lib/algebraic_type'; -import type RawScopedTypeNameV9 from '../lib/autogen/raw_scoped_type_name_v_9_type'; +} from './algebraic_type'; +import type RawScopedTypeNameV9 from './autogen/raw_scoped_type_name_v_9_type'; import type { CamelCase } from './type_util'; +/** + * An untyped representation of the database schema. + */ +export type UntypedSchemaDef = { + tables: readonly UntypedTableDef[]; +}; + +/** + * Helper type to convert an array of TableSchema into a schema definition + */ +type TablesToSchema[]> = { + tables: { + /** @type {UntypedTableDef} */ + readonly [i in keyof T]: { + name: T[i]['tableName']; + accessorName: CamelCase; + columns: T[i]['rowType']['row']; + rowType: T[i]['rowSpacetimeType']; + indexes: T[i]['idxs']; + }; + }; +}; + /** * The global module definition that gets populated by calls to `reducer()` and lifecycle hooks. */ @@ -72,29 +95,6 @@ export function splitName(name: string): RawScopedTypeNameV9 { return { name: scope.pop()!, scope }; } -/** - * An untyped representation of the database schema. - */ -export type UntypedSchemaDef = { - tables: readonly UntypedTableDef[]; -}; - -/** - * Helper type to convert an array of TableSchema into a schema definition - */ -type TablesToSchema[]> = { - tables: { - /** @type {UntypedTableDef} */ - readonly [i in keyof T]: { - name: T[i]['tableName']; - accessorName: CamelCase; - columns: T[i]['rowType']['row']; - rowType: T[i]['rowSpacetimeType']; - indexes: T[i]['idxs']; - }; - }; -}; - /** * The Schema class represents the database schema for a SpacetimeDB application. * It encapsulates the table definitions and typespace, and provides methods to define diff --git a/crates/bindings-typescript/src/server/table.ts b/crates/bindings-typescript/src/lib/table.ts similarity index 95% rename from crates/bindings-typescript/src/server/table.ts rename to crates/bindings-typescript/src/lib/table.ts index 96803cc1646..a4d4d9b5254 100644 --- a/crates/bindings-typescript/src/server/table.ts +++ b/crates/bindings-typescript/src/lib/table.ts @@ -1,9 +1,9 @@ -import { AlgebraicType, ProductType } from '../lib/algebraic_type'; -import type RawConstraintDefV9 from '../lib/autogen/raw_constraint_def_v_9_type'; -import RawIndexAlgorithm from '../lib/autogen/raw_index_algorithm_type'; -import type RawIndexDefV9 from '../lib/autogen/raw_index_def_v_9_type'; -import type RawSequenceDefV9 from '../lib/autogen/raw_sequence_def_v_9_type'; -import type RawTableDefV9 from '../lib/autogen/raw_table_def_v_9_type'; +import { AlgebraicType, ProductType } from './algebraic_type'; +import type RawConstraintDefV9 from './autogen/raw_constraint_def_v_9_type'; +import RawIndexAlgorithm from './autogen/raw_index_algorithm_type'; +import type RawIndexDefV9 from './autogen/raw_index_def_v_9_type'; +import type RawSequenceDefV9 from './autogen/raw_sequence_def_v_9_type'; +import type RawTableDefV9 from './autogen/raw_table_def_v_9_type'; import type { AllUnique } from './constraints'; import type { ColumnIndex, IndexColumns, Indexes, IndexOpts, ReadonlyIndexes } from './indexes'; import { MODULE_DEF, splitName } from './schema'; diff --git a/crates/bindings-typescript/src/server/type_builders.test-d.ts b/crates/bindings-typescript/src/lib/type_builders.test-d.ts similarity index 100% rename from crates/bindings-typescript/src/server/type_builders.test-d.ts rename to crates/bindings-typescript/src/lib/type_builders.test-d.ts diff --git a/crates/bindings-typescript/src/server/type_builders.ts b/crates/bindings-typescript/src/lib/type_builders.ts similarity index 99% rename from crates/bindings-typescript/src/server/type_builders.ts rename to crates/bindings-typescript/src/lib/type_builders.ts index ab440838003..9ede6be0864 100644 --- a/crates/bindings-typescript/src/server/type_builders.ts +++ b/crates/bindings-typescript/src/lib/type_builders.ts @@ -12,8 +12,8 @@ import { type TimeDurationAlgebraicType, type TimestampAlgebraicType, } from '..'; -import type { OptionAlgebraicType } from '../lib/option'; -import { addType, MODULE_DEF } from './schema'; +import type { OptionAlgebraicType } from './option'; +import { addType, MODULE_DEF } from '../server/schema'; import type { CoerceRow } from './table'; import { set, type Set } from './type_util'; diff --git a/crates/bindings-typescript/src/server/type_util.ts b/crates/bindings-typescript/src/lib/type_util.ts similarity index 100% rename from crates/bindings-typescript/src/server/type_util.ts rename to crates/bindings-typescript/src/lib/type_util.ts diff --git a/crates/bindings-typescript/src/lib/utils.ts b/crates/bindings-typescript/src/lib/utils.ts index 0b09319dc53..dfb42ff23e6 100644 --- a/crates/bindings-typescript/src/lib/utils.ts +++ b/crates/bindings-typescript/src/lib/utils.ts @@ -1,5 +1,6 @@ import BinaryReader from './binary_reader'; import BinaryWriter from './binary_writer'; +import type { CamelCase } from './type_util'; export function toPascalCase(s: string): string { const str = s.replace(/([-_][a-z])/gi, $1 => { @@ -98,3 +99,12 @@ export function u256ToUint8Array(data: bigint): Uint8Array { export function u256ToHexString(data: bigint): string { return uint8ArrayToHexString(u256ToUint8Array(data)); } + +/** + * Type safe conversion from a string like "some_identifier-name" to "someIdentifierName". + * @param str The string to convert + * @returns The converted string + */ +export function toCamelCase(str: T): CamelCase { + return str.replace(/[-_]+(\w)/g, (_, c) => c.toUpperCase()) as CamelCase; +} diff --git a/crates/bindings-typescript/src/sdk/client_cache.ts b/crates/bindings-typescript/src/sdk/client_cache.ts index f410911c454..125a43ee99c 100644 --- a/crates/bindings-typescript/src/sdk/client_cache.ts +++ b/crates/bindings-typescript/src/sdk/client_cache.ts @@ -1,5 +1,5 @@ -import type { UntypedSchemaDef } from '../server/schema.ts'; -import type { UntypedTableDef } from '../server/table.ts'; +import type { UntypedSchemaDef } from '../lib/schema.ts'; +import type { UntypedTableDef } from '../lib/table.ts'; import type { UntypedRemoteModule } from './spacetime_module.ts'; import { TableCache } from './table_cache.ts'; diff --git a/crates/bindings-typescript/src/sdk/table_handle.ts b/crates/bindings-typescript/src/sdk/client_table.ts similarity index 93% rename from crates/bindings-typescript/src/sdk/table_handle.ts rename to crates/bindings-typescript/src/sdk/client_table.ts index 9751d8edc96..ca19165f639 100644 --- a/crates/bindings-typescript/src/sdk/table_handle.ts +++ b/crates/bindings-typescript/src/sdk/client_table.ts @@ -1,6 +1,6 @@ -import type { ReadonlyIndexes } from "../server/indexes"; -import type { ReadonlyTableMethods, RowType, TableIndexes, UntypedTableDef } from "../server/table"; -import type { Prettify } from "../server/type_util"; +import type { ReadonlyIndexes } from "../lib/indexes"; +import type { ReadonlyTableMethods, RowType, TableIndexes, UntypedTableDef } from "../lib/table"; +import type { Prettify } from "../lib/type_util"; import type { EventContextInterface } from "./event_context"; import type { UntypedRemoteModule } from "./spacetime_module"; diff --git a/crates/bindings-typescript/src/sdk/db_connection_impl.ts b/crates/bindings-typescript/src/sdk/db_connection_impl.ts index 12bf41202f7..d2854f4f92f 100644 --- a/crates/bindings-typescript/src/sdk/db_connection_impl.ts +++ b/crates/bindings-typescript/src/sdk/db_connection_impl.ts @@ -1,7 +1,6 @@ import { ConnectionId, ProductType } from '../'; import { AlgebraicType, - type AlgebraicTypeVariants, type ComparablePrimitive, } from '../'; import { parseValue } from '../'; @@ -52,9 +51,9 @@ import { import { stdbLogger } from './logger.ts'; import { fromByteArray } from 'base64-js'; import type { ReducersView, SetReducerFlags, UntypedReducersDef } from './reducers.ts'; -import type { ClientDbView, DbView } from '../server/db_view.ts'; -import type { UntypedTableDef } from '../server/table.ts'; -import { toCamelCase } from '../server/runtime.ts'; +import type { ClientDbView } from './db_view.ts'; +import type { UntypedTableDef } from '../lib/table.ts'; +import { toCamelCase } from '../lib/utils.ts'; export { DbConnectionBuilder, SubscriptionBuilderImpl, TableCache, type Event }; diff --git a/crates/bindings-typescript/src/sdk/db_context.ts b/crates/bindings-typescript/src/sdk/db_context.ts index 2816b76b8d4..65c127d67d5 100644 --- a/crates/bindings-typescript/src/sdk/db_context.ts +++ b/crates/bindings-typescript/src/sdk/db_context.ts @@ -1,4 +1,4 @@ -import type { ClientDbView } from '../server/db_view'; +import type { ClientDbView } from './db_view'; import type { ReducersView, SetReducerFlags, UntypedReducersDef } from './reducers'; import type { UntypedRemoteModule } from './spacetime_module'; import type { SubscriptionBuilderImpl } from './subscription_builder_impl'; diff --git a/crates/bindings-typescript/src/sdk/db_view.ts b/crates/bindings-typescript/src/sdk/db_view.ts index 664fcbe2483..2d12c64326e 100644 --- a/crates/bindings-typescript/src/sdk/db_view.ts +++ b/crates/bindings-typescript/src/sdk/db_view.ts @@ -1,14 +1,9 @@ -import type { DbView } from "../server/db_view"; -import type { UntypedSchemaDef } from "../server/schema"; +import type { UntypedRemoteModule } from "./spacetime_module"; +import type { ClientTable } from "./table_handle"; /** - * An untyped database view, where the table names and row types are not known. - * Each key is a camelCased version of the table name, and each value is an untyped table handle. - * - * For example, a database with tables "user_profile" and "game_stats" would have the type: - * { - * userProfile: TableHandle<"user_profile", any>; - * gameStats: TableHandle<"game_stats", any>; - * } + * A type representing a client-side database view, mapping table names to their corresponding client Table handles. */ -export type UntypedDbView = DbView; \ No newline at end of file +export type ClientDbView = { + readonly [Tbl in RemoteModule['tables'][number] as Tbl['accessorName']]: ClientTable; +}; diff --git a/crates/bindings-typescript/src/sdk/reducers.ts b/crates/bindings-typescript/src/sdk/reducers.ts index e25b805c97f..28a7b6804c8 100644 --- a/crates/bindings-typescript/src/sdk/reducers.ts +++ b/crates/bindings-typescript/src/sdk/reducers.ts @@ -1,6 +1,6 @@ import type { ProductType } from "../lib/algebraic_type"; -import type { ParamsObj } from "../server/reducers"; -import type { CamelCase } from "../server/type_util"; +import type { ParamsObj } from "../lib/reducers"; +import type { CamelCase } from "../lib/type_util"; import type { CallReducerFlags } from "./db_connection_impl"; export type ReducersView = { diff --git a/crates/bindings-typescript/src/sdk/spacetime_module.ts b/crates/bindings-typescript/src/sdk/spacetime_module.ts index f9326331198..73f7d5fdca9 100644 --- a/crates/bindings-typescript/src/sdk/spacetime_module.ts +++ b/crates/bindings-typescript/src/sdk/spacetime_module.ts @@ -1,4 +1,4 @@ -import type { UntypedSchemaDef } from '../server/schema'; +import type { UntypedSchemaDef } from '../lib/schema'; import type { UntypedReducersDef } from './reducers'; export type RemoteModule< diff --git a/crates/bindings-typescript/src/sdk/table_cache.ts b/crates/bindings-typescript/src/sdk/table_cache.ts index 53521530beb..c87afc5e895 100644 --- a/crates/bindings-typescript/src/sdk/table_cache.ts +++ b/crates/bindings-typescript/src/sdk/table_cache.ts @@ -3,8 +3,8 @@ import { EventEmitter } from './event_emitter.ts'; import { stdbLogger } from './logger.ts'; import type { ComparablePrimitive } from '../'; import type { EventContextInterface, ClientTable } from './index.ts'; -import type { RowType, Table, UntypedTableDef } from '../server/table.ts'; -import type { ClientTableCore } from './table_handle.ts'; +import type { RowType, Table, UntypedTableDef } from '../lib/table.ts'; +import type { ClientTableCore } from './client_table.ts'; import type { UntypedRemoteModule } from './spacetime_module.ts'; export type Operation< @@ -29,6 +29,7 @@ export type PendingCallback = { table: string; cb: () => void; }; + /** * Builder to generate calls to query a `table` in the database */ diff --git a/crates/bindings-typescript/src/server/db_view.ts b/crates/bindings-typescript/src/server/db_view.ts index ad8e540d192..43a4a284ed3 100644 --- a/crates/bindings-typescript/src/server/db_view.ts +++ b/crates/bindings-typescript/src/server/db_view.ts @@ -1,7 +1,5 @@ -import type { ClientTable } from "../sdk"; -import type { UntypedRemoteModule } from "../sdk/spacetime_module"; -import type { UntypedSchemaDef } from "./schema"; -import type { ReadonlyTable, Table } from "./table"; +import type { UntypedSchemaDef } from "../lib/schema"; +import type { ReadonlyTable, Table } from "../lib/table"; /** * A type representing a read-only database view, mapping table names to their corresponding read-only Table handles. @@ -10,13 +8,6 @@ export type ReadonlyDbView = { readonly [Tbl in SchemaDef['tables'][number] as Tbl['accessorName']]: ReadonlyTable; }; -/** - * A type representing a client-side database view, mapping table names to their corresponding client Table handles. - */ -export type ClientDbView = { - readonly [Tbl in RemoteModule['tables'][number] as Tbl['accessorName']]: ClientTable; -}; - /** * A type representing the database view, mapping table names to their corresponding Table handles. */ diff --git a/crates/bindings-typescript/src/server/index.ts b/crates/bindings-typescript/src/server/index.ts index 6db590d7d07..903bb80ec73 100644 --- a/crates/bindings-typescript/src/server/index.ts +++ b/crates/bindings-typescript/src/server/index.ts @@ -1,10 +1,10 @@ -export * from './type_builders'; -export { schema, type InferSchema } from './schema'; -export { table } from './table'; -export { reducers } from './reducers'; +export * from '../lib/type_builders'; +export { schema, type InferSchema } from '../lib/schema'; +export { table } from '../lib/table'; +export { reducers } from '../lib/reducers'; export * as errors from './errors'; export { SenderError } from './errors'; -export { type Reducer, type ReducerCtx } from './reducers'; +export { type Reducer, type ReducerCtx } from '../lib/reducers'; export { type DbView } from './db_view'; import './polyfills'; // Ensure polyfills are loaded diff --git a/crates/bindings-typescript/src/server/runtime.ts b/crates/bindings-typescript/src/server/runtime.ts index 74533661373..1366c763aa6 100644 --- a/crates/bindings-typescript/src/server/runtime.ts +++ b/crates/bindings-typescript/src/server/runtime.ts @@ -15,33 +15,24 @@ import { type IndexVal, type UniqueIndex, type RangedIndex, -} from './indexes'; -import { type RowType, type Table, type TableMethods } from './table'; +} from '../lib/indexes'; +import { type RowType, type Table, type TableMethods } from '../lib/table'; import { type ReducerCtx, REDUCERS, type JwtClaims, type AuthCtx, type JsonObject, -} from './reducers'; -import { MODULE_DEF } from './schema'; +} from '../lib/reducers'; +import { MODULE_DEF } from '../lib/schema'; import * as _syscalls from 'spacetime:sys@1.0'; import type { u16, u32, ModuleHooks } from 'spacetime:sys@1.0'; import type { DbView } from './db_view'; -import type { CamelCase } from './type_util'; +import { toCamelCase } from '../lib/utils'; const { freeze } = Object; -/** - * Type safe conversion from a string like "some_identifier-name" to "someIdentifierName". - * @param str The string to convert - * @returns The converted string - */ -export function toCamelCase(str: T): CamelCase { - return str.replace(/[-_]+(\w)/g, (_, c) => c.toUpperCase()) as CamelCase; -} - const sys: typeof _syscalls = freeze( Object.fromEntries( Object.entries(_syscalls).map(([name, syscall]) => [ diff --git a/crates/bindings-typescript/test-app/src/module_bindings/index.ts b/crates/bindings-typescript/test-app/src/module_bindings/index.ts index 09683ccc7fa..5f44e5493cc 100644 --- a/crates/bindings-typescript/test-app/src/module_bindings/index.ts +++ b/crates/bindings-typescript/test-app/src/module_bindings/index.ts @@ -54,9 +54,9 @@ import { UnindexedPlayer } from './unindexed_player_type.ts'; export { UnindexedPlayer }; import { User } from './user_type.ts'; import { schema } from '../../../src/server/schema.ts'; -import t from '../../../src/server/type_builders.ts'; -import { table } from '../../../src/server/table.ts'; -import { reducerSchema, reducers } from '../../../src/server/reducers.ts'; +import t from '../../../src/lib/type_builders.ts'; +import { table } from '../../../src/lib/table.ts'; +import { reducerSchema, reducers } from '../../../src/lib/reducers.ts'; import { RemoteModule } from '../../../src/sdk/spacetime_module.ts'; export { User }; diff --git a/crates/bindings-typescript/test-app/src/module_bindings/player_type.ts b/crates/bindings-typescript/test-app/src/module_bindings/player_type.ts index 4bafe1fb1e4..72ace94abbd 100644 --- a/crates/bindings-typescript/test-app/src/module_bindings/player_type.ts +++ b/crates/bindings-typescript/test-app/src/module_bindings/player_type.ts @@ -27,10 +27,18 @@ import { type SubscriptionEventContextInterface as __SubscriptionEventContextInterface, type TableHandle as __TableHandle, } from '../../../src/index'; +import { t } from '../../../src/server'; import { Point } from './point_type'; // Mark import as potentially unused declare type __keep_Point = Point; +t.object('Player', { + ownerId: t.string(), + name: t.string(), + location: Point.getTypeScriptAlgebraicType(), +}); + + export type Player = { ownerId: string; name: string; diff --git a/crates/bindings-typescript/tests/index.test.ts b/crates/bindings-typescript/tests/index.test.ts index 570728769fb..90be9efc2c0 100644 --- a/crates/bindings-typescript/tests/index.test.ts +++ b/crates/bindings-typescript/tests/index.test.ts @@ -6,7 +6,7 @@ import { type IdentityTokenMessage, } from '../src/index'; import type { ColumnBuilder } from '../src/server'; -import { t } from '../src/server/type_builders'; +import { t } from '../src/lib/type_builders'; describe('TypeBuilder', () => { it('builds the correct algebraic type for a point', () => { diff --git a/crates/codegen/src/typescript.rs b/crates/codegen/src/typescript.rs index 2770fc4d6ab..b02e233f777 100644 --- a/crates/codegen/src/typescript.rs +++ b/crates/codegen/src/typescript.rs @@ -24,6 +24,147 @@ use spacetimedb_lib::version::spacetimedb_lib_version; type Imports = BTreeSet; +// Target output +// // THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE +// // WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. + +// // This was generated using ../../../src/index cli version 1.5.0 (commit 5bfc84351742a6a8dc717b6c0011946f2d1b632d). + +// /* eslint-disable */ +// /* tslint:disable */ +// import { +// AlgebraicType as __AlgebraicTypeValue, +// BinaryReader as __BinaryReader, +// BinaryWriter as __BinaryWriter, +// ClientCache as __ClientCache, +// ConnectionId as __ConnectionId, +// DbConnectionBuilder as __DbConnectionBuilder, +// DbConnectionImpl as __DbConnectionImpl, +// Identity as __Identity, +// SubscriptionBuilderImpl as __SubscriptionBuilderImpl, +// TableCache as __TableCache, +// TimeDuration as __TimeDuration, +// Timestamp as __Timestamp, +// deepEqual as __deepEqual, +// type AlgebraicType as __AlgebraicTypeType, +// type AlgebraicTypeVariants as __AlgebraicTypeVariants, +// type CallReducerFlags as __CallReducerFlags, +// type ErrorContextInterface as __ErrorContextInterface, +// type Event as __Event, +// type EventContextInterface as __EventContextInterface, +// type ReducerEventContextInterface as __ReducerEventContextInterface, +// type SubscriptionEventContextInterface as __SubscriptionEventContextInterface, +// type ClientTable as __ClientTable, +// type RemoteModule as __RemoteModule, +// type SetReducerFlags as __SetReducerFlags, +// DbConnectionConfig, +// } from '../../../src/index'; + +// // Import and reexport all reducer arg types +// import { CreatePlayer } from './create_player_reducer.ts'; +// export { CreatePlayer }; + +// // Import and reexport all table handle types +// import { PlayerTableHandle } from './player_table.ts'; +// export { PlayerTableHandle }; +// import { UnindexedPlayerTableHandle } from './unindexed_player_table.ts'; +// export { UnindexedPlayerTableHandle }; +// import { UserTableHandle } from './user_table.ts'; +// export { UserTableHandle }; + +// // Import and reexport all types +// import { Player } from './player_type.ts'; +// export { Player }; +// import { Point } from './point_type.ts'; +// export { Point }; +// import { UnindexedPlayer } from './unindexed_player_type.ts'; +// export { UnindexedPlayer }; +// import { User } from './user_type.ts'; +// import { schema } from '../../../src/server/schema.ts'; +// import t from '../../../src/server/type_builders.ts'; +// import { table } from '../../../src/server/table.ts'; +// import { reducerSchema, reducers } from '../../../src/server/reducers.ts'; +// import { RemoteModule } from '../../../src/sdk/spacetime_module.ts'; +// export { User }; + +// const pointType = t.object('Point', { +// x: t.number(), +// y: t.number(), +// }); + +// const tablesSchema = schema( +// table({ name: 'player', }, t.row({ +// ownerId: t.string(), +// name: t.string(), +// location: pointType, +// })), +// table({ name: 'unindexed_player', }, t.row({ +// ownerId: t.string(), +// name: t.string(), +// location: pointType, +// })), +// table({ name: 'user', primaryKey: 'identity', }, t.row({ +// identity: t.string(), +// name: t.string(), +// })), +// ); + +// const reducersSchema = reducers( +// reducerSchema('create_player', { +// name: t.string(), +// location: pointType, +// }), +// reducerSchema('foo_bar', { +// name: t.string(), +// location: pointType, +// }), +// ); + +// const REMOTE_MODULE = { +// versionInfo: { +// cliVersion: '1.6.0' as const, +// }, +// tables: tablesSchema.schemaType.tables, +// reducers: reducersSchema.reducersType.reducers, +// } satisfies RemoteModule< +// typeof tablesSchema.schemaType, +// typeof reducersSchema.reducersType +// >; + +// export type EventContext = __EventContextInterface< +// typeof REMOTE_MODULE +// >; + +// export type ReducerEventContext = __ReducerEventContextInterface< +// typeof REMOTE_MODULE +// >; + +// export type SubscriptionEventContext = __SubscriptionEventContextInterface< +// typeof REMOTE_MODULE +// >; + +// export type ErrorContext = __ErrorContextInterface< +// typeof REMOTE_MODULE +// >; + +// export class SubscriptionBuilder extends __SubscriptionBuilderImpl< +// typeof REMOTE_MODULE +// > {} + +// export class DbConnectionBuilder extends __DbConnectionBuilder< +// typeof REMOTE_MODULE, +// DbConnection +// > {}; + +// export class DbConnection extends __DbConnectionImpl { +// static builder = (): DbConnectionBuilder => { +// return new DbConnectionBuilder(REMOTE_MODULE, (config: DbConnectionConfig) => new DbConnection(config)); +// }; +// subscriptionBuilder = (): SubscriptionBuilder => { +// return new SubscriptionBuilder(this); +// }; +// } + const INDENT: &str = " "; pub struct TypeScript; From 269ad2f69ebf577dee6bbfcb9e9a4ab4864ac121 Mon Sep 17 00:00:00 2001 From: = Date: Mon, 3 Nov 2025 12:36:49 -0500 Subject: [PATCH 05/49] Small fixes --- .../bindings-typescript/src/react/useTable.ts | 2 +- .../src/sdk/db_connection_impl.ts | 8 ++--- crates/bindings-typescript/src/sdk/db_view.ts | 2 +- crates/bindings-typescript/src/sdk/index.ts | 2 +- .../src/sdk/message_types.ts | 34 +++++++++---------- .../test-app/src/module_bindings/index.ts | 2 +- 6 files changed, 23 insertions(+), 27 deletions(-) diff --git a/crates/bindings-typescript/src/react/useTable.ts b/crates/bindings-typescript/src/react/useTable.ts index 6a7f0f48782..311b3d68663 100644 --- a/crates/bindings-typescript/src/react/useTable.ts +++ b/crates/bindings-typescript/src/react/useTable.ts @@ -7,7 +7,7 @@ import { } from 'react'; import { useSpacetimeDB } from './useSpacetimeDB'; import { DbConnectionImpl, TableCache } from '../sdk/db_connection_impl'; -import type { TableNamesFromDb } from '../sdk/table_handle'; +import type { TableNamesFromDb } from '../sdk/client_table'; import type { ConnectionState } from './connection_state'; import type { UntypedRemoteModule } from '../sdk/spacetime_module'; diff --git a/crates/bindings-typescript/src/sdk/db_connection_impl.ts b/crates/bindings-typescript/src/sdk/db_connection_impl.ts index d2854f4f92f..14ea6d83606 100644 --- a/crates/bindings-typescript/src/sdk/db_connection_impl.ts +++ b/crates/bindings-typescript/src/sdk/db_connection_impl.ts @@ -535,9 +535,7 @@ export class DbConnectionImpl< const parsedTableUpdates = await parseDatabaseUpdate( message.value.update ); - const subscribeAppliedMessage: SubscribeAppliedMessage< - Record - > = { + const subscribeAppliedMessage: SubscribeAppliedMessage = { tag: 'SubscribeApplied', queryId: message.value.queryId.id, tableUpdates: parsedTableUpdates, @@ -549,9 +547,7 @@ export class DbConnectionImpl< const parsedTableUpdates = await parseDatabaseUpdate( message.value.update ); - const unsubscribeAppliedMessage: UnsubscribeAppliedMessage< - Record - > = { + const unsubscribeAppliedMessage: UnsubscribeAppliedMessage = { tag: 'UnsubscribeApplied', queryId: message.value.queryId.id, tableUpdates: parsedTableUpdates, diff --git a/crates/bindings-typescript/src/sdk/db_view.ts b/crates/bindings-typescript/src/sdk/db_view.ts index 2d12c64326e..9d991765226 100644 --- a/crates/bindings-typescript/src/sdk/db_view.ts +++ b/crates/bindings-typescript/src/sdk/db_view.ts @@ -1,5 +1,5 @@ import type { UntypedRemoteModule } from "./spacetime_module"; -import type { ClientTable } from "./table_handle"; +import type { ClientTable } from "./client_table"; /** * A type representing a client-side database view, mapping table names to their corresponding client Table handles. diff --git a/crates/bindings-typescript/src/sdk/index.ts b/crates/bindings-typescript/src/sdk/index.ts index 568e04bd5b5..0f35b9d06f9 100644 --- a/crates/bindings-typescript/src/sdk/index.ts +++ b/crates/bindings-typescript/src/sdk/index.ts @@ -2,6 +2,6 @@ export * from './db_connection_impl.ts'; export * from './client_cache.ts'; export * from './message_types.ts'; -export { type ClientTable } from './table_handle.ts'; +export { type ClientTable } from './client_table.ts'; export { type RemoteModule } from './spacetime_module.ts'; export { type SetReducerFlags } from './reducers.ts'; diff --git a/crates/bindings-typescript/src/sdk/message_types.ts b/crates/bindings-typescript/src/sdk/message_types.ts index ee7842019c0..5051dddeb82 100644 --- a/crates/bindings-typescript/src/sdk/message_types.ts +++ b/crates/bindings-typescript/src/sdk/message_types.ts @@ -3,15 +3,16 @@ import type { UpdateStatus } from './client_api/index.ts'; import { Identity } from '../'; import type { TableUpdate } from './table_cache.ts'; import { Timestamp } from '../'; +import type { RowType, Table, UntypedTableDef } from '../lib/table.ts'; -export type InitialSubscriptionMessage> = { +export type InitialSubscriptionMessage = { tag: 'InitialSubscription'; - tableUpdates: TableUpdate[]; + tableUpdates: TableUpdate[]; }; -export type TransactionUpdateMessage> = { +export type TransactionUpdateMessage = { tag: 'TransactionUpdate'; - tableUpdates: TableUpdate[]; + tableUpdates: TableUpdate[]; identity: Identity; connectionId: ConnectionId | null; reducerInfo?: { @@ -24,10 +25,10 @@ export type TransactionUpdateMessage> = { energyConsumed: bigint; }; -export type TransactionUpdateLightMessage> = +export type TransactionUpdateLightMessage = { tag: 'TransactionUpdateLight'; - tableUpdates: TableUpdate[]; + tableUpdates: TableUpdate[]; }; export type IdentityTokenMessage = { @@ -37,16 +38,16 @@ export type IdentityTokenMessage = { connectionId: ConnectionId; }; -export type SubscribeAppliedMessage> = { +export type SubscribeAppliedMessage = { tag: 'SubscribeApplied'; queryId: number; - tableUpdates: TableUpdate[]; + tableUpdates: TableUpdate[]; }; -export type UnsubscribeAppliedMessage> = { +export type UnsubscribeAppliedMessage = { tag: 'UnsubscribeApplied'; queryId: number; - tableUpdates: TableUpdate[]; + tableUpdates: TableUpdate[]; }; export type SubscriptionError = { @@ -55,12 +56,11 @@ export type SubscriptionError = { error: string; }; -export type Message = Record> = - - | InitialSubscriptionMessage - | TransactionUpdateMessage - | TransactionUpdateLightMessage +export type Message = + | InitialSubscriptionMessage + | TransactionUpdateMessage + | TransactionUpdateLightMessage | IdentityTokenMessage - | SubscribeAppliedMessage - | UnsubscribeAppliedMessage + | SubscribeAppliedMessage + | UnsubscribeAppliedMessage | SubscriptionError; diff --git a/crates/bindings-typescript/test-app/src/module_bindings/index.ts b/crates/bindings-typescript/test-app/src/module_bindings/index.ts index 5f44e5493cc..0768767c9d1 100644 --- a/crates/bindings-typescript/test-app/src/module_bindings/index.ts +++ b/crates/bindings-typescript/test-app/src/module_bindings/index.ts @@ -53,7 +53,7 @@ export { Point }; import { UnindexedPlayer } from './unindexed_player_type.ts'; export { UnindexedPlayer }; import { User } from './user_type.ts'; -import { schema } from '../../../src/server/schema.ts'; +import { schema } from '../../../src/lib/schema.ts'; import t from '../../../src/lib/type_builders.ts'; import { table } from '../../../src/lib/table.ts'; import { reducerSchema, reducers } from '../../../src/lib/reducers.ts'; From 051fb278b3d871c87536cb87c8905c21103728fe Mon Sep 17 00:00:00 2001 From: = Date: Mon, 3 Nov 2025 19:58:49 -0500 Subject: [PATCH 06/49] About to try new code gen --- .../src/lib/type_builders.ts | 2 +- crates/bindings-typescript/src/sdk/index.ts | 4 + .../test-app/src/module_bindings/index.ts | 13 + .../src/module_bindings/player_table.ts | 11 + .../src/module_bindings/player_type.ts | 5 + .../src/module_bindings/point_type.ts | 47 +- crates/codegen/src/typescript.rs | 1128 +++++------------ 7 files changed, 340 insertions(+), 870 deletions(-) diff --git a/crates/bindings-typescript/src/lib/type_builders.ts b/crates/bindings-typescript/src/lib/type_builders.ts index 9ede6be0864..771cce3b188 100644 --- a/crates/bindings-typescript/src/lib/type_builders.ts +++ b/crates/bindings-typescript/src/lib/type_builders.ts @@ -13,7 +13,7 @@ import { type TimestampAlgebraicType, } from '..'; import type { OptionAlgebraicType } from './option'; -import { addType, MODULE_DEF } from '../server/schema'; +import { addType, MODULE_DEF } from '../lib/schema'; import type { CoerceRow } from './table'; import { set, type Set } from './type_util'; diff --git a/crates/bindings-typescript/src/sdk/index.ts b/crates/bindings-typescript/src/sdk/index.ts index 0f35b9d06f9..3a066053531 100644 --- a/crates/bindings-typescript/src/sdk/index.ts +++ b/crates/bindings-typescript/src/sdk/index.ts @@ -5,3 +5,7 @@ export * from './message_types.ts'; export { type ClientTable } from './client_table.ts'; export { type RemoteModule } from './spacetime_module.ts'; export { type SetReducerFlags } from './reducers.ts'; +export * from '../lib/type_builders.ts'; +export { schema } from '../lib/schema.ts'; +export { table } from '../lib/table.ts'; +export { reducerSchema, reducers } from '../lib/reducers.ts'; \ No newline at end of file diff --git a/crates/bindings-typescript/test-app/src/module_bindings/index.ts b/crates/bindings-typescript/test-app/src/module_bindings/index.ts index 0768767c9d1..95c704eaad9 100644 --- a/crates/bindings-typescript/test-app/src/module_bindings/index.ts +++ b/crates/bindings-typescript/test-app/src/module_bindings/index.ts @@ -65,6 +65,19 @@ const pointType = t.object('Point', { y: t.number(), }); +table({ + name: 'player', + primaryKey: 'ownerId', + + indexes: [ + { name: 'this_is_an_index', algorithm: "btree", columns: [ "ownerId" ] } + ], +}, t.row({ + ownerId: t.string(), + name: t.string(), + location: pointType, +})) + const tablesSchema = schema( table({ name: 'player', }, t.row({ ownerId: t.string(), diff --git a/crates/bindings-typescript/test-app/src/module_bindings/player_table.ts b/crates/bindings-typescript/test-app/src/module_bindings/player_table.ts index 53444fbc677..a966cde4283 100644 --- a/crates/bindings-typescript/test-app/src/module_bindings/player_table.ts +++ b/crates/bindings-typescript/test-app/src/module_bindings/player_table.ts @@ -26,6 +26,8 @@ import { type ReducerEventContextInterface as __ReducerEventContextInterface, type SubscriptionEventContextInterface as __SubscriptionEventContextInterface, type ClientTable as __ClientTable, + table, + t, } from '../../../src/index'; import { Player } from './player_type'; import { Point } from './point_type'; @@ -40,6 +42,15 @@ import { } from '.'; declare type __keep = [EventContext, Reducer, RemoteReducers, RemoteTables]; + +export default table({ name: 'player' }, { + id: t.string().primaryKey().index(), + ownerId: t.string().unique(), + timestamp: t.timestamp(), + score: t.i32(), + location: Point, +}); + /** * Table handle for the table `player`. * diff --git a/crates/bindings-typescript/test-app/src/module_bindings/player_type.ts b/crates/bindings-typescript/test-app/src/module_bindings/player_type.ts index 72ace94abbd..d6f04870fa6 100644 --- a/crates/bindings-typescript/test-app/src/module_bindings/player_type.ts +++ b/crates/bindings-typescript/test-app/src/module_bindings/player_type.ts @@ -38,6 +38,11 @@ t.object('Player', { location: Point.getTypeScriptAlgebraicType(), }); +const x = t.enum('PlayerEnum', { + foobar: t.f32(), + bazqux: t.string(), + quxfoo: t.bool(), +}); export type Player = { ownerId: string; diff --git a/crates/bindings-typescript/test-app/src/module_bindings/point_type.ts b/crates/bindings-typescript/test-app/src/module_bindings/point_type.ts index 9bd08a301a1..939de299c8b 100644 --- a/crates/bindings-typescript/test-app/src/module_bindings/point_type.ts +++ b/crates/bindings-typescript/test-app/src/module_bindings/point_type.ts @@ -25,47 +25,10 @@ import { type EventContextInterface as __EventContextInterface, type ReducerEventContextInterface as __ReducerEventContextInterface, type SubscriptionEventContextInterface as __SubscriptionEventContextInterface, - type TableHandle as __TableHandle, + t as __t, } from '../../../src/index'; -export type Point = { - x: number; - y: number; -}; -let _cached_Point_type_value: __AlgebraicTypeType | null = null; - -/** - * An object for generated helper functions. - */ -export const Point = { - /** - * A function which returns this type represented as an AlgebraicType. - * This function is derived from the AlgebraicType used to generate this type. - */ - getTypeScriptAlgebraicType(): __AlgebraicTypeType { - if (_cached_Point_type_value) return _cached_Point_type_value; - _cached_Point_type_value = __AlgebraicTypeValue.Product({ elements: [] }); - _cached_Point_type_value.value.elements.push( - { name: 'x', algebraicType: __AlgebraicTypeValue.U16 }, - { name: 'y', algebraicType: __AlgebraicTypeValue.U16 } - ); - return _cached_Point_type_value; - }, - - serialize(writer: __BinaryWriter, value: Point): void { - __AlgebraicTypeValue.serializeValue( - writer, - Point.getTypeScriptAlgebraicType(), - value - ); - }, - - deserialize(reader: __BinaryReader): Point { - return __AlgebraicTypeValue.deserializeValue( - reader, - Point.getTypeScriptAlgebraicType() - ); - }, -}; - -export default Point; +export default __t.object('Point', { + x: __t.number(), + y: __t.number(), +}); \ No newline at end of file diff --git a/crates/codegen/src/typescript.rs b/crates/codegen/src/typescript.rs index b02e233f777..dd3f0c8b871 100644 --- a/crates/codegen/src/typescript.rs +++ b/crates/codegen/src/typescript.rs @@ -1,8 +1,7 @@ use crate::util::{ - is_reducer_invokable, iter_reducers, iter_tables, iter_types, iter_unique_cols, - print_auto_generated_version_comment, + is_reducer_invokable, iter_indexes, iter_reducers, iter_tables, iter_types, iter_unique_cols, print_auto_generated_version_comment }; -use crate::{indent_scope, OutputFile}; +use crate::{OutputFile}; use super::util::{collect_case, print_auto_generated_file_comment, type_ref_name}; @@ -13,7 +12,8 @@ use std::ops::Deref; use convert_case::{Case, Casing}; use spacetimedb_lib::sats::layout::PrimitiveType; use spacetimedb_lib::sats::AlgebraicTypeRef; -use spacetimedb_schema::def::{ModuleDef, ReducerDef, ScopedTypeName, TableDef, TypeDef}; +use spacetimedb_primitives::ColId; +use spacetimedb_schema::def::{BTreeAlgorithm, IndexAlgorithm, ModuleDef, ReducerDef, ScopedTypeName, TableDef, TypeDef}; use spacetimedb_schema::identifier::Identifier; use spacetimedb_schema::schema::{Schema, TableSchema}; use spacetimedb_schema::type_for_generate::{AlgebraicTypeDef, AlgebraicTypeUse, ProductTypeDef}; @@ -24,147 +24,6 @@ use spacetimedb_lib::version::spacetimedb_lib_version; type Imports = BTreeSet; -// Target output -// // THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// // WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -// // This was generated using ../../../src/index cli version 1.5.0 (commit 5bfc84351742a6a8dc717b6c0011946f2d1b632d). - -// /* eslint-disable */ -// /* tslint:disable */ -// import { -// AlgebraicType as __AlgebraicTypeValue, -// BinaryReader as __BinaryReader, -// BinaryWriter as __BinaryWriter, -// ClientCache as __ClientCache, -// ConnectionId as __ConnectionId, -// DbConnectionBuilder as __DbConnectionBuilder, -// DbConnectionImpl as __DbConnectionImpl, -// Identity as __Identity, -// SubscriptionBuilderImpl as __SubscriptionBuilderImpl, -// TableCache as __TableCache, -// TimeDuration as __TimeDuration, -// Timestamp as __Timestamp, -// deepEqual as __deepEqual, -// type AlgebraicType as __AlgebraicTypeType, -// type AlgebraicTypeVariants as __AlgebraicTypeVariants, -// type CallReducerFlags as __CallReducerFlags, -// type ErrorContextInterface as __ErrorContextInterface, -// type Event as __Event, -// type EventContextInterface as __EventContextInterface, -// type ReducerEventContextInterface as __ReducerEventContextInterface, -// type SubscriptionEventContextInterface as __SubscriptionEventContextInterface, -// type ClientTable as __ClientTable, -// type RemoteModule as __RemoteModule, -// type SetReducerFlags as __SetReducerFlags, -// DbConnectionConfig, -// } from '../../../src/index'; - -// // Import and reexport all reducer arg types -// import { CreatePlayer } from './create_player_reducer.ts'; -// export { CreatePlayer }; - -// // Import and reexport all table handle types -// import { PlayerTableHandle } from './player_table.ts'; -// export { PlayerTableHandle }; -// import { UnindexedPlayerTableHandle } from './unindexed_player_table.ts'; -// export { UnindexedPlayerTableHandle }; -// import { UserTableHandle } from './user_table.ts'; -// export { UserTableHandle }; - -// // Import and reexport all types -// import { Player } from './player_type.ts'; -// export { Player }; -// import { Point } from './point_type.ts'; -// export { Point }; -// import { UnindexedPlayer } from './unindexed_player_type.ts'; -// export { UnindexedPlayer }; -// import { User } from './user_type.ts'; -// import { schema } from '../../../src/server/schema.ts'; -// import t from '../../../src/server/type_builders.ts'; -// import { table } from '../../../src/server/table.ts'; -// import { reducerSchema, reducers } from '../../../src/server/reducers.ts'; -// import { RemoteModule } from '../../../src/sdk/spacetime_module.ts'; -// export { User }; - -// const pointType = t.object('Point', { -// x: t.number(), -// y: t.number(), -// }); - -// const tablesSchema = schema( -// table({ name: 'player', }, t.row({ -// ownerId: t.string(), -// name: t.string(), -// location: pointType, -// })), -// table({ name: 'unindexed_player', }, t.row({ -// ownerId: t.string(), -// name: t.string(), -// location: pointType, -// })), -// table({ name: 'user', primaryKey: 'identity', }, t.row({ -// identity: t.string(), -// name: t.string(), -// })), -// ); - -// const reducersSchema = reducers( -// reducerSchema('create_player', { -// name: t.string(), -// location: pointType, -// }), -// reducerSchema('foo_bar', { -// name: t.string(), -// location: pointType, -// }), -// ); - -// const REMOTE_MODULE = { -// versionInfo: { -// cliVersion: '1.6.0' as const, -// }, -// tables: tablesSchema.schemaType.tables, -// reducers: reducersSchema.reducersType.reducers, -// } satisfies RemoteModule< -// typeof tablesSchema.schemaType, -// typeof reducersSchema.reducersType -// >; - -// export type EventContext = __EventContextInterface< -// typeof REMOTE_MODULE -// >; - -// export type ReducerEventContext = __ReducerEventContextInterface< -// typeof REMOTE_MODULE -// >; - -// export type SubscriptionEventContext = __SubscriptionEventContextInterface< -// typeof REMOTE_MODULE -// >; - -// export type ErrorContext = __ErrorContextInterface< -// typeof REMOTE_MODULE -// >; - -// export class SubscriptionBuilder extends __SubscriptionBuilderImpl< -// typeof REMOTE_MODULE -// > {} - -// export class DbConnectionBuilder extends __DbConnectionBuilder< -// typeof REMOTE_MODULE, -// DbConnection -// > {}; - -// export class DbConnection extends __DbConnectionImpl { -// static builder = (): DbConnectionBuilder => { -// return new DbConnectionBuilder(REMOTE_MODULE, (config: DbConnectionConfig) => new DbConnection(config)); -// }; -// subscriptionBuilder = (): SubscriptionBuilder => { -// return new SubscriptionBuilder(this); -// }; -// } - const INDENT: &str = " "; pub struct TypeScript; @@ -249,6 +108,21 @@ impl Lang for TypeScript { } } + + /// e.g. + /// ```ts + /// table({ + /// name: 'player', + /// indexes: [ + /// { name: 'this_is_an_index', algorithm: "btree", columns: [ "ownerId" ] } + /// ], + /// }, t.row({ + /// id: t.u32().primaryKey(), + /// ownerId: t.string(), + /// name: t.string().unique(), + /// location: pointType, + /// })) + /// ``` fn generate_table_file(&self, module: &ModuleDef, table: &TableDef) -> OutputFile { let schema = TableSchema::from_module_def(module, table, (), 0.into()) .validated() @@ -278,150 +152,67 @@ impl Lang for TypeScript { None, ); - writeln!( - out, - "import {{ type EventContext, type Reducer, RemoteReducers, RemoteTables }} from \".\";" - ); - - // Mark potentially unused types - writeln!( - out, - "declare type __keep = [EventContext, Reducer, RemoteReducers, RemoteTables];" - ); - - let table_name = table.name.deref(); - let table_name_pascalcase = table.name.deref().to_case(Case::Pascal); - let table_handle = table_name_pascalcase.clone() + "TableHandle"; - let accessor_method = table_method_name(&table.name); - writeln!(out); - write!( - out, - "/** - * Table handle for the table `{table_name}`. - * - * Obtain a handle from the [`{accessor_method}`] property on [`RemoteTables`], - * like `ctx.db.{accessor_method}`. - * - * Users are encouraged not to explicitly reference this type, - * but to directly chain method calls, - * like `ctx.db.{accessor_method}.on_insert(...)`. - */ -export class {table_handle} extends __TableCache {{ -" - ); + writeln!(out, "export default table({{"); out.indent(1); - writeln!(out, "// phantom type to track the table name"); - writeln!(out, "readonly tableName!: TableName;"); - writeln!(out, "tableCache: __TableCache<{row_type}>;"); - writeln!(out); - writeln!(out, "constructor(tableCache: __TableCache<{row_type}>) {{"); - out.with_indent(|out| writeln!(out, "this.tableCache = tableCache;")); - writeln!(out, "}}"); - writeln!(out); - writeln!(out, "count(): number {{"); - out.with_indent(|out| { - writeln!(out, "return this.tableCache.count();"); - }); - writeln!(out, "}}"); - writeln!(out); - writeln!(out, "iter(): Iterable<{row_type}> {{"); - out.with_indent(|out| { - writeln!(out, "return this.tableCache.iter();"); - }); - writeln!(out, "}}"); - - for (unique_field_ident, unique_field_type_use) in - iter_unique_cols(module.typespace_for_generate(), &schema, product_def) - { - let unique_field_name = unique_field_ident.deref().to_case(Case::Camel); - let unique_field_name_pascalcase = unique_field_name.to_case(Case::Pascal); - - let unique_constraint = table_name_pascalcase.clone() + &unique_field_name_pascalcase + "Unique"; - let unique_field_type = type_name(module, unique_field_type_use); - - writeln!( - out, - "/** - * Access to the `{unique_field_name}` unique index on the table `{table_name}`, - * which allows point queries on the field of the same name - * via the [`{unique_constraint}.find`] method. - * - * Users are encouraged not to explicitly reference this type, - * but to directly chain method calls, - * like `ctx.db.{accessor_method}.{unique_field_name}().find(...)`. - * - * Get a handle on the `{unique_field_name}` unique index on the table `{table_name}`. - */" - ); - writeln!(out, "{unique_field_name} = {{"); - out.with_indent(|out| { - writeln!( - out, - "// Find the subscribed row whose `{unique_field_name}` column value is equal to `col_val`," - ); - writeln!(out, "// if such a row is present in the client cache."); - writeln!( - out, - "find: (col_val: {unique_field_type}): {row_type} | undefined => {{" - ); - out.with_indent(|out| { - writeln!(out, "for (let row of this.tableCache.iter()) {{"); - out.with_indent(|out| { - writeln!(out, "if (__deepEqual(row.{unique_field_name}, col_val)) {{"); - out.with_indent(|out| { - writeln!(out, "return row;"); - }); - writeln!(out, "}}"); - }); - writeln!(out, "}}"); - }); - writeln!(out, "}},"); - }); - writeln!(out, "}};"); - } - - writeln!(out); - - // TODO: expose non-unique indices. - writeln!( out, - "onInsert = (cb: (ctx: EventContext, row: {row_type}) => void) => {{ -{INDENT}return this.tableCache.onInsert(cb); -}} - -removeOnInsert = (cb: (ctx: EventContext, row: {row_type}) => void) => {{ -{INDENT}return this.tableCache.removeOnInsert(cb); -}} - -onDelete = (cb: (ctx: EventContext, row: {row_type}) => void) => {{ -{INDENT}return this.tableCache.onDelete(cb); -}} - -removeOnDelete = (cb: (ctx: EventContext, row: {row_type}) => void) => {{ -{INDENT}return this.tableCache.removeOnDelete(cb); -}}" + "name: '{}',", + table.name.deref() ); - - if schema.pk().is_some() { - write!( - out, - " -// Updates are only defined for tables with primary keys. -onUpdate = (cb: (ctx: EventContext, oldRow: {row_type}, newRow: {row_type}) => void) => {{ -{INDENT}return this.tableCache.onUpdate(cb); -}} - -removeOnUpdate = (cb: (ctx: EventContext, onRow: {row_type}, newRow: {row_type}) => void) => {{ -{INDENT}return this.tableCache.removeOnUpdate(cb); -}}" - ); + writeln!(out, "indexes: ["); + out.indent(1); + for index_def in iter_indexes(table) { + if !index_def.generated() { + // Skip system-defined indexes + continue; + } + match &index_def.algorithm { + IndexAlgorithm::BTree(BTreeAlgorithm { columns }) => { + let get_name_and_type = |col_pos: ColId| { + let (field_name, field_type) = &product_def.elements[col_pos.idx()]; + let name_camel = field_name.deref().to_case(Case::Camel); + (name_camel, field_type) + }; + writeln!(out, "{{ name: '{}', algorithm: 'btree', columns: [", index_def.name); + out.indent(1); + for col_id in columns.iter() { + writeln!(out, "'{}',", get_name_and_type(col_id).0); + } + out.dedent(1); + writeln!(out, "] }},"); + } + IndexAlgorithm::Direct(_) => { + // Direct indexes are not implemented yet. + continue; + } + _ => todo!(), + }; } out.dedent(1); - - writeln!(out, "}}"); + writeln!(out, "}}, {{"); + out.indent(1); + for (field_ident, field_ty) in &product_def.elements { + let field_name = field_ident.deref().to_case(Case::Camel); + write!(out, "{field_name}: "); + write_type(module, out, field_ty, None, None).unwrap(); + + let mut annotations = Vec::new(); + if schema.pk().map(|pk| *field_ident == Identifier::new(pk.col_name.clone()).unwrap()).unwrap_or(false) { + annotations.push("primaryKey()"); + } else { + for (unique_field_ident, _) in + iter_unique_cols(module.typespace_for_generate(), &schema, product_def) + { + if field_ident == unique_field_ident { + annotations.push("unique()"); + } + } + } + } + writeln!(out, "}});"); + out.dedent(1); OutputFile { filename: table_module_name(&table.name) + ".ts", code: output.into_inner(), @@ -463,12 +254,84 @@ removeOnUpdate = (cb: (ctx: EventContext, onRow: {row_type}, newRow: {row_type}) out.newline(); + // const tablesSchema = schema( +// table({ name: 'player', }, t.row({ +// ownerId: t.string(), +// name: t.string(), +// location: pointType, +// })), +// table({ name: 'unindexed_player', }, t.row({ +// ownerId: t.string(), +// name: t.string(), +// location: pointType, +// })), +// table({ name: 'user', primaryKey: 'identity', }, t.row({ +// identity: t.string(), +// name: t.string(), +// })), +// ); + +// const reducersSchema = reducers( +// reducerSchema('create_player', { +// name: t.string(), +// location: pointType, +// }), +// reducerSchema('foo_bar', { +// name: t.string(), +// location: pointType, +// }), +// ); + +// const REMOTE_MODULE = { +// versionInfo: { +// cliVersion: '1.6.0' as const, +// }, +// tables: tablesSchema.schemaType.tables, +// reducers: reducersSchema.reducersType.reducers, +// } satisfies RemoteModule< +// typeof tablesSchema.schemaType, +// typeof reducersSchema.reducersType +// >; + +// export type EventContext = __EventContextInterface< +// typeof REMOTE_MODULE +// >; + +// export type ReducerEventContext = __ReducerEventContextInterface< +// typeof REMOTE_MODULE +// >; + +// export type SubscriptionEventContext = __SubscriptionEventContextInterface< +// typeof REMOTE_MODULE +// >; + +// export type ErrorContext = __ErrorContextInterface< +// typeof REMOTE_MODULE +// >; + +// export class SubscriptionBuilder extends __SubscriptionBuilderImpl< +// typeof REMOTE_MODULE +// > {} + +// export class DbConnectionBuilder extends __DbConnectionBuilder< +// typeof REMOTE_MODULE, +// DbConnection +// > {}; + +// export class DbConnection extends __DbConnectionImpl { +// static builder = (): DbConnectionBuilder => { +// return new DbConnectionBuilder(REMOTE_MODULE, (config: DbConnectionConfig) => new DbConnection(config)); +// }; +// subscriptionBuilder = (): SubscriptionBuilder => { +// return new SubscriptionBuilder(this); +// }; + writeln!(out, "// Import and reexport all reducer arg types"); for reducer in iter_reducers(module) { let reducer_name = &reducer.name; let reducer_module_name = reducer_module_name(reducer_name) + ".ts"; let args_type = reducer_args_type_name(&reducer.name); - writeln!(out, "import {{ {args_type} }} from \"./{reducer_module_name}\";"); + writeln!(out, "import {args_type} from \"./{reducer_module_name}\";"); writeln!(out, "export {{ {args_type} }};"); } @@ -478,9 +341,8 @@ removeOnUpdate = (cb: (ctx: EventContext, onRow: {row_type}, newRow: {row_type}) let table_name = &table.name; let table_module_name = table_module_name(table_name) + ".ts"; let table_name_pascalcase = table.name.deref().to_case(Case::Pascal); - let table_handle = table_name_pascalcase.clone() + "TableHandle"; - writeln!(out, "import {{ {table_handle} }} from \"./{table_module_name}\";"); - writeln!(out, "export {{ {table_handle} }};"); + writeln!(out, "import {table_name_pascalcase} from \"./{table_module_name}\";"); + writeln!(out, "export {{ {table_name_pascalcase} }};"); } writeln!(out); @@ -488,331 +350,128 @@ removeOnUpdate = (cb: (ctx: EventContext, onRow: {row_type}, newRow: {row_type}) for ty in iter_types(module) { let type_name = collect_case(Case::Pascal, ty.name.name_segments()); let type_module_name = type_module_name(&ty.name) + ".ts"; - writeln!(out, "import {{ {type_name} }} from \"./{type_module_name}\";"); + writeln!(out, "import {type_name} from \"./{type_module_name}\";"); writeln!(out, "export {{ {type_name} }};"); } out.newline(); - - // Define SpacetimeModule - writeln!(out, "const REMOTE_MODULE = {{"); - out.indent(1); - writeln!(out, "tables: {{"); + + writeln!(out); + writeln!(out, "const tablesSchema = schema("); out.indent(1); for table in iter_tables(module) { - let type_ref = table.product_type_ref; - let row_type = type_ref_name(module, type_ref); - let schema = TableSchema::from_module_def(module, table, (), 0.into()) - .validated() - .expect("Failed to generate table due to validation errors"); - writeln!(out, "{}: {{", table.name); - out.indent(1); - writeln!(out, "tableName: \"{}\" as const,", table.name); - writeln!(out, "rowType: {row_type}.getTypeScriptAlgebraicType(),"); - if let Some(pk) = schema.pk() { - // This is left here so we can release the codegen change before releasing a new - // version of the SDK. - // - // Eventually we can remove this and only generate use the `primaryKeyInfo` field. - writeln!(out, "primaryKey: \"{}\" as const,", pk.col_name.to_string().to_case(Case::Camel)); - - writeln!(out, "primaryKeyInfo: {{"); - out.indent(1); - writeln!(out, "colName: \"{}\" as const,", pk.col_name.to_string().to_case(Case::Camel)); - writeln!( - out, - "colType: ({row_type}.getTypeScriptAlgebraicType() as __AlgebraicTypeVariants.Product).value.elements[{}].algebraicType,", - pk.col_pos.0 - ); - out.dedent(1); - writeln!(out, "}},"); - } - out.dedent(1); - writeln!(out, "}},"); + let table_name_pascalcase = table.name.deref().to_case(Case::Pascal); + writeln!(out, "{},", table_name_pascalcase); } out.dedent(1); - writeln!(out, "}},"); - writeln!(out, "reducers: {{"); + writeln!(out, ");"); + + writeln!(out); + + writeln!(out, "const reducersSchema = reducers("); out.indent(1); for reducer in iter_reducers(module) { - writeln!(out, "{}: {{", reducer.name); - out.indent(1); - writeln!(out, "reducerName: \"{}\" as const,", reducer.name); - writeln!( - out, - "argsType: {args_type}.getTypeScriptAlgebraicType(),", - args_type = reducer_args_type_name(&reducer.name) - ); - out.dedent(1); - writeln!(out, "}},"); + if !is_reducer_invokable(reducer) { + // Skip system-defined reducers + continue; + } + let reducer_name = &reducer.name; + let args_type = reducer_args_type_name(&reducer.name); + writeln!(out, "reducerSchema(\"{}\", {}),", reducer_name, args_type); } out.dedent(1); - writeln!(out, "}},"); + writeln!(out, ");"); + + writeln!(out); + + writeln!(out, "const REMOTE_MODULE = {{"); + out.indent(1); writeln!(out, "versionInfo: {{"); out.indent(1); writeln!(out, "cliVersion: \"{}\" as const,", spacetimedb_lib_version()); out.dedent(1); writeln!(out, "}},"); - writeln!( - out, - "// Constructors which are used by the DbConnectionImpl to -// extract type information from the generated RemoteModule. -// -// NOTE: This is not strictly necessary for `eventContextConstructor` because -// all we do is build a TypeScript object which we could have done inside the -// SDK, but if in the future we wanted to create a class this would be -// necessary because classes have methods, so we'll keep it. -eventContextConstructor: (imp: __DbConnectionImpl, event: __Event) => {{ - return {{ - ...(imp as DbConnection), - event - }} -}}, -dbViewConstructor: (imp: __DbConnectionImpl) => {{ - return new RemoteTables(imp); -}}, -reducersConstructor: (imp: __DbConnectionImpl, setReducerFlags: SetReducerFlags) => {{ - return new RemoteReducers(imp, setReducerFlags); -}}, -setReducerFlagsConstructor: () => {{ - return new SetReducerFlags(); -}}" - ); + writeln!(out, "tables: tablesSchema.schemaType.tables,"); + writeln!(out, "reducers: reducersSchema.reducersType.reducers,"); + out.dedent(1); + writeln!(out, "}} satisfies __RemoteModule<"); + out.indent(1); + writeln!(out, "typeof tablesSchema.schemaType,"); + writeln!(out, "typeof reducersSchema.reducersType"); + out.dedent(1); + writeln!(out, ">;"); out.dedent(1); - writeln!(out, "}} satisfies __RemoteModule;"); - - // Define `type Reducer` enum. - writeln!(out); - print_reducer_enum_defn(module, out); - - out.newline(); - - print_remote_reducers(module, out); - - out.newline(); - - print_set_reducer_flags(module, out); - - out.newline(); - - print_remote_tables(module, out); - - out.newline(); - - print_subscription_builder(module, out); - - out.newline(); - - print_db_connection(module, out); out.newline(); + // Write type aliases for EventContext, ReducerEventContext, SubscriptionEventContext, ErrorContext writeln!( out, - "export type EventContext = __EventContextInterface;" + "export type EventContext = __EventContextInterface;" ); - writeln!( out, - "export type ReducerEventContext = __ReducerEventContextInterface;" + "export type ReducerEventContext = __ReducerEventContextInterface;" ); - writeln!( out, - "export type SubscriptionEventContext = __SubscriptionEventContextInterface;" + "export type SubscriptionEventContext = __SubscriptionEventContextInterface;" ); - writeln!( out, - "export type ErrorContext = __ErrorContextInterface;" + "export type ErrorContext = __ErrorContextInterface;" ); - vec![OutputFile { - filename: "index.ts".to_string(), - code: output.into_inner(), - }] - } -} + writeln!(out); -fn print_remote_reducers(module: &ModuleDef, out: &mut Indenter) { - writeln!(out, "export class RemoteReducers {{"); - out.indent(1); - writeln!( - out, - "constructor(private connection: __DbConnectionImpl, private setCallReducerFlags: SetReducerFlags) {{}}" - ); - out.newline(); + writeln!(out, "export class SubscriptionBuilder extends __SubscriptionBuilderImpl<"); + out.indent(1); + writeln!(out, "typeof REMOTE_MODULE"); + out.dedent(1); + writeln!(out, "> {{}}"); - for reducer in iter_reducers(module) { - // The reducer argument names and types as `ident: ty, ident: ty, ident: ty`, - // and the argument names as `ident, ident, ident` - // for passing to function call and struct literal expressions. - let mut arg_list = "".to_string(); - let mut arg_name_list = "".to_string(); - for (arg_ident, arg_ty) in &reducer.params_for_generate.elements[..] { - let arg_name = arg_ident.deref().to_case(Case::Camel); - arg_name_list += &arg_name; - arg_list += &arg_name; - arg_list += ": "; - write_type(module, &mut arg_list, arg_ty, None, None).unwrap(); - arg_list += ", "; - arg_name_list += ", "; - } - let arg_list = arg_list.trim_end_matches(", "); - let arg_name_list = arg_name_list.trim_end_matches(", "); - - let reducer_name = &reducer.name; - - if is_reducer_invokable(reducer) { - let reducer_function_name = reducer_function_name(reducer); - let reducer_variant = reducer_variant_name(&reducer.name); - if reducer.params_for_generate.elements.is_empty() { - writeln!(out, "{reducer_function_name}() {{"); - out.with_indent(|out| { - writeln!( - out, - "this.connection.callReducer(\"{reducer_name}\", new Uint8Array(0), this.setCallReducerFlags.{reducer_function_name}Flags);" - ); - }); - } else { - writeln!(out, "{reducer_function_name}({arg_list}) {{"); - out.with_indent(|out| { - writeln!(out, "const __args = {{ {arg_name_list} }};"); - writeln!(out, "let __writer = new __BinaryWriter(1024);"); - writeln!( - out, - "{reducer_variant}.serialize(__writer, __args);" - ); - writeln!(out, "let __argsBuffer = __writer.getBuffer();"); - writeln!(out, "this.connection.callReducer(\"{reducer_name}\", __argsBuffer, this.setCallReducerFlags.{reducer_function_name}Flags);"); - }); - } - writeln!(out, "}}"); - out.newline(); - } + writeln!(out); + writeln!(out, "export class DbConnectionBuilder extends __DbConnectionBuilder<"); + out.indent(1); + writeln!(out, "typeof REMOTE_MODULE,"); + writeln!(out, "DbConnection"); + out.dedent(1); + writeln!(out, "> {{}}"); - let arg_list_padded = if arg_list.is_empty() { - String::new() - } else { - format!(", {arg_list}") - }; - let reducer_name_pascal = reducer_name.deref().to_case(Case::Pascal); + writeln!(out); writeln!( out, - "on{reducer_name_pascal}(callback: (ctx: ReducerEventContext{arg_list_padded}) => void) {{" + "export class DbConnection extends __DbConnectionImpl {{" ); out.indent(1); - writeln!(out, "this.connection.onReducer(\"{reducer_name}\", callback);"); + writeln!( + out, + "static builder = (): DbConnectionBuilder => {{" + ); + out.indent(1); + writeln!( + out, + "return new DbConnectionBuilder(REMOTE_MODULE, (config: DbConnectionConfig) => new DbConnection(config));" + ); out.dedent(1); - writeln!(out, "}}"); - out.newline(); + writeln!(out, "}};"); writeln!( out, - "removeOn{reducer_name_pascal}(callback: (ctx: ReducerEventContext{arg_list_padded}) => void) {{" + "subscriptionBuilder = (): SubscriptionBuilder => {{" ); out.indent(1); - writeln!(out, "this.connection.offReducer(\"{reducer_name}\", callback);"); + writeln!(out, "return new SubscriptionBuilder(this);"); + out.dedent(1); + writeln!(out, "}};"); out.dedent(1); writeln!(out, "}}"); out.newline(); - } - - out.dedent(1); - writeln!(out, "}}"); -} - -fn print_set_reducer_flags(module: &ModuleDef, out: &mut Indenter) { - writeln!(out, "export class SetReducerFlags {{"); - out.indent(1); - - for reducer in iter_reducers(module).filter(|r| is_reducer_invokable(r)) { - let reducer_function_name = reducer_function_name(reducer); - writeln!(out, "{reducer_function_name}Flags: __CallReducerFlags = 'FullUpdate';"); - writeln!(out, "{reducer_function_name}(flags: __CallReducerFlags) {{"); - out.with_indent(|out| { - writeln!(out, "this.{reducer_function_name}Flags = flags;"); - }); - writeln!(out, "}}"); - out.newline(); - } - - out.dedent(1); - writeln!(out, "}}"); -} - -fn print_remote_tables(module: &ModuleDef, out: &mut Indenter) { - writeln!(out, "export class RemoteTables {{"); - out.indent(1); - writeln!(out, "constructor(private connection: __DbConnectionImpl) {{}}"); - - for table in iter_tables(module) { - writeln!(out); - let table_name = table.name.deref(); - let table_name_pascalcase = table.name.deref().to_case(Case::Pascal); - let table_name_camelcase = table.name.deref().to_case(Case::Camel); - let table_handle = table_name_pascalcase.clone() + "TableHandle"; - let type_ref = table.product_type_ref; - let row_type = type_ref_name(module, type_ref); - writeln!(out, "get {table_name_camelcase}(): {table_handle}<'{table_name}'> {{"); - out.with_indent(|out| { - writeln!(out, "// clientCache is a private property"); - writeln!( - out, - "return new {table_handle}((this.connection as unknown as {{ clientCache: __ClientCache }}).clientCache.getOrCreateTable<{row_type}>(REMOTE_MODULE.tables.{table_name}));" - ); - }); - writeln!(out, "}}"); - } - - out.dedent(1); - writeln!(out, "}}"); -} - -fn print_subscription_builder(_module: &ModuleDef, out: &mut Indenter) { - writeln!( - out, - "export class SubscriptionBuilder extends __SubscriptionBuilderImpl {{ }}" - ); -} - -fn print_db_connection(_module: &ModuleDef, out: &mut Indenter) { - writeln!( - out, - "export class DbConnection extends __DbConnectionImpl {{" - ); - out.indent(1); - writeln!( - out, - "static builder = (): __DbConnectionBuilder => {{" - ); - out.indent(1); - writeln!( - out, - "return new __DbConnectionBuilder(REMOTE_MODULE, (imp: __DbConnectionImpl) => imp as DbConnection);" - ); - out.dedent(1); - writeln!(out, "}}"); - writeln!(out, "subscriptionBuilder = (): SubscriptionBuilder => {{"); - out.indent(1); - writeln!(out, "return new SubscriptionBuilder(this);"); - out.dedent(1); - writeln!(out, "}}"); - out.dedent(1); - writeln!(out, "}}"); -} -fn print_reducer_enum_defn(module: &ModuleDef, out: &mut Indenter) { - writeln!(out, "// A type representing all the possible variants of a reducer."); - writeln!(out, "export type Reducer = never"); - for reducer in iter_reducers(module) { - writeln!( - out, - "| {{ name: \"{}\", args: {} }}", - reducer_variant_name(&reducer.name), - reducer_args_type_name(&reducer.name) - ); + vec![OutputFile { + filename: "index.ts".to_string(), + code: output.into_inner(), + }] } - writeln!(out, ";"); } fn print_spacetimedb_imports(out: &mut Indenter) { @@ -824,13 +483,12 @@ fn print_spacetimedb_imports(out: &mut Indenter) { "type AlgebraicTypeVariants as __AlgebraicTypeVariants", "Identity as __Identity", "ClientCache as __ClientCache", + "ClientTable as __ClientTable", "ConnectionId as __ConnectionId", "Timestamp as __Timestamp", "TimeDuration as __TimeDuration", "DbConnectionBuilder as __DbConnectionBuilder", - "TableCache as __TableCache", "BinaryWriter as __BinaryWriter", - "type TableHandle as __TableHandle", "type CallReducerFlags as __CallReducerFlags", "type EventContextInterface as __EventContextInterface", "type ReducerEventContextInterface as __ReducerEventContextInterface", @@ -842,6 +500,13 @@ fn print_spacetimedb_imports(out: &mut Indenter) { "DbConnectionImpl as __DbConnectionImpl", "type Event as __Event", "deepEqual as __deepEqual", + "schema as __schema", + "table as __table", + "reducers as __reducers", + "reducerSchema as __reducerSchema", + "DbConnectionConfig as __DbConnectionConfig", + "RemoteModule as __RemoteModule", + "t as __t", ]; types.sort(); writeln!(out, "import {{"); @@ -867,111 +532,45 @@ fn print_lint_suppression(output: &mut Indenter) { writeln!(output, "/* tslint:disable */"); } -fn write_get_algebraic_type_for_product( - module: &ModuleDef, - out: &mut Indenter, - type_cache_name: &str, - elements: &[(Identifier, AlgebraicTypeUse)], -) { - writeln!( - out, - "/** -* A function which returns this type represented as an AlgebraicType. -* This function is derived from the AlgebraicType used to generate this type. -*/" - ); - writeln!(out, "getTypeScriptAlgebraicType(): __AlgebraicTypeType {{"); - { - out.indent(1); - writeln!(out, "if ({type_cache_name}) return {type_cache_name};"); - // initialization is split in two because of recursive types - writeln!( - out, - "{type_cache_name} = __AlgebraicTypeValue.Product({{ elements: [] }});" - ); - writeln!(out, "{type_cache_name}.value.elements.push("); - out.indent(1); - convert_product_type_elements(module, out, elements, ""); - out.dedent(1); - writeln!(out, ");"); - writeln!(out, "return {type_cache_name};"); - out.dedent(1); - } - writeln!(out, "}},"); -} - +/// e.g. +/// ```ts +/// export default __t.object('Point', { +/// x: __t.f32(), +/// y: __t.f32(), +/// fooBar: __t.string(), +/// }); +/// ``` fn define_body_for_product( module: &ModuleDef, out: &mut Indenter, name: &str, elements: &[(Identifier, AlgebraicTypeUse)], ) { - write!(out, "export type {name} = {{"); + + write!(out, "export default __t.object(\"{name}\", {{"); if elements.is_empty() { writeln!(out, "}};"); } else { writeln!(out); - out.with_indent(|out| write_arglist_no_delimiters(module, out, elements, None, true).unwrap()); + out.with_indent(|out| write_object_type_builder_fields(module, out, elements, true).unwrap()); writeln!(out, "}};"); } - - let type_cache_name = &*format!("_cached_{name}_type_value"); - writeln!(out, "let {type_cache_name}: __AlgebraicTypeType | null = null;"); - out.newline(); - - writeln!( - out, - "/** - * An object for generated helper functions. - */" - ); - writeln!(out, "export const {name} = {{"); - out.indent(1); - write_get_algebraic_type_for_product(module, out, type_cache_name, elements); - writeln!(out); - - writeln!(out, "serialize(writer: __BinaryWriter, value: {name}): void {{"); - out.indent(1); - writeln!( - out, - "__AlgebraicTypeValue.serializeValue(writer, {name}.getTypeScriptAlgebraicType(), value);" - ); - out.dedent(1); - writeln!(out, "}},"); - writeln!(out); - - writeln!(out, "deserialize(reader: __BinaryReader): {name} {{"); - out.indent(1); - writeln!( - out, - "return __AlgebraicTypeValue.deserializeValue(reader, {name}.getTypeScriptAlgebraicType());" - ); - out.dedent(1); - writeln!(out, "}},"); - writeln!(out); - - out.dedent(1); - writeln!(out, "}}"); - - out.newline(); - - writeln!(out, "export default {name};"); - out.newline(); } -fn write_arglist_no_delimiters( +/// e.g. +/// ```ts +/// x: __t.f32(), +/// y: __t.f32(), +/// fooBar: __t.string(), +/// ``` +fn write_object_type_builder_fields( module: &ModuleDef, out: &mut impl Write, elements: &[(Identifier, AlgebraicTypeUse)], - prefix: Option<&str>, convert_case: bool, ) -> anyhow::Result<()> { for (ident, ty) in elements { - if let Some(prefix) = prefix { - write!(out, "{prefix} ")?; - } - let name = if convert_case { ident.deref().to_case(Case::Camel) } else { @@ -979,13 +578,58 @@ fn write_arglist_no_delimiters( }; write!(out, "{name}: ")?; - write_type(module, out, ty, None, None)?; + write_type_builder(module, out, ty)?; writeln!(out, ",")?; } Ok(()) } +/// e.g. `__t.option(__t.i32())`, `__t.string()` +fn write_type_builder(module: &ModuleDef, out: &mut W, ty: &AlgebraicTypeUse) -> fmt::Result { + match ty { + AlgebraicTypeUse::Unit => write!(out, "__t.unit()")?, + AlgebraicTypeUse::Never => write!(out, "__t.never()")?, + AlgebraicTypeUse::Identity => write!(out, "__t.identity()")?, + AlgebraicTypeUse::ConnectionId => write!(out, "__t.connectionId()")?, + AlgebraicTypeUse::Timestamp => write!(out, "__t.timestamp()")?, + AlgebraicTypeUse::TimeDuration => write!(out, "__t.timeDuration()")?, + AlgebraicTypeUse::ScheduleAt => write!(out, "__t.scheduleAt()")?, + AlgebraicTypeUse::Option(inner_ty) => { + write!(out, "__t.option(")?; + write_type_builder(module, out, inner_ty)?; + write!(out, ")")?; + }, + AlgebraicTypeUse::Primitive(prim) => match prim { + PrimitiveType::Bool => write!(out, "__t.bool()")?, + PrimitiveType::I8 => write!(out, "__t.i8()")?, + PrimitiveType::U8 => write!(out, "__t.u8()")?, + PrimitiveType::I16 => write!(out, "__t.i16()")?, + PrimitiveType::U16 => write!(out, "__t.u16()")?, + PrimitiveType::I32 => write!(out, "__t.i32()")?, + PrimitiveType::U32 => write!(out, "__t.u32()")?, + PrimitiveType::I64 => write!(out, "__t.i64()")?, + PrimitiveType::U64 => write!(out, "__t.u64()")?, + PrimitiveType::I128 => write!(out, "__t.i128()")?, + PrimitiveType::U128 => write!(out, "__t.u128()")?, + PrimitiveType::I256 => write!(out, "__t.i256()")?, + PrimitiveType::U256 => write!(out, "__t.u256()")?, + PrimitiveType::F32 => write!(out, "__t.f32()")?, + PrimitiveType::F64 => write!(out, "__t.f64()")?, + }, + AlgebraicTypeUse::String => write!(out, "__t.string()")?, + AlgebraicTypeUse::Array(elem_ty) => { + write!(out, "__t.array(")?; + write_type_builder(module, out, elem_ty)?; + write!(out, ")")?; + }, + AlgebraicTypeUse::Ref(r) => { + write!(out, "{}", type_ref_name(module, *r))?; + }, + } + Ok(()) +} + fn write_sum_variant_type(module: &ModuleDef, out: &mut Indenter, ident: &Identifier, ty: &AlgebraicTypeUse) { let name = ident.deref().to_case(Case::Pascal); write!(out, "export type {name} = "); @@ -1031,56 +675,14 @@ fn write_variant_types(module: &ModuleDef, out: &mut Indenter, variants: &[(Iden } } -fn write_variant_constructors( - module: &ModuleDef, - out: &mut Indenter, - name: &str, - variants: &[(Identifier, AlgebraicTypeUse)], -) { - // Write all the variant constructors. - // Write all of the variant constructors. - for (ident, ty) in variants { - if matches!(ty, AlgebraicTypeUse::Unit) { - // If the variant has no members, we can export a simple object. - // ``` - // Foo: { tag: "Foo" } = { tag: "Foo" } as const, - // ``` - write!(out, "{ident}: {{ tag: \"{ident}\" }} as const,"); - writeln!(out); - continue; - } - let variant_name = ident.deref().to_case(Case::Pascal); - write!(out, "{variant_name}: (value: "); - write_type(module, out, ty, None, None).unwrap(); - writeln!( - out, - "): {name}Variants.{variant_name} => ({{ tag: \"{variant_name}\", value }})," - ); - } -} - -fn write_get_algebraic_type_for_sum( - module: &ModuleDef, - out: &mut Indenter, - type_cache_name: &str, - variants: &[(Identifier, AlgebraicTypeUse)], -) { - writeln!(out, "getTypeScriptAlgebraicType(): __AlgebraicTypeType {{"); - { - indent_scope!(out); - writeln!(out, "if ({type_cache_name}) return {type_cache_name};"); - // initialization is split in two because of recursive types - writeln!(out, "{type_cache_name} = __AlgebraicTypeValue.Sum({{ variants: [] }});"); - writeln!(out, "{type_cache_name}.value.variants.push("); - out.indent(1); - convert_sum_type_variants(module, &mut out, variants, ""); - out.dedent(1); - writeln!(out, ");"); - writeln!(out, "return {type_cache_name};"); - } - writeln!(out, "}},"); -} - +/// e.g. +/// ```ts +/// // The tagged union or sum type for the algebraic type `Option`. +/// export default __t.enum("Option", { +/// none: __t.unit(), +/// some: { value: __t.i32() }, +/// }); +/// ``` fn define_body_for_sum( module: &ModuleDef, out: &mut Indenter, @@ -1088,71 +690,9 @@ fn define_body_for_sum( variants: &[(Identifier, AlgebraicTypeUse)], ) { writeln!(out, "// The tagged union or sum type for the algebraic type `{name}`."); - write!(out, "export type {name} = "); - - let names = variants - .iter() - .map(|(ident, _)| format!("{name}Variants.{}", ident.deref().to_case(Case::Pascal))) - .collect::>() - .join(" |\n "); - - if variants.is_empty() { - writeln!(out, "never;"); - } else { - writeln!(out, "{names};"); - } - - out.newline(); - - let type_cache_name = &*format!("_cached_{name}_type_value"); - writeln!(out, "let {type_cache_name}: __AlgebraicTypeType | null = null;"); - out.newline(); - - // Write the runtime value with helper functions - writeln!(out, "// A value with helper functions to construct the type."); - writeln!(out, "export const {name} = {{"); - out.indent(1); - - // Write all of the variant constructors. - writeln!( - out, - "// Helper functions for constructing each variant of the tagged union. -// ``` -// const foo = Foo.A(42); -// assert!(foo.tag === \"A\"); -// assert!(foo.value === 42); -// ```" - ); - write_variant_constructors(module, out, name, variants); - writeln!(out); - - // Write the function that generates the algebraic type. - write_get_algebraic_type_for_sum(module, out, type_cache_name, variants); - writeln!(out); - - writeln!( - out, - "serialize(writer: __BinaryWriter, value: {name}): void {{ - __AlgebraicTypeValue.serializeValue(writer, {name}.getTypeScriptAlgebraicType(), value); -}}," - ); - writeln!(out); - - writeln!( - out, - "deserialize(reader: __BinaryReader): {name} {{ - return __AlgebraicTypeValue.deserializeValue(reader, {name}.getTypeScriptAlgebraicType()); -}}," - ); - writeln!(out); - - out.dedent(1); - - writeln!(out, "}}"); - out.newline(); - - writeln!(out, "export default {name};"); - + write!(out, "export default __t.enum(\"{name}\", {{"); + out.with_indent(|out| write_object_type_builder_fields(module, out, variants, true).unwrap()); + writeln!(out, "}});"); out.newline(); } @@ -1290,72 +830,6 @@ pub fn write_type( Ok(()) } -fn convert_algebraic_type<'a>( - module: &'a ModuleDef, - out: &mut Indenter, - ty: &'a AlgebraicTypeUse, - ref_prefix: &'a str, -) { - match ty { - AlgebraicTypeUse::ScheduleAt => write!(out, "__AlgebraicTypeValue.createScheduleAtType()"), - AlgebraicTypeUse::Identity => write!(out, "__AlgebraicTypeValue.createIdentityType()"), - AlgebraicTypeUse::ConnectionId => write!(out, "__AlgebraicTypeValue.createConnectionIdType()"), - AlgebraicTypeUse::Timestamp => write!(out, "__AlgebraicTypeValue.createTimestampType()"), - AlgebraicTypeUse::TimeDuration => write!(out, "__AlgebraicTypeValue.createTimeDurationType()"), - AlgebraicTypeUse::Option(inner_ty) => { - write!(out, "__AlgebraicTypeValue.createOptionType("); - convert_algebraic_type(module, out, inner_ty, ref_prefix); - write!(out, ")"); - } - AlgebraicTypeUse::Array(ty) => { - write!(out, "__AlgebraicTypeValue.Array("); - convert_algebraic_type(module, out, ty, ref_prefix); - write!(out, ")"); - } - AlgebraicTypeUse::Ref(r) => write!( - out, - "{ref_prefix}{}.getTypeScriptAlgebraicType()", - type_ref_name(module, *r) - ), - AlgebraicTypeUse::Primitive(prim) => { - write!(out, "__AlgebraicTypeValue.{prim:?}"); - } - AlgebraicTypeUse::Unit => write!(out, "__AlgebraicTypeValue.Product({{ elements: [] }})"), - AlgebraicTypeUse::Never => unimplemented!(), - AlgebraicTypeUse::String => write!(out, "__AlgebraicTypeValue.String"), - } -} - -fn convert_sum_type_variants<'a>( - module: &'a ModuleDef, - out: &mut Indenter, - variants: &'a [(Identifier, AlgebraicTypeUse)], - ref_prefix: &'a str, -) { - for (ident, ty) in variants { - write!(out, "{{ name: \"{ident}\", algebraicType: ",); - convert_algebraic_type(module, out, ty, ref_prefix); - writeln!(out, " }},"); - } -} - -fn convert_product_type_elements<'a>( - module: &'a ModuleDef, - out: &mut Indenter, - elements: &'a [(Identifier, AlgebraicTypeUse)], - ref_prefix: &'a str, -) { - for (ident, ty) in elements { - write!( - out, - "{{ name: \"{}\", algebraicType: ", - ident.deref().to_case(Case::Camel) - ); - convert_algebraic_type(module, out, ty, ref_prefix); - writeln!(out, " }},"); - } -} - /// Print imports for each of the `imports`. fn print_imports(module: &ModuleDef, out: &mut Indenter, imports: Imports, suffix: Option<&str>) { for typeref in imports { From 83a23f9d1ffeac322d519a70a2f431a84befe8fe Mon Sep 17 00:00:00 2001 From: = Date: Mon, 3 Nov 2025 23:38:34 -0500 Subject: [PATCH 07/49] Almost there, just in a bit of a pickle --- .../src/lib/constraints.ts | 11 + .../bindings-typescript/src/lib/reducers.ts | 5 +- crates/bindings-typescript/src/lib/table.ts | 20 +- .../src/react/SpacetimeDBProvider.ts | 24 +- .../src/react/useReducer.ts | 23 +- .../src/react/useSpacetimeDB.ts | 6 +- .../bindings-typescript/src/react/useTable.ts | 83 +++-- .../src/sdk/client_table.ts | 11 +- .../src/sdk/db_connection_builder.ts | 15 +- .../src/sdk/db_connection_impl.ts | 2 + crates/bindings-typescript/src/sdk/db_view.ts | 4 +- .../bindings-typescript/test-app/src/App.tsx | 2 +- .../module_bindings/create_player_reducer.ts | 59 +-- .../test-app/src/module_bindings/index.ts | 348 +++--------------- .../src/module_bindings/player_table.ts | 115 +----- .../src/module_bindings/player_type.ts | 73 +--- .../src/module_bindings/point_type.ts | 16 +- .../module_bindings/unindexed_player_table.ts | 73 +--- .../module_bindings/unindexed_player_type.ts | 65 +--- .../src/module_bindings/user_table.ts | 100 +---- .../test-app/src/module_bindings/user_type.ts | 58 +-- crates/codegen/src/typescript.rs | 248 +++++-------- 22 files changed, 356 insertions(+), 1005 deletions(-) diff --git a/crates/bindings-typescript/src/lib/constraints.ts b/crates/bindings-typescript/src/lib/constraints.ts index 4301137281f..4b206a8c858 100644 --- a/crates/bindings-typescript/src/lib/constraints.ts +++ b/crates/bindings-typescript/src/lib/constraints.ts @@ -37,3 +37,14 @@ export type ColumnIsUnique> = M extends | { isPrimaryKey: true } ? true : false; + +/** + * Constraint helper type used *inside* {@link table} to enforce the type + * of constraint definitions. + */ +export type ConstraintOpts = { + name?: string; +} & ( + | { constraint: 'unique'; columns: [AllowedCol] } + | { constraint: 'primaryKey'; columns: [AllowedCol] } +); \ No newline at end of file diff --git a/crates/bindings-typescript/src/lib/reducers.ts b/crates/bindings-typescript/src/lib/reducers.ts index e6c1b767a04..64f54c3d961 100644 --- a/crates/bindings-typescript/src/lib/reducers.ts +++ b/crates/bindings-typescript/src/lib/reducers.ts @@ -11,7 +11,6 @@ import type { InferTypeOfRow, RowBuilder, RowObj, - StringBuilder, TypeBuilder, } from './type_builders'; @@ -265,7 +264,7 @@ export function clientDisconnected< */ export type ReducerSchema< ReducerName extends string, - Params extends ParamsObj, + Params extends ParamsObj | RowObj, > = { /** * The name of the reducer. @@ -347,7 +346,7 @@ export function reducerSchema< Params extends ParamsObj, >( name: ReducerName, - params: Params + params: Params ): ReducerSchema { const paramType: ProductType = { elements: Object.entries(params).map(([n, c]) => ({ diff --git a/crates/bindings-typescript/src/lib/table.ts b/crates/bindings-typescript/src/lib/table.ts index a4d4d9b5254..9bbc3e9e99c 100644 --- a/crates/bindings-typescript/src/lib/table.ts +++ b/crates/bindings-typescript/src/lib/table.ts @@ -4,10 +4,11 @@ import RawIndexAlgorithm from './autogen/raw_index_algorithm_type'; import type RawIndexDefV9 from './autogen/raw_index_def_v_9_type'; import type RawSequenceDefV9 from './autogen/raw_sequence_def_v_9_type'; import type RawTableDefV9 from './autogen/raw_table_def_v_9_type'; -import type { AllUnique } from './constraints'; +import type { AllUnique, ConstraintOpts } from './constraints'; import type { ColumnIndex, IndexColumns, Indexes, IndexOpts, ReadonlyIndexes } from './indexes'; import { MODULE_DEF, splitName } from './schema'; import { + ProductBuilder, RowBuilder, type ColumnBuilder, type ColumnMetadata, @@ -87,6 +88,7 @@ export type TableOpts = { name: string; public?: boolean; indexes?: IndexOpts[]; // declarative multi‑column indexes + constraints?: ConstraintOpts[]; scheduled?: string; }; @@ -295,6 +297,22 @@ export function table>( indexes.push({ name: undefined, accessorName: indexOpts.name, algorithm }); } + // add explicit constraints from options.constraints + for (const constraintOpts of opts.constraints ?? []) { + if (constraintOpts.constraint === 'unique') { + let data: RawConstraintDefV9['data']; + data = { + tag: 'Unique', + value: { columns: constraintOpts.columns.map(c => colIds.get(c)!) }, + }; + constraints.push({ name: constraintOpts.name, data }); + continue; + } + if (constraintOpts.constraint === 'primaryKey') { + pk.push(...constraintOpts.columns.map(c => colIds.get(c)!)); + } + } + for (const index of indexes) { const cols = index.algorithm.tag === 'Direct' diff --git a/crates/bindings-typescript/src/react/SpacetimeDBProvider.ts b/crates/bindings-typescript/src/react/SpacetimeDBProvider.ts index 7ddd5b95981..0ca560b86ec 100644 --- a/crates/bindings-typescript/src/react/SpacetimeDBProvider.ts +++ b/crates/bindings-typescript/src/react/SpacetimeDBProvider.ts @@ -2,6 +2,7 @@ import { DbConnectionBuilder, type DbConnectionImpl, type ErrorContextInterface, + type RemoteModuleOf, type SubscriptionEventContextInterface, } from '../sdk/db_connection_impl'; import * as React from 'react'; @@ -12,21 +13,20 @@ import type { UntypedRemoteModule } from '../sdk/spacetime_module'; export interface SpacetimeDBProviderProps< RemoteModule extends UntypedRemoteModule, - DbConnection extends DbConnectionImpl, + DbConnection extends DbConnectionImpl = DbConnectionImpl, > { connectionBuilder: DbConnectionBuilder; children?: React.ReactNode; } export function SpacetimeDBProvider< - RemoteModule extends UntypedRemoteModule, - DbConnection extends DbConnectionImpl, ->({ connectionBuilder, children }: SpacetimeDBProviderProps) { + DbConnection extends DbConnectionImpl, +>({ connectionBuilder, children }: SpacetimeDBProviderProps>) { // Holds the imperative connection instance when (and only when) we’re on the client. const connRef = React.useRef(null); const getConnection = React.useCallback(() => connRef.current, []); - const [state, setState] = React.useState>({ + const [state, setState] = React.useState>({ isActive: false, identity: undefined, token: undefined, @@ -38,7 +38,7 @@ export function SpacetimeDBProvider< // Build on the client only; useEffect won't run during SSR. React.useEffect(() => { // Register callback for onConnect to update state - const onConnect = (conn: DbConnectionImpl) => { + const onConnect = (conn: DbConnectionImpl>) => { setState(s => ({ ...s, isActive: conn.isActive, @@ -47,13 +47,13 @@ export function SpacetimeDBProvider< connectionId: conn.connectionId, })); }; - const onDisconnect = (ctx: ErrorContextInterface) => { + const onDisconnect = (ctx: ErrorContextInterface>) => { setState(s => ({ ...s, isActive: ctx.isActive, })); }; - const onConnectError = (ctx: ErrorContextInterface, err: Error) => { + const onConnectError = (ctx: ErrorContextInterface>, err: Error) => { setState(s => ({ ...s, isActive: ctx.isActive, @@ -75,13 +75,13 @@ export function SpacetimeDBProvider< // Lazily build once if (!connRef.current) { - connRef.current = connectionBuilder.build() as DbConnection; + connRef.current = connectionBuilder.build() as unknown as DbConnection; } return () => { - connRef.current?.removeOnConnect(onConnect); - connRef.current?.removeOnDisconnect(onDisconnect); - connRef.current?.removeOnConnectError(onConnectError); + connRef.current?.removeOnConnect(onConnect as any); + connRef.current?.removeOnDisconnect(onDisconnect as any); + connRef.current?.removeOnConnectError(onConnectError as any); connRef.current?.disconnect(); connRef.current = null; }; diff --git a/crates/bindings-typescript/src/react/useReducer.ts b/crates/bindings-typescript/src/react/useReducer.ts index b7684234b46..06eb76da311 100644 --- a/crates/bindings-typescript/src/react/useReducer.ts +++ b/crates/bindings-typescript/src/react/useReducer.ts @@ -1,19 +1,16 @@ -import type { DbConnectionImpl } from "../sdk/db_connection_impl"; -import type { ReducerNamesFromReducers } from "../sdk/reducer_handle"; +import type { DbConnectionImpl, RemoteModuleOf } from "../sdk/db_connection_impl"; +import type { ReducersView } from "../sdk/reducers"; import type { UntypedRemoteModule } from "../sdk/spacetime_module"; -import { useSpacetimeDB } from "./useSpacetimeDB"; +import { useSpacetimeDB, } from "./useSpacetimeDB"; + export function useReducer< - RemoteModule extends UntypedRemoteModule, - DbConnection extends DbConnectionImpl, - ReducerName extends ReducerNamesFromReducers = ReducerNamesFromReducers< - DbConnection['reducers'] - >, - ReducerType = DbConnection['reducers'][ReducerName & keyof DbConnection['reducers']] + DbConnection extends DbConnectionImpl, + ReducerName extends keyof ReducersView> = keyof ReducersView> >( - reducerName: ReducerName, -): ReducerType { - const connectionState = useSpacetimeDB(); + reducerName: ReducerName +): ReducersView>[ReducerName] { + const connectionState = useSpacetimeDB(); const connection = connectionState.getConnection()!; - return connection.reducers[reducerName as keyof typeof connection.reducers]; + return connection.reducers[reducerName]; } \ No newline at end of file diff --git a/crates/bindings-typescript/src/react/useSpacetimeDB.ts b/crates/bindings-typescript/src/react/useSpacetimeDB.ts index c0421a2ffd2..8eb1a1e01d1 100644 --- a/crates/bindings-typescript/src/react/useSpacetimeDB.ts +++ b/crates/bindings-typescript/src/react/useSpacetimeDB.ts @@ -3,12 +3,12 @@ import type { DbConnectionImpl } from '../sdk/db_connection_impl'; import type { ConnectionState } from './connection_state'; import type { UntypedRemoteModule } from '../sdk/spacetime_module'; -export const SpacetimeDBContext = createContext> | undefined>(undefined); +export const SpacetimeDBContext = createContext> | undefined>(undefined); // Throws an error if used outside of a SpacetimeDBProvider // Error is caught by other hooks like useTable so they can provide better error messages -export function useSpacetimeDB>(): ConnectionState { - const context = useContext(SpacetimeDBContext) as ConnectionState | undefined; +export function useSpacetimeDB>(): ConnectionState { + const context = useContext(SpacetimeDBContext) as ConnectionState | undefined; if (!context) { throw new Error( 'useSpacetimeDB must be used within a SpacetimeDBProvider component. Did you forget to add a `SpacetimeDBProvider` to your component tree?' diff --git a/crates/bindings-typescript/src/react/useTable.ts b/crates/bindings-typescript/src/react/useTable.ts index 311b3d68663..0dc69d54f6a 100644 --- a/crates/bindings-typescript/src/react/useTable.ts +++ b/crates/bindings-typescript/src/react/useTable.ts @@ -6,10 +6,13 @@ import { useSyncExternalStore, } from 'react'; import { useSpacetimeDB } from './useSpacetimeDB'; -import { DbConnectionImpl, TableCache } from '../sdk/db_connection_impl'; -import type { TableNamesFromDb } from '../sdk/client_table'; +import { DbConnectionImpl, TableCache, type EventContextInterface, type RemoteModuleOf } from '../sdk/db_connection_impl'; import type { ConnectionState } from './connection_state'; -import type { UntypedRemoteModule } from '../sdk/spacetime_module'; +import type { RemoteModule, UntypedRemoteModule } from '../sdk/spacetime_module'; +import type { ClientDbView } from '../sdk/db_view'; +import type { RowType, UntypedTableDef } from '../lib/table'; +import type { ClientTable } from '../sdk/client_table'; +import type { Infer, InferTypeOfRow } from '../lib/type_builders'; export interface UseQueryCallbacks { onInsert?: (row: RowType) => void; @@ -69,7 +72,7 @@ export const isOr = ( e: Expr ): e is Extract, { type: 'or' }> => e.type === 'or'; -type RecordLike = Record; +type RecordLike = Record; export function evaluate( expr: Expr, @@ -179,6 +182,15 @@ type ColumnsFromRow = { }[keyof R] & string; +// From a ClientTable, get Tbl +type TableDefOfClient = T extends ClientTable ? Tbl : never; + +// Row type for a given connection + table key +type RowTypeOfTable< + C extends DbConnectionImpl, + K extends keyof ClientDbView> +> = InferTypeOfRow>[K]>>>; + /** * React hook to subscribe to a table in SpacetimeDB and receive live updates as rows are inserted, updated, or deleted. * @@ -214,15 +226,12 @@ type ColumnsFromRow = { */ export function useTable< DbConnection extends DbConnectionImpl, - RowType extends Record, - TableName extends TableNamesFromDb = TableNamesFromDb< - DbConnection['db'] - >, + TableName extends keyof ClientDbView> >( tableName: TableName, - where: Expr>, - callbacks?: UseQueryCallbacks -): Snapshot; + where: Expr>> , + callbacks?: UseQueryCallbacks> +): Snapshot>; /** * React hook to subscribe to a table in SpacetimeDB and receive live updates as rows are inserted, updated, or deleted. @@ -259,37 +268,33 @@ export function useTable< */ export function useTable< DbConnection extends DbConnectionImpl, - RowType extends Record, - TableName extends TableNamesFromDb = TableNamesFromDb< - DbConnection['db'] - >, + TableName extends keyof ClientDbView> >( tableName: TableName, - callbacks?: UseQueryCallbacks -): Snapshot; + callbacks?: UseQueryCallbacks> +): Snapshot>; export function useTable< DbConnection extends DbConnectionImpl, - TableName extends TableNamesFromDb = TableNamesFromDb< - DbConnection['db'] - >, + TableName extends keyof ClientDbView>, >( tableName: TableName, whereClauseOrCallbacks?: - | Expr> - | UseQueryCallbacks, - callbacks?: UseQueryCallbacks -): Snapshot { - let whereClause: Expr> | undefined; + | Expr>> + | UseQueryCallbacks>, + callbacks?: UseQueryCallbacks> +): Snapshot> { + type UseTableRowType = RowTypeOfTable; + let whereClause: Expr> | undefined; if ( whereClauseOrCallbacks && typeof whereClauseOrCallbacks === 'object' && 'type' in whereClauseOrCallbacks ) { - whereClause = whereClauseOrCallbacks as Expr>; + whereClause = whereClauseOrCallbacks as Expr>; } else { callbacks = whereClauseOrCallbacks as - | UseQueryCallbacks + | UseQueryCallbacks | undefined; } const [subscribeApplied, setSubscribeApplied] = useState(false); @@ -305,25 +310,23 @@ export function useTable< } const query = - `SELECT * FROM ${tableName}` + + `SELECT * FROM ${String(tableName)}` + (whereClause ? ` WHERE ${toString(whereClause)}` : ''); const latestTransactionEvent = useRef(null); - const lastSnapshotRef = useRef | null>(null); + const lastSnapshotRef = useRef | null>(null); const whereKey = whereClause ? toString(whereClause) : ''; - const computeSnapshot = useCallback((): Snapshot => { + const computeSnapshot = useCallback((): Snapshot => { const connection = connectionState.getConnection(); if (!connection) { return { rows: [], state: 'loading' }; } - const table = connection.db[ - tableName as keyof typeof connection.db - ]; - const result: readonly RowType[] = whereClause - ? Array.from(table.iter()).filter(row => evaluate(whereClause, row)) - : Array.from(table.iter()); + const table = connection.db[tableName]; + const result: readonly UseTableRowType[] = whereClause + ? Array.from(table.iter()).filter(row => evaluate(whereClause, row as any)) as unknown as readonly UseTableRowType[] + : Array.from(table.iter()) as unknown as readonly UseTableRowType[]; return { rows: result, state: subscribeApplied ? 'ready' : 'loading', @@ -348,7 +351,7 @@ export function useTable< const subscribe = useCallback( (onStoreChange: () => void) => { - const onInsert = (ctx: any, row: RowType) => { + const onInsert = (ctx: EventContextInterface, row: any) => { if (whereClause && !evaluate(whereClause, row)) { return; } @@ -363,7 +366,7 @@ export function useTable< } }; - const onDelete = (ctx: any, row: RowType) => { + const onDelete = (ctx: EventContextInterface, row: any) => { if (whereClause && !evaluate(whereClause, row)) { return; } @@ -378,7 +381,7 @@ export function useTable< } }; - const onUpdate = (ctx: any, oldRow: RowType, newRow: RowType) => { + const onUpdate = (ctx: EventContextInterface, oldRow: any, newRow: any) => { const change = classifyMembership(whereClause, oldRow, newRow); switch (change) { @@ -434,7 +437,7 @@ export function useTable< ] ); - const getSnapshot = useCallback((): Snapshot => { + const getSnapshot = useCallback((): Snapshot => { if (!lastSnapshotRef.current) { lastSnapshotRef.current = computeSnapshot(); } diff --git a/crates/bindings-typescript/src/sdk/client_table.ts b/crates/bindings-typescript/src/sdk/client_table.ts index ca19165f639..6d0e006e9b2 100644 --- a/crates/bindings-typescript/src/sdk/client_table.ts +++ b/crates/bindings-typescript/src/sdk/client_table.ts @@ -55,13 +55,4 @@ export type ClientTableCore< TableDef extends UntypedTableDef, > = ReadonlyTableMethods & - ClientTableMethods; - -/** - * Client database view, mapping table names to their corresponding ClientTable handles. - */ -export type ClientDbView< - RemoteModule extends UntypedRemoteModule, -> = { - readonly [Tbl in RemoteModule['tables'][number] as Tbl['name']]: ClientTable; -}; \ No newline at end of file + ClientTableMethods; \ No newline at end of file diff --git a/crates/bindings-typescript/src/sdk/db_connection_builder.ts b/crates/bindings-typescript/src/sdk/db_connection_builder.ts index 4eec420dd97..cf33668d4c7 100644 --- a/crates/bindings-typescript/src/sdk/db_connection_builder.ts +++ b/crates/bindings-typescript/src/sdk/db_connection_builder.ts @@ -1,16 +1,17 @@ import { DbConnectionImpl, type ConnectionEvent } from './db_connection_impl'; import { EventEmitter } from './event_emitter'; -import type { DbConnectionConfig, ErrorContextInterface, Identity, SubscriptionEventContextInterface } from '../'; +import type { DbConnectionConfig, ErrorContextInterface, Identity, RemoteModuleOf, SubscriptionEventContextInterface } from '../'; import { type UntypedRemoteModule } from './spacetime_module'; import { ensureMinimumVersionOrThrow } from './version'; import { WebsocketDecompressAdapter } from './websocket_decompress_adapter'; /** * The database client connection to a SpacetimeDB server. + * NOTE: DbConnectionImpl is used here */ export class DbConnectionBuilder< RemoteModule extends UntypedRemoteModule, - DbConnection extends DbConnectionImpl, + DbConnection extends DbConnectionImpl > { #uri?: URL; #nameOrAddress?: string; @@ -31,8 +32,8 @@ export class DbConnectionBuilder< * @param dbConnectionConstructor The constructor to use to create a new `DbConnection`. */ constructor( - private remoteModule: RemoteModule, - private dbConnectionCtor: (config: DbConnectionConfig) => DbConnection + private remoteModule: RemoteModuleOf, + private dbConnectionCtor: (config: DbConnectionConfig>) => DbConnection ) { this.#createWSFn = WebsocketDecompressAdapter.createWebSocketFn; } @@ -178,7 +179,7 @@ export class DbConnectionBuilder< * }); * ``` */ - onConnectError(callback: (ctx: ErrorContextInterface, error: Error) => void): this { + onConnectError(callback: (ctx: ErrorContextInterface>, error: Error) => void): this { this.#emitter.on('connectError', callback); return this; } @@ -210,7 +211,7 @@ export class DbConnectionBuilder< * @throws {Error} Throws an error if called multiple times on the same `DbConnectionBuilder`. */ onDisconnect( - callback: (ctx: ErrorContextInterface, error?: Error | undefined) => void + callback: (ctx: ErrorContextInterface>, error?: Error | undefined) => void ): this { this.#emitter.on('disconnect', callback); return this; @@ -230,7 +231,7 @@ export class DbConnectionBuilder< * DbConnection.builder().withUri(host).withModuleName(name_or_address).withToken(auth_token).build(); * ``` */ - build(): DbConnectionImpl { + build(): DbConnection { if (!this.#uri) { throw new Error('URI is required to connect to SpacetimeDB'); } diff --git a/crates/bindings-typescript/src/sdk/db_connection_impl.ts b/crates/bindings-typescript/src/sdk/db_connection_impl.ts index 14ea6d83606..04b1a7967bd 100644 --- a/crates/bindings-typescript/src/sdk/db_connection_impl.ts +++ b/crates/bindings-typescript/src/sdk/db_connection_impl.ts @@ -57,6 +57,8 @@ import { toCamelCase } from '../lib/utils.ts'; export { DbConnectionBuilder, SubscriptionBuilderImpl, TableCache, type Event }; +export type RemoteModuleOf = C extends DbConnectionImpl ? RM : never; + export type { DbContext, EventContextInterface, diff --git a/crates/bindings-typescript/src/sdk/db_view.ts b/crates/bindings-typescript/src/sdk/db_view.ts index 9d991765226..afcdbd4d4d0 100644 --- a/crates/bindings-typescript/src/sdk/db_view.ts +++ b/crates/bindings-typescript/src/sdk/db_view.ts @@ -5,5 +5,5 @@ import type { ClientTable } from "./client_table"; * A type representing a client-side database view, mapping table names to their corresponding client Table handles. */ export type ClientDbView = { - readonly [Tbl in RemoteModule['tables'][number] as Tbl['accessorName']]: ClientTable; -}; + readonly [Tbl in RemoteModule['tables'][number] as Extract]: ClientTable; +}; \ No newline at end of file diff --git a/crates/bindings-typescript/test-app/src/App.tsx b/crates/bindings-typescript/test-app/src/App.tsx index 894e49b9239..bb2e7b1b7bf 100644 --- a/crates/bindings-typescript/test-app/src/App.tsx +++ b/crates/bindings-typescript/test-app/src/App.tsx @@ -7,7 +7,7 @@ function App() { const x = useReducer; const createPlayer = useReducer('createPlayer'); const connection = useSpacetimeDB(); - const players = useTable('player', { + const players = useTable('player', { onInsert: player => { console.log(player); }, diff --git a/crates/bindings-typescript/test-app/src/module_bindings/create_player_reducer.ts b/crates/bindings-typescript/test-app/src/module_bindings/create_player_reducer.ts index 494f9eb5d1e..fdec0043c97 100644 --- a/crates/bindings-typescript/test-app/src/module_bindings/create_player_reducer.ts +++ b/crates/bindings-typescript/test-app/src/module_bindings/create_player_reducer.ts @@ -8,15 +8,21 @@ import { BinaryReader as __BinaryReader, BinaryWriter as __BinaryWriter, ClientCache as __ClientCache, + ClientTable as __ClientTable, ConnectionId as __ConnectionId, DbConnectionBuilder as __DbConnectionBuilder, + DbConnectionConfig as __DbConnectionConfig, DbConnectionImpl as __DbConnectionImpl, Identity as __Identity, SubscriptionBuilderImpl as __SubscriptionBuilderImpl, - TableCache as __TableCache, TimeDuration as __TimeDuration, Timestamp as __Timestamp, deepEqual as __deepEqual, + reducerSchema as __reducerSchema, + reducers as __reducers, + schema as __schema, + t as __t, + table as __table, type AlgebraicType as __AlgebraicTypeType, type AlgebraicTypeVariants as __AlgebraicTypeVariants, type CallReducerFlags as __CallReducerFlags, @@ -24,54 +30,13 @@ import { type Event as __Event, type EventContextInterface as __EventContextInterface, type ReducerEventContextInterface as __ReducerEventContextInterface, + type RemoteModule as __RemoteModule, type SubscriptionEventContextInterface as __SubscriptionEventContextInterface, - type TableHandle as __TableHandle, } from '../../../src/index'; -import { Point } from './point_type'; -// Mark import as potentially unused -declare type __keep_Point = Point; +import Point from './point_type'; -export type CreatePlayer = { - name: string; - location: Point; +export default { + name: __t.string(), + location: Point, }; -let _cached_CreatePlayer_type_value: __AlgebraicTypeType | null = null; - -/** - * An object for generated helper functions. - */ -export const CreatePlayer = { - /** - * A function which returns this type represented as an AlgebraicType. - * This function is derived from the AlgebraicType used to generate this type. - */ - getTypeScriptAlgebraicType(): __AlgebraicTypeType { - if (_cached_CreatePlayer_type_value) return _cached_CreatePlayer_type_value; - _cached_CreatePlayer_type_value = __AlgebraicTypeValue.Product({ - elements: [], - }); - _cached_CreatePlayer_type_value.value.elements.push( - { name: 'name', algebraicType: __AlgebraicTypeValue.String }, - { name: 'location', algebraicType: Point.getTypeScriptAlgebraicType() } - ); - return _cached_CreatePlayer_type_value; - }, - - serialize(writer: __BinaryWriter, value: CreatePlayer): void { - __AlgebraicTypeValue.serializeValue( - writer, - CreatePlayer.getTypeScriptAlgebraicType(), - value - ); - }, - - deserialize(reader: __BinaryReader): CreatePlayer { - return __AlgebraicTypeValue.deserializeValue( - reader, - CreatePlayer.getTypeScriptAlgebraicType() - ); - }, -}; - -export default CreatePlayer; diff --git a/crates/bindings-typescript/test-app/src/module_bindings/index.ts b/crates/bindings-typescript/test-app/src/module_bindings/index.ts index 95c704eaad9..004d8995f86 100644 --- a/crates/bindings-typescript/test-app/src/module_bindings/index.ts +++ b/crates/bindings-typescript/test-app/src/module_bindings/index.ts @@ -1,7 +1,7 @@ // THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE // WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. -// This was generated using ../../../src/index cli version 1.5.0 (commit 5bfc84351742a6a8dc717b6c0011946f2d1b632d). +// This was generated using ../../../src/index cli version 1.6.0 (commit 051fb278b3d871c87536cb87c8905c21103728fe). /* eslint-disable */ /* tslint:disable */ @@ -10,15 +10,21 @@ import { BinaryReader as __BinaryReader, BinaryWriter as __BinaryWriter, ClientCache as __ClientCache, + ClientTable as __ClientTable, ConnectionId as __ConnectionId, DbConnectionBuilder as __DbConnectionBuilder, + DbConnectionConfig as __DbConnectionConfig, DbConnectionImpl as __DbConnectionImpl, Identity as __Identity, SubscriptionBuilderImpl as __SubscriptionBuilderImpl, - TableCache as __TableCache, TimeDuration as __TimeDuration, Timestamp as __Timestamp, deepEqual as __deepEqual, + reducerSchema as __reducerSchema, + reducers as __reducers, + schema as __schema, + t as __t, + table as __table, type AlgebraicType as __AlgebraicTypeType, type AlgebraicTypeVariants as __AlgebraicTypeVariants, type CallReducerFlags as __CallReducerFlags, @@ -26,84 +32,58 @@ import { type Event as __Event, type EventContextInterface as __EventContextInterface, type ReducerEventContextInterface as __ReducerEventContextInterface, - type SubscriptionEventContextInterface as __SubscriptionEventContextInterface, - type ClientTable as __ClientTable, type RemoteModule as __RemoteModule, - type SetReducerFlags as __SetReducerFlags, - DbConnectionConfig, + type SubscriptionEventContextInterface as __SubscriptionEventContextInterface, } from '../../../src/index'; // Import and reexport all reducer arg types -import { CreatePlayer } from './create_player_reducer.ts'; +import CreatePlayer from './create_player_reducer.ts'; export { CreatePlayer }; // Import and reexport all table handle types -import { PlayerTableHandle } from './player_table.ts'; -export { PlayerTableHandle }; -import { UnindexedPlayerTableHandle } from './unindexed_player_table.ts'; -export { UnindexedPlayerTableHandle }; -import { UserTableHandle } from './user_table.ts'; -export { UserTableHandle }; +import PlayerRow from './player_table.ts'; +export { PlayerRow }; +import UnindexedPlayerRow from './unindexed_player_table.ts'; +export { UnindexedPlayerRow }; +import UserRow from './user_table.ts'; +export { UserRow }; // Import and reexport all types -import { Player } from './player_type.ts'; +import Player from './player_type.ts'; export { Player }; -import { Point } from './point_type.ts'; +import Point from './point_type.ts'; export { Point }; -import { UnindexedPlayer } from './unindexed_player_type.ts'; +import UnindexedPlayer from './unindexed_player_type.ts'; export { UnindexedPlayer }; -import { User } from './user_type.ts'; -import { schema } from '../../../src/lib/schema.ts'; -import t from '../../../src/lib/type_builders.ts'; -import { table } from '../../../src/lib/table.ts'; -import { reducerSchema, reducers } from '../../../src/lib/reducers.ts'; -import { RemoteModule } from '../../../src/sdk/spacetime_module.ts'; +import User from './user_type.ts'; export { User }; -const pointType = t.object('Point', { - x: t.number(), - y: t.number(), -}); - -table({ - name: 'player', - primaryKey: 'ownerId', - - indexes: [ - { name: 'this_is_an_index', algorithm: "btree", columns: [ "ownerId" ] } - ], -}, t.row({ - ownerId: t.string(), - name: t.string(), - location: pointType, -})) - -const tablesSchema = schema( - table({ name: 'player', }, t.row({ - ownerId: t.string(), - name: t.string(), - location: pointType, - })), - table({ name: 'unindexed_player', }, t.row({ - ownerId: t.string(), - name: t.string(), - location: pointType, - })), - table({ name: 'user', primaryKey: 'identity', }, t.row({ - identity: t.string(), - name: t.string(), - })), +const tablesSchema = __schema( + __table( + { + name: 'player', + indexes: [], + }, + PlayerRow + ), + __table( + { + name: 'unindexed_player', + indexes: [], + }, + UnindexedPlayerRow + ), + __table( + { + name: 'user', + indexes: [], + }, + UserRow + ) ); -const reducersSchema = reducers( - reducerSchema('create_player', { - name: t.string(), - location: pointType, - }), - reducerSchema('foo_bar', { - name: t.string(), - location: pointType, - }), +const reducersSchema = __reducers( + __reducerSchema('create_player', CreatePlayer) ); const REMOTE_MODULE = { @@ -112,26 +92,21 @@ const REMOTE_MODULE = { }, tables: tablesSchema.schemaType.tables, reducers: reducersSchema.reducersType.reducers, -} satisfies RemoteModule< +} satisfies __RemoteModule< typeof tablesSchema.schemaType, typeof reducersSchema.reducersType >; -export type EventContext = __EventContextInterface< - typeof REMOTE_MODULE ->; +export type Module = typeof REMOTE_MODULE; +export type EventContext = __EventContextInterface; export type ReducerEventContext = __ReducerEventContextInterface< typeof REMOTE_MODULE >; - export type SubscriptionEventContext = __SubscriptionEventContextInterface< typeof REMOTE_MODULE >; - -export type ErrorContext = __ErrorContextInterface< - typeof REMOTE_MODULE ->; +export type ErrorContext = __ErrorContextInterface; export class SubscriptionBuilder extends __SubscriptionBuilderImpl< typeof REMOTE_MODULE @@ -140,232 +115,17 @@ export class SubscriptionBuilder extends __SubscriptionBuilderImpl< export class DbConnectionBuilder extends __DbConnectionBuilder< typeof REMOTE_MODULE, DbConnection -> {}; +> {} export class DbConnection extends __DbConnectionImpl { static builder = (): DbConnectionBuilder => { - return new DbConnectionBuilder(REMOTE_MODULE, (config: DbConnectionConfig) => new DbConnection(config)); + return new DbConnectionBuilder( + REMOTE_MODULE, + (config: __DbConnectionConfig) => + new DbConnection(config) + ); }; subscriptionBuilder = (): SubscriptionBuilder => { return new SubscriptionBuilder(this); }; } - - -// // --- factory returning a well-typed object --- -// function makeReducersObj( -// r: { reducersType: R }, -// call: (name: string, spacetime: R['reducers'][number]['paramsSpacetimeType'], params: R['reducers'][number]['params']) => void -// ): Readonly> { -// const obj: Record = {}; -// for (const red of Object.values(r.reducersType.reducers)) { -// const key = toCamelCase(red.name as string); -// obj[key] = (params: any) => call(red.name as string, red.paramsSpacetimeType, params); -// } -// return Object.freeze(obj) as Readonly>; -// } - -// const reducersObj: UntypedReducers = {} -// for (const reducer of Object.values(reducersSchema.reducersType.reducers)) { -// reducersObj[toCamelCase(reducer.name)] = function(...args: Args) { -// this.#connection.callReducerWithParams( -// reducersSchema.reducersType.reducers[0].name, -// reducersSchema.reducersType.reducers[0].paramsSpacetimeType, -// args, -// "FullUpdate", -// ); -// }; -// } -// Object.freeze(reducersObj); - -// export class RemoteReducers implements UntypedReducersDef { -// [key: string]: (...args: any[]) => void; - -// #connection: __DbConnectionImpl; -// #setCallReducerFlags: SetReducerFlags; - -// constructor( -// connection: __DbConnectionImpl, -// setCallReducerFlags: SetReducerFlags -// ) { -// this.#connection = connection; -// this.#setCallReducerFlags = setCallReducerFlags; -// } - -// createPlayer(name: string, location: Point) { -// this.#connection.callReducerWithParams( -// r.reducersType.reducers[0].name, -// r.reducersType.reducers[0].paramsSpacetimeType, -// [name, location], -// this.#setCallReducerFlags.createPlayerFlags, -// ); -// } - -// // onCreatePlayer( -// // callback: (ctx: ReducerEventContext, name: string, location: Point) => void -// // ) { -// // this.#connection.onReducer('create_player', callback); -// // } - -// // removeOnCreatePlayer( -// // callback: (ctx: ReducerEventContext, name: string, location: Point) => void -// // ) { -// // this.#connection.offReducer('create_player', callback); -// // } -// } - -// export class SetReducerFlags implements __SetReducerFlags { -// createPlayerFlags: __CallReducerFlags = 'FullUpdate'; -// createPlayer(flags: __CallReducerFlags) { -// this.createPlayerFlags = flags; -// } -// } - -// export class RemoteTables implements ClientDbView { -// constructor(private connection: __DbConnectionImpl) {} - -// get player(): PlayerTableHandle { -// // clientCache is a private property -// return new PlayerTableHandle( -// ( -// this.connection as unknown as { clientCache: __ClientCache } -// ).clientCache.getOrCreateTable<"player">(spacetimedb.tablesDef.tables[0]) -// ); -// } - -// get unindexedPlayer(): UnindexedPlayerTableHandle<'unindexed_player'> { -// // clientCache is a private property -// return new UnindexedPlayerTableHandle( -// ( -// this.connection as unknown as { clientCache: __ClientCache } -// ).clientCache.getOrCreateTable<"unindexed_player">( -// REMOTE_MODULE.tables.unindexed_player -// ) -// ); -// } - -// get user(): UserTableHandle<'user'> { -// // clientCache is a private property -// return new UserTableHandle( -// ( -// this.connection as unknown as { clientCache: __ClientCache } -// ).clientCache.getOrCreateTable<"user">(REMOTE_MODULE.tables.user) -// ); -// } -// } - -// export class SubscriptionBuilder extends __SubscriptionBuilderImpl< -// SchemaDef, -// RemoteReducers -// > {} - -// export class DbConnection extends __DbConnectionImpl< -// SchemaDef, -// RemoteReducers, -// > { -// static builder = (): __DbConnectionBuilder< -// DbConnection, -// ErrorContext, -// SubscriptionEventContext -// > => { -// return new __DbConnectionBuilder< -// DbConnection, -// ErrorContext, -// SubscriptionEventContext -// >(REMOTE_MODULE, (imp: __DbConnectionImpl) => imp as DbConnection); -// }; -// subscriptionBuilder = (): SubscriptionBuilder => { -// return new SubscriptionBuilder(this); -// }; -// } - -// export type EventContext = __EventContextInterface< -// RemoteTables, -// RemoteReducers, -// SetReducerFlags, -// Reducer -// >; -// export type ReducerEventContext = __ReducerEventContextInterface< -// RemoteTables, -// RemoteReducers, -// SetReducerFlags, -// Reducer -// >; -// export type SubscriptionEventContext = __SubscriptionEventContextInterface< -// RemoteTables, -// RemoteReducers, -// SetReducerFlags -// >; -// export type ErrorContext = __ErrorContextInterface< -// RemoteTables, -// RemoteReducers, -// SetReducerFlags -// >; - -// const REMOTE_MODULE = { -// tables: { -// player: { -// name: 'player' as const, -// rowType: Player.getTypeScriptAlgebraicType(), -// primaryKey: 'ownerId', -// primaryKeyInfo: { -// colName: 'ownerId', -// colType: ( -// Player.getTypeScriptAlgebraicType() as __AlgebraicTypeVariants.Product -// ).value.elements[0].algebraicType, -// }, -// }, -// unindexed_player: { -// tableName: 'unindexed_player' as const, -// rowType: UnindexedPlayer.getTypeScriptAlgebraicType(), -// }, -// user: { -// tableName: 'user' as const, -// rowType: User.getTypeScriptAlgebraicType(), -// primaryKey: 'identity', -// primaryKeyInfo: { -// colName: 'identity', -// colType: ( -// User.getTypeScriptAlgebraicType() as __AlgebraicTypeVariants.Product -// ).value.elements[0].algebraicType, -// }, -// }, -// }, -// reducers: { -// create_player: { -// reducerName: 'create_player', -// argsType: CreatePlayer.getTypeScriptAlgebraicType(), -// }, -// }, -// versionInfo: { -// cliVersion: '1.5.0', -// }, -// // Constructors which are used by the DbConnectionImpl to -// // extract type information from the generated RemoteModule. -// // -// // NOTE: This is not strictly necessary for `eventContextConstructor` because -// // all we do is build a TypeScript object which we could have done inside the -// // SDK, but if in the future we wanted to create a class this would be -// // necessary because classes have methods, so we'll keep it. -// eventContextConstructor: ( -// imp: __DbConnectionImpl, -// event: __Event -// ) => { -// return { -// ...(imp as DbConnection), -// event, -// }; -// }, -// dbViewConstructor: (imp: __DbConnectionImpl) => { -// return new RemoteTables(imp); -// }, -// reducersConstructor: ( -// imp: __DbConnectionImpl, -// setReducerFlags: SetReducerFlags -// ) => { -// return new RemoteReducers(imp, setReducerFlags); -// }, -// setReducerFlagsConstructor: () => { -// return new SetReducerFlags(); -// }, -// } satisfies __RemoteModule; \ No newline at end of file diff --git a/crates/bindings-typescript/test-app/src/module_bindings/player_table.ts b/crates/bindings-typescript/test-app/src/module_bindings/player_table.ts index a966cde4283..239885c6eb7 100644 --- a/crates/bindings-typescript/test-app/src/module_bindings/player_table.ts +++ b/crates/bindings-typescript/test-app/src/module_bindings/player_table.ts @@ -8,15 +8,21 @@ import { BinaryReader as __BinaryReader, BinaryWriter as __BinaryWriter, ClientCache as __ClientCache, + ClientTable as __ClientTable, ConnectionId as __ConnectionId, DbConnectionBuilder as __DbConnectionBuilder, + DbConnectionConfig as __DbConnectionConfig, DbConnectionImpl as __DbConnectionImpl, Identity as __Identity, SubscriptionBuilderImpl as __SubscriptionBuilderImpl, - TableCache as __TableCache, TimeDuration as __TimeDuration, Timestamp as __Timestamp, deepEqual as __deepEqual, + reducerSchema as __reducerSchema, + reducers as __reducers, + schema as __schema, + t as __t, + table as __table, type AlgebraicType as __AlgebraicTypeType, type AlgebraicTypeVariants as __AlgebraicTypeVariants, type CallReducerFlags as __CallReducerFlags, @@ -24,110 +30,13 @@ import { type Event as __Event, type EventContextInterface as __EventContextInterface, type ReducerEventContextInterface as __ReducerEventContextInterface, + type RemoteModule as __RemoteModule, type SubscriptionEventContextInterface as __SubscriptionEventContextInterface, - type ClientTable as __ClientTable, - table, - t, } from '../../../src/index'; -import { Player } from './player_type'; -import { Point } from './point_type'; -// Mark import as potentially unused -declare type __keep_Point = Point; +import Point from './point_type'; -import { - type EventContext, - type Reducer, - RemoteReducers, - RemoteTables, -} from '.'; -declare type __keep = [EventContext, Reducer, RemoteReducers, RemoteTables]; - - -export default table({ name: 'player' }, { - id: t.string().primaryKey().index(), - ownerId: t.string().unique(), - timestamp: t.timestamp(), - score: t.i32(), +export default __t.row({ + ownerId: __t.string(), + name: __t.string(), location: Point, }); - -/** - * Table handle for the table `player`. - * - * Obtain a handle from the [`player`] property on [`RemoteTables`], - * like `ctx.db.player`. - * - * Users are encouraged not to explicitly reference this type, - * but to directly chain method calls, - * like `ctx.db.player.on_insert(...)`. - */ -export class PlayerTableHandle - implements __ClientTable -{ - // phantom type to track the table name - readonly tableName!: TableName; - tableCache: __TableCache; - - constructor(tableCache: __TableCache) { - this.tableCache = tableCache; - } - - count(): number { - return this.tableCache.count(); - } - - iter(): Iterable { - return this.tableCache.iter(); - } - /** - * Access to the `ownerId` unique index on the table `player`, - * which allows point queries on the field of the same name - * via the [`PlayerOwnerIdUnique.find`] method. - * - * Users are encouraged not to explicitly reference this type, - * but to directly chain method calls, - * like `ctx.db.player.ownerId().find(...)`. - * - * Get a handle on the `ownerId` unique index on the table `player`. - */ - ownerId = { - // Find the subscribed row whose `ownerId` column value is equal to `colVal`, - // if such a row is present in the client cache. - find: (colVal: string): Player | undefined => { - for (let row of this.tableCache.iter()) { - if (__deepEqual(row.ownerId, colVal)) { - return row; - } - } - }, - }; - - onInsert = (cb: (ctx: EventContext, row: Player) => void) => { - return this.tableCache.onInsert(cb); - }; - - removeOnInsert = (cb: (ctx: EventContext, row: Player) => void) => { - return this.tableCache.removeOnInsert(cb); - }; - - onDelete = (cb: (ctx: EventContext, row: Player) => void) => { - return this.tableCache.onDelete(cb); - }; - - removeOnDelete = (cb: (ctx: EventContext, row: Player) => void) => { - return this.tableCache.removeOnDelete(cb); - }; - - // Updates are only defined for tables with primary keys. - onUpdate = ( - cb: (ctx: EventContext, oldRow: Player, newRow: Player) => void - ) => { - return this.tableCache.onUpdate(cb); - }; - - removeOnUpdate = ( - cb: (ctx: EventContext, onRow: Player, newRow: Player) => void - ) => { - return this.tableCache.removeOnUpdate(cb); - }; -} diff --git a/crates/bindings-typescript/test-app/src/module_bindings/player_type.ts b/crates/bindings-typescript/test-app/src/module_bindings/player_type.ts index d6f04870fa6..5249c4a6be3 100644 --- a/crates/bindings-typescript/test-app/src/module_bindings/player_type.ts +++ b/crates/bindings-typescript/test-app/src/module_bindings/player_type.ts @@ -8,15 +8,21 @@ import { BinaryReader as __BinaryReader, BinaryWriter as __BinaryWriter, ClientCache as __ClientCache, + ClientTable as __ClientTable, ConnectionId as __ConnectionId, DbConnectionBuilder as __DbConnectionBuilder, + DbConnectionConfig as __DbConnectionConfig, DbConnectionImpl as __DbConnectionImpl, Identity as __Identity, SubscriptionBuilderImpl as __SubscriptionBuilderImpl, - TableCache as __TableCache, TimeDuration as __TimeDuration, Timestamp as __Timestamp, deepEqual as __deepEqual, + reducerSchema as __reducerSchema, + reducers as __reducers, + schema as __schema, + t as __t, + table as __table, type AlgebraicType as __AlgebraicTypeType, type AlgebraicTypeVariants as __AlgebraicTypeVariants, type CallReducerFlags as __CallReducerFlags, @@ -24,66 +30,13 @@ import { type Event as __Event, type EventContextInterface as __EventContextInterface, type ReducerEventContextInterface as __ReducerEventContextInterface, + type RemoteModule as __RemoteModule, type SubscriptionEventContextInterface as __SubscriptionEventContextInterface, - type TableHandle as __TableHandle, } from '../../../src/index'; -import { t } from '../../../src/server'; -import { Point } from './point_type'; -// Mark import as potentially unused -declare type __keep_Point = Point; +import Point from './point_type'; -t.object('Player', { - ownerId: t.string(), - name: t.string(), - location: Point.getTypeScriptAlgebraicType(), +export default __t.object('Player', { + ownerId: __t.string(), + name: __t.string(), + location: Point, }); - -const x = t.enum('PlayerEnum', { - foobar: t.f32(), - bazqux: t.string(), - quxfoo: t.bool(), -}); - -export type Player = { - ownerId: string; - name: string; - location: Point; -}; -let _cached_Player_type_value: __AlgebraicTypeType | null = null; - -/** - * An object for generated helper functions. - */ -export const Player = { - /** - * A function which returns this type represented as an AlgebraicType. - * This function is derived from the AlgebraicType used to generate this type. - */ - getTypeScriptAlgebraicType(): __AlgebraicTypeType { - if (_cached_Player_type_value) return _cached_Player_type_value; - _cached_Player_type_value = __AlgebraicTypeValue.Product({ elements: [] }); - _cached_Player_type_value.value.elements.push( - { name: 'ownerId', algebraicType: __AlgebraicTypeValue.String }, - { name: 'name', algebraicType: __AlgebraicTypeValue.String }, - { name: 'location', algebraicType: Point.getTypeScriptAlgebraicType() } - ); - return _cached_Player_type_value; - }, - - serialize(writer: __BinaryWriter, value: Player): void { - __AlgebraicTypeValue.serializeValue( - writer, - Player.getTypeScriptAlgebraicType(), - value - ); - }, - - deserialize(reader: __BinaryReader): Player { - return __AlgebraicTypeValue.deserializeValue( - reader, - Player.getTypeScriptAlgebraicType() - ); - }, -}; - -export default Player; diff --git a/crates/bindings-typescript/test-app/src/module_bindings/point_type.ts b/crates/bindings-typescript/test-app/src/module_bindings/point_type.ts index 939de299c8b..3c0f0fd79d3 100644 --- a/crates/bindings-typescript/test-app/src/module_bindings/point_type.ts +++ b/crates/bindings-typescript/test-app/src/module_bindings/point_type.ts @@ -8,15 +8,21 @@ import { BinaryReader as __BinaryReader, BinaryWriter as __BinaryWriter, ClientCache as __ClientCache, + ClientTable as __ClientTable, ConnectionId as __ConnectionId, DbConnectionBuilder as __DbConnectionBuilder, + DbConnectionConfig as __DbConnectionConfig, DbConnectionImpl as __DbConnectionImpl, Identity as __Identity, SubscriptionBuilderImpl as __SubscriptionBuilderImpl, - TableCache as __TableCache, TimeDuration as __TimeDuration, Timestamp as __Timestamp, deepEqual as __deepEqual, + reducerSchema as __reducerSchema, + reducers as __reducers, + schema as __schema, + t as __t, + table as __table, type AlgebraicType as __AlgebraicTypeType, type AlgebraicTypeVariants as __AlgebraicTypeVariants, type CallReducerFlags as __CallReducerFlags, @@ -24,11 +30,11 @@ import { type Event as __Event, type EventContextInterface as __EventContextInterface, type ReducerEventContextInterface as __ReducerEventContextInterface, + type RemoteModule as __RemoteModule, type SubscriptionEventContextInterface as __SubscriptionEventContextInterface, - t as __t, } from '../../../src/index'; export default __t.object('Point', { - x: __t.number(), - y: __t.number(), -}); \ No newline at end of file + x: __t.u16(), + y: __t.u16(), +}); diff --git a/crates/bindings-typescript/test-app/src/module_bindings/unindexed_player_table.ts b/crates/bindings-typescript/test-app/src/module_bindings/unindexed_player_table.ts index eaff291a344..239885c6eb7 100644 --- a/crates/bindings-typescript/test-app/src/module_bindings/unindexed_player_table.ts +++ b/crates/bindings-typescript/test-app/src/module_bindings/unindexed_player_table.ts @@ -8,15 +8,21 @@ import { BinaryReader as __BinaryReader, BinaryWriter as __BinaryWriter, ClientCache as __ClientCache, + ClientTable as __ClientTable, ConnectionId as __ConnectionId, DbConnectionBuilder as __DbConnectionBuilder, + DbConnectionConfig as __DbConnectionConfig, DbConnectionImpl as __DbConnectionImpl, Identity as __Identity, SubscriptionBuilderImpl as __SubscriptionBuilderImpl, - TableCache as __TableCache, TimeDuration as __TimeDuration, Timestamp as __Timestamp, deepEqual as __deepEqual, + reducerSchema as __reducerSchema, + reducers as __reducers, + schema as __schema, + t as __t, + table as __table, type AlgebraicType as __AlgebraicTypeType, type AlgebraicTypeVariants as __AlgebraicTypeVariants, type CallReducerFlags as __CallReducerFlags, @@ -24,64 +30,13 @@ import { type Event as __Event, type EventContextInterface as __EventContextInterface, type ReducerEventContextInterface as __ReducerEventContextInterface, + type RemoteModule as __RemoteModule, type SubscriptionEventContextInterface as __SubscriptionEventContextInterface, - type TableHandle as __TableHandle, } from '../../../src/index'; -import { UnindexedPlayer } from './unindexed_player_type'; -import { Point } from './point_type'; -// Mark import as potentially unused -declare type __keep_Point = Point; +import Point from './point_type'; -import { - type EventContext, - type Reducer, - RemoteReducers, - RemoteTables, -} from '.'; -declare type __keep = [EventContext, Reducer, RemoteReducers, RemoteTables]; - -/** - * Table handle for the table `unindexed_player`. - * - * Obtain a handle from the [`unindexedPlayer`] property on [`RemoteTables`], - * like `ctx.db.unindexedPlayer`. - * - * Users are encouraged not to explicitly reference this type, - * but to directly chain method calls, - * like `ctx.db.unindexedPlayer.on_insert(...)`. - */ -export class UnindexedPlayerTableHandle - implements __TableHandle -{ - // phantom type to track the table name - readonly tableName!: TableName; - tableCache: __TableCache; - - constructor(tableCache: __TableCache) { - this.tableCache = tableCache; - } - - count(): number { - return this.tableCache.count(); - } - - iter(): Iterable { - return this.tableCache.iter(); - } - - onInsert = (cb: (ctx: EventContext, row: UnindexedPlayer) => void) => { - return this.tableCache.onInsert(cb); - }; - - removeOnInsert = (cb: (ctx: EventContext, row: UnindexedPlayer) => void) => { - return this.tableCache.removeOnInsert(cb); - }; - - onDelete = (cb: (ctx: EventContext, row: UnindexedPlayer) => void) => { - return this.tableCache.onDelete(cb); - }; - - removeOnDelete = (cb: (ctx: EventContext, row: UnindexedPlayer) => void) => { - return this.tableCache.removeOnDelete(cb); - }; -} +export default __t.row({ + ownerId: __t.string(), + name: __t.string(), + location: Point, +}); diff --git a/crates/bindings-typescript/test-app/src/module_bindings/unindexed_player_type.ts b/crates/bindings-typescript/test-app/src/module_bindings/unindexed_player_type.ts index 8f2545fa8be..c27daf013e7 100644 --- a/crates/bindings-typescript/test-app/src/module_bindings/unindexed_player_type.ts +++ b/crates/bindings-typescript/test-app/src/module_bindings/unindexed_player_type.ts @@ -8,15 +8,21 @@ import { BinaryReader as __BinaryReader, BinaryWriter as __BinaryWriter, ClientCache as __ClientCache, + ClientTable as __ClientTable, ConnectionId as __ConnectionId, DbConnectionBuilder as __DbConnectionBuilder, + DbConnectionConfig as __DbConnectionConfig, DbConnectionImpl as __DbConnectionImpl, Identity as __Identity, SubscriptionBuilderImpl as __SubscriptionBuilderImpl, - TableCache as __TableCache, TimeDuration as __TimeDuration, Timestamp as __Timestamp, deepEqual as __deepEqual, + reducerSchema as __reducerSchema, + reducers as __reducers, + schema as __schema, + t as __t, + table as __table, type AlgebraicType as __AlgebraicTypeType, type AlgebraicTypeVariants as __AlgebraicTypeVariants, type CallReducerFlags as __CallReducerFlags, @@ -24,56 +30,13 @@ import { type Event as __Event, type EventContextInterface as __EventContextInterface, type ReducerEventContextInterface as __ReducerEventContextInterface, + type RemoteModule as __RemoteModule, type SubscriptionEventContextInterface as __SubscriptionEventContextInterface, - type TableHandle as __TableHandle, } from '../../../src/index'; -import { Point } from './point_type'; -// Mark import as potentially unused -declare type __keep_Point = Point; +import Point from './point_type'; -export type UnindexedPlayer = { - ownerId: string; - name: string; - location: Point; -}; -let _cached_UnindexedPlayer_type_value: __AlgebraicTypeType | null = null; - -/** - * An object for generated helper functions. - */ -export const UnindexedPlayer = { - /** - * A function which returns this type represented as an AlgebraicType. - * This function is derived from the AlgebraicType used to generate this type. - */ - getTypeScriptAlgebraicType(): __AlgebraicTypeType { - if (_cached_UnindexedPlayer_type_value) - return _cached_UnindexedPlayer_type_value; - _cached_UnindexedPlayer_type_value = __AlgebraicTypeValue.Product({ - elements: [], - }); - _cached_UnindexedPlayer_type_value.value.elements.push( - { name: 'ownerId', algebraicType: __AlgebraicTypeValue.String }, - { name: 'name', algebraicType: __AlgebraicTypeValue.String }, - { name: 'location', algebraicType: Point.getTypeScriptAlgebraicType() } - ); - return _cached_UnindexedPlayer_type_value; - }, - - serialize(writer: __BinaryWriter, value: UnindexedPlayer): void { - __AlgebraicTypeValue.serializeValue( - writer, - UnindexedPlayer.getTypeScriptAlgebraicType(), - value - ); - }, - - deserialize(reader: __BinaryReader): UnindexedPlayer { - return __AlgebraicTypeValue.deserializeValue( - reader, - UnindexedPlayer.getTypeScriptAlgebraicType() - ); - }, -}; - -export default UnindexedPlayer; +export default __t.object('UnindexedPlayer', { + ownerId: __t.string(), + name: __t.string(), + location: Point, +}); diff --git a/crates/bindings-typescript/test-app/src/module_bindings/user_table.ts b/crates/bindings-typescript/test-app/src/module_bindings/user_table.ts index e8364a92e8f..29fa7652d66 100644 --- a/crates/bindings-typescript/test-app/src/module_bindings/user_table.ts +++ b/crates/bindings-typescript/test-app/src/module_bindings/user_table.ts @@ -8,15 +8,21 @@ import { BinaryReader as __BinaryReader, BinaryWriter as __BinaryWriter, ClientCache as __ClientCache, + ClientTable as __ClientTable, ConnectionId as __ConnectionId, DbConnectionBuilder as __DbConnectionBuilder, + DbConnectionConfig as __DbConnectionConfig, DbConnectionImpl as __DbConnectionImpl, Identity as __Identity, SubscriptionBuilderImpl as __SubscriptionBuilderImpl, - TableCache as __TableCache, TimeDuration as __TimeDuration, Timestamp as __Timestamp, deepEqual as __deepEqual, + reducerSchema as __reducerSchema, + reducers as __reducers, + schema as __schema, + t as __t, + table as __table, type AlgebraicType as __AlgebraicTypeType, type AlgebraicTypeVariants as __AlgebraicTypeVariants, type CallReducerFlags as __CallReducerFlags, @@ -24,93 +30,11 @@ import { type Event as __Event, type EventContextInterface as __EventContextInterface, type ReducerEventContextInterface as __ReducerEventContextInterface, + type RemoteModule as __RemoteModule, type SubscriptionEventContextInterface as __SubscriptionEventContextInterface, - type TableHandle as __TableHandle, } from '../../../src/index'; -import { User } from './user_type'; -import { - type EventContext, - type Reducer, - RemoteReducers, - RemoteTables, -} from '.'; -declare type __keep = [EventContext, Reducer, RemoteReducers, RemoteTables]; - -/** - * Table handle for the table `user`. - * - * Obtain a handle from the [`user`] property on [`RemoteTables`], - * like `ctx.db.user`. - * - * Users are encouraged not to explicitly reference this type, - * but to directly chain method calls, - * like `ctx.db.user.on_insert(...)`. - */ -export class UserTableHandle - implements __TableHandle -{ - // phantom type to track the table name - readonly tableName!: TableName; - tableCache: __TableCache; - - constructor(tableCache: __TableCache) { - this.tableCache = tableCache; - } - - count(): number { - return this.tableCache.count(); - } - - iter(): Iterable { - return this.tableCache.iter(); - } - /** - * Access to the `identity` unique index on the table `user`, - * which allows point queries on the field of the same name - * via the [`UserIdentityUnique.find`] method. - * - * Users are encouraged not to explicitly reference this type, - * but to directly chain method calls, - * like `ctx.db.user.identity().find(...)`. - * - * Get a handle on the `identity` unique index on the table `user`. - */ - identity = { - // Find the subscribed row whose `identity` column value is equal to `colVal`, - // if such a row is present in the client cache. - find: (colVal: __Identity): User | undefined => { - for (let row of this.tableCache.iter()) { - if (__deepEqual(row.identity, colVal)) { - return row; - } - } - }, - }; - - onInsert = (cb: (ctx: EventContext, row: User) => void) => { - return this.tableCache.onInsert(cb); - }; - - removeOnInsert = (cb: (ctx: EventContext, row: User) => void) => { - return this.tableCache.removeOnInsert(cb); - }; - - onDelete = (cb: (ctx: EventContext, row: User) => void) => { - return this.tableCache.onDelete(cb); - }; - - removeOnDelete = (cb: (ctx: EventContext, row: User) => void) => { - return this.tableCache.removeOnDelete(cb); - }; - - // Updates are only defined for tables with primary keys. - onUpdate = (cb: (ctx: EventContext, oldRow: User, newRow: User) => void) => { - return this.tableCache.onUpdate(cb); - }; - removeOnUpdate = ( - cb: (ctx: EventContext, onRow: User, newRow: User) => void - ) => { - return this.tableCache.removeOnUpdate(cb); - }; -} +export default __t.row({ + identity: __t.identity(), + username: __t.string(), +}); diff --git a/crates/bindings-typescript/test-app/src/module_bindings/user_type.ts b/crates/bindings-typescript/test-app/src/module_bindings/user_type.ts index 6fa4066b314..3a4ccf1be08 100644 --- a/crates/bindings-typescript/test-app/src/module_bindings/user_type.ts +++ b/crates/bindings-typescript/test-app/src/module_bindings/user_type.ts @@ -8,15 +8,21 @@ import { BinaryReader as __BinaryReader, BinaryWriter as __BinaryWriter, ClientCache as __ClientCache, + ClientTable as __ClientTable, ConnectionId as __ConnectionId, DbConnectionBuilder as __DbConnectionBuilder, + DbConnectionConfig as __DbConnectionConfig, DbConnectionImpl as __DbConnectionImpl, Identity as __Identity, SubscriptionBuilderImpl as __SubscriptionBuilderImpl, - TableCache as __TableCache, TimeDuration as __TimeDuration, Timestamp as __Timestamp, deepEqual as __deepEqual, + reducerSchema as __reducerSchema, + reducers as __reducers, + schema as __schema, + t as __t, + table as __table, type AlgebraicType as __AlgebraicTypeType, type AlgebraicTypeVariants as __AlgebraicTypeVariants, type CallReducerFlags as __CallReducerFlags, @@ -24,51 +30,11 @@ import { type Event as __Event, type EventContextInterface as __EventContextInterface, type ReducerEventContextInterface as __ReducerEventContextInterface, + type RemoteModule as __RemoteModule, type SubscriptionEventContextInterface as __SubscriptionEventContextInterface, - type TableHandle as __TableHandle, } from '../../../src/index'; -export type User = { - identity: __Identity; - username: string; -}; -let _cached_User_type_value: __AlgebraicTypeType | null = null; - -/** - * An object for generated helper functions. - */ -export const User = { - /** - * A function which returns this type represented as an AlgebraicType. - * This function is derived from the AlgebraicType used to generate this type. - */ - getTypeScriptAlgebraicType(): __AlgebraicTypeType { - if (_cached_User_type_value) return _cached_User_type_value; - _cached_User_type_value = __AlgebraicTypeValue.Product({ elements: [] }); - _cached_User_type_value.value.elements.push( - { - name: 'identity', - algebraicType: __AlgebraicTypeValue.createIdentityType(), - }, - { name: 'username', algebraicType: __AlgebraicTypeValue.String } - ); - return _cached_User_type_value; - }, - - serialize(writer: __BinaryWriter, value: User): void { - __AlgebraicTypeValue.serializeValue( - writer, - User.getTypeScriptAlgebraicType(), - value - ); - }, - - deserialize(reader: __BinaryReader): User { - return __AlgebraicTypeValue.deserializeValue( - reader, - User.getTypeScriptAlgebraicType() - ); - }, -}; - -export default User; +export default __t.object('User', { + identity: __t.identity(), + username: __t.string(), +}); diff --git a/crates/codegen/src/typescript.rs b/crates/codegen/src/typescript.rs index dd3f0c8b871..4a398e7234e 100644 --- a/crates/codegen/src/typescript.rs +++ b/crates/codegen/src/typescript.rs @@ -1,5 +1,5 @@ use crate::util::{ - is_reducer_invokable, iter_indexes, iter_reducers, iter_tables, iter_types, iter_unique_cols, print_auto_generated_version_comment + is_reducer_invokable, iter_indexes, iter_reducers, iter_tables, iter_types, print_auto_generated_version_comment }; use crate::{OutputFile}; @@ -15,7 +15,6 @@ use spacetimedb_lib::sats::AlgebraicTypeRef; use spacetimedb_primitives::ColId; use spacetimedb_schema::def::{BTreeAlgorithm, IndexAlgorithm, ModuleDef, ReducerDef, ScopedTypeName, TableDef, TypeDef}; use spacetimedb_schema::identifier::Identifier; -use spacetimedb_schema::schema::{Schema, TableSchema}; use spacetimedb_schema::type_for_generate::{AlgebraicTypeDef, AlgebraicTypeUse, ProductTypeDef}; use super::code_indenter::{CodeIndenter, Indenter}; @@ -124,21 +123,12 @@ impl Lang for TypeScript { /// })) /// ``` fn generate_table_file(&self, module: &ModuleDef, table: &TableDef) -> OutputFile { - let schema = TableSchema::from_module_def(module, table, (), 0.into()) - .validated() - .expect("Failed to generate table due to validation errors"); - let mut output = CodeIndenter::new(String::new(), INDENT); let out = &mut output; print_file_header(out, false); let type_ref = table.product_type_ref; - let row_type = type_ref_name(module, type_ref); - let row_type_module = type_ref_module_name(module, type_ref); - - writeln!(out, "import {{ {row_type} }} from \"./{row_type_module}\";"); - let product_def = module.typespace_for_generate()[type_ref].as_product().unwrap(); // Import the types of all fields. @@ -154,65 +144,11 @@ impl Lang for TypeScript { writeln!(out); - writeln!(out, "export default table({{"); - out.indent(1); - writeln!( - out, - "name: '{}',", - table.name.deref() - ); - writeln!(out, "indexes: ["); + writeln!(out, "export default __t.row({{"); out.indent(1); - for index_def in iter_indexes(table) { - if !index_def.generated() { - // Skip system-defined indexes - continue; - } - match &index_def.algorithm { - IndexAlgorithm::BTree(BTreeAlgorithm { columns }) => { - let get_name_and_type = |col_pos: ColId| { - let (field_name, field_type) = &product_def.elements[col_pos.idx()]; - let name_camel = field_name.deref().to_case(Case::Camel); - (name_camel, field_type) - }; - writeln!(out, "{{ name: '{}', algorithm: 'btree', columns: [", index_def.name); - out.indent(1); - for col_id in columns.iter() { - writeln!(out, "'{}',", get_name_and_type(col_id).0); - } - out.dedent(1); - writeln!(out, "] }},"); - } - IndexAlgorithm::Direct(_) => { - // Direct indexes are not implemented yet. - continue; - } - _ => todo!(), - }; - } + write_object_type_builder_fields(module, out, &product_def.elements, true).unwrap(); out.dedent(1); - writeln!(out, "}}, {{"); - out.indent(1); - for (field_ident, field_ty) in &product_def.elements { - let field_name = field_ident.deref().to_case(Case::Camel); - write!(out, "{field_name}: "); - write_type(module, out, field_ty, None, None).unwrap(); - - let mut annotations = Vec::new(); - if schema.pk().map(|pk| *field_ident == Identifier::new(pk.col_name.clone()).unwrap()).unwrap_or(false) { - annotations.push("primaryKey()"); - } else { - for (unique_field_ident, _) in - iter_unique_cols(module.typespace_for_generate(), &schema, product_def) - { - if field_ident == unique_field_ident { - annotations.push("unique()"); - } - } - } - } writeln!(out, "}});"); - out.dedent(1); OutputFile { filename: table_module_name(&table.name) + ".ts", code: output.into_inner(), @@ -236,9 +172,7 @@ impl Lang for TypeScript { None, ); - let args_type = reducer_args_type_name(&reducer.name); - - define_body_for_product(module, out, &args_type, &reducer.params_for_generate.elements); + define_body_for_reducer(module, out, &reducer.params_for_generate.elements); OutputFile { filename: reducer_module_name(&reducer.name) + ".ts", @@ -254,78 +188,6 @@ impl Lang for TypeScript { out.newline(); - // const tablesSchema = schema( -// table({ name: 'player', }, t.row({ -// ownerId: t.string(), -// name: t.string(), -// location: pointType, -// })), -// table({ name: 'unindexed_player', }, t.row({ -// ownerId: t.string(), -// name: t.string(), -// location: pointType, -// })), -// table({ name: 'user', primaryKey: 'identity', }, t.row({ -// identity: t.string(), -// name: t.string(), -// })), -// ); - -// const reducersSchema = reducers( -// reducerSchema('create_player', { -// name: t.string(), -// location: pointType, -// }), -// reducerSchema('foo_bar', { -// name: t.string(), -// location: pointType, -// }), -// ); - -// const REMOTE_MODULE = { -// versionInfo: { -// cliVersion: '1.6.0' as const, -// }, -// tables: tablesSchema.schemaType.tables, -// reducers: reducersSchema.reducersType.reducers, -// } satisfies RemoteModule< -// typeof tablesSchema.schemaType, -// typeof reducersSchema.reducersType -// >; - -// export type EventContext = __EventContextInterface< -// typeof REMOTE_MODULE -// >; - -// export type ReducerEventContext = __ReducerEventContextInterface< -// typeof REMOTE_MODULE -// >; - -// export type SubscriptionEventContext = __SubscriptionEventContextInterface< -// typeof REMOTE_MODULE -// >; - -// export type ErrorContext = __ErrorContextInterface< -// typeof REMOTE_MODULE -// >; - -// export class SubscriptionBuilder extends __SubscriptionBuilderImpl< -// typeof REMOTE_MODULE -// > {} - -// export class DbConnectionBuilder extends __DbConnectionBuilder< -// typeof REMOTE_MODULE, -// DbConnection -// > {}; - -// export class DbConnection extends __DbConnectionImpl { -// static builder = (): DbConnectionBuilder => { -// return new DbConnectionBuilder(REMOTE_MODULE, (config: DbConnectionConfig) => new DbConnection(config)); -// }; -// subscriptionBuilder = (): SubscriptionBuilder => { -// return new SubscriptionBuilder(this); -// }; - writeln!(out, "// Import and reexport all reducer arg types"); for reducer in iter_reducers(module) { let reducer_name = &reducer.name; @@ -341,8 +203,10 @@ impl Lang for TypeScript { let table_name = &table.name; let table_module_name = table_module_name(table_name) + ".ts"; let table_name_pascalcase = table.name.deref().to_case(Case::Pascal); - writeln!(out, "import {table_name_pascalcase} from \"./{table_module_name}\";"); - writeln!(out, "export {{ {table_name_pascalcase} }};"); + // TODO: This really shouldn't be necessary. We could also have `table()` accept + // `__t.object(...)`s. + writeln!(out, "import {table_name_pascalcase}Row from \"./{table_module_name}\";"); + writeln!(out, "export {{ {table_name_pascalcase}Row }};"); } writeln!(out); @@ -357,18 +221,23 @@ impl Lang for TypeScript { out.newline(); writeln!(out); - writeln!(out, "const tablesSchema = schema("); + writeln!(out, "const tablesSchema = __schema("); out.indent(1); for table in iter_tables(module) { - let table_name_pascalcase = table.name.deref().to_case(Case::Pascal); - writeln!(out, "{},", table_name_pascalcase); + let type_ref = table.product_type_ref; + let row_type_name = type_ref_name(module, type_ref); + writeln!(out, "__table({{"); + out.indent(1); + write_table_opts(module, out, table); + out.dedent(1); + writeln!(out, "}}, {}Row),", row_type_name); } out.dedent(1); writeln!(out, ");"); writeln!(out); - writeln!(out, "const reducersSchema = reducers("); + writeln!(out, "const reducersSchema = __reducers("); out.indent(1); for reducer in iter_reducers(module) { if !is_reducer_invokable(reducer) { @@ -377,7 +246,7 @@ impl Lang for TypeScript { } let reducer_name = &reducer.name; let args_type = reducer_args_type_name(&reducer.name); - writeln!(out, "reducerSchema(\"{}\", {}),", reducer_name, args_type); + writeln!(out, "__reducerSchema(\"{}\", {}),", reducer_name, args_type); } out.dedent(1); writeln!(out, ");"); @@ -451,7 +320,7 @@ impl Lang for TypeScript { out.indent(1); writeln!( out, - "return new DbConnectionBuilder(REMOTE_MODULE, (config: DbConnectionConfig) => new DbConnection(config));" + "return new DbConnectionBuilder(REMOTE_MODULE, (config: __DbConnectionConfig) => new DbConnection(config));" ); out.dedent(1); writeln!(out, "}};"); @@ -492,9 +361,9 @@ fn print_spacetimedb_imports(out: &mut Indenter) { "type CallReducerFlags as __CallReducerFlags", "type EventContextInterface as __EventContextInterface", "type ReducerEventContextInterface as __ReducerEventContextInterface", - "type RemoteModule as __RemoteModule", "type SubscriptionEventContextInterface as __SubscriptionEventContextInterface", "type ErrorContextInterface as __ErrorContextInterface", + "type RemoteModule as __RemoteModule", "SubscriptionBuilderImpl as __SubscriptionBuilderImpl", "BinaryReader as __BinaryReader", "DbConnectionImpl as __DbConnectionImpl", @@ -505,7 +374,6 @@ fn print_spacetimedb_imports(out: &mut Indenter) { "reducers as __reducers", "reducerSchema as __reducerSchema", "DbConnectionConfig as __DbConnectionConfig", - "RemoteModule as __RemoteModule", "t as __t", ]; types.sort(); @@ -532,6 +400,29 @@ fn print_lint_suppression(output: &mut Indenter) { writeln!(output, "/* tslint:disable */"); } +/// e.g. +/// ```ts +/// export default { +/// x: __t.f32(), +/// y: __t.f32(), +/// fooBar: __t.string(), +/// }; +/// ``` +fn define_body_for_reducer( + module: &ModuleDef, + out: &mut Indenter, + params: &[(Identifier, AlgebraicTypeUse)], +) { + write!(out, "export default {{"); + if params.is_empty() { + writeln!(out, "}};"); + } else { + writeln!(out); + out.with_indent(|out| write_object_type_builder_fields(module, out, params, true).unwrap()); + writeln!(out, "}};"); + } +} + /// e.g. /// ```ts /// export default __t.object('Point', { @@ -549,15 +440,56 @@ fn define_body_for_product( write!(out, "export default __t.object(\"{name}\", {{"); if elements.is_empty() { - writeln!(out, "}};"); + writeln!(out, "}});"); } else { writeln!(out); out.with_indent(|out| write_object_type_builder_fields(module, out, elements, true).unwrap()); - writeln!(out, "}};"); + writeln!(out, "}});"); } out.newline(); } +fn write_table_opts(module: &ModuleDef, out: &mut Indenter, table: &TableDef) { + let type_ref = table.product_type_ref; + let product_def = module.typespace_for_generate()[type_ref].as_product().unwrap(); + writeln!( + out, + "name: '{}',", + table.name.deref() + ); + writeln!(out, "indexes: ["); + out.indent(1); + for index_def in iter_indexes(table) { + if !index_def.generated() { + // Skip system-defined indexes + continue; + } + match &index_def.algorithm { + IndexAlgorithm::BTree(BTreeAlgorithm { columns }) => { + let get_name_and_type = |col_pos: ColId| { + let (field_name, field_type) = &product_def.elements[col_pos.idx()]; + let name_camel = field_name.deref().to_case(Case::Camel); + (name_camel, field_type) + }; + writeln!(out, "{{ name: '{}', algorithm: 'btree', columns: [", index_def.name); + out.indent(1); + for col_id in columns.iter() { + writeln!(out, "'{}',", get_name_and_type(col_id).0); + } + out.dedent(1); + writeln!(out, "] }},"); + } + IndexAlgorithm::Direct(_) => { + // Direct indexes are not implemented yet. + continue; + } + _ => todo!(), + }; + } + out.dedent(1); + writeln!(out, "],"); +} + /// e.g. /// ```ts /// x: __t.f32(), @@ -838,14 +770,10 @@ fn print_imports(module: &ModuleDef, out: &mut Indenter, imports: Imports, suffi if let Some(suffix) = suffix { writeln!( out, - "import {{ {type_name} as {type_name}{suffix} }} from \"./{module_name}\";" + "import {type_name}{suffix} from \"./{module_name}\";" ); - writeln!(out, "// Mark import as potentially unused"); - writeln!(out, "declare type __keep_{type_name}{suffix} = {type_name}{suffix};"); } else { - writeln!(out, "import {{ {type_name} }} from \"./{module_name}\";"); - writeln!(out, "// Mark import as potentially unused"); - writeln!(out, "declare type __keep_{type_name} = {type_name};"); + writeln!(out, "import {type_name} from \"./{module_name}\";"); } } } From ae3556ed584ab41f29187826c0fac8dc54479dc3 Mon Sep 17 00:00:00 2001 From: = Date: Tue, 4 Nov 2025 20:41:46 -0500 Subject: [PATCH 08/49] Fixed many small issues, now begin the AlgebraicType stuff --- .../src/lib/reducer_schema.ts | 38 ++ .../bindings-typescript/src/lib/reducers.ts | 49 +- crates/bindings-typescript/src/lib/schema.ts | 15 +- crates/bindings-typescript/src/lib/table.ts | 38 +- .../src/lib/table_schema.ts | 38 ++ .../src/lib/type_builders.ts | 544 +++++++++--------- .../bindings-typescript/src/lib/type_util.ts | 18 +- .../src/react/SpacetimeDBProvider.ts | 15 +- .../src/react/connection_state.ts | 5 +- .../src/react/useReducer.ts | 19 +- .../src/react/useSpacetimeDB.ts | 6 +- .../bindings-typescript/src/react/useTable.ts | 103 ++-- .../src/sdk/client_cache.ts | 14 +- .../src/sdk/client_table.ts | 79 ++- .../src/sdk/db_connection_builder.ts | 9 +- .../src/sdk/db_connection_impl.ts | 21 +- crates/bindings-typescript/src/sdk/db_view.ts | 2 +- crates/bindings-typescript/src/sdk/event.ts | 4 +- .../src/sdk/event_context.ts | 6 +- crates/bindings-typescript/src/sdk/index.ts | 2 +- .../src/sdk/reducer_event.ts | 4 +- .../bindings-typescript/src/sdk/reducers.ts | 18 +- .../src/sdk/table_cache.ts | 45 +- .../bindings-typescript/test-app/src/App.tsx | 23 +- .../module_bindings/create_player_reducer.ts | 14 +- .../test-app/src/module_bindings/index.ts | 24 +- .../src/module_bindings/player_table.ts | 14 +- .../src/module_bindings/player_type.ts | 14 +- .../src/module_bindings/point_type.ts | 14 +- .../module_bindings/unindexed_player_table.ts | 14 +- .../module_bindings/unindexed_player_type.ts | 14 +- .../src/module_bindings/user_table.ts | 14 +- .../test-app/src/module_bindings/user_type.ts | 14 +- crates/codegen/src/typescript.rs | 21 +- 34 files changed, 631 insertions(+), 641 deletions(-) create mode 100644 crates/bindings-typescript/src/lib/reducer_schema.ts create mode 100644 crates/bindings-typescript/src/lib/table_schema.ts diff --git a/crates/bindings-typescript/src/lib/reducer_schema.ts b/crates/bindings-typescript/src/lib/reducer_schema.ts new file mode 100644 index 00000000000..1d0b2f71221 --- /dev/null +++ b/crates/bindings-typescript/src/lib/reducer_schema.ts @@ -0,0 +1,38 @@ +import type { ProductType } from "./algebraic_type"; +import type RawReducerDefV9 from "./autogen/raw_reducer_def_v_9_type"; +import type { ParamsObj } from "./reducers"; +import type { Infer, RowBuilder, RowObj } from "./type_builders"; +import type { CamelCase } from "./type_util"; + +/** + * Represents a handle to a database reducer, including its name and argument type. + */ +export type ReducerSchema< + ReducerName extends string, + Params extends ParamsObj | RowObj, +> = { + /** + * The name of the reducer. + */ + readonly reducerName: ReducerName; + + /** + * The accessor name for the reducer. + */ + readonly accessorName: CamelCase; + + /** + * The TypeBuilder representation of the reducer's parameter type. + */ + readonly params: RowBuilder; + + /** + * The {@link ProductType} representing the structure of the reducer's parameters. + */ + readonly paramsSpacetimeType: ProductType; + + /** + * The {@link RawReducerDefV9} of the configured reducer. + */ + readonly reducerDef: RawReducerDefV9; +}; \ No newline at end of file diff --git a/crates/bindings-typescript/src/lib/reducers.ts b/crates/bindings-typescript/src/lib/reducers.ts index 64f54c3d961..7e2835df33c 100644 --- a/crates/bindings-typescript/src/lib/reducers.ts +++ b/crates/bindings-typescript/src/lib/reducers.ts @@ -7,12 +7,17 @@ import type { Timestamp } from './timestamp'; import type { UntypedReducersDef } from '../sdk/reducers'; import type { DbView } from '../server/db_view'; import { MODULE_DEF, type UntypedSchemaDef } from './schema'; -import type { - InferTypeOfRow, +import { RowBuilder, - RowObj, - TypeBuilder, + type Infer, + type InferTypeOfRow, + type ProductBuilder, + type RowObj, + type TypeBuilder, } from './type_builders'; +import type { CamelCase } from './type_util'; +import type { ReducerSchema } from './reducer_schema'; +import { toCamelCase } from './utils'; /** * Helper to extract the parameter types from an object type @@ -259,34 +264,6 @@ export function clientDisconnected< pushReducer(name, params, fn, Lifecycle.OnDisconnect); } -/** - * Represents a handle to a database reducer, including its name and argument type. - */ -export type ReducerSchema< - ReducerName extends string, - Params extends ParamsObj | RowObj, -> = { - /** - * The name of the reducer. - */ - readonly reducerName: ReducerName; - - /** - * The type of the parameters object expected by the reducer. - */ - readonly paramsType: Params; - - /** - * - */ - readonly paramsSpacetimeType: ProductType; - - /** - * The {@link RawReducerDefV9} of the configured reducer. - */ - readonly reducerDef: RawReducerDefV9; -}; - class Reducers { /** * Phantom type to track the reducers definition @@ -302,8 +279,9 @@ type ReducersToSchema[]> = { /** @type {UntypedReducerDef} */ readonly [i in keyof T]: { name: T[i]['reducerName']; - params: T[i]['paramsType']; - paramsSpacetimeType: T[i]['paramsSpacetimeType']; + accessorName: T[i]['accessorName']; + params: T[i]['params']['row']; + paramsType: T[i]['paramsSpacetimeType']; }; }; }; @@ -356,7 +334,8 @@ export function reducerSchema< }; return { reducerName: name, - paramsType: params, + accessorName: toCamelCase(name), + params: new RowBuilder(params), paramsSpacetimeType: paramType, reducerDef: { name, diff --git a/crates/bindings-typescript/src/lib/schema.ts b/crates/bindings-typescript/src/lib/schema.ts index 1a33c11473d..16fe41680d7 100644 --- a/crates/bindings-typescript/src/lib/schema.ts +++ b/crates/bindings-typescript/src/lib/schema.ts @@ -7,7 +7,7 @@ import { // eslint-disable-next-line @typescript-eslint/no-unused-vars type TypeBuilder, } from './type_builders'; -import type { TableSchema, UntypedTableDef } from './table'; +import type { UntypedTableDef } from './table'; import { clientConnected, clientDisconnected, @@ -23,6 +23,9 @@ import { } from './algebraic_type'; import type RawScopedTypeNameV9 from './autogen/raw_scoped_type_name_v_9_type'; import type { CamelCase } from './type_util'; +import type { TableSchema } from './table_schema'; + +export type TableNamesOf = S['tables'][number]['name']; /** * An untyped representation of the database schema. @@ -363,3 +366,13 @@ export function schema[]>( return new Schema(tableDefs, MODULE_DEF.typespace); } + +type HasAccessor = { accessorName: PropertyKey }; + +export type ConvertToAccessorMap = { + [Tbl in TableDefs[number] as Tbl["accessorName"]]: Tbl +}; + +export function convertToAccessorMap(arr: T): ConvertToAccessorMap { + return Object.fromEntries(arr.map(v => [v.accessorName, v])) as ConvertToAccessorMap; +} diff --git a/crates/bindings-typescript/src/lib/table.ts b/crates/bindings-typescript/src/lib/table.ts index 9bbc3e9e99c..4fe94e545df 100644 --- a/crates/bindings-typescript/src/lib/table.ts +++ b/crates/bindings-typescript/src/lib/table.ts @@ -7,6 +7,7 @@ import type RawTableDefV9 from './autogen/raw_table_def_v_9_type'; import type { AllUnique, ConstraintOpts } from './constraints'; import type { ColumnIndex, IndexColumns, Indexes, IndexOpts, ReadonlyIndexes } from './indexes'; import { MODULE_DEF, splitName } from './schema'; +import type { TableSchema } from './table_schema'; import { ProductBuilder, RowBuilder, @@ -16,7 +17,7 @@ import { type RowObj, type TypeBuilder, } from './type_builders'; -import type { Prettify } from './type_util'; +import type { Prettify, PrettifyDeep } from './type_util'; export type AlgebraicTypeRef = number; type ColId = number; @@ -35,7 +36,7 @@ export type RowType = InferTypeOfRow< export type CoerceColumn< Col extends TypeBuilder | ColumnBuilder, > = - Col extends TypeBuilder ? ColumnBuilder : Col; + Col extends TypeBuilder ? ColumnBuilder> : Col; /** * Coerces a RowObj where TypeBuilders are replaced with ColumnBuilders @@ -55,7 +56,7 @@ type CoerceArray[]> = X; export type UntypedTableDef = { name: string; accessorName: string; - columns: Record>>; + columns: CoerceRow; rowType: ProductType; indexes: IndexOpts[]; }; @@ -149,37 +150,6 @@ export type TableMethods = ReadonlyTableMethod delete(row: RowType): boolean; }; -/** - * Represents a handle to a database table, including its name, row type, and row spacetime type. - */ -export type TableSchema< - TableName extends string, - Row extends Record>, - Idx extends readonly IndexOpts[], -> = { - readonly rowType: RowBuilder; - - /** - * The name of the table. - */ - readonly tableName: TableName; - - /** - * The {@link ProductType} representing the structure of a row in the table. - */ - readonly rowSpacetimeType: ProductType; - - /** - * The {@link RawTableDefV9} of the configured table - */ - readonly tableDef: RawTableDefV9; - - /** - * The indexes defined on the table. - */ - readonly idxs: Idx; -}; - /** * Defines a database table with schema and options * @param opts - Table configuration including name, indexes, and access control diff --git a/crates/bindings-typescript/src/lib/table_schema.ts b/crates/bindings-typescript/src/lib/table_schema.ts new file mode 100644 index 00000000000..a76d05ef4ec --- /dev/null +++ b/crates/bindings-typescript/src/lib/table_schema.ts @@ -0,0 +1,38 @@ +import type { ProductType } from "./algebraic_type"; +import type RawTableDefV9 from "./autogen/raw_table_def_v_9_type"; +import type { IndexOpts } from "./indexes"; +import type { ColumnBuilder, RowBuilder } from "./type_builders"; + +/** + * Represents a handle to a database table, including its name, row type, and row spacetime type. + */ +export type TableSchema< + TableName extends string, + Row extends Record>, + Idx extends readonly IndexOpts[], +> = { + /** + * The name of the table. + */ + readonly tableName: TableName; + + /** + * The TypeBuilder representation of the type of the rows in the table. + **/ + readonly rowType: RowBuilder; + + /** + * The {@link ProductType} representing the structure of a row in the table. + */ + readonly rowSpacetimeType: ProductType; + + /** + * The {@link RawTableDefV9} of the configured table + */ + readonly tableDef: RawTableDefV9; + + /** + * The indexes defined on the table. + */ + readonly idxs: Idx; +}; \ No newline at end of file diff --git a/crates/bindings-typescript/src/lib/type_builders.ts b/crates/bindings-typescript/src/lib/type_builders.ts index 771cce3b188..c046b9a4067 100644 --- a/crates/bindings-typescript/src/lib/type_builders.ts +++ b/crates/bindings-typescript/src/lib/type_builders.ts @@ -15,7 +15,7 @@ import { import type { OptionAlgebraicType } from './option'; import { addType, MODULE_DEF } from '../lib/schema'; import type { CoerceRow } from './table'; -import { set, type Set } from './type_util'; +import { set, type SetField } from './type_util'; /** * Helper type to extract the TypeScript type from a TypeBuilder @@ -54,7 +54,7 @@ type CollapseColumn< */ export type RowObj = Record< string, - TypeBuilder | ColumnBuilder + TypeBuilder | ColumnBuilder> >; /** @@ -199,7 +199,7 @@ interface PrimaryKeyable< primaryKey(): ColumnBuilder< Type, SpacetimeType, - Set + SetField >; } @@ -228,7 +228,7 @@ interface Uniqueable< /** * Specify this column as unique */ - unique(): ColumnBuilder>; + unique(): ColumnBuilder>; } /** @@ -256,10 +256,10 @@ interface Indexable< * Specify the index type for this column * @param algorithm The index algorithm to use */ - index(): ColumnBuilder>; + index(): ColumnBuilder>; index>( algorithm: N - ): ColumnBuilder>; + ): ColumnBuilder>; } /** @@ -290,7 +290,7 @@ interface AutoIncrementable< autoInc(): ColumnBuilder< Type, SpacetimeType, - Set + SetField >; } @@ -344,7 +344,7 @@ interface Defaultable< */ default( value: Type - ): ColumnBuilder>; + ): ColumnBuilder>; } export class U8Builder @@ -359,28 +359,28 @@ export class U8Builder constructor() { super(AlgebraicType.U8); } - index(): U8ColumnBuilder>; + index(): U8ColumnBuilder>; index>( algorithm: N - ): U8ColumnBuilder>; + ): U8ColumnBuilder>; index( algorithm: IndexTypes = 'btree' - ): U8ColumnBuilder> { + ): U8ColumnBuilder> { return new U8ColumnBuilder( this, set(defaultMetadata, { indexType: algorithm }) ); } - unique(): U8ColumnBuilder> { + unique(): U8ColumnBuilder> { return new U8ColumnBuilder(this, set(defaultMetadata, { isUnique: true })); } - primaryKey(): U8ColumnBuilder> { + primaryKey(): U8ColumnBuilder> { return new U8ColumnBuilder( this, set(defaultMetadata, { isPrimaryKey: true }) ); } - autoInc(): U8ColumnBuilder> { + autoInc(): U8ColumnBuilder> { return new U8ColumnBuilder( this, set(defaultMetadata, { isAutoIncrement: true }) @@ -388,7 +388,7 @@ export class U8Builder } default( value: number - ): U8ColumnBuilder> { + ): U8ColumnBuilder> { return new U8ColumnBuilder( this, set(defaultMetadata, { defaultValue: value }) @@ -408,28 +408,28 @@ export class U16Builder constructor() { super(AlgebraicType.U16); } - index(): U16ColumnBuilder>; + index(): U16ColumnBuilder>; index>( algorithm: N - ): U16ColumnBuilder>; + ): U16ColumnBuilder>; index( algorithm: IndexTypes = 'btree' - ): U16ColumnBuilder> { + ): U16ColumnBuilder> { return new U16ColumnBuilder( this, set(defaultMetadata, { indexType: algorithm }) ); } - unique(): U16ColumnBuilder> { + unique(): U16ColumnBuilder> { return new U16ColumnBuilder(this, set(defaultMetadata, { isUnique: true })); } - primaryKey(): U16ColumnBuilder> { + primaryKey(): U16ColumnBuilder> { return new U16ColumnBuilder( this, set(defaultMetadata, { isPrimaryKey: true }) ); } - autoInc(): U16ColumnBuilder> { + autoInc(): U16ColumnBuilder> { return new U16ColumnBuilder( this, set(defaultMetadata, { isAutoIncrement: true }) @@ -437,7 +437,7 @@ export class U16Builder } default( value: number - ): U16ColumnBuilder> { + ): U16ColumnBuilder> { return new U16ColumnBuilder( this, set(defaultMetadata, { defaultValue: value }) @@ -457,28 +457,28 @@ export class U32Builder constructor() { super(AlgebraicType.U32); } - index(): U32ColumnBuilder>; + index(): U32ColumnBuilder>; index>( algorithm: N - ): U32ColumnBuilder>; + ): U32ColumnBuilder>; index( algorithm: IndexTypes = 'btree' - ): U32ColumnBuilder> { + ): U32ColumnBuilder> { return new U32ColumnBuilder( this, set(defaultMetadata, { indexType: algorithm }) ); } - unique(): U32ColumnBuilder> { + unique(): U32ColumnBuilder> { return new U32ColumnBuilder(this, set(defaultMetadata, { isUnique: true })); } - primaryKey(): U32ColumnBuilder> { + primaryKey(): U32ColumnBuilder> { return new U32ColumnBuilder( this, set(defaultMetadata, { isPrimaryKey: true }) ); } - autoInc(): U32ColumnBuilder> { + autoInc(): U32ColumnBuilder> { return new U32ColumnBuilder( this, set(defaultMetadata, { isAutoIncrement: true }) @@ -486,7 +486,7 @@ export class U32Builder } default( value: number - ): U32ColumnBuilder> { + ): U32ColumnBuilder> { return new U32ColumnBuilder( this, set(defaultMetadata, { defaultValue: value }) @@ -506,28 +506,28 @@ export class U64Builder constructor() { super(AlgebraicType.U64); } - index(): U64ColumnBuilder>; + index(): U64ColumnBuilder>; index>( algorithm: N - ): U64ColumnBuilder>; + ): U64ColumnBuilder>; index( algorithm: IndexTypes = 'btree' - ): U64ColumnBuilder> { + ): U64ColumnBuilder> { return new U64ColumnBuilder( this, set(defaultMetadata, { indexType: algorithm }) ); } - unique(): U64ColumnBuilder> { + unique(): U64ColumnBuilder> { return new U64ColumnBuilder(this, set(defaultMetadata, { isUnique: true })); } - primaryKey(): U64ColumnBuilder> { + primaryKey(): U64ColumnBuilder> { return new U64ColumnBuilder( this, set(defaultMetadata, { isPrimaryKey: true }) ); } - autoInc(): U64ColumnBuilder> { + autoInc(): U64ColumnBuilder> { return new U64ColumnBuilder( this, set(defaultMetadata, { isAutoIncrement: true }) @@ -535,7 +535,7 @@ export class U64Builder } default( value: bigint - ): U64ColumnBuilder> { + ): U64ColumnBuilder> { return new U64ColumnBuilder( this, set(defaultMetadata, { defaultValue: value }) @@ -555,31 +555,31 @@ export class U128Builder constructor() { super(AlgebraicType.U128); } - index(): U128ColumnBuilder>; + index(): U128ColumnBuilder>; index>( algorithm: N - ): U128ColumnBuilder>; + ): U128ColumnBuilder>; index( algorithm: IndexTypes = 'btree' - ): U128ColumnBuilder> { + ): U128ColumnBuilder> { return new U128ColumnBuilder( this, set(defaultMetadata, { indexType: algorithm }) ); } - unique(): U128ColumnBuilder> { + unique(): U128ColumnBuilder> { return new U128ColumnBuilder( this, set(defaultMetadata, { isUnique: true }) ); } - primaryKey(): U128ColumnBuilder> { + primaryKey(): U128ColumnBuilder> { return new U128ColumnBuilder( this, set(defaultMetadata, { isPrimaryKey: true }) ); } - autoInc(): U128ColumnBuilder> { + autoInc(): U128ColumnBuilder> { return new U128ColumnBuilder( this, set(defaultMetadata, { isAutoIncrement: true }) @@ -587,7 +587,7 @@ export class U128Builder } default( value: bigint - ): U128ColumnBuilder> { + ): U128ColumnBuilder> { return new U128ColumnBuilder( this, set(defaultMetadata, { defaultValue: value }) @@ -607,31 +607,31 @@ export class U256Builder constructor() { super(AlgebraicType.U256); } - index(): U256ColumnBuilder>; + index(): U256ColumnBuilder>; index>( algorithm: N - ): U256ColumnBuilder>; + ): U256ColumnBuilder>; index( algorithm: IndexTypes = 'btree' - ): U256ColumnBuilder> { + ): U256ColumnBuilder> { return new U256ColumnBuilder( this, set(defaultMetadata, { indexType: algorithm }) ); } - unique(): U256ColumnBuilder> { + unique(): U256ColumnBuilder> { return new U256ColumnBuilder( this, set(defaultMetadata, { isUnique: true }) ); } - primaryKey(): U256ColumnBuilder> { + primaryKey(): U256ColumnBuilder> { return new U256ColumnBuilder( this, set(defaultMetadata, { isPrimaryKey: true }) ); } - autoInc(): U256ColumnBuilder> { + autoInc(): U256ColumnBuilder> { return new U256ColumnBuilder( this, set(defaultMetadata, { isAutoIncrement: true }) @@ -639,7 +639,7 @@ export class U256Builder } default( value: bigint - ): U256ColumnBuilder> { + ): U256ColumnBuilder> { return new U256ColumnBuilder( this, set(defaultMetadata, { defaultValue: value }) @@ -659,28 +659,28 @@ export class I8Builder constructor() { super(AlgebraicType.I8); } - index(): I8ColumnBuilder>; + index(): I8ColumnBuilder>; index>( algorithm: N - ): I8ColumnBuilder>; + ): I8ColumnBuilder>; index( algorithm: IndexTypes = 'btree' - ): I8ColumnBuilder> { + ): I8ColumnBuilder> { return new I8ColumnBuilder( this, set(defaultMetadata, { indexType: algorithm }) ); } - unique(): I8ColumnBuilder> { + unique(): I8ColumnBuilder> { return new I8ColumnBuilder(this, set(defaultMetadata, { isUnique: true })); } - primaryKey(): I8ColumnBuilder> { + primaryKey(): I8ColumnBuilder> { return new I8ColumnBuilder( this, set(defaultMetadata, { isPrimaryKey: true }) ); } - autoInc(): I8ColumnBuilder> { + autoInc(): I8ColumnBuilder> { return new I8ColumnBuilder( this, set(defaultMetadata, { isAutoIncrement: true }) @@ -688,7 +688,7 @@ export class I8Builder } default( value: number - ): I8ColumnBuilder> { + ): I8ColumnBuilder> { return new I8ColumnBuilder( this, set(defaultMetadata, { defaultValue: value }) @@ -708,28 +708,28 @@ export class I16Builder constructor() { super(AlgebraicType.I16); } - index(): I16ColumnBuilder>; + index(): I16ColumnBuilder>; index>( algorithm: N - ): I16ColumnBuilder>; + ): I16ColumnBuilder>; index( algorithm: IndexTypes = 'btree' - ): I16ColumnBuilder> { + ): I16ColumnBuilder> { return new I16ColumnBuilder( this, set(defaultMetadata, { indexType: algorithm }) ); } - unique(): I16ColumnBuilder> { + unique(): I16ColumnBuilder> { return new I16ColumnBuilder(this, set(defaultMetadata, { isUnique: true })); } - primaryKey(): I16ColumnBuilder> { + primaryKey(): I16ColumnBuilder> { return new I16ColumnBuilder( this, set(defaultMetadata, { isPrimaryKey: true }) ); } - autoInc(): I16ColumnBuilder> { + autoInc(): I16ColumnBuilder> { return new I16ColumnBuilder( this, set(defaultMetadata, { isAutoIncrement: true }) @@ -737,7 +737,7 @@ export class I16Builder } default( value: number - ): I16ColumnBuilder> { + ): I16ColumnBuilder> { return new I16ColumnBuilder( this, set(defaultMetadata, { defaultValue: value }) @@ -758,28 +758,28 @@ export class I32Builder constructor() { super(AlgebraicType.I32); } - index(): I32ColumnBuilder>; + index(): I32ColumnBuilder>; index>( algorithm: N - ): I32ColumnBuilder>; + ): I32ColumnBuilder>; index( algorithm: IndexTypes = 'btree' - ): I32ColumnBuilder> { + ): I32ColumnBuilder> { return new I32ColumnBuilder( this, set(defaultMetadata, { indexType: algorithm }) ); } - unique(): I32ColumnBuilder> { + unique(): I32ColumnBuilder> { return new I32ColumnBuilder(this, set(defaultMetadata, { isUnique: true })); } - primaryKey(): I32ColumnBuilder> { + primaryKey(): I32ColumnBuilder> { return new I32ColumnBuilder( this, set(defaultMetadata, { isPrimaryKey: true }) ); } - autoInc(): I32ColumnBuilder> { + autoInc(): I32ColumnBuilder> { return new I32ColumnBuilder( this, set(defaultMetadata, { isAutoIncrement: true }) @@ -787,7 +787,7 @@ export class I32Builder } default( value: number - ): I32ColumnBuilder> { + ): I32ColumnBuilder> { return new I32ColumnBuilder( this, set(defaultMetadata, { defaultValue: value }) @@ -807,28 +807,28 @@ export class I64Builder constructor() { super(AlgebraicType.I64); } - index(): I64ColumnBuilder>; + index(): I64ColumnBuilder>; index>( algorithm: N - ): I64ColumnBuilder>; + ): I64ColumnBuilder>; index( algorithm: IndexTypes = 'btree' - ): I64ColumnBuilder> { + ): I64ColumnBuilder> { return new I64ColumnBuilder( this, set(defaultMetadata, { indexType: algorithm }) ); } - unique(): I64ColumnBuilder> { + unique(): I64ColumnBuilder> { return new I64ColumnBuilder(this, set(defaultMetadata, { isUnique: true })); } - primaryKey(): I64ColumnBuilder> { + primaryKey(): I64ColumnBuilder> { return new I64ColumnBuilder( this, set(defaultMetadata, { isPrimaryKey: true }) ); } - autoInc(): I64ColumnBuilder> { + autoInc(): I64ColumnBuilder> { return new I64ColumnBuilder( this, set(defaultMetadata, { isAutoIncrement: true }) @@ -836,7 +836,7 @@ export class I64Builder } default( value: bigint - ): I64ColumnBuilder> { + ): I64ColumnBuilder> { return new I64ColumnBuilder( this, set(defaultMetadata, { defaultValue: value }) @@ -856,31 +856,31 @@ export class I128Builder constructor() { super(AlgebraicType.I128); } - index(): I128ColumnBuilder>; + index(): I128ColumnBuilder>; index>( algorithm: N - ): I128ColumnBuilder>; + ): I128ColumnBuilder>; index( algorithm: IndexTypes = 'btree' - ): I128ColumnBuilder> { + ): I128ColumnBuilder> { return new I128ColumnBuilder( this, set(defaultMetadata, { indexType: algorithm }) ); } - unique(): I128ColumnBuilder> { + unique(): I128ColumnBuilder> { return new I128ColumnBuilder( this, set(defaultMetadata, { isUnique: true }) ); } - primaryKey(): I128ColumnBuilder> { + primaryKey(): I128ColumnBuilder> { return new I128ColumnBuilder( this, set(defaultMetadata, { isPrimaryKey: true }) ); } - autoInc(): I128ColumnBuilder> { + autoInc(): I128ColumnBuilder> { return new I128ColumnBuilder( this, set(defaultMetadata, { isAutoIncrement: true }) @@ -888,7 +888,7 @@ export class I128Builder } default( value: bigint - ): I128ColumnBuilder> { + ): I128ColumnBuilder> { return new I128ColumnBuilder( this, set(defaultMetadata, { defaultValue: value }) @@ -908,31 +908,31 @@ export class I256Builder constructor() { super(AlgebraicType.I256); } - index(): I256ColumnBuilder>; + index(): I256ColumnBuilder>; index>( algorithm: N - ): I256ColumnBuilder>; + ): I256ColumnBuilder>; index( algorithm: IndexTypes = 'btree' - ): I256ColumnBuilder> { + ): I256ColumnBuilder> { return new I256ColumnBuilder( this, set(defaultMetadata, { indexType: algorithm }) ); } - unique(): I256ColumnBuilder> { + unique(): I256ColumnBuilder> { return new I256ColumnBuilder( this, set(defaultMetadata, { isUnique: true }) ); } - primaryKey(): I256ColumnBuilder> { + primaryKey(): I256ColumnBuilder> { return new I256ColumnBuilder( this, set(defaultMetadata, { isPrimaryKey: true }) ); } - autoInc(): I256ColumnBuilder> { + autoInc(): I256ColumnBuilder> { return new I256ColumnBuilder( this, set(defaultMetadata, { isAutoIncrement: true }) @@ -940,7 +940,7 @@ export class I256Builder } default( value: bigint - ): I256ColumnBuilder> { + ): I256ColumnBuilder> { return new I256ColumnBuilder( this, set(defaultMetadata, { defaultValue: value }) @@ -957,7 +957,7 @@ export class F32Builder } default( value: number - ): F32ColumnBuilder> { + ): F32ColumnBuilder> { return new F32ColumnBuilder( this, set(defaultMetadata, { defaultValue: value }) @@ -974,7 +974,7 @@ export class F64Builder } default( value: number - ): F64ColumnBuilder> { + ): F64ColumnBuilder> { return new F64ColumnBuilder( this, set(defaultMetadata, { defaultValue: value }) @@ -993,25 +993,25 @@ export class BoolBuilder constructor() { super(AlgebraicType.Bool); } - index(): BoolColumnBuilder>; + index(): BoolColumnBuilder>; index>( algorithm: N - ): BoolColumnBuilder>; + ): BoolColumnBuilder>; index( algorithm: IndexTypes = 'btree' - ): BoolColumnBuilder> { + ): BoolColumnBuilder> { return new BoolColumnBuilder( this, set(defaultMetadata, { indexType: algorithm }) ); } - unique(): BoolColumnBuilder> { + unique(): BoolColumnBuilder> { return new BoolColumnBuilder( this, set(defaultMetadata, { isUnique: true }) ); } - primaryKey(): BoolColumnBuilder> { + primaryKey(): BoolColumnBuilder> { return new BoolColumnBuilder( this, set(defaultMetadata, { isPrimaryKey: true }) @@ -1019,7 +1019,7 @@ export class BoolBuilder } default( value: boolean - ): BoolColumnBuilder> { + ): BoolColumnBuilder> { return new BoolColumnBuilder( this, set(defaultMetadata, { defaultValue: value }) @@ -1038,26 +1038,26 @@ export class StringBuilder constructor() { super(AlgebraicType.String); } - index(): StringColumnBuilder>; + index(): StringColumnBuilder>; index>( algorithm: N - ): StringColumnBuilder>; + ): StringColumnBuilder>; index( algorithm: IndexTypes = 'btree' - ): StringColumnBuilder> { + ): StringColumnBuilder> { return new StringColumnBuilder( this, set(defaultMetadata, { indexType: algorithm }) ); } - unique(): StringColumnBuilder> { + unique(): StringColumnBuilder> { return new StringColumnBuilder( this, set(defaultMetadata, { isUnique: true }) ); } primaryKey(): StringColumnBuilder< - Set + SetField > { return new StringColumnBuilder( this, @@ -1066,7 +1066,7 @@ export class StringBuilder } default( value: string - ): StringColumnBuilder> { + ): StringColumnBuilder> { return new StringColumnBuilder( this, set(defaultMetadata, { defaultValue: value }) @@ -1091,7 +1091,7 @@ export class ArrayBuilder> } default( value: Array> - ): ArrayColumnBuilder> { + ): ArrayColumnBuilder> { return new ArrayColumnBuilder( this.element, set(defaultMetadata, { defaultValue: value }) @@ -1125,7 +1125,7 @@ export class OptionBuilder> value: InferTypeOfTypeBuilder | undefined ): OptionColumnBuilder< InferTypeOfTypeBuilder, - Set< + SetField< DefaultMetadata, 'defaultValue', InferTypeOfTypeBuilder | undefined @@ -1166,7 +1166,7 @@ export class ProductBuilder } default( value: ObjectType - ): ProductColumnBuilder> { + ): ProductColumnBuilder> { return new ProductColumnBuilder( this, set(defaultMetadata, { defaultValue: value }) @@ -1229,7 +1229,7 @@ export class SumBuilder extends TypeBuilder< } default( value: EnumType - ): SumColumnBuilder> { + ): SumColumnBuilder> { return new SumColumnBuilder( this, set(defaultMetadata, { defaultValue: value }) @@ -1257,16 +1257,16 @@ export class SimpleSumBuilder { index(): SimpleSumColumnBuilder< Variants, - Set + SetField >; index>( algorithm: N - ): SimpleSumColumnBuilder>; + ): SimpleSumColumnBuilder>; index( algorithm: IndexTypes = 'btree' ): SimpleSumColumnBuilder< Variants, - Set + SetField > { return new SimpleSumColumnBuilder( this, @@ -1275,7 +1275,7 @@ export class SimpleSumBuilder } primaryKey(): SimpleSumColumnBuilder< Variants, - Set + SetField > { return new SimpleSumColumnBuilder( this, @@ -1295,26 +1295,26 @@ export class IdentityBuilder constructor() { super(Identity.getAlgebraicType()); } - index(): IdentityColumnBuilder>; + index(): IdentityColumnBuilder>; index>( algorithm: N - ): IdentityColumnBuilder>; + ): IdentityColumnBuilder>; index( algorithm: IndexTypes = 'btree' - ): IdentityColumnBuilder> { + ): IdentityColumnBuilder> { return new IdentityColumnBuilder( this, set(defaultMetadata, { indexType: algorithm }) ); } - unique(): IdentityColumnBuilder> { + unique(): IdentityColumnBuilder> { return new IdentityColumnBuilder( this, set(defaultMetadata, { isUnique: true }) ); } primaryKey(): IdentityColumnBuilder< - Set + SetField > { return new IdentityColumnBuilder( this, @@ -1322,7 +1322,7 @@ export class IdentityBuilder ); } autoInc(): IdentityColumnBuilder< - Set + SetField > { return new IdentityColumnBuilder( this, @@ -1331,7 +1331,7 @@ export class IdentityBuilder } default( value: Identity - ): IdentityColumnBuilder> { + ): IdentityColumnBuilder> { return new IdentityColumnBuilder( this, set(defaultMetadata, { defaultValue: value }) @@ -1351,27 +1351,27 @@ export class ConnectionIdBuilder super(ConnectionId.getAlgebraicType()); } index(): ConnectionIdColumnBuilder< - Set + SetField >; index>( algorithm: N - ): ConnectionIdColumnBuilder>; + ): ConnectionIdColumnBuilder>; index( algorithm: IndexTypes = 'btree' - ): ConnectionIdColumnBuilder> { + ): ConnectionIdColumnBuilder> { return new ConnectionIdColumnBuilder( this, set(defaultMetadata, { indexType: algorithm }) ); } - unique(): ConnectionIdColumnBuilder> { + unique(): ConnectionIdColumnBuilder> { return new ConnectionIdColumnBuilder( this, set(defaultMetadata, { isUnique: true }) ); } primaryKey(): ConnectionIdColumnBuilder< - Set + SetField > { return new ConnectionIdColumnBuilder( this, @@ -1379,7 +1379,7 @@ export class ConnectionIdBuilder ); } autoInc(): ConnectionIdColumnBuilder< - Set + SetField > { return new ConnectionIdColumnBuilder( this, @@ -1389,7 +1389,7 @@ export class ConnectionIdBuilder default( value: ConnectionId ): ConnectionIdColumnBuilder< - Set + SetField > { return new ConnectionIdColumnBuilder( this, @@ -1409,26 +1409,26 @@ export class TimestampBuilder constructor() { super(Timestamp.getAlgebraicType()); } - index(): TimestampColumnBuilder>; + index(): TimestampColumnBuilder>; index>( algorithm: N - ): TimestampColumnBuilder>; + ): TimestampColumnBuilder>; index( algorithm: IndexTypes = 'btree' - ): TimestampColumnBuilder> { + ): TimestampColumnBuilder> { return new TimestampColumnBuilder( this, set(defaultMetadata, { indexType: algorithm }) ); } - unique(): TimestampColumnBuilder> { + unique(): TimestampColumnBuilder> { return new TimestampColumnBuilder( this, set(defaultMetadata, { isUnique: true }) ); } primaryKey(): TimestampColumnBuilder< - Set + SetField > { return new TimestampColumnBuilder( this, @@ -1436,7 +1436,7 @@ export class TimestampBuilder ); } autoInc(): TimestampColumnBuilder< - Set + SetField > { return new TimestampColumnBuilder( this, @@ -1445,7 +1445,7 @@ export class TimestampBuilder } default( value: Timestamp - ): TimestampColumnBuilder> { + ): TimestampColumnBuilder> { return new TimestampColumnBuilder( this, set(defaultMetadata, { defaultValue: value }) @@ -1465,27 +1465,27 @@ export class TimeDurationBuilder super(TimeDuration.getAlgebraicType()); } index(): TimeDurationColumnBuilder< - Set + SetField >; index>( algorithm: N - ): TimeDurationColumnBuilder>; + ): TimeDurationColumnBuilder>; index( algorithm: IndexTypes = 'btree' - ): TimeDurationColumnBuilder> { + ): TimeDurationColumnBuilder> { return new TimeDurationColumnBuilder( this, set(defaultMetadata, { indexType: algorithm }) ); } - unique(): TimeDurationColumnBuilder> { + unique(): TimeDurationColumnBuilder> { return new TimeDurationColumnBuilder( this, set(defaultMetadata, { isUnique: true }) ); } primaryKey(): TimeDurationColumnBuilder< - Set + SetField > { return new TimeDurationColumnBuilder( this, @@ -1493,7 +1493,7 @@ export class TimeDurationBuilder ); } autoInc(): TimeDurationColumnBuilder< - Set + SetField > { return new TimeDurationColumnBuilder( this, @@ -1503,7 +1503,7 @@ export class TimeDurationBuilder default( value: TimeDuration ): TimeDurationColumnBuilder< - Set + SetField > { return new TimeDurationColumnBuilder( this, @@ -1570,37 +1570,37 @@ export class U8ColumnBuilder = DefaultMetadata> AutoIncrementable, Defaultable { - index(): U8ColumnBuilder>; + index(): U8ColumnBuilder>; index>( algorithm: N - ): U8ColumnBuilder>; + ): U8ColumnBuilder>; index( algorithm: IndexTypes = 'btree' - ): U8ColumnBuilder> { + ): U8ColumnBuilder> { return new U8ColumnBuilder( this.typeBuilder, set(this.columnMetadata, { indexType: algorithm }) ); } - unique(): U8ColumnBuilder> { + unique(): U8ColumnBuilder> { return new U8ColumnBuilder( this.typeBuilder, set(this.columnMetadata, { isUnique: true }) ); } - primaryKey(): U8ColumnBuilder> { + primaryKey(): U8ColumnBuilder> { return new U8ColumnBuilder( this.typeBuilder, set(this.columnMetadata, { isPrimaryKey: true }) ); } - autoInc(): U8ColumnBuilder> { + autoInc(): U8ColumnBuilder> { return new U8ColumnBuilder( this.typeBuilder, set(this.columnMetadata, { isAutoIncrement: true }) ); } - default(value: number): U8ColumnBuilder> { + default(value: number): U8ColumnBuilder> { return new U8ColumnBuilder(this.typeBuilder, { ...this.columnMetadata, defaultValue: value, @@ -1619,37 +1619,37 @@ export class U16ColumnBuilder< AutoIncrementable, Defaultable { - index(): U16ColumnBuilder>; + index(): U16ColumnBuilder>; index>( algorithm: N - ): U16ColumnBuilder>; + ): U16ColumnBuilder>; index( algorithm: IndexTypes = 'btree' - ): U16ColumnBuilder> { + ): U16ColumnBuilder> { return new U16ColumnBuilder( this.typeBuilder, set(this.columnMetadata, { indexType: algorithm }) ); } - unique(): U16ColumnBuilder> { + unique(): U16ColumnBuilder> { return new U16ColumnBuilder( this.typeBuilder, set(this.columnMetadata, { isUnique: true }) ); } - primaryKey(): U16ColumnBuilder> { + primaryKey(): U16ColumnBuilder> { return new U16ColumnBuilder( this.typeBuilder, set(this.columnMetadata, { isPrimaryKey: true }) ); } - autoInc(): U16ColumnBuilder> { + autoInc(): U16ColumnBuilder> { return new U16ColumnBuilder( this.typeBuilder, set(this.columnMetadata, { isAutoIncrement: true }) ); } - default(value: number): U16ColumnBuilder> { + default(value: number): U16ColumnBuilder> { return new U16ColumnBuilder(this.typeBuilder, { ...this.columnMetadata, defaultValue: value, @@ -1668,37 +1668,37 @@ export class U32ColumnBuilder< AutoIncrementable, Defaultable { - index(): U32ColumnBuilder>; + index(): U32ColumnBuilder>; index>( algorithm: N - ): U32ColumnBuilder>; + ): U32ColumnBuilder>; index( algorithm: IndexTypes = 'btree' - ): U32ColumnBuilder> { + ): U32ColumnBuilder> { return new U32ColumnBuilder( this.typeBuilder, set(this.columnMetadata, { indexType: algorithm }) ); } - unique(): U32ColumnBuilder> { + unique(): U32ColumnBuilder> { return new U32ColumnBuilder( this.typeBuilder, set(this.columnMetadata, { isUnique: true }) ); } - primaryKey(): U32ColumnBuilder> { + primaryKey(): U32ColumnBuilder> { return new U32ColumnBuilder( this.typeBuilder, set(this.columnMetadata, { isPrimaryKey: true }) ); } - autoInc(): U32ColumnBuilder> { + autoInc(): U32ColumnBuilder> { return new U32ColumnBuilder( this.typeBuilder, set(this.columnMetadata, { isAutoIncrement: true }) ); } - default(value: number): U32ColumnBuilder> { + default(value: number): U32ColumnBuilder> { return new U32ColumnBuilder(this.typeBuilder, { ...this.columnMetadata, defaultValue: value, @@ -1717,37 +1717,37 @@ export class U64ColumnBuilder< AutoIncrementable, Defaultable { - index(): U64ColumnBuilder>; + index(): U64ColumnBuilder>; index>( algorithm: N - ): U64ColumnBuilder>; + ): U64ColumnBuilder>; index( algorithm: IndexTypes = 'btree' - ): U64ColumnBuilder> { + ): U64ColumnBuilder> { return new U64ColumnBuilder( this.typeBuilder, set(this.columnMetadata, { indexType: algorithm }) ); } - unique(): U64ColumnBuilder> { + unique(): U64ColumnBuilder> { return new U64ColumnBuilder( this.typeBuilder, set(this.columnMetadata, { isUnique: true }) ); } - primaryKey(): U64ColumnBuilder> { + primaryKey(): U64ColumnBuilder> { return new U64ColumnBuilder( this.typeBuilder, set(this.columnMetadata, { isPrimaryKey: true }) ); } - autoInc(): U64ColumnBuilder> { + autoInc(): U64ColumnBuilder> { return new U64ColumnBuilder( this.typeBuilder, set(this.columnMetadata, { isAutoIncrement: true }) ); } - default(value: bigint): U64ColumnBuilder> { + default(value: bigint): U64ColumnBuilder> { return new U64ColumnBuilder(this.typeBuilder, { ...this.columnMetadata, defaultValue: value, @@ -1766,37 +1766,37 @@ export class U128ColumnBuilder< AutoIncrementable, Defaultable { - index(): U128ColumnBuilder>; + index(): U128ColumnBuilder>; index>( algorithm: N - ): U128ColumnBuilder>; + ): U128ColumnBuilder>; index( algorithm: IndexTypes = 'btree' - ): U128ColumnBuilder> { + ): U128ColumnBuilder> { return new U128ColumnBuilder( this.typeBuilder, set(this.columnMetadata, { indexType: algorithm }) ); } - unique(): U128ColumnBuilder> { + unique(): U128ColumnBuilder> { return new U128ColumnBuilder( this.typeBuilder, set(this.columnMetadata, { isUnique: true }) ); } - primaryKey(): U128ColumnBuilder> { + primaryKey(): U128ColumnBuilder> { return new U128ColumnBuilder( this.typeBuilder, set(this.columnMetadata, { isPrimaryKey: true }) ); } - autoInc(): U128ColumnBuilder> { + autoInc(): U128ColumnBuilder> { return new U128ColumnBuilder( this.typeBuilder, set(this.columnMetadata, { isAutoIncrement: true }) ); } - default(value: bigint): U128ColumnBuilder> { + default(value: bigint): U128ColumnBuilder> { return new U128ColumnBuilder(this.typeBuilder, { ...this.columnMetadata, defaultValue: value, @@ -1815,37 +1815,37 @@ export class U256ColumnBuilder< AutoIncrementable, Defaultable { - index(): U256ColumnBuilder>; + index(): U256ColumnBuilder>; index>( algorithm: N - ): U256ColumnBuilder>; + ): U256ColumnBuilder>; index( algorithm: IndexTypes = 'btree' - ): U256ColumnBuilder> { + ): U256ColumnBuilder> { return new U256ColumnBuilder( this.typeBuilder, set(this.columnMetadata, { indexType: algorithm }) ); } - unique(): U256ColumnBuilder> { + unique(): U256ColumnBuilder> { return new U256ColumnBuilder( this.typeBuilder, set(this.columnMetadata, { isUnique: true }) ); } - primaryKey(): U256ColumnBuilder> { + primaryKey(): U256ColumnBuilder> { return new U256ColumnBuilder( this.typeBuilder, set(this.columnMetadata, { isPrimaryKey: true }) ); } - autoInc(): U256ColumnBuilder> { + autoInc(): U256ColumnBuilder> { return new U256ColumnBuilder( this.typeBuilder, set(this.columnMetadata, { isAutoIncrement: true }) ); } - default(value: bigint): U256ColumnBuilder> { + default(value: bigint): U256ColumnBuilder> { return new U256ColumnBuilder(this.typeBuilder, { ...this.columnMetadata, defaultValue: value, @@ -1862,37 +1862,37 @@ export class I8ColumnBuilder = DefaultMetadata> AutoIncrementable, Defaultable { - index(): I8ColumnBuilder>; + index(): I8ColumnBuilder>; index>( algorithm: N - ): I8ColumnBuilder>; + ): I8ColumnBuilder>; index( algorithm: IndexTypes = 'btree' - ): I8ColumnBuilder> { + ): I8ColumnBuilder> { return new I8ColumnBuilder( this.typeBuilder, set(this.columnMetadata, { indexType: algorithm }) ); } - unique(): I8ColumnBuilder> { + unique(): I8ColumnBuilder> { return new I8ColumnBuilder( this.typeBuilder, set(this.columnMetadata, { isUnique: true }) ); } - primaryKey(): I8ColumnBuilder> { + primaryKey(): I8ColumnBuilder> { return new I8ColumnBuilder( this.typeBuilder, set(this.columnMetadata, { isPrimaryKey: true }) ); } - autoInc(): I8ColumnBuilder> { + autoInc(): I8ColumnBuilder> { return new I8ColumnBuilder( this.typeBuilder, set(this.columnMetadata, { isAutoIncrement: true }) ); } - default(value: number): I8ColumnBuilder> { + default(value: number): I8ColumnBuilder> { return new I8ColumnBuilder(this.typeBuilder, { ...this.columnMetadata, defaultValue: value, @@ -1911,37 +1911,37 @@ export class I16ColumnBuilder< AutoIncrementable, Defaultable { - index(): I16ColumnBuilder>; + index(): I16ColumnBuilder>; index>( algorithm: N - ): I16ColumnBuilder>; + ): I16ColumnBuilder>; index( algorithm: IndexTypes = 'btree' - ): I16ColumnBuilder> { + ): I16ColumnBuilder> { return new I16ColumnBuilder( this.typeBuilder, set(this.columnMetadata, { indexType: algorithm }) ); } - unique(): I16ColumnBuilder> { + unique(): I16ColumnBuilder> { return new I16ColumnBuilder( this.typeBuilder, set(this.columnMetadata, { isUnique: true }) ); } - primaryKey(): I16ColumnBuilder> { + primaryKey(): I16ColumnBuilder> { return new I16ColumnBuilder( this.typeBuilder, set(this.columnMetadata, { isPrimaryKey: true }) ); } - autoInc(): I16ColumnBuilder> { + autoInc(): I16ColumnBuilder> { return new I16ColumnBuilder( this.typeBuilder, set(this.columnMetadata, { isAutoIncrement: true }) ); } - default(value: number): I16ColumnBuilder> { + default(value: number): I16ColumnBuilder> { return new I16ColumnBuilder(this.typeBuilder, { ...this.columnMetadata, defaultValue: value, @@ -1960,37 +1960,37 @@ export class I32ColumnBuilder< AutoIncrementable, Defaultable { - index(): I32ColumnBuilder>; + index(): I32ColumnBuilder>; index>( algorithm: N - ): I32ColumnBuilder>; + ): I32ColumnBuilder>; index( algorithm: IndexTypes = 'btree' - ): I32ColumnBuilder> { + ): I32ColumnBuilder> { return new I32ColumnBuilder( this.typeBuilder, set(this.columnMetadata, { indexType: algorithm }) ); } - unique(): I32ColumnBuilder> { + unique(): I32ColumnBuilder> { return new I32ColumnBuilder( this.typeBuilder, set(this.columnMetadata, { isUnique: true }) ); } - primaryKey(): I32ColumnBuilder> { + primaryKey(): I32ColumnBuilder> { return new I32ColumnBuilder( this.typeBuilder, set(this.columnMetadata, { isPrimaryKey: true }) ); } - autoInc(): I32ColumnBuilder> { + autoInc(): I32ColumnBuilder> { return new I32ColumnBuilder( this.typeBuilder, set(this.columnMetadata, { isAutoIncrement: true }) ); } - default(value: number): I32ColumnBuilder> { + default(value: number): I32ColumnBuilder> { return new I32ColumnBuilder(this.typeBuilder, { ...this.columnMetadata, defaultValue: value, @@ -2009,37 +2009,37 @@ export class I64ColumnBuilder< AutoIncrementable, Defaultable { - index(): I64ColumnBuilder>; + index(): I64ColumnBuilder>; index>( algorithm: N - ): I64ColumnBuilder>; + ): I64ColumnBuilder>; index( algorithm: IndexTypes = 'btree' - ): I64ColumnBuilder> { + ): I64ColumnBuilder> { return new I64ColumnBuilder( this.typeBuilder, set(this.columnMetadata, { indexType: algorithm }) ); } - unique(): I64ColumnBuilder> { + unique(): I64ColumnBuilder> { return new I64ColumnBuilder( this.typeBuilder, set(this.columnMetadata, { isUnique: true }) ); } - primaryKey(): I64ColumnBuilder> { + primaryKey(): I64ColumnBuilder> { return new I64ColumnBuilder( this.typeBuilder, set(this.columnMetadata, { isPrimaryKey: true }) ); } - autoInc(): I64ColumnBuilder> { + autoInc(): I64ColumnBuilder> { return new I64ColumnBuilder( this.typeBuilder, set(this.columnMetadata, { isAutoIncrement: true }) ); } - default(value: bigint): I64ColumnBuilder> { + default(value: bigint): I64ColumnBuilder> { return new I64ColumnBuilder(this.typeBuilder, { ...this.columnMetadata, defaultValue: value, @@ -2058,37 +2058,37 @@ export class I128ColumnBuilder< AutoIncrementable, Defaultable { - index(): I128ColumnBuilder>; + index(): I128ColumnBuilder>; index>( algorithm: N - ): I128ColumnBuilder>; + ): I128ColumnBuilder>; index( algorithm: IndexTypes = 'btree' - ): I128ColumnBuilder> { + ): I128ColumnBuilder> { return new I128ColumnBuilder( this.typeBuilder, set(this.columnMetadata, { indexType: algorithm }) ); } - unique(): I128ColumnBuilder> { + unique(): I128ColumnBuilder> { return new I128ColumnBuilder( this.typeBuilder, set(this.columnMetadata, { isUnique: true }) ); } - primaryKey(): I128ColumnBuilder> { + primaryKey(): I128ColumnBuilder> { return new I128ColumnBuilder( this.typeBuilder, set(this.columnMetadata, { isPrimaryKey: true }) ); } - autoInc(): I128ColumnBuilder> { + autoInc(): I128ColumnBuilder> { return new I128ColumnBuilder( this.typeBuilder, set(this.columnMetadata, { isAutoIncrement: true }) ); } - default(value: bigint): I128ColumnBuilder> { + default(value: bigint): I128ColumnBuilder> { return new I128ColumnBuilder(this.typeBuilder, { ...this.columnMetadata, defaultValue: value, @@ -2107,37 +2107,37 @@ export class I256ColumnBuilder< AutoIncrementable, Defaultable { - index(): I256ColumnBuilder>; + index(): I256ColumnBuilder>; index>( algorithm: N - ): I256ColumnBuilder>; + ): I256ColumnBuilder>; index( algorithm: IndexTypes = 'btree' - ): I256ColumnBuilder> { + ): I256ColumnBuilder> { return new I256ColumnBuilder( this.typeBuilder, set(this.columnMetadata, { indexType: algorithm }) ); } - unique(): I256ColumnBuilder> { + unique(): I256ColumnBuilder> { return new I256ColumnBuilder( this.typeBuilder, set(this.columnMetadata, { isUnique: true }) ); } - primaryKey(): I256ColumnBuilder> { + primaryKey(): I256ColumnBuilder> { return new I256ColumnBuilder( this.typeBuilder, set(this.columnMetadata, { isPrimaryKey: true }) ); } - autoInc(): I256ColumnBuilder> { + autoInc(): I256ColumnBuilder> { return new I256ColumnBuilder( this.typeBuilder, set(this.columnMetadata, { isAutoIncrement: true }) ); } - default(value: bigint): I256ColumnBuilder> { + default(value: bigint): I256ColumnBuilder> { return new I256ColumnBuilder(this.typeBuilder, { ...this.columnMetadata, defaultValue: value, @@ -2151,7 +2151,7 @@ export class F32ColumnBuilder< extends ColumnBuilder implements Defaultable { - default(value: number): F32ColumnBuilder> { + default(value: number): F32ColumnBuilder> { return new F32ColumnBuilder(this.typeBuilder, { ...this.columnMetadata, defaultValue: value, @@ -2165,7 +2165,7 @@ export class F64ColumnBuilder< extends ColumnBuilder implements Defaultable { - default(value: number): F64ColumnBuilder> { + default(value: number): F64ColumnBuilder> { return new F64ColumnBuilder(this.typeBuilder, { ...this.columnMetadata, defaultValue: value, @@ -2183,31 +2183,31 @@ export class BoolColumnBuilder< PrimaryKeyable, Defaultable { - index(): BoolColumnBuilder>; + index(): BoolColumnBuilder>; index>( algorithm: N - ): BoolColumnBuilder>; + ): BoolColumnBuilder>; index( algorithm: IndexTypes = 'btree' - ): BoolColumnBuilder> { + ): BoolColumnBuilder> { return new BoolColumnBuilder( this.typeBuilder, set(this.columnMetadata, { indexType: algorithm }) ); } - unique(): BoolColumnBuilder> { + unique(): BoolColumnBuilder> { return new BoolColumnBuilder( this.typeBuilder, set(this.columnMetadata, { isUnique: true }) ); } - primaryKey(): BoolColumnBuilder> { + primaryKey(): BoolColumnBuilder> { return new BoolColumnBuilder( this.typeBuilder, set(this.columnMetadata, { isPrimaryKey: true }) ); } - default(value: boolean): BoolColumnBuilder> { + default(value: boolean): BoolColumnBuilder> { return new BoolColumnBuilder(this.typeBuilder, { ...this.columnMetadata, defaultValue: value, @@ -2225,31 +2225,31 @@ export class StringColumnBuilder< PrimaryKeyable, Defaultable { - index(): StringColumnBuilder>; + index(): StringColumnBuilder>; index>( algorithm: N - ): StringColumnBuilder>; + ): StringColumnBuilder>; index( algorithm: IndexTypes = 'btree' - ): StringColumnBuilder> { + ): StringColumnBuilder> { return new StringColumnBuilder( this.typeBuilder, set(this.columnMetadata, { indexType: algorithm }) ); } - unique(): StringColumnBuilder> { + unique(): StringColumnBuilder> { return new StringColumnBuilder( this.typeBuilder, set(this.columnMetadata, { isUnique: true }) ); } - primaryKey(): StringColumnBuilder> { + primaryKey(): StringColumnBuilder> { return new StringColumnBuilder( this.typeBuilder, set(this.columnMetadata, { isPrimaryKey: true }) ); } - default(value: string): StringColumnBuilder> { + default(value: string): StringColumnBuilder> { return new StringColumnBuilder(this.typeBuilder, { ...this.columnMetadata, defaultValue: value, @@ -2278,7 +2278,7 @@ export class ArrayColumnBuilder< value: Array> ): ArrayColumnBuilder< Element, - Set>> + SetField>> > { return new ArrayColumnBuilder(this.typeBuilder, { ...this.columnMetadata, @@ -2305,7 +2305,7 @@ export class OptionColumnBuilder< value: InferTypeOfTypeBuilder | undefined ): OptionColumnBuilder< InferTypeOfTypeBuilder, - Set | undefined> + SetField | undefined> > { return new OptionColumnBuilder(this.typeBuilder, { ...this.columnMetadata, @@ -2330,7 +2330,7 @@ export class ProductColumnBuilder< { default( value: ObjectType - ): ProductColumnBuilder> { + ): ProductColumnBuilder> { return new ProductColumnBuilder( this.typeBuilder, set(this.columnMetadata, { defaultValue: value }) @@ -2351,7 +2351,7 @@ export class SumColumnBuilder< { default( value: EnumType - ): SumColumnBuilder> { + ): SumColumnBuilder> { return new SumColumnBuilder( this.typeBuilder, set(this.columnMetadata, { defaultValue: value }) @@ -2370,16 +2370,16 @@ export class SimpleSumColumnBuilder< { index(): SimpleSumColumnBuilder< Variants, - Set + SetField >; index>( algorithm: N - ): SimpleSumColumnBuilder>; + ): SimpleSumColumnBuilder>; index( algorithm: IndexTypes = 'btree' ): SimpleSumColumnBuilder< Variants, - Set + SetField > { return new SimpleSumColumnBuilder( this.typeBuilder, @@ -2388,7 +2388,7 @@ export class SimpleSumColumnBuilder< } primaryKey(): SimpleSumColumnBuilder< Variants, - Set + SetField > { return new SimpleSumColumnBuilder( this.typeBuilder, @@ -2407,25 +2407,25 @@ export class IdentityColumnBuilder< PrimaryKeyable, Defaultable { - index(): IdentityColumnBuilder>; + index(): IdentityColumnBuilder>; index>( algorithm: N - ): IdentityColumnBuilder>; + ): IdentityColumnBuilder>; index( algorithm: IndexTypes = 'btree' - ): IdentityColumnBuilder> { + ): IdentityColumnBuilder> { return new IdentityColumnBuilder( this.typeBuilder, set(this.columnMetadata, { indexType: algorithm }) ); } - unique(): IdentityColumnBuilder> { + unique(): IdentityColumnBuilder> { return new IdentityColumnBuilder( this.typeBuilder, set(this.columnMetadata, { isUnique: true }) ); } - primaryKey(): IdentityColumnBuilder> { + primaryKey(): IdentityColumnBuilder> { return new IdentityColumnBuilder( this.typeBuilder, set(this.columnMetadata, { isPrimaryKey: true }) @@ -2433,7 +2433,7 @@ export class IdentityColumnBuilder< } default( value: Identity - ): IdentityColumnBuilder> { + ): IdentityColumnBuilder> { return new IdentityColumnBuilder(this.typeBuilder, { ...this.columnMetadata, defaultValue: value, @@ -2451,25 +2451,25 @@ export class ConnectionIdColumnBuilder< PrimaryKeyable, Defaultable { - index(): ConnectionIdColumnBuilder>; + index(): ConnectionIdColumnBuilder>; index>( algorithm: N - ): ConnectionIdColumnBuilder>; + ): ConnectionIdColumnBuilder>; index( algorithm: IndexTypes = 'btree' - ): ConnectionIdColumnBuilder> { + ): ConnectionIdColumnBuilder> { return new ConnectionIdColumnBuilder( this.typeBuilder, set(this.columnMetadata, { indexType: algorithm }) ); } - unique(): ConnectionIdColumnBuilder> { + unique(): ConnectionIdColumnBuilder> { return new ConnectionIdColumnBuilder( this.typeBuilder, set(this.columnMetadata, { isUnique: true }) ); } - primaryKey(): ConnectionIdColumnBuilder> { + primaryKey(): ConnectionIdColumnBuilder> { return new ConnectionIdColumnBuilder( this.typeBuilder, set(this.columnMetadata, { isPrimaryKey: true }) @@ -2477,7 +2477,7 @@ export class ConnectionIdColumnBuilder< } default( value: ConnectionId - ): ConnectionIdColumnBuilder> { + ): ConnectionIdColumnBuilder> { return new ConnectionIdColumnBuilder(this.typeBuilder, { ...this.columnMetadata, defaultValue: value, @@ -2495,25 +2495,25 @@ export class TimestampColumnBuilder< PrimaryKeyable, Defaultable { - index(): TimestampColumnBuilder>; + index(): TimestampColumnBuilder>; index>( algorithm: N - ): TimestampColumnBuilder>; + ): TimestampColumnBuilder>; index( algorithm: IndexTypes = 'btree' - ): TimestampColumnBuilder> { + ): TimestampColumnBuilder> { return new TimestampColumnBuilder( this.typeBuilder, set(this.columnMetadata, { indexType: algorithm }) ); } - unique(): TimestampColumnBuilder> { + unique(): TimestampColumnBuilder> { return new TimestampColumnBuilder( this.typeBuilder, set(this.columnMetadata, { isUnique: true }) ); } - primaryKey(): TimestampColumnBuilder> { + primaryKey(): TimestampColumnBuilder> { return new TimestampColumnBuilder( this.typeBuilder, set(this.columnMetadata, { isPrimaryKey: true }) @@ -2521,7 +2521,7 @@ export class TimestampColumnBuilder< } default( value: Timestamp - ): TimestampColumnBuilder> { + ): TimestampColumnBuilder> { return new TimestampColumnBuilder(this.typeBuilder, { ...this.columnMetadata, defaultValue: value, @@ -2539,25 +2539,25 @@ export class TimeDurationColumnBuilder< PrimaryKeyable, Defaultable { - index(): TimeDurationColumnBuilder>; + index(): TimeDurationColumnBuilder>; index>( algorithm: N - ): TimeDurationColumnBuilder>; + ): TimeDurationColumnBuilder>; index( algorithm: IndexTypes = 'btree' - ): TimeDurationColumnBuilder> { + ): TimeDurationColumnBuilder> { return new TimeDurationColumnBuilder( this.typeBuilder, set(this.columnMetadata, { indexType: algorithm }) ); } - unique(): TimeDurationColumnBuilder> { + unique(): TimeDurationColumnBuilder> { return new TimeDurationColumnBuilder( this.typeBuilder, set(this.columnMetadata, { isUnique: true }) ); } - primaryKey(): TimeDurationColumnBuilder> { + primaryKey(): TimeDurationColumnBuilder> { return new TimeDurationColumnBuilder( this.typeBuilder, set(this.columnMetadata, { isPrimaryKey: true }) @@ -2565,7 +2565,7 @@ export class TimeDurationColumnBuilder< } default( value: TimeDuration - ): TimeDurationColumnBuilder> { + ): TimeDurationColumnBuilder> { return new TimeDurationColumnBuilder(this.typeBuilder, { ...this.columnMetadata, defaultValue: value, diff --git a/crates/bindings-typescript/src/lib/type_util.ts b/crates/bindings-typescript/src/lib/type_util.ts index ae9e978c7e9..04a33bfd528 100644 --- a/crates/bindings-typescript/src/lib/type_util.ts +++ b/crates/bindings-typescript/src/lib/type_util.ts @@ -3,10 +3,24 @@ */ export type Prettify = { [K in keyof T]: T[K] } & {}; +type Builtin = + | string | number | boolean | symbol | bigint | null | undefined + | Function | Date | RegExp | Error + | Map | Set | WeakMap | WeakSet + | Promise; + +// Deep +export type PrettifyDeep = + T extends Builtin ? T : + T extends readonly [...infer _] ? { [K in keyof T]: PrettifyDeep } : + T extends ReadonlyArray ? ReadonlyArray> : + T extends object ? Prettify<{ [K in keyof T]: PrettifyDeep }> : + T; + /** * Helper function to sets a field in an object */ -export type Set = Prettify< +export type SetField = Prettify< Omit & { [K in F]: V } >; @@ -19,7 +33,7 @@ export type Set = Prettify< export function set( x: T, t: { [k in F]: V } -): Set { +): SetField { return { ...x, ...t }; } diff --git a/crates/bindings-typescript/src/react/SpacetimeDBProvider.ts b/crates/bindings-typescript/src/react/SpacetimeDBProvider.ts index 0ca560b86ec..c728d424548 100644 --- a/crates/bindings-typescript/src/react/SpacetimeDBProvider.ts +++ b/crates/bindings-typescript/src/react/SpacetimeDBProvider.ts @@ -12,33 +12,32 @@ import { ConnectionId } from '../lib/connection_id'; import type { UntypedRemoteModule } from '../sdk/spacetime_module'; export interface SpacetimeDBProviderProps< - RemoteModule extends UntypedRemoteModule, - DbConnection extends DbConnectionImpl = DbConnectionImpl, + DbConnection extends DbConnectionImpl, > { - connectionBuilder: DbConnectionBuilder; + connectionBuilder: DbConnectionBuilder; children?: React.ReactNode; } export function SpacetimeDBProvider< DbConnection extends DbConnectionImpl, ->({ connectionBuilder, children }: SpacetimeDBProviderProps>) { +>({ connectionBuilder, children }: SpacetimeDBProviderProps) { // Holds the imperative connection instance when (and only when) we’re on the client. const connRef = React.useRef(null); const getConnection = React.useCallback(() => connRef.current, []); - const [state, setState] = React.useState>({ + const [state, setState] = React.useState({ isActive: false, identity: undefined, token: undefined, connectionId: ConnectionId.random(), connectionError: undefined, - getConnection, + getConnection: getConnection as ConnectionState["getConnection"], }); // Build on the client only; useEffect won't run during SSR. React.useEffect(() => { // Register callback for onConnect to update state - const onConnect = (conn: DbConnectionImpl>) => { + const onConnect = (conn: DbConnection) => { setState(s => ({ ...s, isActive: conn.isActive, @@ -75,7 +74,7 @@ export function SpacetimeDBProvider< // Lazily build once if (!connRef.current) { - connRef.current = connectionBuilder.build() as unknown as DbConnection; + connRef.current = connectionBuilder.build(); } return () => { diff --git a/crates/bindings-typescript/src/react/connection_state.ts b/crates/bindings-typescript/src/react/connection_state.ts index 6d63e91d693..f9c333c100f 100644 --- a/crates/bindings-typescript/src/react/connection_state.ts +++ b/crates/bindings-typescript/src/react/connection_state.ts @@ -1,13 +1,12 @@ import type { ConnectionId } from "../lib/connection_id"; import type { Identity } from "../lib/identity"; import type { DbConnectionImpl } from "../sdk/db_connection_impl"; -import type { UntypedRemoteModule } from "../sdk/spacetime_module"; -export type ConnectionState> = { +export type ConnectionState = { isActive: boolean; identity?: Identity; token?: string; connectionId: ConnectionId; connectionError?: Error; - getConnection(): DbConnection | null; + getConnection>(): DbConnection | null; }; diff --git a/crates/bindings-typescript/src/react/useReducer.ts b/crates/bindings-typescript/src/react/useReducer.ts index 06eb76da311..ee21aceb8c3 100644 --- a/crates/bindings-typescript/src/react/useReducer.ts +++ b/crates/bindings-typescript/src/react/useReducer.ts @@ -1,16 +1,15 @@ -import type { DbConnectionImpl, RemoteModuleOf } from "../sdk/db_connection_impl"; -import type { ReducersView } from "../sdk/reducers"; -import type { UntypedRemoteModule } from "../sdk/spacetime_module"; +import type { InferTypeOfRow } from "../lib/type_builders"; +import type { PrettifyDeep } from "../lib/type_util"; +import type { UntypedReducerDef } from "../sdk/reducers"; import { useSpacetimeDB, } from "./useSpacetimeDB"; - export function useReducer< - DbConnection extends DbConnectionImpl, - ReducerName extends keyof ReducersView> = keyof ReducersView> + ReducerDef extends UntypedReducerDef >( - reducerName: ReducerName -): ReducersView>[ReducerName] { - const connectionState = useSpacetimeDB(); + reducerDef: ReducerDef, +): (params: PrettifyDeep>) => void { + const reducerName = reducerDef.accessorName; + const connectionState = useSpacetimeDB(); const connection = connectionState.getConnection()!; - return connection.reducers[reducerName]; + return connection.reducers[reducerName as any] as (params: PrettifyDeep>) => void; } \ No newline at end of file diff --git a/crates/bindings-typescript/src/react/useSpacetimeDB.ts b/crates/bindings-typescript/src/react/useSpacetimeDB.ts index 8eb1a1e01d1..619a5b39dea 100644 --- a/crates/bindings-typescript/src/react/useSpacetimeDB.ts +++ b/crates/bindings-typescript/src/react/useSpacetimeDB.ts @@ -3,12 +3,12 @@ import type { DbConnectionImpl } from '../sdk/db_connection_impl'; import type { ConnectionState } from './connection_state'; import type { UntypedRemoteModule } from '../sdk/spacetime_module'; -export const SpacetimeDBContext = createContext> | undefined>(undefined); +export const SpacetimeDBContext = createContext(undefined); // Throws an error if used outside of a SpacetimeDBProvider // Error is caught by other hooks like useTable so they can provide better error messages -export function useSpacetimeDB>(): ConnectionState { - const context = useContext(SpacetimeDBContext) as ConnectionState | undefined; +export function useSpacetimeDB(): ConnectionState { + const context = useContext(SpacetimeDBContext) as ConnectionState | undefined; if (!context) { throw new Error( 'useSpacetimeDB must be used within a SpacetimeDBProvider component. Did you forget to add a `SpacetimeDBProvider` to your component tree?' diff --git a/crates/bindings-typescript/src/react/useTable.ts b/crates/bindings-typescript/src/react/useTable.ts index 0dc69d54f6a..b8ac3fab862 100644 --- a/crates/bindings-typescript/src/react/useTable.ts +++ b/crates/bindings-typescript/src/react/useTable.ts @@ -6,15 +6,15 @@ import { useSyncExternalStore, } from 'react'; import { useSpacetimeDB } from './useSpacetimeDB'; -import { DbConnectionImpl, TableCache, type EventContextInterface, type RemoteModuleOf } from '../sdk/db_connection_impl'; +import { DbConnectionImpl, type EventContextInterface, type RemoteModuleOf } from '../sdk/db_connection_impl'; import type { ConnectionState } from './connection_state'; -import type { RemoteModule, UntypedRemoteModule } from '../sdk/spacetime_module'; -import type { ClientDbView } from '../sdk/db_view'; -import type { RowType, UntypedTableDef } from '../lib/table'; +import type { UntypedRemoteModule } from '../sdk/spacetime_module'; +import type { RowType, Table, UntypedTableDef } from '../lib/table'; import type { ClientTable } from '../sdk/client_table'; -import type { Infer, InferTypeOfRow } from '../lib/type_builders'; +import type { InferTypeOfRow } from '../lib/type_builders'; +import type { PrettifyDeep } from '../lib/type_util'; -export interface UseQueryCallbacks { +export interface UseTableCallbacks { onInsert?: (row: RowType) => void; onDelete?: (row: RowType) => void; onUpdate?: (oldRow: RowType, newRow: RowType) => void; @@ -72,11 +72,9 @@ export const isOr = ( e: Expr ): e is Extract, { type: 'or' }> => e.type === 'or'; -type RecordLike = Record; - export function evaluate( expr: Expr, - row: RecordLike + row: Record ): boolean { switch (expr.type) { case 'eq': { @@ -142,11 +140,6 @@ export function where(expr: Expr): Expr { return expr; } -type Snapshot = { - readonly rows: readonly RowType[]; - readonly state: 'loading' | 'ready'; -}; - type MembershipChange = 'enter' | 'leave' | 'stayIn' | 'stayOut'; function classifyMembership< @@ -182,14 +175,10 @@ type ColumnsFromRow = { }[keyof R] & string; -// From a ClientTable, get Tbl -type TableDefOfClient = T extends ClientTable ? Tbl : never; - // Row type for a given connection + table key type RowTypeOfTable< - C extends DbConnectionImpl, - K extends keyof ClientDbView> -> = InferTypeOfRow>[K]>>>; + TableDef extends UntypedTableDef, +> = InferTypeOfRow>; /** * React hook to subscribe to a table in SpacetimeDB and receive live updates as rows are inserted, updated, or deleted. @@ -225,13 +214,12 @@ type RowTypeOfTable< * ``` */ export function useTable< - DbConnection extends DbConnectionImpl, - TableName extends keyof ClientDbView> + TableDef extends UntypedTableDef, >( - tableName: TableName, - where: Expr>> , - callbacks?: UseQueryCallbacks> -): Snapshot>; + tableDef: TableDef, + where: Expr>>, + callbacks?: UseTableCallbacks> +): PrettifyDeep>[]; /** * React hook to subscribe to a table in SpacetimeDB and receive live updates as rows are inserted, updated, or deleted. @@ -266,25 +254,31 @@ export function useTable< * }); * ``` */ +// export function useTable< +// TableDef extends UntypedTableDef, +// >( +// tableDef: TableDef, +// where: Expr>>, +// callbacks?: UseQueryCallbacks> +// ): Snapshot>>; export function useTable< - DbConnection extends DbConnectionImpl, - TableName extends keyof ClientDbView> + TableDef extends UntypedTableDef, >( - tableName: TableName, - callbacks?: UseQueryCallbacks> -): Snapshot>; + tableDef: TableDef, + callbacks?: UseTableCallbacks> +): PrettifyDeep>[]; export function useTable< - DbConnection extends DbConnectionImpl, - TableName extends keyof ClientDbView>, + TableDef extends UntypedTableDef, >( - tableName: TableName, + tableDef: TableDef, whereClauseOrCallbacks?: - | Expr>> - | UseQueryCallbacks>, - callbacks?: UseQueryCallbacks> -): Snapshot> { - type UseTableRowType = RowTypeOfTable; + | Expr>> + | UseTableCallbacks>, + callbacks?: UseTableCallbacks> +): readonly RowTypeOfTable[] { + type UseTableRowType = RowTypeOfTable; + const tableName = tableDef.name; let whereClause: Expr> | undefined; if ( whereClauseOrCallbacks && @@ -294,13 +288,13 @@ export function useTable< whereClause = whereClauseOrCallbacks as Expr>; } else { callbacks = whereClauseOrCallbacks as - | UseQueryCallbacks + | UseTableCallbacks | undefined; } const [subscribeApplied, setSubscribeApplied] = useState(false); - let connectionState: ConnectionState | undefined; + let connectionState: ConnectionState | undefined; try { - connectionState = useSpacetimeDB(); + connectionState = useSpacetimeDB(); } catch { throw new Error( 'Could not find SpacetimeDB client! Did you forget to add a ' + @@ -310,27 +304,24 @@ export function useTable< } const query = - `SELECT * FROM ${String(tableName)}` + + `SELECT * FROM ${tableName}` + (whereClause ? ` WHERE ${toString(whereClause)}` : ''); const latestTransactionEvent = useRef(null); - const lastSnapshotRef = useRef | null>(null); + const lastSnapshotRef = useRef(null); const whereKey = whereClause ? toString(whereClause) : ''; - const computeSnapshot = useCallback((): Snapshot => { + const computeSnapshot = useCallback((): readonly UseTableRowType[] => { const connection = connectionState.getConnection(); if (!connection) { - return { rows: [], state: 'loading' }; + return []; } - const table = connection.db[tableName]; + const table = connection.db[tableName] as ClientTable; const result: readonly UseTableRowType[] = whereClause - ? Array.from(table.iter()).filter(row => evaluate(whereClause, row as any)) as unknown as readonly UseTableRowType[] - : Array.from(table.iter()) as unknown as readonly UseTableRowType[]; - return { - rows: result, - state: subscribeApplied ? 'ready' : 'loading', - }; + ? (Array.from(table.iter()).filter(row => evaluate(whereClause, row as UseTableRowType)) as UseTableRowType[]) + : (Array.from(table.iter()) as UseTableRowType[]); + return result; // eslint-disable-next-line react-hooks/exhaustive-deps }, [connectionState, tableName, whereKey, subscribeApplied]); @@ -413,9 +404,7 @@ export function useTable< return () => {}; } - const table = connection.db[ - tableName as keyof typeof connection.db - ]; + const table = connection.db[tableName]; table.onInsert(onInsert); table.onDelete(onDelete); table.onUpdate?.(onUpdate); @@ -437,7 +426,7 @@ export function useTable< ] ); - const getSnapshot = useCallback((): Snapshot => { + const getSnapshot = useCallback((): readonly UseTableRowType[] => { if (!lastSnapshotRef.current) { lastSnapshotRef.current = computeSnapshot(); } diff --git a/crates/bindings-typescript/src/sdk/client_cache.ts b/crates/bindings-typescript/src/sdk/client_cache.ts index 125a43ee99c..8f07f15af37 100644 --- a/crates/bindings-typescript/src/sdk/client_cache.ts +++ b/crates/bindings-typescript/src/sdk/client_cache.ts @@ -1,20 +1,20 @@ -import type { UntypedSchemaDef } from '../lib/schema.ts'; +import type { TableNamesOf, UntypedSchemaDef } from '../lib/schema.ts'; import type { UntypedTableDef } from '../lib/table.ts'; import type { UntypedRemoteModule } from './spacetime_module.ts'; import { TableCache } from './table_cache.ts'; type TableName = - [SchemaDef] extends [UntypedSchemaDef] ? SchemaDef['tables'][number]['name'] : string; + [SchemaDef] extends [UntypedSchemaDef] ? TableNamesOf : string; -export type TableDefForTableName = +export type TableDefForTableName> = [SchemaDef] extends [UntypedSchemaDef] - ? Extract + ? (SchemaDef['tables'][number] & { name: N }) : UntypedTableDef; type TableCacheForTableName< RemoteModule extends UntypedRemoteModule, - N -> = TableCache>; + TableName extends TableNamesOf, +> = TableCache; /** * This is a helper class that provides a mapping from table names to their corresponding TableCache instances @@ -92,7 +92,7 @@ export class ClientCache { return table; } - const newTable = new TableCache>(tableDef); + const newTable = new TableCache(tableDef); this.tables.set(name, newTable); return newTable; } diff --git a/crates/bindings-typescript/src/sdk/client_table.ts b/crates/bindings-typescript/src/sdk/client_table.ts index 6d0e006e9b2..bafaf8eb49f 100644 --- a/crates/bindings-typescript/src/sdk/client_table.ts +++ b/crates/bindings-typescript/src/sdk/client_table.ts @@ -1,34 +1,55 @@ import type { ReadonlyIndexes } from "../lib/indexes"; +import type { TableNamesOf } from "../lib/schema"; import type { ReadonlyTableMethods, RowType, TableIndexes, UntypedTableDef } from "../lib/table"; +import type { ColumnBuilder } from "../lib/type_builders"; import type { Prettify } from "../lib/type_util"; +import type { TableDefForTableName } from "./client_cache"; import type { EventContextInterface } from "./event_context"; import type { UntypedRemoteModule } from "./spacetime_module"; +export type ClientTablePrimaryKeyMethods< + RemoteModule extends UntypedRemoteModule, + TableName extends TableNamesOf, +> = { + /** + * Registers a callback to be invoked when a row is updated in the table. + * Requires that the table has a primary key defined. + * @param cb The callback to invoke when a row is updated. + */ + onUpdate(cb: (ctx: EventContextInterface, oldRow: RowType>, newRow: RowType>) => void): void; + + /** + * Removes a previously registered update event listener. + * @param cb The callback to remove from the update event listeners. + */ + removeOnUpdate(cb: (ctx: EventContextInterface, oldRow: RowType>, newRow: RowType>) => void): void; +}; + export type ClientTableMethods< RemoteModule extends UntypedRemoteModule, - TableDef extends UntypedTableDef, + TableName extends TableNamesOf, > = { /** * Registers a callback to be invoked when a row is inserted into the table. */ - onInsert(cb: (ctx: EventContextInterface, row: RowType) => void): void; + onInsert(cb: (ctx: EventContextInterface, row: RowType>) => void): void; /** * Removes a previously registered insert event listener. * @param cb The callback to remove from the insert event listeners. */ - removeOnInsert(cb: (ctx: EventContextInterface, row: RowType) => void): void; + removeOnInsert(cb: (ctx: EventContextInterface, row: RowType>) => void): void; /** * Registers a callback to be invoked when a row is deleted from the table. */ - onDelete(cb: (ctx: EventContextInterface, row: RowType) => void): void; + onDelete(cb: (ctx: EventContextInterface, row: RowType>) => void): void; /** * Removes a previously registered delete event listener. * @param cb The callback to remove from the delete event listeners. */ - removeOnDelete(cb: (ctx: EventContextInterface, row: RowType) => void): void; + removeOnDelete(cb: (ctx: EventContextInterface, row: RowType>) => void): void; }; /** @@ -40,19 +61,55 @@ export type ClientTableMethods< */ export type ClientTable< RemoteModule extends UntypedRemoteModule, - TableDef extends UntypedTableDef + TableName extends TableNamesOf, > = Prettify< - ClientTableCore & - ReadonlyIndexes> + ClientTableCore & + ReadonlyIndexes, TableIndexes>> >; +type HasPrimaryKey = + ColumnsHavePrimaryKey; + +type ColumnsHavePrimaryKey< + Cs extends Record> +> = + { + [K in keyof Cs]: + Cs[K] extends ColumnBuilder + ? (M extends { isPrimaryKey: true } ? true : never) + : never + }[keyof Cs] extends true ? true : false; + +type MaybePKMethods< + RemoteModule extends UntypedRemoteModule, + TableName extends TableNamesOf, +> = Partial>; + +/** + * A variant of ClientTableCore where the primary key methods are always optional, + * allowing for classes like TableCache to implement this interface + */ +export type ClientTableCoreImplementable< + RemoteModule extends UntypedRemoteModule, + TableName extends TableNamesOf, +> = + ReadonlyTableMethods> & + ClientTableMethods & + // always present but optional -> statically known member set + MaybePKMethods; + /** * Core methods of ClientTable, without the indexes mixed in. * Includes only staticly known methods. */ export type ClientTableCore< RemoteModule extends UntypedRemoteModule, - TableDef extends UntypedTableDef, + TableName extends TableNamesOf, > = - ReadonlyTableMethods & - ClientTableMethods; \ No newline at end of file + ReadonlyTableMethods> & + ClientTableMethods & + ( + HasPrimaryKey> extends true + ? ClientTablePrimaryKeyMethods + : {} + ); \ No newline at end of file diff --git a/crates/bindings-typescript/src/sdk/db_connection_builder.ts b/crates/bindings-typescript/src/sdk/db_connection_builder.ts index cf33668d4c7..90ac3cd5015 100644 --- a/crates/bindings-typescript/src/sdk/db_connection_builder.ts +++ b/crates/bindings-typescript/src/sdk/db_connection_builder.ts @@ -7,11 +7,14 @@ import { WebsocketDecompressAdapter } from './websocket_decompress_adapter'; /** * The database client connection to a SpacetimeDB server. - * NOTE: DbConnectionImpl is used here + * NOTE: DbConnectionImpl is used here because UntypedRemoteModule causes + * variance issues with function paramters, and the end user will never be + * constructing a DbConnectionBuilder directly since it's code generated. We will + * always have a concrete RemoteModule type in those cases. Even if they user + * did do this, they would just lose type safety on the RemoteModule. */ export class DbConnectionBuilder< - RemoteModule extends UntypedRemoteModule, - DbConnection extends DbConnectionImpl + DbConnection extends DbConnectionImpl > { #uri?: URL; #nameOrAddress?: string; diff --git a/crates/bindings-typescript/src/sdk/db_connection_impl.ts b/crates/bindings-typescript/src/sdk/db_connection_impl.ts index 04b1a7967bd..d51dded9905 100644 --- a/crates/bindings-typescript/src/sdk/db_connection_impl.ts +++ b/crates/bindings-typescript/src/sdk/db_connection_impl.ts @@ -25,7 +25,7 @@ import { } from './event_context.ts'; import { EventEmitter } from './event_emitter.ts'; import { decompress } from './decompress.ts'; -import type { Identity } from '../'; +import type { Identity, InferTypeOfRow } from '../'; import type { IdentityTokenMessage, Message, @@ -50,7 +50,7 @@ import { } from './subscription_builder_impl.ts'; import { stdbLogger } from './logger.ts'; import { fromByteArray } from 'base64-js'; -import type { ReducersView, SetReducerFlags, UntypedReducersDef } from './reducers.ts'; +import type { ReducerEventInfo, ReducersView, SetReducerFlags, UntypedReducersDef } from './reducers.ts'; import type { ClientDbView } from './db_view.ts'; import type { UntypedTableDef } from '../lib/table.ts'; import { toCamelCase } from '../lib/utils.ts'; @@ -261,11 +261,11 @@ export class DbConnectionImpl< for (const reducer of def.reducers) { const key = toCamelCase(reducer.name); - (out as any)[key] = (params: typeof reducer.params) => { + (out as any)[key] = (params: InferTypeOfRow) => { const flags = this.#callReducerFlags.get(reducer.name) ?? 'FullUpdate'; this.callReducerWithParams( reducer.name, - reducer.paramsSpacetimeType, + reducer.paramsType, params, flags ); @@ -291,7 +291,7 @@ export class DbConnectionImpl< } #makeEventContext( - event: Event + event: Event>> ): EventContextInterface { // Bind methods to preserve `this` (#private fields safe) return { @@ -648,7 +648,7 @@ export class DbConnectionImpl< case 'TransactionUpdate': { let reducerInfo = message.reducerInfo; let unknownTransaction = false; - let reducerArgs: any | undefined; + let reducerArgs: InferTypeOfRow | undefined; const reducer = this.#remoteModule.reducers.find(t => t.name === reducerInfo!.reducerName)!; if (!reducerInfo) { unknownTransaction = true; @@ -658,7 +658,7 @@ export class DbConnectionImpl< const reader = new BinaryReader(reducerInfo.args as Uint8Array); reducerArgs = ProductType.deserializeValue( reader, - reducer?.paramsSpacetimeType + reducer?.paramsType ); } catch { // This should only be printed in development, since it's @@ -686,6 +686,7 @@ export class DbConnectionImpl< // At this point, we know that `reducerInfo` is not null because // we return if `unknownTransaction` is true. reducerInfo = reducerInfo!; + reducerArgs = reducerArgs!; // Thus this must be a reducer event create it and emit it. const reducerEvent = { @@ -696,9 +697,7 @@ export class DbConnectionImpl< energyConsumed: message.energyConsumed, reducer: { name: reducerInfo.reducerName, - // TODO(cloutiertyler): rename back to args to maintain API compatibility - params: reducerArgs, - paramsSpacetimeType: reducer.paramsSpacetimeType, + args: reducerArgs, }, }; const event: Event = { @@ -718,7 +717,7 @@ export class DbConnectionImpl< const argsArray: any[] = []; ( - reducer.paramsSpacetimeType + reducer.paramsType ).elements.forEach(element => { argsArray.push(reducerArgs[element.name!]); }); diff --git a/crates/bindings-typescript/src/sdk/db_view.ts b/crates/bindings-typescript/src/sdk/db_view.ts index afcdbd4d4d0..ffdee9e7199 100644 --- a/crates/bindings-typescript/src/sdk/db_view.ts +++ b/crates/bindings-typescript/src/sdk/db_view.ts @@ -5,5 +5,5 @@ import type { ClientTable } from "./client_table"; * A type representing a client-side database view, mapping table names to their corresponding client Table handles. */ export type ClientDbView = { - readonly [Tbl in RemoteModule['tables'][number] as Extract]: ClientTable; + readonly [Tbl in RemoteModule['tables'][number] as Tbl['accessorName']]: ClientTable; }; \ No newline at end of file diff --git a/crates/bindings-typescript/src/sdk/event.ts b/crates/bindings-typescript/src/sdk/event.ts index 98254af3ca5..b3d07405d37 100644 --- a/crates/bindings-typescript/src/sdk/event.ts +++ b/crates/bindings-typescript/src/sdk/event.ts @@ -1,7 +1,7 @@ import type { ReducerEvent } from './reducer_event'; -import type { UntypedReducerDef } from './reducers'; +import type { ReducerEventInfo } from './reducers'; -export type Event = +export type Event = | { tag: 'Reducer'; value: ReducerEvent } | { tag: 'SubscribeApplied' } | { tag: 'UnsubscribeApplied' } diff --git a/crates/bindings-typescript/src/sdk/event_context.ts b/crates/bindings-typescript/src/sdk/event_context.ts index 1a69b4c2a3c..8511832cac3 100644 --- a/crates/bindings-typescript/src/sdk/event_context.ts +++ b/crates/bindings-typescript/src/sdk/event_context.ts @@ -1,6 +1,8 @@ +import type { InferTypeOfRow } from '../lib/type_builders.ts'; import type { DbContext } from './db_context'; import type { Event } from './event.ts'; import type { ReducerEvent } from './reducer_event.ts'; +import type { ReducerEventInfo } from './reducers.ts'; import type { UntypedRemoteModule } from './spacetime_module.ts'; export type UntypedEventContext = EventContextInterface; @@ -9,14 +11,14 @@ export interface EventContextInterface< RemoteModule extends UntypedRemoteModule, > extends DbContext { /** Enum with variants for all possible events. */ - event: Event; + event: Event>>; } export interface ReducerEventContextInterface< RemoteModule extends UntypedRemoteModule, > extends DbContext { /** Enum with variants for all possible events. */ - event: ReducerEvent; + event: ReducerEvent>>; } // eslint-disable-next-line @typescript-eslint/no-empty-object-type diff --git a/crates/bindings-typescript/src/sdk/index.ts b/crates/bindings-typescript/src/sdk/index.ts index 3a066053531..06cf0cdc3b9 100644 --- a/crates/bindings-typescript/src/sdk/index.ts +++ b/crates/bindings-typescript/src/sdk/index.ts @@ -6,6 +6,6 @@ export { type ClientTable } from './client_table.ts'; export { type RemoteModule } from './spacetime_module.ts'; export { type SetReducerFlags } from './reducers.ts'; export * from '../lib/type_builders.ts'; -export { schema } from '../lib/schema.ts'; +export { schema, convertToAccessorMap } from '../lib/schema.ts'; export { table } from '../lib/table.ts'; export { reducerSchema, reducers } from '../lib/reducers.ts'; \ No newline at end of file diff --git a/crates/bindings-typescript/src/sdk/reducer_event.ts b/crates/bindings-typescript/src/sdk/reducer_event.ts index 1ffe5c79177..60638bd2f43 100644 --- a/crates/bindings-typescript/src/sdk/reducer_event.ts +++ b/crates/bindings-typescript/src/sdk/reducer_event.ts @@ -2,9 +2,9 @@ import { ConnectionId } from '../'; import { Timestamp } from '../'; import type { UpdateStatus } from './client_api/index.ts'; import { Identity } from '../'; -import type { UntypedReducerDef } from './reducers.ts'; +import type { ReducerEventInfo } from './reducers.ts'; -export type ReducerEvent = { +export type ReducerEvent = { /** * The time when the reducer started running. * diff --git a/crates/bindings-typescript/src/sdk/reducers.ts b/crates/bindings-typescript/src/sdk/reducers.ts index 28a7b6804c8..567c16df2f7 100644 --- a/crates/bindings-typescript/src/sdk/reducers.ts +++ b/crates/bindings-typescript/src/sdk/reducers.ts @@ -1,19 +1,25 @@ import type { ProductType } from "../lib/algebraic_type"; import type { ParamsObj } from "../lib/reducers"; -import type { CamelCase } from "../lib/type_util"; +import type { CoerceRow } from "../lib/table"; +import type { InferTypeOfRow } from "../lib/type_builders"; +import type { CamelCase, PrettifyDeep } from "../lib/type_util"; import type { CallReducerFlags } from "./db_connection_impl"; export type ReducersView = { - [I in keyof R['reducers'] as CamelCase]: - (params: R['reducers'][number]['params']) => void + [I in keyof R['reducers'] as CamelCase]: + (params: PrettifyDeep>) => void }; -export type UntypedReducers = Record void>; +export type ReducerEventInfo = { + name: string; + args: Args; +}; export type UntypedReducerDef = { name: string; - params: ParamsObj; - paramsSpacetimeType: ProductType; + accessorName: string; + params: CoerceRow; + paramsType: ProductType; }; export type UntypedReducersDef = { diff --git a/crates/bindings-typescript/src/sdk/table_cache.ts b/crates/bindings-typescript/src/sdk/table_cache.ts index c87afc5e895..655a17278f9 100644 --- a/crates/bindings-typescript/src/sdk/table_cache.ts +++ b/crates/bindings-typescript/src/sdk/table_cache.ts @@ -2,10 +2,11 @@ import { EventEmitter } from './event_emitter.ts'; import { stdbLogger } from './logger.ts'; import type { ComparablePrimitive } from '../'; -import type { EventContextInterface, ClientTable } from './index.ts'; +import type { EventContextInterface, ClientTable, TableDefForTableName } from './index.ts'; import type { RowType, Table, UntypedTableDef } from '../lib/table.ts'; -import type { ClientTableCore } from './client_table.ts'; +import type { ClientTableCore, ClientTableCoreImplementable } from './client_table.ts'; import type { UntypedRemoteModule } from './spacetime_module.ts'; +import type { TableNamesOf } from '../lib/schema.ts'; export type Operation< RowType extends Record = Record, @@ -35,10 +36,10 @@ export type PendingCallback = { */ export class TableCache< RemoteModule extends UntypedRemoteModule, - TableDef extends UntypedTableDef, -> implements ClientTableCore { - private rows: Map, number]>; - private tableDef: TableDef; + TableName extends TableNamesOf, +> implements ClientTableCoreImplementable { + private rows: Map>, number]>; + private tableDef: TableDefForTableName; private emitter: EventEmitter<'insert' | 'delete' | 'update'>; /** @@ -47,7 +48,7 @@ export class TableCache< * @param primaryKey column name designated as `#[primarykey]` * @param entityClass the entityClass */ - constructor(tableDef: TableDef) { + constructor(tableDef: TableDefForTableName) { this.tableDef = tableDef; this.rows = new Map(); this.emitter = new EventEmitter(); @@ -63,8 +64,8 @@ export class TableCache< /** * @returns The values of the rows in the table */ - iter(): IterableIterator> { - function* generator(rows: Map, number]>): IterableIterator> { + iter(): IterableIterator>> { + function* generator(rows: Map>, number]>): IterableIterator>> { for (const [row] of rows.values()) { yield row; } @@ -76,12 +77,12 @@ export class TableCache< * Allows iteration over the rows in the table * @returns An iterator over the rows in the table */ - [Symbol.iterator](): IterableIterator> { + [Symbol.iterator](): IterableIterator>> { return this.iter(); } applyOperations = ( - operations: Operation>[], + operations: Operation>>[], ctx: EventContextInterface ): PendingCallback[] => { const pendingCallbacks: PendingCallback[] = []; @@ -90,11 +91,11 @@ export class TableCache< if (hasPrimaryKey) { const insertMap = new Map< ComparablePrimitive, - [Operation>, number] + [Operation>>, number] >(); const deleteMap = new Map< ComparablePrimitive, - [Operation>, number] + [Operation>>, number] >(); for (const op of operations) { if (op.type === 'insert') { @@ -157,7 +158,7 @@ export class TableCache< update = ( ctx: EventContextInterface, rowId: ComparablePrimitive, - newRow: RowType, + newRow: RowType>, refCountDelta: number = 0 ): PendingCallback | undefined => { const existingEntry = this.rows.get(rowId); @@ -204,7 +205,7 @@ export class TableCache< insert = ( ctx: EventContextInterface, - operation: Operation>, + operation: Operation>>, count: number = 1 ): PendingCallback | undefined => { const [_, previousCount] = this.rows.get(operation.rowId) || [ @@ -227,7 +228,7 @@ export class TableCache< delete = ( ctx: EventContextInterface, - operation: Operation>, + operation: Operation>>, count: number = 1 ): PendingCallback | undefined => { const [_, previousCount] = this.rows.get(operation.rowId) || [ @@ -271,7 +272,7 @@ export class TableCache< * @param cb Callback to be called when a new row is inserted */ onInsert = ( - cb: (ctx: EventContextInterface, row: RowType) => void + cb: (ctx: EventContextInterface, row: RowType>) => void ): void => { this.emitter.on('insert', cb); }; @@ -292,7 +293,7 @@ export class TableCache< * @param cb Callback to be called when a new row is inserted */ onDelete = ( - cb: (ctx: EventContextInterface, row: RowType) => void + cb: (ctx: EventContextInterface, row: RowType>) => void ): void => { this.emitter.on('delete', cb); }; @@ -313,7 +314,7 @@ export class TableCache< * @param cb Callback to be called when a new row is inserted */ onUpdate = ( - cb: (ctx: EventContextInterface, oldRow: RowType, row: RowType) => void + cb: (ctx: EventContextInterface, oldRow: RowType>, row: RowType>) => void ): void => { this.emitter.on('update', cb); }; @@ -324,7 +325,7 @@ export class TableCache< * @param cb Callback to be removed */ removeOnInsert = ( - cb: (ctx: EventContextInterface, row: RowType) => void + cb: (ctx: EventContextInterface, row: RowType>) => void ): void => { this.emitter.off('insert', cb); }; @@ -335,7 +336,7 @@ export class TableCache< * @param cb Callback to be removed */ removeOnDelete = ( - cb: (ctx: EventContextInterface, row: RowType) => void + cb: (ctx: EventContextInterface, row: RowType>) => void ): void => { this.emitter.off('delete', cb); }; @@ -346,7 +347,7 @@ export class TableCache< * @param cb Callback to be removed */ removeOnUpdate = ( - cb: (ctx: EventContextInterface, oldRow: RowType, row: RowType) => void + cb: (ctx: EventContextInterface, oldRow: RowType>, row: RowType>) => void ): void => { this.emitter.off('update', cb); }; diff --git a/crates/bindings-typescript/test-app/src/App.tsx b/crates/bindings-typescript/test-app/src/App.tsx index bb2e7b1b7bf..fdb4fcdf554 100644 --- a/crates/bindings-typescript/test-app/src/App.tsx +++ b/crates/bindings-typescript/test-app/src/App.tsx @@ -1,23 +1,19 @@ -import { DbConnection, Player } from './module_bindings'; +import { tables, reducers, DbConnection } from './module_bindings'; import { useEffect } from 'react'; import './App.css'; import { useReducer, useSpacetimeDB, useTable } from '../../src/react'; function App() { - const x = useReducer; - const createPlayer = useReducer('createPlayer'); - const connection = useSpacetimeDB(); - const players = useTable('player', { - onInsert: player => { - console.log(player); - }, - }); + const connection = useSpacetimeDB(); + const players = useTable(tables.player); + const createPlayer = useReducer(reducers.createPlayer); + createPlayer({ name: 'Test', location: { x: 0, y: 0 } }); useEffect(() => { setTimeout(() => { - console.log(Array.from(players.rows)); + console.log(Array.from(players)); }, 5000); - }, [connection, players.rows]); + }, [connection, players]); return (
@@ -26,7 +22,10 @@ function App() { +
+ {Array.from(players).map((player, i) => ( +
+ {player.name} - ({player.location.x}, {player.location.y}) +
+ ))} +
); } diff --git a/crates/bindings-typescript/test-app/src/main.tsx b/crates/bindings-typescript/test-app/src/main.tsx index fcb7271984b..028148b3eb7 100644 --- a/crates/bindings-typescript/test-app/src/main.tsx +++ b/crates/bindings-typescript/test-app/src/main.tsx @@ -12,8 +12,8 @@ const connectionBuilder = DbConnection.builder() .onDisconnect(() => { console.log('disconnected'); }) - .onConnectError(() => { - console.log('client_error'); + .onConnectError((ctx, err) => { + console.log('client_error: ', err); }) .onConnect((conn, identity, _token) => { console.log( @@ -22,10 +22,7 @@ const connectionBuilder = DbConnection.builder() ); conn.subscriptionBuilder().subscribe('SELECT * FROM player'); - }) - .withToken( - 'eyJhbGciOiJSUzI1NiJ9.eyJzdWIiOiIwMUpCQTBYRzRESFpIWUdQQk5GRFk5RDQ2SiIsImlzcyI6Imh0dHBzOi8vYXV0aC5zdGFnaW5nLnNwYWNldGltZWRiLmNvbSIsImlhdCI6MTczMDgwODUwNSwiZXhwIjoxNzkzODgwNTA1fQ.kGM4HGX0c0twL8NJoSQowzSZa8dc2Ogc-fsvaDK7otUrcdGFsZ3KsNON2eNkFh73FER0hl55_eJStr2tgoPwfTyl_v_TqkY45iUOUlLmHfB-X42cMzpE7PXbR_PKYcp-P-Wa4jGtVl4oF7CvdGKxlhIYEk3e0ElQlA9ThnZN4IEciYV0vwAXGqbaO9SOG8jbrmlmfN7oKgl02EgpodEAHTrnB2mD1qf1YyOw7_9n_EkxJxWLkJf9-nFCVRrbfSLqSJBeE6OKNAu2VLLYrSFE7GkVXNCFVugoCDM2oVJogX75AgzWimrp75QRmLsXbvB-YvvRkQ8Gfb2RZnqCj9kiYg' - ); + }); ReactDOM.createRoot(document.getElementById('root')!).render( diff --git a/crates/bindings-typescript/test-app/src/module_bindings/player_table.ts b/crates/bindings-typescript/test-app/src/module_bindings/player_table.ts index 8acf176ea68..ee98682e78b 100644 --- a/crates/bindings-typescript/test-app/src/module_bindings/player_table.ts +++ b/crates/bindings-typescript/test-app/src/module_bindings/player_table.ts @@ -12,7 +12,8 @@ import { import Point from './point_type'; export default __t.row({ - ownerId: __t.string(), + id: __t.u32(), + userId: __t.identity(), name: __t.string(), get location() { return Point; diff --git a/crates/bindings-typescript/test-app/src/module_bindings/player_type.ts b/crates/bindings-typescript/test-app/src/module_bindings/player_type.ts index 3a1d4492baa..596b73f7d06 100644 --- a/crates/bindings-typescript/test-app/src/module_bindings/player_type.ts +++ b/crates/bindings-typescript/test-app/src/module_bindings/player_type.ts @@ -12,7 +12,8 @@ import { import Point from './point_type'; export default __t.object('Player', { - ownerId: __t.string(), + id: __t.u32(), + userId: __t.identity(), name: __t.string(), get location() { return Point; diff --git a/crates/bindings-typescript/test-app/src/module_bindings/unindexed_player_table.ts b/crates/bindings-typescript/test-app/src/module_bindings/unindexed_player_table.ts index 8acf176ea68..96f056baeb7 100644 --- a/crates/bindings-typescript/test-app/src/module_bindings/unindexed_player_table.ts +++ b/crates/bindings-typescript/test-app/src/module_bindings/unindexed_player_table.ts @@ -12,7 +12,8 @@ import { import Point from './point_type'; export default __t.row({ - ownerId: __t.string(), + id: __t.u32(), + ownerId: __t.identity(), name: __t.string(), get location() { return Point; diff --git a/crates/bindings-typescript/test-app/src/module_bindings/unindexed_player_type.ts b/crates/bindings-typescript/test-app/src/module_bindings/unindexed_player_type.ts index f697863ed0c..5f717022485 100644 --- a/crates/bindings-typescript/test-app/src/module_bindings/unindexed_player_type.ts +++ b/crates/bindings-typescript/test-app/src/module_bindings/unindexed_player_type.ts @@ -12,7 +12,8 @@ import { import Point from './point_type'; export default __t.object('UnindexedPlayer', { - ownerId: __t.string(), + id: __t.u32(), + ownerId: __t.identity(), name: __t.string(), get location() { return Point; From 16814cb5555ef9c95ddff6e56d7c9b975de82d6d Mon Sep 17 00:00:00 2001 From: = Date: Sat, 8 Nov 2025 21:23:32 -0500 Subject: [PATCH 17/49] Small adjustments --- crates/bindings-typescript/src/lib/connection_id.ts | 7 +++++++ crates/bindings-typescript/src/lib/identity.ts | 9 ++++++++- crates/bindings-typescript/test-app/src/App.tsx | 9 +++++++-- 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/crates/bindings-typescript/src/lib/connection_id.ts b/crates/bindings-typescript/src/lib/connection_id.ts index 64da6361395..80a940115c4 100644 --- a/crates/bindings-typescript/src/lib/connection_id.ts +++ b/crates/bindings-typescript/src/lib/connection_id.ts @@ -63,6 +63,13 @@ export class ConnectionId { return this.__connection_id__ == other.__connection_id__; } + /** + * Check if two connection IDs are equal. + */ + equals(other: ConnectionId): boolean { + return this.isEqual(other); + } + /** * Print the connection ID as a hexadecimal string. */ diff --git a/crates/bindings-typescript/src/lib/identity.ts b/crates/bindings-typescript/src/lib/identity.ts index 3b2b0e60ed8..68d890c4f39 100644 --- a/crates/bindings-typescript/src/lib/identity.ts +++ b/crates/bindings-typescript/src/lib/identity.ts @@ -36,12 +36,19 @@ export class Identity { } /** - * Compare two identities for equality. + * Check if two identities are equal. */ isEqual(other: Identity): boolean { return this.toHexString() === other.toHexString(); } + /** + * Check if two identities are equal. + */ + equals(other: Identity): boolean { + return this.isEqual(other); + } + /** * Print the identity as a hexadecimal string. */ diff --git a/crates/bindings-typescript/test-app/src/App.tsx b/crates/bindings-typescript/test-app/src/App.tsx index d68312f00d9..3ef576fb0e1 100644 --- a/crates/bindings-typescript/test-app/src/App.tsx +++ b/crates/bindings-typescript/test-app/src/App.tsx @@ -1,7 +1,7 @@ import { tables, reducers } from './module_bindings'; import { useEffect } from 'react'; import './App.css'; -import { useReducer, useSpacetimeDB, useTable } from '../../src/react'; +import { eq, useReducer, useSpacetimeDB, useTable, where } from '../../src/react'; function getRandomInt(max: number) { return Math.floor(Math.random() * max); @@ -9,7 +9,12 @@ function getRandomInt(max: number) { function App() { const connection = useSpacetimeDB(); - const players = useTable(tables.player); + const players = useTable(tables.player, where(eq('name', 'Hello')), { + onInsert: (row) => { + console.log('Player inserted:', rows); + }, + + }); const x = players[0]; const createPlayer = useReducer(reducers.createPlayer); From 384f8b02b50eb5d5467004b6e1336a962c1aeb83 Mon Sep 17 00:00:00 2001 From: = Date: Sun, 9 Nov 2025 01:04:52 -0500 Subject: [PATCH 18/49] pnpm format --- .../examples/quickstart-chat/src/App.tsx | 2 +- .../src/module_bindings/user_table.ts | 6 +- .../src/lib/algebraic_type.ts | 17 +- .../src/lib/algebraic_type_variants.ts | 8 +- .../src/lib/constraints.ts | 2 +- .../bindings-typescript/src/lib/identity.ts | 2 +- crates/bindings-typescript/src/lib/indexes.ts | 2 +- .../src/lib/reducer_schema.ts | 16 +- .../bindings-typescript/src/lib/reducers.ts | 22 +- crates/bindings-typescript/src/lib/schema.ts | 89 +- crates/bindings-typescript/src/lib/table.ts | 62 +- .../src/lib/table_schema.ts | 10 +- .../src/lib/type_builders.ts | 1031 ++++++++++------- .../bindings-typescript/src/lib/type_util.ts | 35 +- .../src/react/SpacetimeDBProvider.ts | 20 +- .../src/react/connection_state.ts | 10 +- .../src/react/useReducer.ts | 50 +- .../src/react/useSpacetimeDB.ts | 6 +- .../bindings-typescript/src/react/useTable.ts | 77 +- .../src/sdk/client_cache.ts | 57 +- .../src/sdk/client_table.ts | 111 +- .../src/sdk/db_connection_builder.ts | 30 +- .../src/sdk/db_connection_impl.ts | 109 +- .../bindings-typescript/src/sdk/db_context.ts | 10 +- crates/bindings-typescript/src/sdk/db_view.ts | 11 +- .../src/sdk/event_context.ts | 18 +- crates/bindings-typescript/src/sdk/index.ts | 2 +- .../src/sdk/message_types.ts | 23 +- .../src/sdk/reducer_handle.ts | 4 +- .../bindings-typescript/src/sdk/reducers.ts | 25 +- .../src/sdk/set_reducer_flags.ts | 7 +- .../src/sdk/spacetime_module.ts | 22 +- .../src/sdk/subscription_builder_impl.ts | 60 +- .../src/sdk/table_cache.ts | 100 +- .../src/sdk/websocket_test_adapter.ts | 6 +- .../bindings-typescript/src/server/db_view.ts | 6 +- .../bindings-typescript/src/server/runtime.ts | 14 +- .../bindings-typescript/test-app/src/App.tsx | 13 +- .../bindings-typescript/tests/serde.test.ts | 9 +- 39 files changed, 1307 insertions(+), 797 deletions(-) diff --git a/crates/bindings-typescript/examples/quickstart-chat/src/App.tsx b/crates/bindings-typescript/examples/quickstart-chat/src/App.tsx index 0fa172b20ab..a6cf1f2751c 100644 --- a/crates/bindings-typescript/examples/quickstart-chat/src/App.tsx +++ b/crates/bindings-typescript/examples/quickstart-chat/src/App.tsx @@ -18,7 +18,7 @@ function App() { const [newMessage, setNewMessage] = useState(''); const conn = useSpacetimeDB(); - conn.setReducerFlags() + conn.setReducerFlags(); const { identity, isActive: connected } = conn; // Subscribe to all messages in the chat diff --git a/crates/bindings-typescript/examples/quickstart-chat/src/module_bindings/user_table.ts b/crates/bindings-typescript/examples/quickstart-chat/src/module_bindings/user_table.ts index 9b35746a2ab..61c82b8de12 100644 --- a/crates/bindings-typescript/examples/quickstart-chat/src/module_bindings/user_table.ts +++ b/crates/bindings-typescript/examples/quickstart-chat/src/module_bindings/user_table.ts @@ -46,9 +46,9 @@ declare type __keep = [EventContext, Reducer, RemoteReducers, RemoteTables]; * but to directly chain method calls, * like `ctx.db.user.on_insert(...)`. */ -export class UserTableHandle - extends ClientTable -{ +export class UserTableHandle< + TableName extends string, +> extends ClientTable { // phantom type to track the table name readonly tableName!: TableName; tableCache: __TableCache; diff --git a/crates/bindings-typescript/src/lib/algebraic_type.ts b/crates/bindings-typescript/src/lib/algebraic_type.ts index 4bb42a475e9..2f8b4bdbba3 100644 --- a/crates/bindings-typescript/src/lib/algebraic_type.ts +++ b/crates/bindings-typescript/src/lib/algebraic_type.ts @@ -69,17 +69,24 @@ export type AlgebraicType = AlgebraicTypeType; /** * The variant types of the Algebraic Type tagged union. */ -export { AlgebraicTypeVariants } +export { AlgebraicTypeVariants }; // A value with helper functions to construct the type. export const AlgebraicType = { Ref: (value: number): AlgebraicTypeVariants.Ref => ({ tag: 'Ref', value }), - Sum: (value: T): { tag: 'Sum'; value: T } => ({ tag: 'Sum', value }), - Product: (value: T): { tag: 'Product'; value: T } => ({ + Sum: (value: T): { tag: 'Sum'; value: T } => ({ + tag: 'Sum', + value, + }), + Product: ( + value: T + ): { tag: 'Product'; value: T } => ({ tag: 'Product', value, }), - Array: (value: T): { tag: 'Array'; value: T } => ({ + Array: ( + value: T + ): { tag: 'Array'; value: T } => ({ tag: 'Array', value, }), @@ -280,7 +287,7 @@ export const AlgebraicType = { } } }, -} +}; /** * A structural product type of the factors given by `elements`. diff --git a/crates/bindings-typescript/src/lib/algebraic_type_variants.ts b/crates/bindings-typescript/src/lib/algebraic_type_variants.ts index 0a911a40438..5890d53c148 100644 --- a/crates/bindings-typescript/src/lib/algebraic_type_variants.ts +++ b/crates/bindings-typescript/src/lib/algebraic_type_variants.ts @@ -1,4 +1,8 @@ -import type { AlgebraicTypeType, ProductTypeType, SumTypeType } from "./algebraic_type"; +import type { + AlgebraicTypeType, + ProductTypeType, + SumTypeType, +} from './algebraic_type'; export type Ref = { tag: 'Ref'; value: number }; export type Sum = { tag: 'Sum'; value: SumTypeType }; @@ -19,4 +23,4 @@ export type U128 = { tag: 'U128' }; export type I256 = { tag: 'I256' }; export type U256 = { tag: 'U256' }; export type F32 = { tag: 'F32' }; -export type F64 = { tag: 'F64' }; \ No newline at end of file +export type F64 = { tag: 'F64' }; diff --git a/crates/bindings-typescript/src/lib/constraints.ts b/crates/bindings-typescript/src/lib/constraints.ts index 4b206a8c858..c3ee5a87c6f 100644 --- a/crates/bindings-typescript/src/lib/constraints.ts +++ b/crates/bindings-typescript/src/lib/constraints.ts @@ -47,4 +47,4 @@ export type ConstraintOpts = { } & ( | { constraint: 'unique'; columns: [AllowedCol] } | { constraint: 'primaryKey'; columns: [AllowedCol] } -); \ No newline at end of file +); diff --git a/crates/bindings-typescript/src/lib/identity.ts b/crates/bindings-typescript/src/lib/identity.ts index 68d890c4f39..3ec9081c835 100644 --- a/crates/bindings-typescript/src/lib/identity.ts +++ b/crates/bindings-typescript/src/lib/identity.ts @@ -36,7 +36,7 @@ export class Identity { } /** - * Check if two identities are equal. + * Check if two identities are equal. */ isEqual(other: Identity): boolean { return this.toHexString() === other.toHexString(); diff --git a/crates/bindings-typescript/src/lib/indexes.ts b/crates/bindings-typescript/src/lib/indexes.ts index 5c93c9aac9b..04e3215e466 100644 --- a/crates/bindings-typescript/src/lib/indexes.ts +++ b/crates/bindings-typescript/src/lib/indexes.ts @@ -100,7 +100,7 @@ export type UniqueIndex< }; /** - * A type representing a read-only ranged index on a database table. + * A type representing a read-only ranged index on a database table. */ export type ReadonlyRangedIndex< TableDef extends UntypedTableDef, diff --git a/crates/bindings-typescript/src/lib/reducer_schema.ts b/crates/bindings-typescript/src/lib/reducer_schema.ts index d8fd614de91..c68a350f2d8 100644 --- a/crates/bindings-typescript/src/lib/reducer_schema.ts +++ b/crates/bindings-typescript/src/lib/reducer_schema.ts @@ -1,8 +1,8 @@ -import type { ProductType } from "./algebraic_type"; -import type RawReducerDefV9 from "./autogen/raw_reducer_def_v_9_type"; -import type { ParamsObj } from "./reducers"; -import type { Infer, RowBuilder, RowObj } from "./type_builders"; -import type { CamelCase } from "./type_util"; +import type { ProductType } from './algebraic_type'; +import type RawReducerDefV9 from './autogen/raw_reducer_def_v_9_type'; +import type { ParamsObj } from './reducers'; +import type { Infer, RowBuilder, RowObj } from './type_builders'; +import type { CamelCase } from './type_util'; /** * Represents a handle to a database reducer, including its name and argument type. @@ -15,7 +15,7 @@ export type ReducerSchema< * The name of the reducer. */ readonly reducerName: ReducerName; - + /** * The accessor name for the reducer. */ @@ -25,7 +25,7 @@ export type ReducerSchema< * The TypeBuilder representation of the reducer's parameter type. */ readonly params: RowBuilder; - + /** * The {@link ProductType} representing the structure of the reducer's parameters. */ @@ -35,4 +35,4 @@ export type ReducerSchema< * The {@link RawReducerDefV9} of the configured reducer. */ readonly reducerDef: Infer; -}; \ No newline at end of file +}; diff --git a/crates/bindings-typescript/src/lib/reducers.ts b/crates/bindings-typescript/src/lib/reducers.ts index 14f7a9caffa..da7191d8f76 100644 --- a/crates/bindings-typescript/src/lib/reducers.ts +++ b/crates/bindings-typescript/src/lib/reducers.ts @@ -288,9 +288,9 @@ type ReducersToSchema[]> = { }; export function reducersToSchema< - const T extends readonly ReducerSchema[] + const T extends readonly ReducerSchema[], >(reducers: T): ReducersToSchema { - const mapped = reducers.map((r) => { + const mapped = reducers.map(r => { const paramsRow = r.params.row; return { @@ -308,7 +308,7 @@ export function reducersToSchema< paramsType: T[I]['paramsSpacetimeType']; }; }; - + const result = { reducers: mapped } satisfies ReducersToSchema; return result; } @@ -339,21 +339,18 @@ export function reducers[]>( ): Reducers>; export function reducers[]>( - ...args: - | [H] - | H + ...args: [H] | H ): Reducers> { - const handles = (args.length === 1 && Array.isArray(args[0]) ? args[0] : args) as H; + const handles = ( + args.length === 1 && Array.isArray(args[0]) ? args[0] : args + ) as H; return new Reducers(handles); } export function reducerSchema< ReducerName extends string, Params extends ParamsObj, ->( - name: ReducerName, - params: Params -): ReducerSchema { +>(name: ReducerName, params: Params): ReducerSchema { const paramType: ProductType = { elements: Object.entries(params).map(([n, c]) => ({ name: n, @@ -371,5 +368,4 @@ export function reducerSchema< lifecycle: undefined, }, }; -} - +} diff --git a/crates/bindings-typescript/src/lib/schema.ts b/crates/bindings-typescript/src/lib/schema.ts index a06293e8f49..5c764537d88 100644 --- a/crates/bindings-typescript/src/lib/schema.ts +++ b/crates/bindings-typescript/src/lib/schema.ts @@ -34,7 +34,8 @@ import type { CamelCase } from './type_util'; import type { TableSchema } from './table_schema'; import { toCamelCase } from './utils'; -export type TableNamesOf = S['tables'][number]['name']; +export type TableNamesOf = + S['tables'][number]['name']; /** * An untyped representation of the database schema. @@ -60,10 +61,10 @@ type TablesToSchema[]> = { }; export function tablesToSchema< - const T extends readonly TableSchema[] + const T extends readonly TableSchema[], >(tables: T): TablesToSchema { const result = { - tables: tables.map((schema) => { + tables: tables.map(schema => { return { name: schema.tableName, accessorName: toCamelCase(schema.tableName), @@ -73,15 +74,15 @@ export function tablesToSchema< indexes: [...schema.idxs], } as const; }) as { - // preserve tuple indices so the return type matches `[i in keyof T]` - readonly [I in keyof T]: { - name: T[I]['tableName']; - accessorName: CamelCase; - columns: T[I]['rowType']['row']; - rowType: T[I]['rowSpacetimeType']; - indexes: T[I]['idxs']; - }; - }, + // preserve tuple indices so the return type matches `[i in keyof T]` + readonly [I in keyof T]: { + name: T[I]['tableName']; + accessorName: CamelCase; + columns: T[I]['rowType']['row']; + rowType: T[I]['rowSpacetimeType']; + indexes: T[I]['idxs']; + }; + }, } satisfies TablesToSchema; return result; } @@ -123,12 +124,15 @@ export function resolveType( /** * Adds a type to the module definition's typespace as a `Ref` if it is a named compound type (Product or Sum). * Otherwise, returns the type as is. - * @param name - * @param ty - * @returns + * @param name + * @param ty + * @returns */ export function registerTypesRecursively( - typeBuilder: SumBuilder | ProductBuilder | RowBuilder + typeBuilder: + | SumBuilder + | ProductBuilder + | RowBuilder ): RefBuilder { const ty = typeBuilder.algebraicType; const name = typeBuilder.typeName; @@ -142,21 +146,42 @@ export function registerTypesRecursively( // Recursively register nested compound types if (typeBuilder instanceof RowBuilder) { for (const [name, elem] of Object.entries(typeBuilder.row)) { - if (!(elem instanceof ProductBuilder || elem instanceof SumBuilder || elem instanceof RowBuilder)) { + if ( + !( + elem instanceof ProductBuilder || + elem instanceof SumBuilder || + elem instanceof RowBuilder + ) + ) { continue; } - typeBuilder.row[name] = new ColumnBuilder(registerTypesRecursively(elem), {}); + typeBuilder.row[name] = new ColumnBuilder( + registerTypesRecursively(elem), + {} + ); } } else if (typeBuilder instanceof ProductBuilder) { for (const [name, elem] of Object.entries(typeBuilder.elements)) { - if (!(elem instanceof ProductBuilder || elem instanceof SumBuilder || elem instanceof RowBuilder)) { + if ( + !( + elem instanceof ProductBuilder || + elem instanceof SumBuilder || + elem instanceof RowBuilder + ) + ) { continue; } typeBuilder.elements[name] = registerTypesRecursively(elem); } } else if (typeBuilder instanceof SumBuilder) { for (const [name, variant] of Object.entries(typeBuilder.variants)) { - if (!(variant instanceof ProductBuilder || variant instanceof SumBuilder || variant instanceof RowBuilder)) { + if ( + !( + variant instanceof ProductBuilder || + variant instanceof SumBuilder || + variant instanceof RowBuilder + ) + ) { continue; } typeBuilder.variants[name] = registerTypesRecursively(variant); @@ -221,7 +246,11 @@ class Schema { readonly typespace: Infer; readonly schemaType: S; - constructor(tables: Infer[], typespace: Infer, handles: readonly TableSchema[]) { + constructor( + tables: Infer[], + typespace: Infer, + handles: readonly TableSchema[] + ) { this.tablesDef = { tables }; this.typespace = typespace; // TODO: TableSchema and TableDef should really be unified @@ -428,11 +457,11 @@ export function schema[]>( * ``` */ export function schema[]>( - ...args: - | [H] - | H + ...args: [H] | H ): Schema> { - const handles = (args.length === 1 && Array.isArray(args[0]) ? args[0] : args) as H; + const handles = ( + args.length === 1 && Array.isArray(args[0]) ? args[0] : args + ) as H; const tableDefs = handles.map(h => h.tableDef); // Side-effect: @@ -455,9 +484,13 @@ export function schema[]>( type HasAccessor = { accessorName: PropertyKey }; export type ConvertToAccessorMap = { - [Tbl in TableDefs[number] as Tbl["accessorName"]]: Tbl + [Tbl in TableDefs[number] as Tbl['accessorName']]: Tbl; }; -export function convertToAccessorMap(arr: T): ConvertToAccessorMap { - return Object.fromEntries(arr.map(v => [v.accessorName, v])) as ConvertToAccessorMap; +export function convertToAccessorMap( + arr: T +): ConvertToAccessorMap { + return Object.fromEntries( + arr.map(v => [v.accessorName, v]) + ) as ConvertToAccessorMap; } diff --git a/crates/bindings-typescript/src/lib/table.ts b/crates/bindings-typescript/src/lib/table.ts index a57f8fbebb5..6d27e10a799 100644 --- a/crates/bindings-typescript/src/lib/table.ts +++ b/crates/bindings-typescript/src/lib/table.ts @@ -5,8 +5,19 @@ import type RawIndexDefV9 from './autogen/raw_index_def_v_9_type'; import type RawSequenceDefV9 from './autogen/raw_sequence_def_v_9_type'; import type RawTableDefV9 from './autogen/raw_table_def_v_9_type'; import type { AllUnique, ConstraintOpts } from './constraints'; -import type { ColumnIndex, IndexColumns, Indexes, IndexOpts, ReadonlyIndexes } from './indexes'; -import { registerTypesRecursively, MODULE_DEF, resolveType, splitName } from './schema'; +import type { + ColumnIndex, + IndexColumns, + Indexes, + IndexOpts, + ReadonlyIndexes, +} from './indexes'; +import { + registerTypesRecursively, + MODULE_DEF, + resolveType, + splitName, +} from './schema'; import type { TableSchema } from './table_schema'; import { RowBuilder, @@ -17,7 +28,7 @@ import { type RowObj, type TypeBuilder, } from './type_builders'; -import type { Prettify, } from './type_util'; +import type { Prettify } from './type_util'; export type AlgebraicTypeRef = number; type ColId = number; @@ -26,9 +37,9 @@ type ColList = ColId[]; /** * A helper type to extract the row type from a TableDef */ -export type RowType = Prettify = InferTypeOfRow< TableDef['columns'] ->>; +>; /** * Coerces a column which may be a TypeBuilder or ColumnBuilder into a ColumnBuilder @@ -36,7 +47,9 @@ export type RowType = Prettify | ColumnBuilder, > = - Col extends TypeBuilder ? ColumnBuilder> : Col; + Col extends TypeBuilder + ? ColumnBuilder> + : Col; /** * Coerces a RowObj where TypeBuilders are replaced with ColumnBuilders @@ -136,19 +149,20 @@ export type ReadonlyTableMethods = { /** * A type representing the methods available on a table. */ -export type TableMethods = ReadonlyTableMethods & { - /** - * Insert and return the inserted row (auto-increment fields filled). - * - * May throw on error: - * * If there are any unique or primary key columns in this table, may throw {@link UniqueAlreadyExists}. - * * If there are any auto-incrementing columns in this table, may throw {@link AutoIncOverflow}. - * */ - insert(row: RowType): RowType; - - /** Delete a row equal to `row`. Returns true if something was deleted. */ - delete(row: RowType): boolean; -}; +export type TableMethods = + ReadonlyTableMethods & { + /** + * Insert and return the inserted row (auto-increment fields filled). + * + * May throw on error: + * * If there are any unique or primary key columns in this table, may throw {@link UniqueAlreadyExists}. + * * If there are any auto-incrementing columns in this table, may throw {@link AutoIncOverflow}. + * */ + insert(row: RowType): RowType; + + /** Delete a row equal to `row`. Returns true if something was deleted. */ + delete(row: RowType): boolean; + }; /** * Defines a database table with schema and options @@ -279,7 +293,7 @@ export function table>( }; constraints.push({ name: constraintOpts.name, data }); continue; - } + } if (constraintOpts.constraint === 'primaryKey') { pk.push(...constraintOpts.columns.map(c => colIds.get(c)!)); } @@ -325,9 +339,11 @@ export function table>( } const productType = { - elements: resolveType(MODULE_DEF.typespace, row).value.elements.map(elem => { - return { name: elem.name, algebraicType: elem.algebraicType }; - }), + elements: resolveType(MODULE_DEF.typespace, row).value.elements.map( + elem => { + return { name: elem.name, algebraicType: elem.algebraicType }; + } + ), }; return { diff --git a/crates/bindings-typescript/src/lib/table_schema.ts b/crates/bindings-typescript/src/lib/table_schema.ts index c160989e4a3..540af16673a 100644 --- a/crates/bindings-typescript/src/lib/table_schema.ts +++ b/crates/bindings-typescript/src/lib/table_schema.ts @@ -1,7 +1,7 @@ -import type { ProductType } from "./algebraic_type"; -import type RawTableDefV9 from "./autogen/raw_table_def_v_9_type"; -import type { IndexOpts } from "./indexes"; -import type { ColumnBuilder, Infer, RowBuilder } from "./type_builders"; +import type { ProductType } from './algebraic_type'; +import type RawTableDefV9 from './autogen/raw_table_def_v_9_type'; +import type { IndexOpts } from './indexes'; +import type { ColumnBuilder, Infer, RowBuilder } from './type_builders'; /** * Represents a handle to a database table, including its name, row type, and row spacetime type. @@ -35,4 +35,4 @@ export type TableSchema< * The indexes defined on the table. */ readonly idxs: Idx; -}; \ No newline at end of file +}; diff --git a/crates/bindings-typescript/src/lib/type_builders.ts b/crates/bindings-typescript/src/lib/type_builders.ts index b616e5d27ab..567bae3975f 100644 --- a/crates/bindings-typescript/src/lib/type_builders.ts +++ b/crates/bindings-typescript/src/lib/type_builders.ts @@ -117,9 +117,9 @@ type IsUnit = B extends UnitBuilder ? true : false; * e.g. { A: I32TypeBuilder, B: StringBuilder } -> { tag: "A", value: number } | { tag: "B", value: string } */ type EnumType = { - [K in keyof Variants & string]: - (IsUnit extends true ? { tag: K } - : { tag: K; value: InferTypeOfTypeBuilder }) + [K in keyof Variants & string]: IsUnit extends true + ? { tag: K } + : { tag: K; value: InferTypeOfTypeBuilder }; }[keyof Variants & string]; /** @@ -135,7 +135,8 @@ type VariantsArrayFromVariantsObj = { * and the corresponding `AlgebraicType`. */ export class TypeBuilder - implements Optional { + implements Optional +{ /** * The TypeScript phantom type. This is not stored at runtime, * but is visible to the compiler @@ -247,7 +248,11 @@ interface Indexable< * Specify the index type for this column * @param algorithm The index algorithm to use */ - index(): ColumnBuilder>; + index(): ColumnBuilder< + Type, + SpacetimeType, + SetField + >; index>( algorithm: N ): ColumnBuilder>; @@ -341,11 +346,12 @@ interface Defaultable< export class U8Builder extends TypeBuilder implements - Indexable, - Uniqueable, - PrimaryKeyable, - AutoIncrementable, - Defaultable { + Indexable, + Uniqueable, + PrimaryKeyable, + AutoIncrementable, + Defaultable +{ constructor() { super(AlgebraicType.U8); } @@ -364,13 +370,17 @@ export class U8Builder unique(): U8ColumnBuilder> { return new U8ColumnBuilder(this, set(defaultMetadata, { isUnique: true })); } - primaryKey(): U8ColumnBuilder> { + primaryKey(): U8ColumnBuilder< + SetField + > { return new U8ColumnBuilder( this, set(defaultMetadata, { isPrimaryKey: true }) ); } - autoInc(): U8ColumnBuilder> { + autoInc(): U8ColumnBuilder< + SetField + > { return new U8ColumnBuilder( this, set(defaultMetadata, { isAutoIncrement: true }) @@ -389,11 +399,12 @@ export class U8Builder export class U16Builder extends TypeBuilder implements - Indexable, - Uniqueable, - PrimaryKeyable, - AutoIncrementable, - Defaultable { + Indexable, + Uniqueable, + PrimaryKeyable, + AutoIncrementable, + Defaultable +{ constructor() { super(AlgebraicType.U16); } @@ -412,13 +423,17 @@ export class U16Builder unique(): U16ColumnBuilder> { return new U16ColumnBuilder(this, set(defaultMetadata, { isUnique: true })); } - primaryKey(): U16ColumnBuilder> { + primaryKey(): U16ColumnBuilder< + SetField + > { return new U16ColumnBuilder( this, set(defaultMetadata, { isPrimaryKey: true }) ); } - autoInc(): U16ColumnBuilder> { + autoInc(): U16ColumnBuilder< + SetField + > { return new U16ColumnBuilder( this, set(defaultMetadata, { isAutoIncrement: true }) @@ -437,11 +452,12 @@ export class U16Builder export class U32Builder extends TypeBuilder implements - Indexable, - Uniqueable, - PrimaryKeyable, - AutoIncrementable, - Defaultable { + Indexable, + Uniqueable, + PrimaryKeyable, + AutoIncrementable, + Defaultable +{ constructor() { super(AlgebraicType.U32); } @@ -460,13 +476,17 @@ export class U32Builder unique(): U32ColumnBuilder> { return new U32ColumnBuilder(this, set(defaultMetadata, { isUnique: true })); } - primaryKey(): U32ColumnBuilder> { + primaryKey(): U32ColumnBuilder< + SetField + > { return new U32ColumnBuilder( this, set(defaultMetadata, { isPrimaryKey: true }) ); } - autoInc(): U32ColumnBuilder> { + autoInc(): U32ColumnBuilder< + SetField + > { return new U32ColumnBuilder( this, set(defaultMetadata, { isAutoIncrement: true }) @@ -485,11 +505,12 @@ export class U32Builder export class U64Builder extends TypeBuilder implements - Indexable, - Uniqueable, - PrimaryKeyable, - AutoIncrementable, - Defaultable { + Indexable, + Uniqueable, + PrimaryKeyable, + AutoIncrementable, + Defaultable +{ constructor() { super(AlgebraicType.U64); } @@ -508,13 +529,17 @@ export class U64Builder unique(): U64ColumnBuilder> { return new U64ColumnBuilder(this, set(defaultMetadata, { isUnique: true })); } - primaryKey(): U64ColumnBuilder> { + primaryKey(): U64ColumnBuilder< + SetField + > { return new U64ColumnBuilder( this, set(defaultMetadata, { isPrimaryKey: true }) ); } - autoInc(): U64ColumnBuilder> { + autoInc(): U64ColumnBuilder< + SetField + > { return new U64ColumnBuilder( this, set(defaultMetadata, { isAutoIncrement: true }) @@ -533,11 +558,12 @@ export class U64Builder export class U128Builder extends TypeBuilder implements - Indexable, - Uniqueable, - PrimaryKeyable, - AutoIncrementable, - Defaultable { + Indexable, + Uniqueable, + PrimaryKeyable, + AutoIncrementable, + Defaultable +{ constructor() { super(AlgebraicType.U128); } @@ -559,13 +585,17 @@ export class U128Builder set(defaultMetadata, { isUnique: true }) ); } - primaryKey(): U128ColumnBuilder> { + primaryKey(): U128ColumnBuilder< + SetField + > { return new U128ColumnBuilder( this, set(defaultMetadata, { isPrimaryKey: true }) ); } - autoInc(): U128ColumnBuilder> { + autoInc(): U128ColumnBuilder< + SetField + > { return new U128ColumnBuilder( this, set(defaultMetadata, { isAutoIncrement: true }) @@ -584,11 +614,12 @@ export class U128Builder export class U256Builder extends TypeBuilder implements - Indexable, - Uniqueable, - PrimaryKeyable, - AutoIncrementable, - Defaultable { + Indexable, + Uniqueable, + PrimaryKeyable, + AutoIncrementable, + Defaultable +{ constructor() { super(AlgebraicType.U256); } @@ -610,13 +641,17 @@ export class U256Builder set(defaultMetadata, { isUnique: true }) ); } - primaryKey(): U256ColumnBuilder> { + primaryKey(): U256ColumnBuilder< + SetField + > { return new U256ColumnBuilder( this, set(defaultMetadata, { isPrimaryKey: true }) ); } - autoInc(): U256ColumnBuilder> { + autoInc(): U256ColumnBuilder< + SetField + > { return new U256ColumnBuilder( this, set(defaultMetadata, { isAutoIncrement: true }) @@ -635,11 +670,12 @@ export class U256Builder export class I8Builder extends TypeBuilder implements - Indexable, - Uniqueable, - PrimaryKeyable, - AutoIncrementable, - Defaultable { + Indexable, + Uniqueable, + PrimaryKeyable, + AutoIncrementable, + Defaultable +{ constructor() { super(AlgebraicType.I8); } @@ -658,13 +694,17 @@ export class I8Builder unique(): I8ColumnBuilder> { return new I8ColumnBuilder(this, set(defaultMetadata, { isUnique: true })); } - primaryKey(): I8ColumnBuilder> { + primaryKey(): I8ColumnBuilder< + SetField + > { return new I8ColumnBuilder( this, set(defaultMetadata, { isPrimaryKey: true }) ); } - autoInc(): I8ColumnBuilder> { + autoInc(): I8ColumnBuilder< + SetField + > { return new I8ColumnBuilder( this, set(defaultMetadata, { isAutoIncrement: true }) @@ -683,11 +723,12 @@ export class I8Builder export class I16Builder extends TypeBuilder implements - Indexable, - Uniqueable, - PrimaryKeyable, - AutoIncrementable, - Defaultable { + Indexable, + Uniqueable, + PrimaryKeyable, + AutoIncrementable, + Defaultable +{ constructor() { super(AlgebraicType.I16); } @@ -706,13 +747,17 @@ export class I16Builder unique(): I16ColumnBuilder> { return new I16ColumnBuilder(this, set(defaultMetadata, { isUnique: true })); } - primaryKey(): I16ColumnBuilder> { + primaryKey(): I16ColumnBuilder< + SetField + > { return new I16ColumnBuilder( this, set(defaultMetadata, { isPrimaryKey: true }) ); } - autoInc(): I16ColumnBuilder> { + autoInc(): I16ColumnBuilder< + SetField + > { return new I16ColumnBuilder( this, set(defaultMetadata, { isAutoIncrement: true }) @@ -731,12 +776,13 @@ export class I16Builder export class I32Builder extends TypeBuilder implements - TypeBuilder, - Indexable, - Uniqueable, - PrimaryKeyable, - AutoIncrementable, - Defaultable { + TypeBuilder, + Indexable, + Uniqueable, + PrimaryKeyable, + AutoIncrementable, + Defaultable +{ constructor() { super(AlgebraicType.I32); } @@ -755,13 +801,17 @@ export class I32Builder unique(): I32ColumnBuilder> { return new I32ColumnBuilder(this, set(defaultMetadata, { isUnique: true })); } - primaryKey(): I32ColumnBuilder> { + primaryKey(): I32ColumnBuilder< + SetField + > { return new I32ColumnBuilder( this, set(defaultMetadata, { isPrimaryKey: true }) ); } - autoInc(): I32ColumnBuilder> { + autoInc(): I32ColumnBuilder< + SetField + > { return new I32ColumnBuilder( this, set(defaultMetadata, { isAutoIncrement: true }) @@ -780,11 +830,12 @@ export class I32Builder export class I64Builder extends TypeBuilder implements - Indexable, - Uniqueable, - PrimaryKeyable, - AutoIncrementable, - Defaultable { + Indexable, + Uniqueable, + PrimaryKeyable, + AutoIncrementable, + Defaultable +{ constructor() { super(AlgebraicType.I64); } @@ -803,13 +854,17 @@ export class I64Builder unique(): I64ColumnBuilder> { return new I64ColumnBuilder(this, set(defaultMetadata, { isUnique: true })); } - primaryKey(): I64ColumnBuilder> { + primaryKey(): I64ColumnBuilder< + SetField + > { return new I64ColumnBuilder( this, set(defaultMetadata, { isPrimaryKey: true }) ); } - autoInc(): I64ColumnBuilder> { + autoInc(): I64ColumnBuilder< + SetField + > { return new I64ColumnBuilder( this, set(defaultMetadata, { isAutoIncrement: true }) @@ -828,11 +883,12 @@ export class I64Builder export class I128Builder extends TypeBuilder implements - Indexable, - Uniqueable, - PrimaryKeyable, - AutoIncrementable, - Defaultable { + Indexable, + Uniqueable, + PrimaryKeyable, + AutoIncrementable, + Defaultable +{ constructor() { super(AlgebraicType.I128); } @@ -854,13 +910,17 @@ export class I128Builder set(defaultMetadata, { isUnique: true }) ); } - primaryKey(): I128ColumnBuilder> { + primaryKey(): I128ColumnBuilder< + SetField + > { return new I128ColumnBuilder( this, set(defaultMetadata, { isPrimaryKey: true }) ); } - autoInc(): I128ColumnBuilder> { + autoInc(): I128ColumnBuilder< + SetField + > { return new I128ColumnBuilder( this, set(defaultMetadata, { isAutoIncrement: true }) @@ -879,11 +939,12 @@ export class I128Builder export class I256Builder extends TypeBuilder implements - Indexable, - Uniqueable, - PrimaryKeyable, - AutoIncrementable, - Defaultable { + Indexable, + Uniqueable, + PrimaryKeyable, + AutoIncrementable, + Defaultable +{ constructor() { super(AlgebraicType.I256); } @@ -905,13 +966,17 @@ export class I256Builder set(defaultMetadata, { isUnique: true }) ); } - primaryKey(): I256ColumnBuilder> { + primaryKey(): I256ColumnBuilder< + SetField + > { return new I256ColumnBuilder( this, set(defaultMetadata, { isPrimaryKey: true }) ); } - autoInc(): I256ColumnBuilder> { + autoInc(): I256ColumnBuilder< + SetField + > { return new I256ColumnBuilder( this, set(defaultMetadata, { isAutoIncrement: true }) @@ -929,7 +994,8 @@ export class I256Builder export class F32Builder extends TypeBuilder - implements Defaultable { + implements Defaultable +{ constructor() { super(AlgebraicType.F32); } @@ -945,7 +1011,8 @@ export class F32Builder export class F64Builder extends TypeBuilder - implements Defaultable { + implements Defaultable +{ constructor() { super(AlgebraicType.F64); } @@ -962,10 +1029,11 @@ export class F64Builder export class BoolBuilder extends TypeBuilder implements - Indexable, - Uniqueable, - PrimaryKeyable, - Defaultable { + Indexable, + Uniqueable, + PrimaryKeyable, + Defaultable +{ constructor() { super(AlgebraicType.Bool); } @@ -987,7 +1055,9 @@ export class BoolBuilder set(defaultMetadata, { isUnique: true }) ); } - primaryKey(): BoolColumnBuilder> { + primaryKey(): BoolColumnBuilder< + SetField + > { return new BoolColumnBuilder( this, set(defaultMetadata, { isPrimaryKey: true }) @@ -1006,10 +1076,11 @@ export class BoolBuilder export class StringBuilder extends TypeBuilder implements - Indexable, - Uniqueable, - PrimaryKeyable, - Defaultable { + Indexable, + Uniqueable, + PrimaryKeyable, + Defaultable +{ constructor() { super(AlgebraicType.String); } @@ -1054,7 +1125,8 @@ export class ArrayBuilder> Array>, { tag: 'Array'; value: InferSpacetimeTypeOfTypeBuilder } > - implements Defaultable>, any> { + implements Defaultable>, any> +{ /** * The phantom element type of the array for TypeScript */ @@ -1065,7 +1137,10 @@ export class ArrayBuilder> } default( value: Array> - ): ArrayColumnBuilder> { + ): ArrayColumnBuilder< + Element, + SetField + > { return new ArrayColumnBuilder( this.element, set(defaultMetadata, { defaultValue: value }) @@ -1078,13 +1153,13 @@ export class ByteArrayBuilder Uint8Array, { tag: 'Array'; value: AlgebraicTypeVariants.U8 } > - implements Defaultable { - + implements Defaultable +{ constructor() { super(AlgebraicType.Array(AlgebraicType.U8)); } default( - value: Uint8Array + value: Uint8Array ): ByteArrayColumnBuilder> { return new ByteArrayColumnBuilder( set(defaultMetadata, { defaultValue: value }) @@ -1098,7 +1173,8 @@ export class OptionBuilder> OptionAlgebraicType > implements - Defaultable | undefined, OptionAlgebraicType> { + Defaultable | undefined, OptionAlgebraicType> +{ /** * The phantom value type of the option for TypeScript */ @@ -1138,7 +1214,8 @@ export class ProductBuilder value: { elements: ElementsArrayFromElementsObj }; } > - implements Defaultable, any> { + implements Defaultable, any> +{ readonly typeName: string | undefined; readonly elements: Elements; constructor(elements: Elements, name?: string) { @@ -1158,7 +1235,10 @@ export class ProductBuilder } default( value: ObjectType - ): ProductColumnBuilder> { + ): ProductColumnBuilder< + Elements, + SetField + > { return new ProductColumnBuilder( this, set(defaultMetadata, { defaultValue: value }) @@ -1199,8 +1279,8 @@ export class RowBuilder extends TypeBuilder< // Value type produced for a given variant key + builder type EnumValue> = IsUnit extends true - ? { tag: K } - : { tag: K; value: InferTypeOfTypeBuilder }; + ? { tag: K } + : { tag: K; value: InferTypeOfTypeBuilder }; export class SumBuilder extends TypeBuilder< EnumType, @@ -1232,19 +1312,23 @@ export class SumBuilder extends TypeBuilder< */ create( ...args: IsUnit extends true - ? [tag: K] // unit variant: only the tag + ? [tag: K] // unit variant: only the tag : [tag: K, value: InferTypeOfTypeBuilder] // payload variant: tag + value ): EnumValue { const [tag, value] = args as [K, unknown]; // just return the shape, types guarantee correctness - return (value === undefined - ? { tag } - : { tag, value }) as EnumValue; + return (value === undefined ? { tag } : { tag, value }) as EnumValue< + K, + Variants[K] + >; } default( value: EnumType - ): SumColumnBuilder> { + ): SumColumnBuilder< + Variants, + SetField + > { return new SumColumnBuilder( this, set(defaultMetadata, { defaultValue: value }) @@ -1255,27 +1339,31 @@ export class SumBuilder extends TypeBuilder< export class SimpleSumBuilder extends SumBuilder implements - Indexable< - EnumType, - { - tag: 'Sum'; - value: { variants: VariantsArrayFromVariantsObj }; - } - >, - PrimaryKeyable< - EnumType, - { - tag: 'Sum'; - value: { variants: VariantsArrayFromVariantsObj }; - } - > { + Indexable< + EnumType, + { + tag: 'Sum'; + value: { variants: VariantsArrayFromVariantsObj }; + } + >, + PrimaryKeyable< + EnumType, + { + tag: 'Sum'; + value: { variants: VariantsArrayFromVariantsObj }; + } + > +{ index(): SimpleSumColumnBuilder< Variants, SetField >; index>( algorithm: N - ): SimpleSumColumnBuilder>; + ): SimpleSumColumnBuilder< + Variants, + SetField + >; index( algorithm: IndexTypes = 'btree' ): SimpleSumColumnBuilder< @@ -1301,14 +1389,17 @@ export class SimpleSumBuilder export class IdentityBuilder extends TypeBuilder implements - Indexable, - Uniqueable, - PrimaryKeyable, - Defaultable { + Indexable, + Uniqueable, + PrimaryKeyable, + Defaultable +{ constructor() { super(Identity.getAlgebraicType()); } - index(): IdentityColumnBuilder>; + index(): IdentityColumnBuilder< + SetField + >; index>( algorithm: N ): IdentityColumnBuilder>; @@ -1344,7 +1435,9 @@ export class IdentityBuilder } default( value: Identity - ): IdentityColumnBuilder> { + ): IdentityColumnBuilder< + SetField + > { return new IdentityColumnBuilder( this, set(defaultMetadata, { defaultValue: value }) @@ -1355,10 +1448,11 @@ export class IdentityBuilder export class ConnectionIdBuilder extends TypeBuilder implements - Indexable, - Uniqueable, - PrimaryKeyable, - Defaultable { + Indexable, + Uniqueable, + PrimaryKeyable, + Defaultable +{ constructor() { super(ConnectionId.getAlgebraicType()); } @@ -1370,13 +1464,17 @@ export class ConnectionIdBuilder ): ConnectionIdColumnBuilder>; index( algorithm: IndexTypes = 'btree' - ): ConnectionIdColumnBuilder> { + ): ConnectionIdColumnBuilder< + SetField + > { return new ConnectionIdColumnBuilder( this, set(defaultMetadata, { indexType: algorithm }) ); } - unique(): ConnectionIdColumnBuilder> { + unique(): ConnectionIdColumnBuilder< + SetField + > { return new ConnectionIdColumnBuilder( this, set(defaultMetadata, { isUnique: true }) @@ -1413,26 +1511,33 @@ export class ConnectionIdBuilder export class TimestampBuilder extends TypeBuilder implements - Indexable, - Uniqueable, - PrimaryKeyable, - Defaultable { + Indexable, + Uniqueable, + PrimaryKeyable, + Defaultable +{ constructor() { super(Timestamp.getAlgebraicType()); } - index(): TimestampColumnBuilder>; + index(): TimestampColumnBuilder< + SetField + >; index>( algorithm: N ): TimestampColumnBuilder>; index( algorithm: IndexTypes = 'btree' - ): TimestampColumnBuilder> { + ): TimestampColumnBuilder< + SetField + > { return new TimestampColumnBuilder( this, set(defaultMetadata, { indexType: algorithm }) ); } - unique(): TimestampColumnBuilder> { + unique(): TimestampColumnBuilder< + SetField + > { return new TimestampColumnBuilder( this, set(defaultMetadata, { isUnique: true }) @@ -1456,7 +1561,9 @@ export class TimestampBuilder } default( value: Timestamp - ): TimestampColumnBuilder> { + ): TimestampColumnBuilder< + SetField + > { return new TimestampColumnBuilder( this, set(defaultMetadata, { defaultValue: value }) @@ -1467,10 +1574,11 @@ export class TimestampBuilder export class TimeDurationBuilder extends TypeBuilder implements - Indexable, - Uniqueable, - PrimaryKeyable, - Defaultable { + Indexable, + Uniqueable, + PrimaryKeyable, + Defaultable +{ constructor() { super(TimeDuration.getAlgebraicType()); } @@ -1482,13 +1590,17 @@ export class TimeDurationBuilder ): TimeDurationColumnBuilder>; index( algorithm: IndexTypes = 'btree' - ): TimeDurationColumnBuilder> { + ): TimeDurationColumnBuilder< + SetField + > { return new TimeDurationColumnBuilder( this, set(defaultMetadata, { indexType: algorithm }) ); } - unique(): TimeDurationColumnBuilder> { + unique(): TimeDurationColumnBuilder< + SetField + > { return new TimeDurationColumnBuilder( this, set(defaultMetadata, { isUnique: true }) @@ -1556,8 +1668,8 @@ const defaultMetadata: ColumnMetadata = {}; * * It carries both a phantom TypeScript type (the `Type`) and * runtime algebraic type information. - * - * IMPORTANT! We have deliberately chosen to not have {@link ColumnBuilder} + * + * IMPORTANT! We have deliberately chosen to not have {@link ColumnBuilder} * extend {@link TypeBuilder} so that you cannot pass a {@link ColumnBuilder} * where a {@link TypeBuilder} is expected. i.e. We want to maintain * contravariance for functions that accept {@link TypeBuilder} parameters. @@ -1579,11 +1691,12 @@ export class ColumnBuilder< export class U8ColumnBuilder = DefaultMetadata> extends ColumnBuilder implements - Indexable, - Uniqueable, - PrimaryKeyable, - AutoIncrementable, - Defaultable { + Indexable, + Uniqueable, + PrimaryKeyable, + AutoIncrementable, + Defaultable +{ index(): U8ColumnBuilder>; index>( algorithm: N @@ -1615,22 +1728,26 @@ export class U8ColumnBuilder = DefaultMetadata> ); } default(value: number): U8ColumnBuilder> { - return new U8ColumnBuilder(this.typeBuilder, set(this.columnMetadata, { - defaultValue: value, - })); + return new U8ColumnBuilder( + this.typeBuilder, + set(this.columnMetadata, { + defaultValue: value, + }) + ); } } export class U16ColumnBuilder< - M extends ColumnMetadata = DefaultMetadata, -> + M extends ColumnMetadata = DefaultMetadata, + > extends ColumnBuilder implements - Indexable, - Uniqueable, - PrimaryKeyable, - AutoIncrementable, - Defaultable { + Indexable, + Uniqueable, + PrimaryKeyable, + AutoIncrementable, + Defaultable +{ index(): U16ColumnBuilder>; index>( algorithm: N @@ -1661,23 +1778,29 @@ export class U16ColumnBuilder< set(this.columnMetadata, { isAutoIncrement: true }) ); } - default(value: number): U16ColumnBuilder> { - return new U16ColumnBuilder(this.typeBuilder, set(this.columnMetadata, { - defaultValue: value, - })); + default( + value: number + ): U16ColumnBuilder> { + return new U16ColumnBuilder( + this.typeBuilder, + set(this.columnMetadata, { + defaultValue: value, + }) + ); } } export class U32ColumnBuilder< - M extends ColumnMetadata = DefaultMetadata, -> + M extends ColumnMetadata = DefaultMetadata, + > extends ColumnBuilder implements - Indexable, - Uniqueable, - PrimaryKeyable, - AutoIncrementable, - Defaultable { + Indexable, + Uniqueable, + PrimaryKeyable, + AutoIncrementable, + Defaultable +{ index(): U32ColumnBuilder>; index>( algorithm: N @@ -1708,23 +1831,29 @@ export class U32ColumnBuilder< set(this.columnMetadata, { isAutoIncrement: true }) ); } - default(value: number): U32ColumnBuilder> { - return new U32ColumnBuilder(this.typeBuilder, set(this.columnMetadata, { - defaultValue: value, - })); + default( + value: number + ): U32ColumnBuilder> { + return new U32ColumnBuilder( + this.typeBuilder, + set(this.columnMetadata, { + defaultValue: value, + }) + ); } } export class U64ColumnBuilder< - M extends ColumnMetadata = DefaultMetadata, -> + M extends ColumnMetadata = DefaultMetadata, + > extends ColumnBuilder implements - Indexable, - Uniqueable, - PrimaryKeyable, - AutoIncrementable, - Defaultable { + Indexable, + Uniqueable, + PrimaryKeyable, + AutoIncrementable, + Defaultable +{ index(): U64ColumnBuilder>; index>( algorithm: N @@ -1755,23 +1884,29 @@ export class U64ColumnBuilder< set(this.columnMetadata, { isAutoIncrement: true }) ); } - default(value: bigint): U64ColumnBuilder> { - return new U64ColumnBuilder(this.typeBuilder, set(this.columnMetadata, { - defaultValue: value, - })); + default( + value: bigint + ): U64ColumnBuilder> { + return new U64ColumnBuilder( + this.typeBuilder, + set(this.columnMetadata, { + defaultValue: value, + }) + ); } } export class U128ColumnBuilder< - M extends ColumnMetadata = DefaultMetadata, -> + M extends ColumnMetadata = DefaultMetadata, + > extends ColumnBuilder implements - Indexable, - Uniqueable, - PrimaryKeyable, - AutoIncrementable, - Defaultable { + Indexable, + Uniqueable, + PrimaryKeyable, + AutoIncrementable, + Defaultable +{ index(): U128ColumnBuilder>; index>( algorithm: N @@ -1802,23 +1937,29 @@ export class U128ColumnBuilder< set(this.columnMetadata, { isAutoIncrement: true }) ); } - default(value: bigint): U128ColumnBuilder> { - return new U128ColumnBuilder(this.typeBuilder, set(this.columnMetadata, { - defaultValue: value, - })); + default( + value: bigint + ): U128ColumnBuilder> { + return new U128ColumnBuilder( + this.typeBuilder, + set(this.columnMetadata, { + defaultValue: value, + }) + ); } } export class U256ColumnBuilder< - M extends ColumnMetadata = DefaultMetadata, -> + M extends ColumnMetadata = DefaultMetadata, + > extends ColumnBuilder implements - Indexable, - Uniqueable, - PrimaryKeyable, - AutoIncrementable, - Defaultable { + Indexable, + Uniqueable, + PrimaryKeyable, + AutoIncrementable, + Defaultable +{ index(): U256ColumnBuilder>; index>( algorithm: N @@ -1849,21 +1990,27 @@ export class U256ColumnBuilder< set(this.columnMetadata, { isAutoIncrement: true }) ); } - default(value: bigint): U256ColumnBuilder> { - return new U256ColumnBuilder(this.typeBuilder, set(this.columnMetadata, { - defaultValue: value, - })); + default( + value: bigint + ): U256ColumnBuilder> { + return new U256ColumnBuilder( + this.typeBuilder, + set(this.columnMetadata, { + defaultValue: value, + }) + ); } } export class I8ColumnBuilder = DefaultMetadata> extends ColumnBuilder implements - Indexable, - Uniqueable, - PrimaryKeyable, - AutoIncrementable, - Defaultable { + Indexable, + Uniqueable, + PrimaryKeyable, + AutoIncrementable, + Defaultable +{ index(): I8ColumnBuilder>; index>( algorithm: N @@ -1895,22 +2042,26 @@ export class I8ColumnBuilder = DefaultMetadata> ); } default(value: number): I8ColumnBuilder> { - return new I8ColumnBuilder(this.typeBuilder, set(this.columnMetadata, { - defaultValue: value, - })); + return new I8ColumnBuilder( + this.typeBuilder, + set(this.columnMetadata, { + defaultValue: value, + }) + ); } } export class I16ColumnBuilder< - M extends ColumnMetadata = DefaultMetadata, -> + M extends ColumnMetadata = DefaultMetadata, + > extends ColumnBuilder implements - Indexable, - Uniqueable, - PrimaryKeyable, - AutoIncrementable, - Defaultable { + Indexable, + Uniqueable, + PrimaryKeyable, + AutoIncrementable, + Defaultable +{ index(): I16ColumnBuilder>; index>( algorithm: N @@ -1941,23 +2092,29 @@ export class I16ColumnBuilder< set(this.columnMetadata, { isAutoIncrement: true }) ); } - default(value: number): I16ColumnBuilder> { - return new I16ColumnBuilder(this.typeBuilder, set(this.columnMetadata, { - defaultValue: value, - })); + default( + value: number + ): I16ColumnBuilder> { + return new I16ColumnBuilder( + this.typeBuilder, + set(this.columnMetadata, { + defaultValue: value, + }) + ); } } export class I32ColumnBuilder< - M extends ColumnMetadata = DefaultMetadata, -> + M extends ColumnMetadata = DefaultMetadata, + > extends ColumnBuilder implements - Indexable, - Uniqueable, - PrimaryKeyable, - AutoIncrementable, - Defaultable { + Indexable, + Uniqueable, + PrimaryKeyable, + AutoIncrementable, + Defaultable +{ index(): I32ColumnBuilder>; index>( algorithm: N @@ -1988,23 +2145,29 @@ export class I32ColumnBuilder< set(this.columnMetadata, { isAutoIncrement: true }) ); } - default(value: number): I32ColumnBuilder> { - return new I32ColumnBuilder(this.typeBuilder, set(this.columnMetadata, { - defaultValue: value, - })); + default( + value: number + ): I32ColumnBuilder> { + return new I32ColumnBuilder( + this.typeBuilder, + set(this.columnMetadata, { + defaultValue: value, + }) + ); } } export class I64ColumnBuilder< - M extends ColumnMetadata = DefaultMetadata, -> + M extends ColumnMetadata = DefaultMetadata, + > extends ColumnBuilder implements - Indexable, - Uniqueable, - PrimaryKeyable, - AutoIncrementable, - Defaultable { + Indexable, + Uniqueable, + PrimaryKeyable, + AutoIncrementable, + Defaultable +{ index(): I64ColumnBuilder>; index>( algorithm: N @@ -2035,23 +2198,29 @@ export class I64ColumnBuilder< set(this.columnMetadata, { isAutoIncrement: true }) ); } - default(value: bigint): I64ColumnBuilder> { - return new I64ColumnBuilder(this.typeBuilder, set(this.columnMetadata, { - defaultValue: value, - })); + default( + value: bigint + ): I64ColumnBuilder> { + return new I64ColumnBuilder( + this.typeBuilder, + set(this.columnMetadata, { + defaultValue: value, + }) + ); } } export class I128ColumnBuilder< - M extends ColumnMetadata = DefaultMetadata, -> + M extends ColumnMetadata = DefaultMetadata, + > extends ColumnBuilder implements - Indexable, - Uniqueable, - PrimaryKeyable, - AutoIncrementable, - Defaultable { + Indexable, + Uniqueable, + PrimaryKeyable, + AutoIncrementable, + Defaultable +{ index(): I128ColumnBuilder>; index>( algorithm: N @@ -2082,23 +2251,29 @@ export class I128ColumnBuilder< set(this.columnMetadata, { isAutoIncrement: true }) ); } - default(value: bigint): I128ColumnBuilder> { - return new I128ColumnBuilder(this.typeBuilder, set(this.columnMetadata, { - defaultValue: value, - })); + default( + value: bigint + ): I128ColumnBuilder> { + return new I128ColumnBuilder( + this.typeBuilder, + set(this.columnMetadata, { + defaultValue: value, + }) + ); } } export class I256ColumnBuilder< - M extends ColumnMetadata = DefaultMetadata, -> + M extends ColumnMetadata = DefaultMetadata, + > extends ColumnBuilder implements - Indexable, - Uniqueable, - PrimaryKeyable, - AutoIncrementable, - Defaultable { + Indexable, + Uniqueable, + PrimaryKeyable, + AutoIncrementable, + Defaultable +{ index(): I256ColumnBuilder>; index>( algorithm: N @@ -2129,46 +2304,64 @@ export class I256ColumnBuilder< set(this.columnMetadata, { isAutoIncrement: true }) ); } - default(value: bigint): I256ColumnBuilder> { - return new I256ColumnBuilder(this.typeBuilder, set(this.columnMetadata, { - defaultValue: value, - })); + default( + value: bigint + ): I256ColumnBuilder> { + return new I256ColumnBuilder( + this.typeBuilder, + set(this.columnMetadata, { + defaultValue: value, + }) + ); } } export class F32ColumnBuilder< - M extends ColumnMetadata = DefaultMetadata, -> + M extends ColumnMetadata = DefaultMetadata, + > extends ColumnBuilder - implements Defaultable { - default(value: number): F32ColumnBuilder> { - return new F32ColumnBuilder(this.typeBuilder, set(this.columnMetadata, { - defaultValue: value, - })); + implements Defaultable +{ + default( + value: number + ): F32ColumnBuilder> { + return new F32ColumnBuilder( + this.typeBuilder, + set(this.columnMetadata, { + defaultValue: value, + }) + ); } } export class F64ColumnBuilder< - M extends ColumnMetadata = DefaultMetadata, -> + M extends ColumnMetadata = DefaultMetadata, + > extends ColumnBuilder - implements Defaultable { - default(value: number): F64ColumnBuilder> { - return new F64ColumnBuilder(this.typeBuilder, set(this.columnMetadata, { - defaultValue: value, - })); + implements Defaultable +{ + default( + value: number + ): F64ColumnBuilder> { + return new F64ColumnBuilder( + this.typeBuilder, + set(this.columnMetadata, { + defaultValue: value, + }) + ); } } export class BoolColumnBuilder< - M extends ColumnMetadata = DefaultMetadata, -> + M extends ColumnMetadata = DefaultMetadata, + > extends ColumnBuilder implements - Indexable, - Uniqueable, - PrimaryKeyable, - Defaultable { + Indexable, + Uniqueable, + PrimaryKeyable, + Defaultable +{ index(): BoolColumnBuilder>; index>( algorithm: N @@ -2193,22 +2386,28 @@ export class BoolColumnBuilder< set(this.columnMetadata, { isPrimaryKey: true }) ); } - default(value: boolean): BoolColumnBuilder> { - return new BoolColumnBuilder(this.typeBuilder, set(this.columnMetadata, { - defaultValue: value, - })); + default( + value: boolean + ): BoolColumnBuilder> { + return new BoolColumnBuilder( + this.typeBuilder, + set(this.columnMetadata, { + defaultValue: value, + }) + ); } } export class StringColumnBuilder< - M extends ColumnMetadata = DefaultMetadata, -> + M extends ColumnMetadata = DefaultMetadata, + > extends ColumnBuilder implements - Indexable, - Uniqueable, - PrimaryKeyable, - Defaultable { + Indexable, + Uniqueable, + PrimaryKeyable, + Defaultable +{ index(): StringColumnBuilder>; index>( algorithm: N @@ -2233,80 +2432,98 @@ export class StringColumnBuilder< set(this.columnMetadata, { isPrimaryKey: true }) ); } - default(value: string): StringColumnBuilder> { - return new StringColumnBuilder(this.typeBuilder, set(this.columnMetadata, { - defaultValue: value, - })); + default( + value: string + ): StringColumnBuilder> { + return new StringColumnBuilder( + this.typeBuilder, + set(this.columnMetadata, { + defaultValue: value, + }) + ); } } export class ArrayColumnBuilder< - Element extends TypeBuilder, - M extends ColumnMetadata< - Array> - > = DefaultMetadata, -> + Element extends TypeBuilder, + M extends ColumnMetadata< + Array> + > = DefaultMetadata, + > extends ColumnBuilder< Array>, { tag: 'Array'; value: InferSpacetimeTypeOfTypeBuilder }, M > implements - Defaultable< - Array>, - AlgebraicTypeVariants.Array - > { + Defaultable< + Array>, + AlgebraicTypeVariants.Array + > +{ default( value: Array> ): ArrayColumnBuilder< Element, SetField>> > { - return new ArrayColumnBuilder(this.typeBuilder, set(this.columnMetadata, { - defaultValue: value, - })); + return new ArrayColumnBuilder( + this.typeBuilder, + set(this.columnMetadata, { + defaultValue: value, + }) + ); } } -export class ByteArrayColumnBuilder = DefaultMetadata> - extends ColumnBuilder = DefaultMetadata, +> extends ColumnBuilder< + Uint8Array, + { tag: 'Array'; value: AlgebraicTypeVariants.U8; - }, M> { + }, + M +> { constructor(metadata: M) { super(new TypeBuilder(AlgebraicType.Array(AlgebraicType.U8)), metadata); } } export class OptionColumnBuilder< - Value extends TypeBuilder, - M extends ColumnMetadata< - InferTypeOfTypeBuilder | undefined - > = DefaultMetadata, -> + Value extends TypeBuilder, + M extends ColumnMetadata< + InferTypeOfTypeBuilder | undefined + > = DefaultMetadata, + > extends ColumnBuilder< InferTypeOfTypeBuilder | undefined, OptionAlgebraicType, M > implements - Defaultable | undefined, OptionAlgebraicType> { + Defaultable | undefined, OptionAlgebraicType> +{ default( value: InferTypeOfTypeBuilder | undefined ): OptionColumnBuilder< Value, SetField | undefined> > { - return new OptionColumnBuilder(this.typeBuilder, set(this.columnMetadata, { - defaultValue: value, - })); + return new OptionColumnBuilder( + this.typeBuilder, + set(this.columnMetadata, { + defaultValue: value, + }) + ); } } export class ProductColumnBuilder< - Elements extends ElementsObj, - M extends ColumnMetadata> = DefaultMetadata, -> + Elements extends ElementsObj, + M extends ColumnMetadata> = DefaultMetadata, + > extends ColumnBuilder< ObjectType, { @@ -2315,10 +2532,14 @@ export class ProductColumnBuilder< }, M > - implements Defaultable, AlgebraicTypeVariants.Product> { + implements Defaultable, AlgebraicTypeVariants.Product> +{ default( value: ObjectType - ): ProductColumnBuilder> { + ): ProductColumnBuilder< + Elements, + SetField + > { return new ProductColumnBuilder( this.typeBuilder, set(this.columnMetadata, { defaultValue: value }) @@ -2327,18 +2548,22 @@ export class ProductColumnBuilder< } export class SumColumnBuilder< - Variants extends VariantsObj, - M extends ColumnMetadata> = DefaultMetadata, -> + Variants extends VariantsObj, + M extends ColumnMetadata> = DefaultMetadata, + > extends ColumnBuilder< EnumType, { tag: 'Sum'; value: { variants: VariantsArrayFromVariantsObj } }, M > - implements Defaultable, AlgebraicTypeVariants.Sum> { + implements Defaultable, AlgebraicTypeVariants.Sum> +{ default( value: EnumType - ): SumColumnBuilder> { + ): SumColumnBuilder< + Variants, + SetField + > { return new SumColumnBuilder( this.typeBuilder, set(this.columnMetadata, { defaultValue: value }) @@ -2347,20 +2572,24 @@ export class SumColumnBuilder< } export class SimpleSumColumnBuilder< - Variants extends VariantsObj, - M extends ColumnMetadata> = DefaultMetadata, -> + Variants extends VariantsObj, + M extends ColumnMetadata> = DefaultMetadata, + > extends SumColumnBuilder implements - Indexable, AlgebraicTypeVariants.Sum>, - PrimaryKeyable, AlgebraicTypeVariants.Sum> { + Indexable, AlgebraicTypeVariants.Sum>, + PrimaryKeyable, AlgebraicTypeVariants.Sum> +{ index(): SimpleSumColumnBuilder< Variants, SetField >; index>( algorithm: N - ): SimpleSumColumnBuilder>; + ): SimpleSumColumnBuilder< + Variants, + SetField + >; index( algorithm: IndexTypes = 'btree' ): SimpleSumColumnBuilder< @@ -2384,14 +2613,15 @@ export class SimpleSumColumnBuilder< } export class IdentityColumnBuilder< - M extends ColumnMetadata = DefaultMetadata, -> + M extends ColumnMetadata = DefaultMetadata, + > extends ColumnBuilder implements - Indexable, - Uniqueable, - PrimaryKeyable, - Defaultable { + Indexable, + Uniqueable, + PrimaryKeyable, + Defaultable +{ index(): IdentityColumnBuilder>; index>( algorithm: N @@ -2419,19 +2649,23 @@ export class IdentityColumnBuilder< default( value: Identity ): IdentityColumnBuilder> { - return new IdentityColumnBuilder(this.typeBuilder, set(this.columnMetadata, { defaultValue: value })); + return new IdentityColumnBuilder( + this.typeBuilder, + set(this.columnMetadata, { defaultValue: value }) + ); } } export class ConnectionIdColumnBuilder< - M extends ColumnMetadata = DefaultMetadata, -> + M extends ColumnMetadata = DefaultMetadata, + > extends ColumnBuilder implements - Indexable, - Uniqueable, - PrimaryKeyable, - Defaultable { + Indexable, + Uniqueable, + PrimaryKeyable, + Defaultable +{ index(): ConnectionIdColumnBuilder>; index>( algorithm: N @@ -2459,19 +2693,23 @@ export class ConnectionIdColumnBuilder< default( value: ConnectionId ): ConnectionIdColumnBuilder> { - return new ConnectionIdColumnBuilder(this.typeBuilder, set(this.columnMetadata, { defaultValue: value })); + return new ConnectionIdColumnBuilder( + this.typeBuilder, + set(this.columnMetadata, { defaultValue: value }) + ); } } export class TimestampColumnBuilder< - M extends ColumnMetadata = DefaultMetadata, -> + M extends ColumnMetadata = DefaultMetadata, + > extends ColumnBuilder implements - Indexable, - Uniqueable, - PrimaryKeyable, - Defaultable { + Indexable, + Uniqueable, + PrimaryKeyable, + Defaultable +{ index(): TimestampColumnBuilder>; index>( algorithm: N @@ -2499,19 +2737,23 @@ export class TimestampColumnBuilder< default( value: Timestamp ): TimestampColumnBuilder> { - return new TimestampColumnBuilder(this.typeBuilder, set(this.columnMetadata, { defaultValue: value })); + return new TimestampColumnBuilder( + this.typeBuilder, + set(this.columnMetadata, { defaultValue: value }) + ); } } export class TimeDurationColumnBuilder< - M extends ColumnMetadata = DefaultMetadata, -> + M extends ColumnMetadata = DefaultMetadata, + > extends ColumnBuilder implements - Indexable, - Uniqueable, - PrimaryKeyable, - Defaultable { + Indexable, + Uniqueable, + PrimaryKeyable, + Defaultable +{ index(): TimeDurationColumnBuilder>; index>( algorithm: N @@ -2539,7 +2781,10 @@ export class TimeDurationColumnBuilder< default( value: TimeDuration ): TimeDurationColumnBuilder> { - return new TimeDurationColumnBuilder(this.typeBuilder, set(this.columnMetadata, { defaultValue: value })); + return new TimeDurationColumnBuilder( + this.typeBuilder, + set(this.columnMetadata, { defaultValue: value }) + ); } } @@ -2592,10 +2837,10 @@ const enumImpl = ((nameOrObj: any, maybeObj?: any) => { let obj: any = nameOrObj; let name: string | undefined = undefined; - if (typeof nameOrObj === "string") { + if (typeof nameOrObj === 'string') { if (!maybeObj) { throw new TypeError( - "When providing a name, you must also provide the variants object or array." + 'When providing a name, you must also provide the variants object or array.' ); } obj = maybeObj; @@ -2834,9 +3079,9 @@ export const t = { /** * Creates a lazily-evaluated {@link TypeBuilder}. This is useful for creating - * recursive types, such as a tree or linked list. + * recursive types, such as a tree or linked list. * @param thunk A function that returns a {@link TypeBuilder}. - * @returns A proxy {@link TypeBuilder} that evaluates the thunk on first access. + * @returns A proxy {@link TypeBuilder} that evaluates the thunk on first access. */ lazy TypeBuilder>( thunk: Build @@ -2849,7 +3094,7 @@ export const t = { get(_t, prop, recv) { const target = get() as any; const val = Reflect.get(target, prop, recv); - return typeof val === "function" ? val.bind(target) : val; + return typeof val === 'function' ? val.bind(target) : val; }, set(_t, prop, value, recv) { return Reflect.set(get() as any, prop, value, recv); @@ -2937,7 +3182,7 @@ export const t = { /** * This is a convenience method for creating a column with the {@link ByteArray} type. - * You can create a column of the same type by constructing an `array` of `u8`. + * You can create a column of the same type by constructing an `array` of `u8`. * The TypeScript representation is {@link Uint8Array}. * @returns A new {@link ByteArrayBuilder} instance with the {@link ByteArray} type. */ diff --git a/crates/bindings-typescript/src/lib/type_util.ts b/crates/bindings-typescript/src/lib/type_util.ts index 1c0bc697284..55aa63ec162 100644 --- a/crates/bindings-typescript/src/lib/type_util.ts +++ b/crates/bindings-typescript/src/lib/type_util.ts @@ -1,16 +1,22 @@ -import type { ConnectionId } from "./connection_id"; -import type { Identity } from "./identity"; -import type { ScheduleAt } from "./schedule_at"; -import type { TimeDuration } from "./time_duration"; -import type { Timestamp } from "./timestamp"; - -type DoNotPrettify = Identity | ConnectionId | Timestamp | TimeDuration | ScheduleAt; +import type { ConnectionId } from './connection_id'; +import type { Identity } from './identity'; +import type { ScheduleAt } from './schedule_at'; +import type { TimeDuration } from './time_duration'; +import type { Timestamp } from './timestamp'; + +type DoNotPrettify = + | Identity + | ConnectionId + | Timestamp + | TimeDuration + | ScheduleAt; /** * Utility to make TS show cleaner types by flattening intersections. */ -export type Prettify = - T extends DoNotPrettify ? T : { [K in keyof T]: T[K] } & {}; +export type Prettify = T extends DoNotPrettify + ? T + : { [K in keyof T]: T[K] } & {}; /** * Helper function to sets a field in an object @@ -42,14 +48,15 @@ export type Values = T[keyof T]; */ export type CollapseTuple
= A extends [infer T] ? T : A; -type CamelCaseImpl = - S extends `${infer Head}_${infer Tail}` ? `${Head}${Capitalize>}` : - S extends `${infer Head}-${infer Tail}` ? `${Head}${Capitalize>}` : - S; +type CamelCaseImpl = S extends `${infer Head}_${infer Tail}` + ? `${Head}${Capitalize>}` + : S extends `${infer Head}-${infer Tail}` + ? `${Head}${Capitalize>}` + : S; /** * Convert "Some_identifier-name" -> "someIdentifierName" * - No spaces; allowed separators: "_" and "-" * - Normalizes the *first* character to lowercase (e.g. "User_Name" -> "userName") */ -export type CamelCase = Uncapitalize>; \ No newline at end of file +export type CamelCase = Uncapitalize>; diff --git a/crates/bindings-typescript/src/react/SpacetimeDBProvider.ts b/crates/bindings-typescript/src/react/SpacetimeDBProvider.ts index 26ccbb78c89..5c10b2aed8c 100644 --- a/crates/bindings-typescript/src/react/SpacetimeDBProvider.ts +++ b/crates/bindings-typescript/src/react/SpacetimeDBProvider.ts @@ -18,7 +18,10 @@ export interface SpacetimeDBProviderProps< export function SpacetimeDBProvider< DbConnection extends DbConnectionImpl, ->({ connectionBuilder, children }: SpacetimeDBProviderProps): React.JSX.Element { +>({ + connectionBuilder, + children, +}: SpacetimeDBProviderProps): React.JSX.Element { // Holds the imperative connection instance when (and only when) we’re on the client. const connRef = React.useRef(null); const getConnection = React.useCallback(() => connRef.current, []); @@ -29,7 +32,7 @@ export function SpacetimeDBProvider< token: undefined, connectionId: ConnectionId.random(), connectionError: undefined, - getConnection: getConnection as ConnectionState["getConnection"], + getConnection: getConnection as ConnectionState['getConnection'], }); // Build on the client only; useEffect won't run during SSR. @@ -37,7 +40,7 @@ export function SpacetimeDBProvider< if (!connRef.current) { connRef.current = connectionBuilder.build(); } - console.log("HAPPPP"); + console.log('HAPPPP'); // Register callback for onConnect to update state const onConnect = (conn: DbConnection) => { setState(s => ({ @@ -48,13 +51,18 @@ export function SpacetimeDBProvider< connectionId: conn.connectionId, })); }; - const onDisconnect = (ctx: ErrorContextInterface>) => { + const onDisconnect = ( + ctx: ErrorContextInterface> + ) => { setState(s => ({ ...s, isActive: ctx.isActive, })); }; - const onConnectError = (ctx: ErrorContextInterface>, err: Error) => { + const onConnectError = ( + ctx: ErrorContextInterface>, + err: Error + ) => { setState(s => ({ ...s, isActive: ctx.isActive, @@ -88,4 +96,4 @@ export function SpacetimeDBProvider< { value: state }, children ); - } \ No newline at end of file +} diff --git a/crates/bindings-typescript/src/react/connection_state.ts b/crates/bindings-typescript/src/react/connection_state.ts index f9c333c100f..056a3c7b3d3 100644 --- a/crates/bindings-typescript/src/react/connection_state.ts +++ b/crates/bindings-typescript/src/react/connection_state.ts @@ -1,6 +1,6 @@ -import type { ConnectionId } from "../lib/connection_id"; -import type { Identity } from "../lib/identity"; -import type { DbConnectionImpl } from "../sdk/db_connection_impl"; +import type { ConnectionId } from '../lib/connection_id'; +import type { Identity } from '../lib/identity'; +import type { DbConnectionImpl } from '../sdk/db_connection_impl'; export type ConnectionState = { isActive: boolean; @@ -8,5 +8,7 @@ export type ConnectionState = { token?: string; connectionId: ConnectionId; connectionError?: Error; - getConnection>(): DbConnection | null; + getConnection< + DbConnection extends DbConnectionImpl, + >(): DbConnection | null; }; diff --git a/crates/bindings-typescript/src/react/useReducer.ts b/crates/bindings-typescript/src/react/useReducer.ts index 3d43e672718..6a16f1a2a38 100644 --- a/crates/bindings-typescript/src/react/useReducer.ts +++ b/crates/bindings-typescript/src/react/useReducer.ts @@ -1,17 +1,18 @@ -import { useCallback, useEffect, useRef } from "react"; -import type { InferTypeOfRow } from "../lib/type_builders"; -import type { UntypedReducerDef } from "../sdk/reducers"; -import { useSpacetimeDB, } from "./useSpacetimeDB"; +import { useCallback, useEffect, useRef } from 'react'; +import type { InferTypeOfRow } from '../lib/type_builders'; +import type { UntypedReducerDef } from '../sdk/reducers'; +import { useSpacetimeDB } from './useSpacetimeDB'; +import type { Prettify } from '../lib/type_util'; export function useReducer( - reducerDef: ReducerDef, -): (params: InferTypeOfRow) => void { + reducerDef: ReducerDef +): (params: Prettify>) => void { const { getConnection, isActive } = useSpacetimeDB(); const reducerName = reducerDef.accessorName; // Holds calls made before the connection exists const queueRef = useRef< - Array> + Array>> >([]); // Flush when we finally have a connection @@ -20,26 +21,27 @@ export function useReducer( if (!conn) { return; } - const fn = - (conn.reducers as any)[reducerName] as - (p: InferTypeOfRow) => void; + const fn = (conn.reducers as any)[reducerName] as ( + p: InferTypeOfRow + ) => void; if (queueRef.current.length) { const pending = queueRef.current.splice(0); for (const params of pending) fn(params); } }, [getConnection, reducerName, isActive]); - return useCallback(( - params: InferTypeOfRow - ) => { - const conn = getConnection(); - if (!conn) { - queueRef.current.push(params); - return; - } - const fn = - (conn.reducers as any)[reducerName] as - (p: InferTypeOfRow) => void; - return fn(params); - }, [getConnection, reducerName]); -} \ No newline at end of file + return useCallback( + (params: Prettify>) => { + const conn = getConnection(); + if (!conn) { + queueRef.current.push(params); + return; + } + const fn = (conn.reducers as any)[reducerName] as ( + p: Prettify> + ) => void; + return fn(params); + }, + [getConnection, reducerName] + ); +} diff --git a/crates/bindings-typescript/src/react/useSpacetimeDB.ts b/crates/bindings-typescript/src/react/useSpacetimeDB.ts index 619a5b39dea..9298eb3fda4 100644 --- a/crates/bindings-typescript/src/react/useSpacetimeDB.ts +++ b/crates/bindings-typescript/src/react/useSpacetimeDB.ts @@ -3,7 +3,9 @@ import type { DbConnectionImpl } from '../sdk/db_connection_impl'; import type { ConnectionState } from './connection_state'; import type { UntypedRemoteModule } from '../sdk/spacetime_module'; -export const SpacetimeDBContext = createContext(undefined); +export const SpacetimeDBContext = createContext( + undefined +); // Throws an error if used outside of a SpacetimeDBProvider // Error is caught by other hooks like useTable so they can provide better error messages @@ -15,4 +17,4 @@ export function useSpacetimeDB(): ConnectionState { ); } return context; -} \ No newline at end of file +} diff --git a/crates/bindings-typescript/src/react/useTable.ts b/crates/bindings-typescript/src/react/useTable.ts index fe337e1780c..98b4d55a68c 100644 --- a/crates/bindings-typescript/src/react/useTable.ts +++ b/crates/bindings-typescript/src/react/useTable.ts @@ -206,13 +206,11 @@ type ColumnsFromRow = { * }); * ``` */ -export function useTable< - TableDef extends UntypedTableDef, ->( +export function useTable( tableDef: TableDef, where: Expr>>, - callbacks?: UseTableCallbacks> -): readonly RowType[]; + callbacks?: UseTableCallbacks>> +): readonly Prettify>[]; /** * React hook to subscribe to a table in SpacetimeDB and receive live updates as rows are inserted, updated, or deleted. @@ -247,22 +245,18 @@ export function useTable< * }); * ``` */ -export function useTable< - TableDef extends UntypedTableDef, ->( +export function useTable( tableDef: TableDef, - callbacks?: UseTableCallbacks> -): readonly RowType[]; + callbacks?: UseTableCallbacks>> +): readonly Prettify>[]; -export function useTable< - TableDef extends UntypedTableDef, ->( +export function useTable( tableDef: TableDef, whereClauseOrCallbacks?: | Expr>> | UseTableCallbacks>, callbacks?: UseTableCallbacks> -): readonly RowType[] { +): readonly Prettify>[] { type UseTableRowType = RowType; const tableName = tableDef.name; let whereClause: Expr> | undefined; @@ -271,7 +265,9 @@ export function useTable< typeof whereClauseOrCallbacks === 'object' && 'type' in whereClauseOrCallbacks ) { - whereClause = whereClauseOrCallbacks as Expr>; + whereClause = whereClauseOrCallbacks as Expr< + ColumnsFromRow + >; } else { callbacks = whereClauseOrCallbacks as | UseTableCallbacks @@ -294,27 +290,32 @@ export function useTable< (whereClause ? ` WHERE ${toString(whereClause)}` : ''); const latestTransactionEvent = useRef(null); - const lastSnapshotRef = useRef(null); + const lastSnapshotRef = useRef[] | null>( + null + ); const whereKey = whereClause ? toString(whereClause) : ''; - const computeSnapshot = useCallback((): readonly UseTableRowType[] => { - const connection = connectionState.getConnection(); - if (!connection) { - return []; - } - const table = connection.db[tableName]; - const result: readonly UseTableRowType[] = whereClause - ? (Array.from(table.iter()).filter(row => evaluate(whereClause, row as UseTableRowType)) as UseTableRowType[]) - : (Array.from(table.iter()) as UseTableRowType[]); - return result; - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [connectionState, tableName, whereKey, subscribeApplied]); + const computeSnapshot = + useCallback((): readonly Prettify[] => { + const connection = connectionState.getConnection(); + if (!connection) { + return []; + } + const table = connection.db[tableName]; + const result: readonly Prettify[] = whereClause + ? (Array.from(table.iter()).filter(row => + evaluate(whereClause, row as UseTableRowType) + ) as Prettify[]) + : (Array.from(table.iter()) as Prettify[]); + return result; + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [connectionState, tableName, whereKey, subscribeApplied]); useEffect(() => { const connection = connectionState.getConnection()!; if (connectionState.isActive && connection) { - const cancel = connection + const cancel = connection .subscriptionBuilder() .onApplied(() => { setSubscribeApplied(true); @@ -328,7 +329,10 @@ export function useTable< const subscribe = useCallback( (onStoreChange: () => void) => { - const onInsert = (ctx: EventContextInterface, row: any) => { + const onInsert = ( + ctx: EventContextInterface, + row: any + ) => { if (whereClause && !evaluate(whereClause, row)) { return; } @@ -343,7 +347,10 @@ export function useTable< } }; - const onDelete = (ctx: EventContextInterface, row: any) => { + const onDelete = ( + ctx: EventContextInterface, + row: any + ) => { if (whereClause && !evaluate(whereClause, row)) { return; } @@ -358,7 +365,11 @@ export function useTable< } }; - const onUpdate = (ctx: EventContextInterface, oldRow: any, newRow: any) => { + const onUpdate = ( + ctx: EventContextInterface, + oldRow: any, + newRow: any + ) => { const change = classifyMembership(whereClause, oldRow, newRow); switch (change) { @@ -412,7 +423,7 @@ export function useTable< ] ); - const getSnapshot = useCallback((): readonly UseTableRowType[] => { + const getSnapshot = useCallback((): readonly Prettify[] => { if (!lastSnapshotRef.current) { lastSnapshotRef.current = computeSnapshot(); } diff --git a/crates/bindings-typescript/src/sdk/client_cache.ts b/crates/bindings-typescript/src/sdk/client_cache.ts index 8f07f15af37..afadb578a50 100644 --- a/crates/bindings-typescript/src/sdk/client_cache.ts +++ b/crates/bindings-typescript/src/sdk/client_cache.ts @@ -3,13 +3,16 @@ import type { UntypedTableDef } from '../lib/table.ts'; import type { UntypedRemoteModule } from './spacetime_module.ts'; import { TableCache } from './table_cache.ts'; -type TableName = - [SchemaDef] extends [UntypedSchemaDef] ? TableNamesOf : string; +type TableName = [SchemaDef] extends [UntypedSchemaDef] + ? TableNamesOf + : string; -export type TableDefForTableName> = - [SchemaDef] extends [UntypedSchemaDef] - ? (SchemaDef['tables'][number] & { name: N }) - : UntypedTableDef; +export type TableDefForTableName< + SchemaDef extends UntypedSchemaDef, + N extends TableName, +> = [SchemaDef] extends [UntypedSchemaDef] + ? SchemaDef['tables'][number] & { name: N } + : UntypedTableDef; type TableCacheForTableName< RemoteModule extends UntypedRemoteModule, @@ -21,14 +24,24 @@ type TableCacheForTableName< * while preserving the correspondence between the key and value type. */ class TableMap { - private readonly map: Map>> = new Map(); + private readonly map: Map< + string, + TableCacheForTableName> + > = new Map(); - get>(key: K): TableCacheForTableName | undefined { + get>( + key: K + ): TableCacheForTableName | undefined { // Cast required: a Map can't refine the union to the exact K-specific member on get(key: K). - return this.map.get(key) as TableCacheForTableName | undefined; + return this.map.get(key) as + | TableCacheForTableName + | undefined; } - set>(key: K, value: TableCacheForTableName): this { + set>( + key: K, + value: TableCacheForTableName + ): this { this.map.set(key, value); return this; } @@ -42,10 +55,22 @@ class TableMap { } // optional: iteration stays broadly typed (cannot express per-key relation here) - keys(): IterableIterator { return this.map.keys(); } - values(): IterableIterator>> { return this.map.values(); } - entries(): IterableIterator<[string, TableCacheForTableName>]> { return this.map.entries(); } - [Symbol.iterator]() { return this.entries(); } + keys(): IterableIterator { + return this.map.keys(); + } + values(): IterableIterator< + TableCacheForTableName> + > { + return this.map.values(); + } + entries(): IterableIterator< + [string, TableCacheForTableName>] + > { + return this.map.entries(); + } + [Symbol.iterator]() { + return this.entries(); + } } /** @@ -65,7 +90,9 @@ export class ClientCache { * and the return type matches that table. * - If SchemaDef is undefined, `name` is string and the return type is untyped. */ - getTable>(name: N): TableCacheForTableName { + getTable>( + name: N + ): TableCacheForTableName { const table = this.tables.get(name); if (!table) { console.error( diff --git a/crates/bindings-typescript/src/sdk/client_table.ts b/crates/bindings-typescript/src/sdk/client_table.ts index bafaf8eb49f..ac20b83decf 100644 --- a/crates/bindings-typescript/src/sdk/client_table.ts +++ b/crates/bindings-typescript/src/sdk/client_table.ts @@ -1,11 +1,16 @@ -import type { ReadonlyIndexes } from "../lib/indexes"; -import type { TableNamesOf } from "../lib/schema"; -import type { ReadonlyTableMethods, RowType, TableIndexes, UntypedTableDef } from "../lib/table"; -import type { ColumnBuilder } from "../lib/type_builders"; -import type { Prettify } from "../lib/type_util"; -import type { TableDefForTableName } from "./client_cache"; -import type { EventContextInterface } from "./event_context"; -import type { UntypedRemoteModule } from "./spacetime_module"; +import type { ReadonlyIndexes } from '../lib/indexes'; +import type { TableNamesOf } from '../lib/schema'; +import type { + ReadonlyTableMethods, + RowType, + TableIndexes, + UntypedTableDef, +} from '../lib/table'; +import type { ColumnBuilder } from '../lib/type_builders'; +import type { Prettify } from '../lib/type_util'; +import type { TableDefForTableName } from './client_cache'; +import type { EventContextInterface } from './event_context'; +import type { UntypedRemoteModule } from './spacetime_module'; export type ClientTablePrimaryKeyMethods< RemoteModule extends UntypedRemoteModule, @@ -16,13 +21,25 @@ export type ClientTablePrimaryKeyMethods< * Requires that the table has a primary key defined. * @param cb The callback to invoke when a row is updated. */ - onUpdate(cb: (ctx: EventContextInterface, oldRow: RowType>, newRow: RowType>) => void): void; + onUpdate( + cb: ( + ctx: EventContextInterface, + oldRow: RowType>, + newRow: RowType> + ) => void + ): void; /** - * Removes a previously registered update event listener. + * Removes a previously registered update event listener. * @param cb The callback to remove from the update event listeners. */ - removeOnUpdate(cb: (ctx: EventContextInterface, oldRow: RowType>, newRow: RowType>) => void): void; + removeOnUpdate( + cb: ( + ctx: EventContextInterface, + oldRow: RowType>, + newRow: RowType> + ) => void + ): void; }; export type ClientTableMethods< @@ -32,24 +49,44 @@ export type ClientTableMethods< /** * Registers a callback to be invoked when a row is inserted into the table. */ - onInsert(cb: (ctx: EventContextInterface, row: RowType>) => void): void; + onInsert( + cb: ( + ctx: EventContextInterface, + row: RowType> + ) => void + ): void; /** - * Removes a previously registered insert event listener. + * Removes a previously registered insert event listener. * @param cb The callback to remove from the insert event listeners. */ - removeOnInsert(cb: (ctx: EventContextInterface, row: RowType>) => void): void; + removeOnInsert( + cb: ( + ctx: EventContextInterface, + row: RowType> + ) => void + ): void; /** * Registers a callback to be invoked when a row is deleted from the table. */ - onDelete(cb: (ctx: EventContextInterface, row: RowType>) => void): void; + onDelete( + cb: ( + ctx: EventContextInterface, + row: RowType> + ) => void + ): void; /** * Removes a previously registered delete event listener. * @param cb The callback to remove from the delete event listeners. */ - removeOnDelete(cb: (ctx: EventContextInterface, row: RowType>) => void): void; + removeOnDelete( + cb: ( + ctx: EventContextInterface, + row: RowType> + ) => void + ): void; }; /** @@ -64,21 +101,27 @@ export type ClientTable< TableName extends TableNamesOf, > = Prettify< ClientTableCore & - ReadonlyIndexes, TableIndexes>> + ReadonlyIndexes< + TableDefForTableName, + TableIndexes> + > >; -type HasPrimaryKey = - ColumnsHavePrimaryKey; +type HasPrimaryKey = ColumnsHavePrimaryKey< + TableDef['columns'] +>; type ColumnsHavePrimaryKey< - Cs extends Record> -> = - { - [K in keyof Cs]: - Cs[K] extends ColumnBuilder - ? (M extends { isPrimaryKey: true } ? true : never) - : never - }[keyof Cs] extends true ? true : false; + Cs extends Record>, +> = { + [K in keyof Cs]: Cs[K] extends ColumnBuilder + ? M extends { isPrimaryKey: true } + ? true + : never + : never; +}[keyof Cs] extends true + ? true + : false; type MaybePKMethods< RemoteModule extends UntypedRemoteModule, @@ -92,8 +135,7 @@ type MaybePKMethods< export type ClientTableCoreImplementable< RemoteModule extends UntypedRemoteModule, TableName extends TableNamesOf, -> = - ReadonlyTableMethods> & +> = ReadonlyTableMethods> & ClientTableMethods & // always present but optional -> statically known member set MaybePKMethods; @@ -105,11 +147,8 @@ export type ClientTableCoreImplementable< export type ClientTableCore< RemoteModule extends UntypedRemoteModule, TableName extends TableNamesOf, -> = - ReadonlyTableMethods> & +> = ReadonlyTableMethods> & ClientTableMethods & - ( - HasPrimaryKey> extends true - ? ClientTablePrimaryKeyMethods - : {} - ); \ No newline at end of file + (HasPrimaryKey> extends true + ? ClientTablePrimaryKeyMethods + : {}); diff --git a/crates/bindings-typescript/src/sdk/db_connection_builder.ts b/crates/bindings-typescript/src/sdk/db_connection_builder.ts index 1e5b4be9abf..1842f31fde2 100644 --- a/crates/bindings-typescript/src/sdk/db_connection_builder.ts +++ b/crates/bindings-typescript/src/sdk/db_connection_builder.ts @@ -1,6 +1,12 @@ import { DbConnectionImpl, type ConnectionEvent } from './db_connection_impl'; import { EventEmitter } from './event_emitter'; -import type { DbConnectionConfig, ErrorContextInterface, Identity, RemoteModuleOf, SubscriptionEventContextInterface } from '../'; +import type { + DbConnectionConfig, + ErrorContextInterface, + Identity, + RemoteModuleOf, + SubscriptionEventContextInterface, +} from '../'; import { ensureMinimumVersionOrThrow } from './version'; import { WebsocketDecompressAdapter } from './websocket_decompress_adapter'; @@ -12,9 +18,7 @@ import { WebsocketDecompressAdapter } from './websocket_decompress_adapter'; * always have a concrete RemoteModule type in those cases. Even if they user * did do this, they would just lose type safety on the RemoteModule. */ -export class DbConnectionBuilder< - DbConnection extends DbConnectionImpl -> { +export class DbConnectionBuilder> { #uri?: URL; #nameOrAddress?: string; #identity?: Identity; @@ -35,7 +39,9 @@ export class DbConnectionBuilder< */ constructor( private remoteModule: RemoteModuleOf, - private dbConnectionCtor: (config: DbConnectionConfig>) => DbConnection + private dbConnectionCtor: ( + config: DbConnectionConfig> + ) => DbConnection ) { this.#createWSFn = WebsocketDecompressAdapter.createWebSocketFn; } @@ -181,7 +187,12 @@ export class DbConnectionBuilder< * }); * ``` */ - onConnectError(callback: (ctx: ErrorContextInterface>, error: Error) => void): this { + onConnectError( + callback: ( + ctx: ErrorContextInterface>, + error: Error + ) => void + ): this { this.#emitter.on('connectError', callback); return this; } @@ -213,7 +224,10 @@ export class DbConnectionBuilder< * @throws {Error} Throws an error if called multiple times on the same `DbConnectionBuilder`. */ onDisconnect( - callback: (ctx: ErrorContextInterface>, error?: Error | undefined) => void + callback: ( + ctx: ErrorContextInterface>, + error?: Error | undefined + ) => void ): this { this.#emitter.on('disconnect', callback); return this; @@ -258,6 +272,6 @@ export class DbConnectionBuilder< confirmedReads: this.#confirmedReads, createWSFn: this.#createWSFn, remoteModule: this.remoteModule, - }) + }); } } diff --git a/crates/bindings-typescript/src/sdk/db_connection_impl.ts b/crates/bindings-typescript/src/sdk/db_connection_impl.ts index e2a7ced5371..cae78d0564c 100644 --- a/crates/bindings-typescript/src/sdk/db_connection_impl.ts +++ b/crates/bindings-typescript/src/sdk/db_connection_impl.ts @@ -1,8 +1,5 @@ import { ConnectionId, ProductType } from '../'; -import { - AlgebraicType, - type ComparablePrimitive, -} from '../'; +import { AlgebraicType, type ComparablePrimitive } from '../'; import { BinaryReader } from '../'; import { BinaryWriter } from '../'; import BsatnRowList from './client_api/bsatn_row_list_type.ts'; @@ -31,7 +28,10 @@ import type { UnsubscribeAppliedMessage, } from './message_types.ts'; import type { ReducerEvent } from './reducer_event.ts'; -import { type RemoteModule, type UntypedRemoteModule } from './spacetime_module.ts'; +import { + type RemoteModule, + type UntypedRemoteModule, +} from './spacetime_module.ts'; import { TableCache, type Operation, @@ -48,14 +48,20 @@ import { } from './subscription_builder_impl.ts'; import { stdbLogger } from './logger.ts'; import { fromByteArray } from 'base64-js'; -import type { ReducerEventInfo, ReducersView, SetReducerFlags, UntypedReducersDef } from './reducers.ts'; +import type { + ReducerEventInfo, + ReducersView, + SetReducerFlags, + UntypedReducersDef, +} from './reducers.ts'; import type { ClientDbView } from './db_view.ts'; import type { UntypedTableDef } from '../lib/table.ts'; import { toCamelCase } from '../lib/utils.ts'; export { DbConnectionBuilder, SubscriptionBuilderImpl, TableCache, type Event }; -export type RemoteModuleOf = C extends DbConnectionImpl ? RM : never; +export type RemoteModuleOf = + C extends DbConnectionImpl ? RM : never; export type { DbContext, @@ -69,13 +75,16 @@ export type { export type ConnectionEvent = 'connect' | 'disconnect' | 'connectError'; export type CallReducerFlags = 'FullUpdate' | 'NoSuccessNotify'; -type ReducerEventCallback = ( +type ReducerEventCallback< + RemoteModule extends UntypedRemoteModule, + ReducerArgs extends any[] = any[], +> = ( ctx: ReducerEventContextInterface, ...args: ReducerArgs ) => void; type SubscriptionEventCallback = ( - ctx: SubscriptionEventContextInterface, + ctx: SubscriptionEventContextInterface ) => void; function callReducerFlagsToNumber(flags: CallReducerFlags): number { @@ -100,9 +109,9 @@ export type DbConnectionConfig = { remoteModule: RemoteModule; }; -export class DbConnectionImpl< - RemoteModule extends UntypedRemoteModule, -> implements DbContext { +export class DbConnectionImpl + implements DbContext +{ /** * Whether or not the connection is active. */ @@ -240,7 +249,7 @@ export class DbConnectionImpl< for (const tbl of def.tables) { // ClientDbView uses this name verbatim - const key = tbl.accessorName; + const key = tbl.accessorName; Object.defineProperty(view, key, { enumerable: true, configurable: false, @@ -289,7 +298,11 @@ export class DbConnectionImpl< } #makeEventContext( - event: Event>> + event: Event< + ReducerEventInfo< + InferTypeOfRow + > + > ): EventContextInterface { // Bind methods to preserve `this` (#private fields safe) return { @@ -316,7 +329,10 @@ export class DbConnectionImpl< registerSubscription( handle: SubscriptionHandleImpl, - handleEmitter: EventEmitter>, + handleEmitter: EventEmitter< + SubscribeEvent, + SubscriptionEventCallback + >, querySql: string[] ): number { const queryId = this.#getNextQueryId(); @@ -364,14 +380,17 @@ export class DbConnectionImpl< const table = this.#remoteModule.tables.find(t => t.name === tableName); const rowType = table!.rowType; const columnsArray = Object.entries(table!.columns); - const primaryKeyColumnEntry = columnsArray.find(col => col[1].columnMetadata.isPrimaryKey); + const primaryKeyColumnEntry = columnsArray.find( + col => col[1].columnMetadata.isPrimaryKey + ); let previousOffset = 0; while (reader.remaining > 0) { const row = ProductType.deserializeValue(reader, rowType); let rowId: ComparablePrimitive | undefined = undefined; if (primaryKeyColumnEntry !== undefined) { const primaryKeyColName = primaryKeyColumnEntry[0]; - const primaryKeyColType = primaryKeyColumnEntry[1].typeBuilder.algebraicType; + const primaryKeyColType = + primaryKeyColumnEntry[1].typeBuilder.algebraicType; rowId = AlgebraicType.intoMapKey( primaryKeyColType, row[primaryKeyColName] @@ -494,9 +513,9 @@ export class DbConnectionImpl< let reducerInfo: | { - reducerName: string; - args: Uint8Array; - } + reducerName: string; + args: Uint8Array; + } | undefined; if (reducerName !== '') { reducerInfo = { @@ -573,7 +592,11 @@ export class DbConnectionImpl< this.wsPromise.then(wsResolved => { if (wsResolved) { const writer = new BinaryWriter(1024); - AlgebraicType.serializeValue(writer, ClientMessage.algebraicType, message); + AlgebraicType.serializeValue( + writer, + ClientMessage.algebraicType, + message + ); const encoded = writer.getBuffer(); wsResolved.send(encoded); } @@ -596,7 +619,9 @@ export class DbConnectionImpl< // Get table information for the table being updated const tableName = tableUpdate.tableName; // TODO: performance - const tableDef = this.#remoteModule.tables.find(t => t.name === tableName)!; + const tableDef = this.#remoteModule.tables.find( + t => t.name === tableName + )!; const table = this.clientCache.getOrCreateTable(tableDef); const newCallbacks = table.applyOperations( tableUpdate.operations, @@ -610,7 +635,10 @@ export class DbConnectionImpl< } async #processMessage(data: Uint8Array): Promise { - const serverMessage = AlgebraicType.deserializeValue(new BinaryReader(data), ServerMessage.algebraicType); + const serverMessage = AlgebraicType.deserializeValue( + new BinaryReader(data), + ServerMessage.algebraicType + ); const message = await this.#processParsedMessage(serverMessage); if (!message) { return; @@ -651,7 +679,9 @@ export class DbConnectionImpl< let reducerInfo = message.reducerInfo; let unknownTransaction = false; let reducerArgs: InferTypeOfRow | undefined; - const reducer = this.#remoteModule.reducers.find(t => t.name === reducerInfo!.reducerName)!; + const reducer = this.#remoteModule.reducers.find( + t => t.name === reducerInfo!.reducerName + )!; if (!reducerInfo) { unknownTransaction = true; } else { @@ -706,7 +736,7 @@ export class DbConnectionImpl< tag: 'Reducer', value: reducerEvent, }; - const eventContext = this.#makeEventContext(event); + const eventContext = this.#makeEventContext(event); const reducerEventContext = { ...eventContext, event: reducerEvent, @@ -718,9 +748,7 @@ export class DbConnectionImpl< ); const argsArray: any[] = []; - ( - reducer.paramsType - ).elements.forEach(element => { + reducer.paramsType.elements.forEach(element => { argsArray.push(reducerArgs[element.name!]); }); this.#reducerEmitter.emit( @@ -861,17 +889,18 @@ export class DbConnectionImpl< * Call a reducer on your SpacetimeDB module with typed arguments. * @param reducerSchema The schema of the reducer to call * @param callReducerFlags The flags for the reducer call - * @param params The arguments to pass to the reducer + * @param params The arguments to pass to the reducer */ - callReducerWithParams(reducerName: string, paramsType: ProductType, params: object, flags: CallReducerFlags) { + callReducerWithParams( + reducerName: string, + paramsType: ProductType, + params: object, + flags: CallReducerFlags + ) { let writer = new BinaryWriter(1024); ProductType.serializeValue(writer, paramsType, params); let argsBuffer = writer.getBuffer(); - this.callReducer( - reducerName, - argsBuffer, - flags - ); + this.callReducer(reducerName, argsBuffer, flags); } /** @@ -944,13 +973,19 @@ export class DbConnectionImpl< // Note: This is required to be public because it needs to be // called from the `RemoteReducers` class. - onReducer(reducerName: string, callback: ReducerEventCallback): void { + onReducer( + reducerName: string, + callback: ReducerEventCallback + ): void { this.#reducerEmitter.on(reducerName, callback); } // Note: This is required to be public because it needs to be // called from the `RemoteReducers` class. - offReducer(reducerName: string, callback: ReducerEventCallback): void { + offReducer( + reducerName: string, + callback: ReducerEventCallback + ): void { this.#reducerEmitter.off(reducerName, callback); } } diff --git a/crates/bindings-typescript/src/sdk/db_context.ts b/crates/bindings-typescript/src/sdk/db_context.ts index 65c127d67d5..a991794594e 100644 --- a/crates/bindings-typescript/src/sdk/db_context.ts +++ b/crates/bindings-typescript/src/sdk/db_context.ts @@ -1,5 +1,9 @@ import type { ClientDbView } from './db_view'; -import type { ReducersView, SetReducerFlags, UntypedReducersDef } from './reducers'; +import type { + ReducersView, + SetReducerFlags, + UntypedReducersDef, +} from './reducers'; import type { UntypedRemoteModule } from './spacetime_module'; import type { SubscriptionBuilderImpl } from './subscription_builder_impl'; @@ -21,9 +25,7 @@ export interface DbContext { * * @returns The subscription builder. */ - subscriptionBuilder(): SubscriptionBuilderImpl< - RemoteModule - >; + subscriptionBuilder(): SubscriptionBuilderImpl; /** * Disconnects from the database. diff --git a/crates/bindings-typescript/src/sdk/db_view.ts b/crates/bindings-typescript/src/sdk/db_view.ts index ffdee9e7199..dcfd6b13517 100644 --- a/crates/bindings-typescript/src/sdk/db_view.ts +++ b/crates/bindings-typescript/src/sdk/db_view.ts @@ -1,9 +1,12 @@ -import type { UntypedRemoteModule } from "./spacetime_module"; -import type { ClientTable } from "./client_table"; +import type { UntypedRemoteModule } from './spacetime_module'; +import type { ClientTable } from './client_table'; /** * A type representing a client-side database view, mapping table names to their corresponding client Table handles. */ export type ClientDbView = { - readonly [Tbl in RemoteModule['tables'][number] as Tbl['accessorName']]: ClientTable; -}; \ No newline at end of file + readonly [Tbl in RemoteModule['tables'][number] as Tbl['accessorName']]: ClientTable< + RemoteModule, + Tbl['name'] + >; +}; diff --git a/crates/bindings-typescript/src/sdk/event_context.ts b/crates/bindings-typescript/src/sdk/event_context.ts index 8511832cac3..677adcac90d 100644 --- a/crates/bindings-typescript/src/sdk/event_context.ts +++ b/crates/bindings-typescript/src/sdk/event_context.ts @@ -7,18 +7,21 @@ import type { UntypedRemoteModule } from './spacetime_module.ts'; export type UntypedEventContext = EventContextInterface; -export interface EventContextInterface< - RemoteModule extends UntypedRemoteModule, -> extends DbContext { +export interface EventContextInterface + extends DbContext { /** Enum with variants for all possible events. */ - event: Event>>; + event: Event< + ReducerEventInfo> + >; } export interface ReducerEventContextInterface< RemoteModule extends UntypedRemoteModule, > extends DbContext { /** Enum with variants for all possible events. */ - event: ReducerEvent>>; + event: ReducerEvent< + ReducerEventInfo> + >; } // eslint-disable-next-line @typescript-eslint/no-empty-object-type @@ -28,9 +31,8 @@ export interface SubscriptionEventContextInterface< /** No event is provided **/ } -export interface ErrorContextInterface< - RemoteModule extends UntypedRemoteModule, -> extends DbContext { +export interface ErrorContextInterface + extends DbContext { /** Enum with variants for all possible events. */ event?: Error; } diff --git a/crates/bindings-typescript/src/sdk/index.ts b/crates/bindings-typescript/src/sdk/index.ts index 06cf0cdc3b9..30f7b0e90cd 100644 --- a/crates/bindings-typescript/src/sdk/index.ts +++ b/crates/bindings-typescript/src/sdk/index.ts @@ -8,4 +8,4 @@ export { type SetReducerFlags } from './reducers.ts'; export * from '../lib/type_builders.ts'; export { schema, convertToAccessorMap } from '../lib/schema.ts'; export { table } from '../lib/table.ts'; -export { reducerSchema, reducers } from '../lib/reducers.ts'; \ No newline at end of file +export { reducerSchema, reducers } from '../lib/reducers.ts'; diff --git a/crates/bindings-typescript/src/sdk/message_types.ts b/crates/bindings-typescript/src/sdk/message_types.ts index 3ae8314b2c2..24e834a1ebe 100644 --- a/crates/bindings-typescript/src/sdk/message_types.ts +++ b/crates/bindings-typescript/src/sdk/message_types.ts @@ -25,11 +25,10 @@ export type TransactionUpdateMessage = { energyConsumed: bigint; }; -export type TransactionUpdateLightMessage = - { - tag: 'TransactionUpdateLight'; - tableUpdates: TableUpdate[]; - }; +export type TransactionUpdateLightMessage = { + tag: 'TransactionUpdateLight'; + tableUpdates: TableUpdate[]; +}; export type IdentityTokenMessage = { tag: 'IdentityToken'; @@ -57,10 +56,10 @@ export type SubscriptionError = { }; export type Message = - | InitialSubscriptionMessage - | TransactionUpdateMessage - | TransactionUpdateLightMessage - | IdentityTokenMessage - | SubscribeAppliedMessage - | UnsubscribeAppliedMessage - | SubscriptionError; + | InitialSubscriptionMessage + | TransactionUpdateMessage + | TransactionUpdateLightMessage + | IdentityTokenMessage + | SubscribeAppliedMessage + | UnsubscribeAppliedMessage + | SubscriptionError; diff --git a/crates/bindings-typescript/src/sdk/reducer_handle.ts b/crates/bindings-typescript/src/sdk/reducer_handle.ts index a4e76eda4a4..17a80e72000 100644 --- a/crates/bindings-typescript/src/sdk/reducer_handle.ts +++ b/crates/bindings-typescript/src/sdk/reducer_handle.ts @@ -3,10 +3,10 @@ export type ReducerHandle = { readonly reducerName?: ReducerName; }; -export type ReducerNamesFromReducers = R extends object +export type ReducerNamesFromReducers = R extends object ? { [K in keyof R]: R[K] extends ReducerHandle - ? ReducerName + ? ReducerName : never; }[keyof R] : never; diff --git a/crates/bindings-typescript/src/sdk/reducers.ts b/crates/bindings-typescript/src/sdk/reducers.ts index f341e73dd36..e8bf048e868 100644 --- a/crates/bindings-typescript/src/sdk/reducers.ts +++ b/crates/bindings-typescript/src/sdk/reducers.ts @@ -1,13 +1,14 @@ -import type { ProductType } from "../lib/algebraic_type"; -import type { ParamsObj } from "../lib/reducers"; -import type { CoerceRow } from "../lib/table"; -import type { InferTypeOfRow } from "../lib/type_builders"; -import type { CamelCase } from "../lib/type_util"; -import type { CallReducerFlags } from "./db_connection_impl"; +import type { ProductType } from '../lib/algebraic_type'; +import type { ParamsObj } from '../lib/reducers'; +import type { CoerceRow } from '../lib/table'; +import type { InferTypeOfRow } from '../lib/type_builders'; +import type { CamelCase } from '../lib/type_util'; +import type { CallReducerFlags } from './db_connection_impl'; export type ReducersView = { - [I in keyof R['reducers'] as CamelCase]: - (params: InferTypeOfRow) => void + [I in keyof R['reducers'] as CamelCase< + R['reducers'][number]['accessorName'] + >]: (params: InferTypeOfRow) => void; }; export type ReducerEventInfo = { @@ -18,7 +19,7 @@ export type ReducerEventInfo = { export type UntypedReducerDef = { name: string; accessorName: string; - params: CoerceRow; + params: CoerceRow; paramsType: ProductType; }; @@ -27,5 +28,7 @@ export type UntypedReducersDef = { }; export type SetReducerFlags = { - [K in keyof R['reducers'] as CamelCase]: (flags: CallReducerFlags) => void; -}; \ No newline at end of file + [K in keyof R['reducers'] as CamelCase]: ( + flags: CallReducerFlags + ) => void; +}; diff --git a/crates/bindings-typescript/src/sdk/set_reducer_flags.ts b/crates/bindings-typescript/src/sdk/set_reducer_flags.ts index a5648b67d36..35fdf3a1c39 100644 --- a/crates/bindings-typescript/src/sdk/set_reducer_flags.ts +++ b/crates/bindings-typescript/src/sdk/set_reducer_flags.ts @@ -1,3 +1,6 @@ -import type { CallReducerFlags } from "./db_connection_impl"; +import type { CallReducerFlags } from './db_connection_impl'; -export type UntypedSetReducerFlags = Record void>; \ No newline at end of file +export type UntypedSetReducerFlags = Record< + string, + (flags: CallReducerFlags) => void +>; diff --git a/crates/bindings-typescript/src/sdk/spacetime_module.ts b/crates/bindings-typescript/src/sdk/spacetime_module.ts index 73f7d5fdca9..bf37b798d2f 100644 --- a/crates/bindings-typescript/src/sdk/spacetime_module.ts +++ b/crates/bindings-typescript/src/sdk/spacetime_module.ts @@ -4,15 +4,21 @@ import type { UntypedReducersDef } from './reducers'; export type RemoteModule< SchemaDef extends UntypedSchemaDef, ReducersDef extends UntypedReducersDef, - CLI extends string = string -> = SchemaDef & ReducersDef & { - versionInfo: { - cliVersion: CLI; + CLI extends string = string, +> = SchemaDef & + ReducersDef & { + versionInfo: { + cliVersion: CLI; + }; }; -} -export type UntypedRemoteModule = RemoteModule; +export type UntypedRemoteModule = RemoteModule< + UntypedSchemaDef, + UntypedReducersDef +>; -export type SchemaDef = RemoteModule['tables']; +export type SchemaDef = + RemoteModule['tables']; -export type ReducersDef = RemoteModule['reducers']; \ No newline at end of file +export type ReducersDef = + RemoteModule['reducers']; diff --git a/crates/bindings-typescript/src/sdk/subscription_builder_impl.ts b/crates/bindings-typescript/src/sdk/subscription_builder_impl.ts index 842e055b791..851b6baffe0 100644 --- a/crates/bindings-typescript/src/sdk/subscription_builder_impl.ts +++ b/crates/bindings-typescript/src/sdk/subscription_builder_impl.ts @@ -6,18 +6,11 @@ import type { import { EventEmitter } from './event_emitter'; import type { UntypedRemoteModule } from './spacetime_module'; -export class SubscriptionBuilderImpl< - RemoteModule extends UntypedRemoteModule, -> { - #onApplied?: ( - ctx: SubscriptionEventContextInterface - ) => void = undefined; - #onError?: ( - ctx: ErrorContextInterface - ) => void = undefined; - constructor( - private db: DbConnectionImpl - ) {} +export class SubscriptionBuilderImpl { + #onApplied?: (ctx: SubscriptionEventContextInterface) => void = + undefined; + #onError?: (ctx: ErrorContextInterface) => void = undefined; + constructor(private db: DbConnectionImpl) {} /** * Registers `callback` to run when this query is successfully added to our subscribed set, @@ -35,9 +28,7 @@ export class SubscriptionBuilderImpl< * @returns The current `SubscriptionBuilder` instance. */ onApplied( - cb: ( - ctx: SubscriptionEventContextInterface - ) => void + cb: (ctx: SubscriptionEventContextInterface) => void ): SubscriptionBuilderImpl { this.#onApplied = cb; return this; @@ -128,13 +119,14 @@ export type SubscribeEvent = 'applied' | 'error' | 'end'; export class SubscriptionManager { subscriptions: Map< number, - { handle: SubscriptionHandleImpl; emitter: EventEmitter } + { + handle: SubscriptionHandleImpl; + emitter: EventEmitter; + } > = new Map(); } -export class SubscriptionHandleImpl< - RemoteModule extends UntypedRemoteModule, -> { +export class SubscriptionHandleImpl { #queryId: number; #unsubscribeCalled: boolean = false; #endedState: boolean = false; @@ -145,19 +137,12 @@ export class SubscriptionHandleImpl< constructor( private db: DbConnectionImpl, querySql: string[], - onApplied?: ( - ctx: SubscriptionEventContextInterface - ) => void, - onError?: ( - ctx: ErrorContextInterface, - error: Error - ) => void + onApplied?: (ctx: SubscriptionEventContextInterface) => void, + onError?: (ctx: ErrorContextInterface, error: Error) => void ) { this.#emitter.on( 'applied', - ( - ctx: SubscriptionEventContextInterface - ) => { + (ctx: SubscriptionEventContextInterface) => { this.#activeState = true; if (onApplied) { onApplied(ctx); @@ -166,10 +151,7 @@ export class SubscriptionHandleImpl< ); this.#emitter.on( 'error', - ( - ctx: ErrorContextInterface, - error: Error - ) => { + (ctx: ErrorContextInterface, error: Error) => { this.#activeState = false; this.#endedState = true; if (onError) { @@ -193,9 +175,7 @@ export class SubscriptionHandleImpl< this.db.unregisterSubscription(this.#queryId); this.#emitter.on( 'end', - ( - _ctx: SubscriptionEventContextInterface - ) => { + (_ctx: SubscriptionEventContextInterface) => { this.#endedState = true; this.#activeState = false; } @@ -213,9 +193,7 @@ export class SubscriptionHandleImpl< * @param onEnd - Callback to run upon successful unsubscribe. */ unsubscribeThen( - onEnd: ( - ctx: SubscriptionEventContextInterface - ) => void + onEnd: (ctx: SubscriptionEventContextInterface) => void ): void { if (this.#endedState) { throw new Error('Subscription has already ended'); @@ -227,9 +205,7 @@ export class SubscriptionHandleImpl< this.db.unregisterSubscription(this.#queryId); this.#emitter.on( 'end', - ( - ctx: SubscriptionEventContextInterface - ) => { + (ctx: SubscriptionEventContextInterface) => { this.#endedState = true; this.#activeState = false; onEnd(ctx); diff --git a/crates/bindings-typescript/src/sdk/table_cache.ts b/crates/bindings-typescript/src/sdk/table_cache.ts index 655a17278f9..66e8330dc0b 100644 --- a/crates/bindings-typescript/src/sdk/table_cache.ts +++ b/crates/bindings-typescript/src/sdk/table_cache.ts @@ -2,9 +2,16 @@ import { EventEmitter } from './event_emitter.ts'; import { stdbLogger } from './logger.ts'; import type { ComparablePrimitive } from '../'; -import type { EventContextInterface, ClientTable, TableDefForTableName } from './index.ts'; +import type { + EventContextInterface, + ClientTable, + TableDefForTableName, +} from './index.ts'; import type { RowType, Table, UntypedTableDef } from '../lib/table.ts'; -import type { ClientTableCore, ClientTableCoreImplementable } from './client_table.ts'; +import type { + ClientTableCore, + ClientTableCoreImplementable, +} from './client_table.ts'; import type { UntypedRemoteModule } from './spacetime_module.ts'; import type { TableNamesOf } from '../lib/schema.ts'; @@ -18,9 +25,7 @@ export type Operation< row: RowType; }; -export type TableUpdate< - TableDef extends UntypedTableDef, -> = { +export type TableUpdate = { tableName: string; operations: Operation>[]; }; @@ -37,8 +42,12 @@ export type PendingCallback = { export class TableCache< RemoteModule extends UntypedRemoteModule, TableName extends TableNamesOf, -> implements ClientTableCoreImplementable { - private rows: Map>, number]>; +> implements ClientTableCoreImplementable +{ + private rows: Map< + ComparablePrimitive, + [RowType>, number] + >; private tableDef: TableDefForTableName; private emitter: EventEmitter<'insert' | 'delete' | 'update'>; @@ -64,8 +73,17 @@ export class TableCache< /** * @returns The values of the rows in the table */ - iter(): IterableIterator>> { - function* generator(rows: Map>, number]>): IterableIterator>> { + iter(): IterableIterator< + RowType> + > { + function* generator( + rows: Map< + ComparablePrimitive, + [RowType>, number] + > + ): IterableIterator< + RowType> + > { for (const [row] of rows.values()) { yield row; } @@ -74,28 +92,40 @@ export class TableCache< } /** - * Allows iteration over the rows in the table + * Allows iteration over the rows in the table * @returns An iterator over the rows in the table */ - [Symbol.iterator](): IterableIterator>> { + [Symbol.iterator](): IterableIterator< + RowType> + > { return this.iter(); } applyOperations = ( - operations: Operation>>[], + operations: Operation< + RowType> + >[], ctx: EventContextInterface ): PendingCallback[] => { const pendingCallbacks: PendingCallback[] = []; // TODO: performance - const hasPrimaryKey = Object.values(this.tableDef.columns).some(col => col.columnMetadata.isPrimaryKey === true); + const hasPrimaryKey = Object.values(this.tableDef.columns).some( + col => col.columnMetadata.isPrimaryKey === true + ); if (hasPrimaryKey) { const insertMap = new Map< ComparablePrimitive, - [Operation>>, number] + [ + Operation>>, + number, + ] >(); const deleteMap = new Map< ComparablePrimitive, - [Operation>>, number] + [ + Operation>>, + number, + ] >(); for (const op of operations) { if (op.type === 'insert') { @@ -205,7 +235,9 @@ export class TableCache< insert = ( ctx: EventContextInterface, - operation: Operation>>, + operation: Operation< + RowType> + >, count: number = 1 ): PendingCallback | undefined => { const [_, previousCount] = this.rows.get(operation.rowId) || [ @@ -228,7 +260,9 @@ export class TableCache< delete = ( ctx: EventContextInterface, - operation: Operation>>, + operation: Operation< + RowType> + >, count: number = 1 ): PendingCallback | undefined => { const [_, previousCount] = this.rows.get(operation.rowId) || [ @@ -272,7 +306,10 @@ export class TableCache< * @param cb Callback to be called when a new row is inserted */ onInsert = ( - cb: (ctx: EventContextInterface, row: RowType>) => void + cb: ( + ctx: EventContextInterface, + row: RowType> + ) => void ): void => { this.emitter.on('insert', cb); }; @@ -293,7 +330,10 @@ export class TableCache< * @param cb Callback to be called when a new row is inserted */ onDelete = ( - cb: (ctx: EventContextInterface, row: RowType>) => void + cb: ( + ctx: EventContextInterface, + row: RowType> + ) => void ): void => { this.emitter.on('delete', cb); }; @@ -314,7 +354,11 @@ export class TableCache< * @param cb Callback to be called when a new row is inserted */ onUpdate = ( - cb: (ctx: EventContextInterface, oldRow: RowType>, row: RowType>) => void + cb: ( + ctx: EventContextInterface, + oldRow: RowType>, + row: RowType> + ) => void ): void => { this.emitter.on('update', cb); }; @@ -325,7 +369,10 @@ export class TableCache< * @param cb Callback to be removed */ removeOnInsert = ( - cb: (ctx: EventContextInterface, row: RowType>) => void + cb: ( + ctx: EventContextInterface, + row: RowType> + ) => void ): void => { this.emitter.off('insert', cb); }; @@ -336,7 +383,10 @@ export class TableCache< * @param cb Callback to be removed */ removeOnDelete = ( - cb: (ctx: EventContextInterface, row: RowType>) => void + cb: ( + ctx: EventContextInterface, + row: RowType> + ) => void ): void => { this.emitter.off('delete', cb); }; @@ -347,7 +397,11 @@ export class TableCache< * @param cb Callback to be removed */ removeOnUpdate = ( - cb: (ctx: EventContextInterface, oldRow: RowType>, row: RowType>) => void + cb: ( + ctx: EventContextInterface, + oldRow: RowType>, + row: RowType> + ) => void ): void => { this.emitter.off('update', cb); }; diff --git a/crates/bindings-typescript/src/sdk/websocket_test_adapter.ts b/crates/bindings-typescript/src/sdk/websocket_test_adapter.ts index 2b1dc2ac25f..58f1861603a 100644 --- a/crates/bindings-typescript/src/sdk/websocket_test_adapter.ts +++ b/crates/bindings-typescript/src/sdk/websocket_test_adapter.ts @@ -30,11 +30,7 @@ class WebsocketTestAdapter { sendToClient(message: Infer): void { const writer = new BinaryWriter(1024); - AlgebraicType.serializeValue( - writer, - ServerMessage.algebraicType, - message - ); + AlgebraicType.serializeValue(writer, ServerMessage.algebraicType, message); const rawBytes = writer.getBuffer(); // The brotli library's `compress` is somehow broken: it returns `null` for some inputs. // See https://github.com/foliojs/brotli.js/issues/36, which is closed but not actually fixed. diff --git a/crates/bindings-typescript/src/server/db_view.ts b/crates/bindings-typescript/src/server/db_view.ts index 43a4a284ed3..25e3978c288 100644 --- a/crates/bindings-typescript/src/server/db_view.ts +++ b/crates/bindings-typescript/src/server/db_view.ts @@ -1,5 +1,5 @@ -import type { UntypedSchemaDef } from "../lib/schema"; -import type { ReadonlyTable, Table } from "../lib/table"; +import type { UntypedSchemaDef } from '../lib/schema'; +import type { ReadonlyTable, Table } from '../lib/table'; /** * A type representing a read-only database view, mapping table names to their corresponding read-only Table handles. @@ -13,4 +13,4 @@ export type ReadonlyDbView = { */ export type DbView = { readonly [Tbl in SchemaDef['tables'][number] as Tbl['accessorName']]: Table; -}; \ No newline at end of file +}; diff --git a/crates/bindings-typescript/src/server/runtime.ts b/crates/bindings-typescript/src/server/runtime.ts index ea442b38308..fd2a9e6a02b 100644 --- a/crates/bindings-typescript/src/server/runtime.ts +++ b/crates/bindings-typescript/src/server/runtime.ts @@ -180,8 +180,8 @@ export const hooks: ModuleHooks = { AlgebraicType.serializeValue( writer, RawModuleDef.algebraicType, - RawModuleDef.create('V9', MODULE_DEF), - ) + RawModuleDef.create('V9', MODULE_DEF) + ); return writer.getBuffer(); }, __call_reducer__(reducerId, sender, connId, timestamp, argsBuf) { @@ -235,7 +235,10 @@ function makeDbView(moduleDef: Infer): DbView { ); } -function makeTableView(typespace: Infer, table: Infer): Table { +function makeTableView( + typespace: Infer, + table: Infer +): Table { const table_id = sys.table_id_from_name(table.name); const rowType = typespace.types[table.productTypeRef]; if (rowType.tag !== 'Product') { @@ -472,7 +475,10 @@ function makeTableView(typespace: Infer, table: Infer, ty: AlgebraicType): number { +function bsatnBaseSize( + typespace: Infer, + ty: AlgebraicType +): number { const assumedArrayLength = 4; while (ty.tag === 'Ref') ty = typespace.types[ty.value]; if (ty.tag === 'Product') { diff --git a/crates/bindings-typescript/test-app/src/App.tsx b/crates/bindings-typescript/test-app/src/App.tsx index 3ef576fb0e1..3bbee2cbf27 100644 --- a/crates/bindings-typescript/test-app/src/App.tsx +++ b/crates/bindings-typescript/test-app/src/App.tsx @@ -1,7 +1,13 @@ import { tables, reducers } from './module_bindings'; import { useEffect } from 'react'; import './App.css'; -import { eq, useReducer, useSpacetimeDB, useTable, where } from '../../src/react'; +import { + eq, + useReducer, + useSpacetimeDB, + useTable, + where, +} from '../../src/react'; function getRandomInt(max: number) { return Math.floor(Math.random() * max); @@ -10,10 +16,9 @@ function getRandomInt(max: number) { function App() { const connection = useSpacetimeDB(); const players = useTable(tables.player, where(eq('name', 'Hello')), { - onInsert: (row) => { - console.log('Player inserted:', rows); + onInsert: row => { + console.log('Player inserted:', row); }, - }); const x = players[0]; const createPlayer = useReducer(reducers.createPlayer); diff --git a/crates/bindings-typescript/tests/serde.test.ts b/crates/bindings-typescript/tests/serde.test.ts index 21cb3d639cb..c740dd2ec8e 100644 --- a/crates/bindings-typescript/tests/serde.test.ts +++ b/crates/bindings-typescript/tests/serde.test.ts @@ -1,5 +1,12 @@ import { describe, expect, test } from 'vitest'; -import { AlgebraicType, BinaryReader, BinaryWriter, ConnectionId, Identity, ScheduleAt } from 'spacetimedb'; +import { + AlgebraicType, + BinaryReader, + BinaryWriter, + ConnectionId, + Identity, + ScheduleAt, +} from 'spacetimedb'; describe('it correctly serializes and deserializes algebraic values', () => { test('when it serializes and deserializes with a product type', () => { From cb16789be729954a7c47b87fb40b35baa0bd1029 Mon Sep 17 00:00:00 2001 From: = Date: Sun, 9 Nov 2025 15:51:00 -0500 Subject: [PATCH 19/49] Removed generation of variant types since they can now be derived from the type builders --- .../src/lib/autogen/algebraic_type_type.ts | 2 - .../lib/autogen/algebraic_type_variants.ts | 38 -- .../src/lib/autogen/index_type_type.ts | 1 - .../src/lib/autogen/index_type_variants.ts | 14 - .../src/lib/autogen/lifecycle_type.ts | 1 - .../src/lib/autogen/lifecycle_variants.ts | 15 - .../lib/autogen/misc_module_export_type.ts | 2 - .../autogen/misc_module_export_variants.ts | 17 - .../autogen/raw_constraint_data_v_9_type.ts | 2 - .../raw_constraint_data_v_9_variants.ts | 17 - .../lib/autogen/raw_index_algorithm_type.ts | 1 - .../autogen/raw_index_algorithm_variants.ts | 15 - .../raw_misc_module_export_v_9_type.ts | 2 - .../raw_misc_module_export_v_9_variants.ts | 24 -- .../src/lib/autogen/raw_module_def_type.ts | 2 - .../lib/autogen/raw_module_def_variants.ts | 19 - .../src/lib/autogen/table_access_type.ts | 1 - .../src/lib/autogen/table_access_variants.ts | 14 - .../src/lib/autogen/table_type_type.ts | 1 - .../src/lib/autogen/table_type_variants.ts | 14 - .../bindings-typescript/src/lib/reducers.ts | 1 - crates/bindings-typescript/src/lib/table.ts | 3 +- .../src/lib/type_builders.ts | 1 + .../src/react/useReducer.ts | 21 +- .../src/react/useSpacetimeDB.ts | 2 - .../src/sdk/client_api/client_message_type.ts | 2 - .../sdk/client_api/client_message_variants.ts | 52 --- .../compressable_query_update_type.ts | 2 - .../compressable_query_update_variants.ts | 19 - .../sdk/client_api/procedure_status_type.ts | 1 - .../client_api/procedure_status_variants.ts | 15 - .../src/sdk/client_api/row_size_hint_type.ts | 1 - .../sdk/client_api/row_size_hint_variants.ts | 14 - .../src/sdk/client_api/server_message_type.ts | 2 - .../sdk/client_api/server_message_variants.ts | 67 ---- .../src/sdk/client_api/update_status_type.ts | 2 - .../sdk/client_api/update_status_variants.ts | 19 - .../src/sdk/client_cache.ts | 2 +- .../src/sdk/db_connection_builder.ts | 1 - .../src/sdk/db_connection_impl.ts | 6 +- .../bindings-typescript/src/sdk/db_context.ts | 1 - .../src/sdk/message_types.ts | 2 +- .../src/sdk/table_cache.ts | 4 +- .../bindings-typescript/test-app/src/App.tsx | 1 - .../test-app/src/module_bindings/index.ts | 16 +- .../test-react-router-app/package.json | 1 + .../test-react-router-app/server/src/lib.rs | 1 + .../module_bindings/clear_counter_reducer.ts | 64 +--- .../client_connected_reducer.ts | 65 +--- .../client_disconnected_reducer.ts | 65 +--- .../src/module_bindings/counter_table.ts | 118 +------ .../src/module_bindings/counter_type.ts | 71 +--- .../increment_counter_reducer.ts | 65 +--- .../src/module_bindings/index.ts | 333 +++++------------- .../src/module_bindings/offline_user_table.ts | 116 +----- .../src/module_bindings/user_table.ts | 116 +----- .../src/module_bindings/user_type.ts | 74 +--- .../src/pages/CounterPage.tsx | 13 +- .../src/pages/UserPage.tsx | 26 +- crates/codegen/src/typescript.rs | 172 ++------- pnpm-lock.yaml | 179 ++++++++-- 61 files changed, 380 insertions(+), 1558 deletions(-) delete mode 100644 crates/bindings-typescript/src/lib/autogen/algebraic_type_variants.ts delete mode 100644 crates/bindings-typescript/src/lib/autogen/index_type_variants.ts delete mode 100644 crates/bindings-typescript/src/lib/autogen/lifecycle_variants.ts delete mode 100644 crates/bindings-typescript/src/lib/autogen/misc_module_export_variants.ts delete mode 100644 crates/bindings-typescript/src/lib/autogen/raw_constraint_data_v_9_variants.ts delete mode 100644 crates/bindings-typescript/src/lib/autogen/raw_index_algorithm_variants.ts delete mode 100644 crates/bindings-typescript/src/lib/autogen/raw_misc_module_export_v_9_variants.ts delete mode 100644 crates/bindings-typescript/src/lib/autogen/raw_module_def_variants.ts delete mode 100644 crates/bindings-typescript/src/lib/autogen/table_access_variants.ts delete mode 100644 crates/bindings-typescript/src/lib/autogen/table_type_variants.ts delete mode 100644 crates/bindings-typescript/src/sdk/client_api/client_message_variants.ts delete mode 100644 crates/bindings-typescript/src/sdk/client_api/compressable_query_update_variants.ts delete mode 100644 crates/bindings-typescript/src/sdk/client_api/procedure_status_variants.ts delete mode 100644 crates/bindings-typescript/src/sdk/client_api/row_size_hint_variants.ts delete mode 100644 crates/bindings-typescript/src/sdk/client_api/server_message_variants.ts delete mode 100644 crates/bindings-typescript/src/sdk/client_api/update_status_variants.ts diff --git a/crates/bindings-typescript/src/lib/autogen/algebraic_type_type.ts b/crates/bindings-typescript/src/lib/autogen/algebraic_type_type.ts index fd16d887075..8ec644f676b 100644 --- a/crates/bindings-typescript/src/lib/autogen/algebraic_type_type.ts +++ b/crates/bindings-typescript/src/lib/autogen/algebraic_type_type.ts @@ -12,8 +12,6 @@ import { import SumType from './sum_type_type'; import ProductType from './product_type_type'; -import * as AlgebraicTypeVariants from './algebraic_type_variants'; - // The tagged union or sum type for the algebraic type `AlgebraicType`. const AlgebraicType: __TypeBuilder<__AlgebraicTypeType, __AlgebraicTypeType> = __t.enum('AlgebraicType', { diff --git a/crates/bindings-typescript/src/lib/autogen/algebraic_type_variants.ts b/crates/bindings-typescript/src/lib/autogen/algebraic_type_variants.ts deleted file mode 100644 index b81b181d802..00000000000 --- a/crates/bindings-typescript/src/lib/autogen/algebraic_type_variants.ts +++ /dev/null @@ -1,38 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -/* eslint-disable */ -/* tslint:disable */ -import { - TypeBuilder as __TypeBuilder, - t as __t, - type AlgebraicTypeType as __AlgebraicTypeType, - type Infer as __Infer, -} from '../../index'; -import AlgebraicTypeType from './algebraic_type_type'; -import SumTypeType from './sum_type_type'; -import ProductTypeType from './product_type_type'; - -export type Ref = { tag: 'Ref'; value: number }; -export type Sum = { tag: 'Sum'; value: __Infer }; -export type Product = { - tag: 'Product'; - value: __Infer; -}; -export type Array = { tag: 'Array'; value: __Infer }; -export type String = { tag: 'String' }; -export type Bool = { tag: 'Bool' }; -export type I8 = { tag: 'I8' }; -export type U8 = { tag: 'U8' }; -export type I16 = { tag: 'I16' }; -export type U16 = { tag: 'U16' }; -export type I32 = { tag: 'I32' }; -export type U32 = { tag: 'U32' }; -export type I64 = { tag: 'I64' }; -export type U64 = { tag: 'U64' }; -export type I128 = { tag: 'I128' }; -export type U128 = { tag: 'U128' }; -export type I256 = { tag: 'I256' }; -export type U256 = { tag: 'U256' }; -export type F32 = { tag: 'F32' }; -export type F64 = { tag: 'F64' }; diff --git a/crates/bindings-typescript/src/lib/autogen/index_type_type.ts b/crates/bindings-typescript/src/lib/autogen/index_type_type.ts index 7253194254a..4c2c4d6f3fc 100644 --- a/crates/bindings-typescript/src/lib/autogen/index_type_type.ts +++ b/crates/bindings-typescript/src/lib/autogen/index_type_type.ts @@ -9,7 +9,6 @@ import { type AlgebraicTypeType as __AlgebraicTypeType, type Infer as __Infer, } from '../../index'; -import * as IndexTypeVariants from './index_type_variants'; // The tagged union or sum type for the algebraic type `IndexType`. const IndexType = __t.enum('IndexType', { diff --git a/crates/bindings-typescript/src/lib/autogen/index_type_variants.ts b/crates/bindings-typescript/src/lib/autogen/index_type_variants.ts deleted file mode 100644 index 37e5ee90972..00000000000 --- a/crates/bindings-typescript/src/lib/autogen/index_type_variants.ts +++ /dev/null @@ -1,14 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -/* eslint-disable */ -/* tslint:disable */ -import { - TypeBuilder as __TypeBuilder, - t as __t, - type AlgebraicTypeType as __AlgebraicTypeType, - type Infer as __Infer, -} from '../../index'; - -export type BTree = { tag: 'BTree' }; -export type Hash = { tag: 'Hash' }; diff --git a/crates/bindings-typescript/src/lib/autogen/lifecycle_type.ts b/crates/bindings-typescript/src/lib/autogen/lifecycle_type.ts index 3f80e90dfb4..8de101313f0 100644 --- a/crates/bindings-typescript/src/lib/autogen/lifecycle_type.ts +++ b/crates/bindings-typescript/src/lib/autogen/lifecycle_type.ts @@ -9,7 +9,6 @@ import { type AlgebraicTypeType as __AlgebraicTypeType, type Infer as __Infer, } from '../../index'; -import * as LifecycleVariants from './lifecycle_variants'; // The tagged union or sum type for the algebraic type `Lifecycle`. const Lifecycle = __t.enum('Lifecycle', { diff --git a/crates/bindings-typescript/src/lib/autogen/lifecycle_variants.ts b/crates/bindings-typescript/src/lib/autogen/lifecycle_variants.ts deleted file mode 100644 index 0570638b19f..00000000000 --- a/crates/bindings-typescript/src/lib/autogen/lifecycle_variants.ts +++ /dev/null @@ -1,15 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -/* eslint-disable */ -/* tslint:disable */ -import { - TypeBuilder as __TypeBuilder, - t as __t, - type AlgebraicTypeType as __AlgebraicTypeType, - type Infer as __Infer, -} from '../../index'; - -export type Init = { tag: 'Init' }; -export type OnConnect = { tag: 'OnConnect' }; -export type OnDisconnect = { tag: 'OnDisconnect' }; diff --git a/crates/bindings-typescript/src/lib/autogen/misc_module_export_type.ts b/crates/bindings-typescript/src/lib/autogen/misc_module_export_type.ts index b4d4be33f34..753169f2831 100644 --- a/crates/bindings-typescript/src/lib/autogen/misc_module_export_type.ts +++ b/crates/bindings-typescript/src/lib/autogen/misc_module_export_type.ts @@ -11,8 +11,6 @@ import { } from '../../index'; import TypeAlias from './type_alias_type'; -import * as MiscModuleExportVariants from './misc_module_export_variants'; - // The tagged union or sum type for the algebraic type `MiscModuleExport`. const MiscModuleExport = __t.enum('MiscModuleExport', { get TypeAlias() { diff --git a/crates/bindings-typescript/src/lib/autogen/misc_module_export_variants.ts b/crates/bindings-typescript/src/lib/autogen/misc_module_export_variants.ts deleted file mode 100644 index 99d584fbdca..00000000000 --- a/crates/bindings-typescript/src/lib/autogen/misc_module_export_variants.ts +++ /dev/null @@ -1,17 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -/* eslint-disable */ -/* tslint:disable */ -import { - TypeBuilder as __TypeBuilder, - t as __t, - type AlgebraicTypeType as __AlgebraicTypeType, - type Infer as __Infer, -} from '../../index'; -import TypeAliasType from './type_alias_type'; - -export type TypeAlias = { - tag: 'TypeAlias'; - value: __Infer; -}; diff --git a/crates/bindings-typescript/src/lib/autogen/raw_constraint_data_v_9_type.ts b/crates/bindings-typescript/src/lib/autogen/raw_constraint_data_v_9_type.ts index 314c7014bfb..dafe670e956 100644 --- a/crates/bindings-typescript/src/lib/autogen/raw_constraint_data_v_9_type.ts +++ b/crates/bindings-typescript/src/lib/autogen/raw_constraint_data_v_9_type.ts @@ -11,8 +11,6 @@ import { } from '../../index'; import RawUniqueConstraintDataV9 from './raw_unique_constraint_data_v_9_type'; -import * as RawConstraintDataV9Variants from './raw_constraint_data_v_9_variants'; - // The tagged union or sum type for the algebraic type `RawConstraintDataV9`. const RawConstraintDataV9 = __t.enum('RawConstraintDataV9', { get Unique() { diff --git a/crates/bindings-typescript/src/lib/autogen/raw_constraint_data_v_9_variants.ts b/crates/bindings-typescript/src/lib/autogen/raw_constraint_data_v_9_variants.ts deleted file mode 100644 index 5ace6a528b1..00000000000 --- a/crates/bindings-typescript/src/lib/autogen/raw_constraint_data_v_9_variants.ts +++ /dev/null @@ -1,17 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -/* eslint-disable */ -/* tslint:disable */ -import { - TypeBuilder as __TypeBuilder, - t as __t, - type AlgebraicTypeType as __AlgebraicTypeType, - type Infer as __Infer, -} from '../../index'; -import RawUniqueConstraintDataV9Type from './raw_unique_constraint_data_v_9_type'; - -export type Unique = { - tag: 'Unique'; - value: __Infer; -}; diff --git a/crates/bindings-typescript/src/lib/autogen/raw_index_algorithm_type.ts b/crates/bindings-typescript/src/lib/autogen/raw_index_algorithm_type.ts index e755ee94c7e..f70c8992c68 100644 --- a/crates/bindings-typescript/src/lib/autogen/raw_index_algorithm_type.ts +++ b/crates/bindings-typescript/src/lib/autogen/raw_index_algorithm_type.ts @@ -9,7 +9,6 @@ import { type AlgebraicTypeType as __AlgebraicTypeType, type Infer as __Infer, } from '../../index'; -import * as RawIndexAlgorithmVariants from './raw_index_algorithm_variants'; // The tagged union or sum type for the algebraic type `RawIndexAlgorithm`. const RawIndexAlgorithm = __t.enum('RawIndexAlgorithm', { diff --git a/crates/bindings-typescript/src/lib/autogen/raw_index_algorithm_variants.ts b/crates/bindings-typescript/src/lib/autogen/raw_index_algorithm_variants.ts deleted file mode 100644 index 709fb79d6d2..00000000000 --- a/crates/bindings-typescript/src/lib/autogen/raw_index_algorithm_variants.ts +++ /dev/null @@ -1,15 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -/* eslint-disable */ -/* tslint:disable */ -import { - TypeBuilder as __TypeBuilder, - t as __t, - type AlgebraicTypeType as __AlgebraicTypeType, - type Infer as __Infer, -} from '../../index'; - -export type BTree = { tag: 'BTree'; value: number[] }; -export type Hash = { tag: 'Hash'; value: number[] }; -export type Direct = { tag: 'Direct'; value: number }; diff --git a/crates/bindings-typescript/src/lib/autogen/raw_misc_module_export_v_9_type.ts b/crates/bindings-typescript/src/lib/autogen/raw_misc_module_export_v_9_type.ts index 5f592285551..81612d985f9 100644 --- a/crates/bindings-typescript/src/lib/autogen/raw_misc_module_export_v_9_type.ts +++ b/crates/bindings-typescript/src/lib/autogen/raw_misc_module_export_v_9_type.ts @@ -13,8 +13,6 @@ import RawColumnDefaultValueV9 from './raw_column_default_value_v_9_type'; import RawProcedureDefV9 from './raw_procedure_def_v_9_type'; import RawViewDefV9 from './raw_view_def_v_9_type'; -import * as RawMiscModuleExportV9Variants from './raw_misc_module_export_v_9_variants'; - // The tagged union or sum type for the algebraic type `RawMiscModuleExportV9`. const RawMiscModuleExportV9 = __t.enum('RawMiscModuleExportV9', { get ColumnDefaultValue() { diff --git a/crates/bindings-typescript/src/lib/autogen/raw_misc_module_export_v_9_variants.ts b/crates/bindings-typescript/src/lib/autogen/raw_misc_module_export_v_9_variants.ts deleted file mode 100644 index ec0e9e4f899..00000000000 --- a/crates/bindings-typescript/src/lib/autogen/raw_misc_module_export_v_9_variants.ts +++ /dev/null @@ -1,24 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -/* eslint-disable */ -/* tslint:disable */ -import { - TypeBuilder as __TypeBuilder, - t as __t, - type AlgebraicTypeType as __AlgebraicTypeType, - type Infer as __Infer, -} from '../../index'; -import RawColumnDefaultValueV9Type from './raw_column_default_value_v_9_type'; -import RawProcedureDefV9Type from './raw_procedure_def_v_9_type'; -import RawViewDefV9Type from './raw_view_def_v_9_type'; - -export type ColumnDefaultValue = { - tag: 'ColumnDefaultValue'; - value: __Infer; -}; -export type Procedure = { - tag: 'Procedure'; - value: __Infer; -}; -export type View = { tag: 'View'; value: __Infer }; diff --git a/crates/bindings-typescript/src/lib/autogen/raw_module_def_type.ts b/crates/bindings-typescript/src/lib/autogen/raw_module_def_type.ts index e808e1528a7..ac92d10fa65 100644 --- a/crates/bindings-typescript/src/lib/autogen/raw_module_def_type.ts +++ b/crates/bindings-typescript/src/lib/autogen/raw_module_def_type.ts @@ -12,8 +12,6 @@ import { import RawModuleDefV8 from './raw_module_def_v_8_type'; import RawModuleDefV9 from './raw_module_def_v_9_type'; -import * as RawModuleDefVariants from './raw_module_def_variants'; - // The tagged union or sum type for the algebraic type `RawModuleDef`. const RawModuleDef = __t.enum('RawModuleDef', { get V8BackCompat() { diff --git a/crates/bindings-typescript/src/lib/autogen/raw_module_def_variants.ts b/crates/bindings-typescript/src/lib/autogen/raw_module_def_variants.ts deleted file mode 100644 index 2f1f1e2d2b0..00000000000 --- a/crates/bindings-typescript/src/lib/autogen/raw_module_def_variants.ts +++ /dev/null @@ -1,19 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -/* eslint-disable */ -/* tslint:disable */ -import { - TypeBuilder as __TypeBuilder, - t as __t, - type AlgebraicTypeType as __AlgebraicTypeType, - type Infer as __Infer, -} from '../../index'; -import RawModuleDefV8Type from './raw_module_def_v_8_type'; -import RawModuleDefV9Type from './raw_module_def_v_9_type'; - -export type V8BackCompat = { - tag: 'V8BackCompat'; - value: __Infer; -}; -export type V9 = { tag: 'V9'; value: __Infer }; diff --git a/crates/bindings-typescript/src/lib/autogen/table_access_type.ts b/crates/bindings-typescript/src/lib/autogen/table_access_type.ts index 0d310bf2d23..80d87d447c0 100644 --- a/crates/bindings-typescript/src/lib/autogen/table_access_type.ts +++ b/crates/bindings-typescript/src/lib/autogen/table_access_type.ts @@ -9,7 +9,6 @@ import { type AlgebraicTypeType as __AlgebraicTypeType, type Infer as __Infer, } from '../../index'; -import * as TableAccessVariants from './table_access_variants'; // The tagged union or sum type for the algebraic type `TableAccess`. const TableAccess = __t.enum('TableAccess', { diff --git a/crates/bindings-typescript/src/lib/autogen/table_access_variants.ts b/crates/bindings-typescript/src/lib/autogen/table_access_variants.ts deleted file mode 100644 index 9567b4f4006..00000000000 --- a/crates/bindings-typescript/src/lib/autogen/table_access_variants.ts +++ /dev/null @@ -1,14 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -/* eslint-disable */ -/* tslint:disable */ -import { - TypeBuilder as __TypeBuilder, - t as __t, - type AlgebraicTypeType as __AlgebraicTypeType, - type Infer as __Infer, -} from '../../index'; - -export type Public = { tag: 'Public' }; -export type Private = { tag: 'Private' }; diff --git a/crates/bindings-typescript/src/lib/autogen/table_type_type.ts b/crates/bindings-typescript/src/lib/autogen/table_type_type.ts index ee5cfa6b497..b5d1071151c 100644 --- a/crates/bindings-typescript/src/lib/autogen/table_type_type.ts +++ b/crates/bindings-typescript/src/lib/autogen/table_type_type.ts @@ -9,7 +9,6 @@ import { type AlgebraicTypeType as __AlgebraicTypeType, type Infer as __Infer, } from '../../index'; -import * as TableTypeVariants from './table_type_variants'; // The tagged union or sum type for the algebraic type `TableType`. const TableType = __t.enum('TableType', { diff --git a/crates/bindings-typescript/src/lib/autogen/table_type_variants.ts b/crates/bindings-typescript/src/lib/autogen/table_type_variants.ts deleted file mode 100644 index ea10b2d5aaa..00000000000 --- a/crates/bindings-typescript/src/lib/autogen/table_type_variants.ts +++ /dev/null @@ -1,14 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -/* eslint-disable */ -/* tslint:disable */ -import { - TypeBuilder as __TypeBuilder, - t as __t, - type AlgebraicTypeType as __AlgebraicTypeType, - type Infer as __Infer, -} from '../../index'; - -export type System = { tag: 'System' }; -export type User = { tag: 'User' }; diff --git a/crates/bindings-typescript/src/lib/reducers.ts b/crates/bindings-typescript/src/lib/reducers.ts index da7191d8f76..1550173e1ee 100644 --- a/crates/bindings-typescript/src/lib/reducers.ts +++ b/crates/bindings-typescript/src/lib/reducers.ts @@ -11,7 +11,6 @@ import { RowBuilder, type Infer, type InferTypeOfRow, - type ProductBuilder, type RowObj, type TypeBuilder, } from './type_builders'; diff --git a/crates/bindings-typescript/src/lib/table.ts b/crates/bindings-typescript/src/lib/table.ts index 6d27e10a799..6187f5a4b78 100644 --- a/crates/bindings-typescript/src/lib/table.ts +++ b/crates/bindings-typescript/src/lib/table.ts @@ -286,8 +286,7 @@ export function table>( // add explicit constraints from options.constraints for (const constraintOpts of opts.constraints ?? []) { if (constraintOpts.constraint === 'unique') { - let data: Infer['data']; - data = { + const data: Infer['data'] = { tag: 'Unique', value: { columns: constraintOpts.columns.map(c => colIds.get(c)!) }, }; diff --git a/crates/bindings-typescript/src/lib/type_builders.ts b/crates/bindings-typescript/src/lib/type_builders.ts index 567bae3975f..408467fed9d 100644 --- a/crates/bindings-typescript/src/lib/type_builders.ts +++ b/crates/bindings-typescript/src/lib/type_builders.ts @@ -1303,6 +1303,7 @@ export class SumBuilder extends TypeBuilder< }) ); this.variants = variants; + this.typeName = name; } /** diff --git a/crates/bindings-typescript/src/react/useReducer.ts b/crates/bindings-typescript/src/react/useReducer.ts index 6a16f1a2a38..dc93ae01b58 100644 --- a/crates/bindings-typescript/src/react/useReducer.ts +++ b/crates/bindings-typescript/src/react/useReducer.ts @@ -4,15 +4,22 @@ import type { UntypedReducerDef } from '../sdk/reducers'; import { useSpacetimeDB } from './useSpacetimeDB'; import type { Prettify } from '../lib/type_util'; +type IsEmptyObject = [keyof T] extends [never] ? true : false; +type MaybeParams = IsEmptyObject extends true ? [] : [params: T]; + +type ParamsType = MaybeParams +>>; + export function useReducer( reducerDef: ReducerDef -): (params: Prettify>) => void { +): (...params: ParamsType) => void { const { getConnection, isActive } = useSpacetimeDB(); const reducerName = reducerDef.accessorName; // Holds calls made before the connection exists const queueRef = useRef< - Array>> + ParamsType[] >([]); // Flush when we finally have a connection @@ -22,23 +29,25 @@ export function useReducer( return; } const fn = (conn.reducers as any)[reducerName] as ( - p: InferTypeOfRow + p: ParamsType ) => void; if (queueRef.current.length) { const pending = queueRef.current.splice(0); - for (const params of pending) fn(params); + for (const params of pending) { + fn(params); + } } }, [getConnection, reducerName, isActive]); return useCallback( - (params: Prettify>) => { + (...params: ParamsType) => { const conn = getConnection(); if (!conn) { queueRef.current.push(params); return; } const fn = (conn.reducers as any)[reducerName] as ( - p: Prettify> + p: ParamsType ) => void; return fn(params); }, diff --git a/crates/bindings-typescript/src/react/useSpacetimeDB.ts b/crates/bindings-typescript/src/react/useSpacetimeDB.ts index 9298eb3fda4..2a7cbfc828a 100644 --- a/crates/bindings-typescript/src/react/useSpacetimeDB.ts +++ b/crates/bindings-typescript/src/react/useSpacetimeDB.ts @@ -1,7 +1,5 @@ import { createContext, useContext } from 'react'; -import type { DbConnectionImpl } from '../sdk/db_connection_impl'; import type { ConnectionState } from './connection_state'; -import type { UntypedRemoteModule } from '../sdk/spacetime_module'; export const SpacetimeDBContext = createContext( undefined diff --git a/crates/bindings-typescript/src/sdk/client_api/client_message_type.ts b/crates/bindings-typescript/src/sdk/client_api/client_message_type.ts index a9235ed5572..7024d9d2840 100644 --- a/crates/bindings-typescript/src/sdk/client_api/client_message_type.ts +++ b/crates/bindings-typescript/src/sdk/client_api/client_message_type.ts @@ -18,8 +18,6 @@ import Unsubscribe from './unsubscribe_type'; import UnsubscribeMulti from './unsubscribe_multi_type'; import CallProcedure from './call_procedure_type'; -import * as ClientMessageVariants from './client_message_variants'; - // The tagged union or sum type for the algebraic type `ClientMessage`. const ClientMessage = __t.enum('ClientMessage', { get CallReducer() { diff --git a/crates/bindings-typescript/src/sdk/client_api/client_message_variants.ts b/crates/bindings-typescript/src/sdk/client_api/client_message_variants.ts deleted file mode 100644 index b85719a2956..00000000000 --- a/crates/bindings-typescript/src/sdk/client_api/client_message_variants.ts +++ /dev/null @@ -1,52 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -/* eslint-disable */ -/* tslint:disable */ -import { - TypeBuilder as __TypeBuilder, - t as __t, - type AlgebraicTypeType as __AlgebraicTypeType, - type Infer as __Infer, -} from '../../lib/type_builders'; -import CallReducerType from './call_reducer_type'; -import SubscribeType from './subscribe_type'; -import OneOffQueryType from './one_off_query_type'; -import SubscribeSingleType from './subscribe_single_type'; -import SubscribeMultiType from './subscribe_multi_type'; -import UnsubscribeType from './unsubscribe_type'; -import UnsubscribeMultiType from './unsubscribe_multi_type'; -import CallProcedureType from './call_procedure_type'; - -export type CallReducer = { - tag: 'CallReducer'; - value: __Infer; -}; -export type Subscribe = { - tag: 'Subscribe'; - value: __Infer; -}; -export type OneOffQuery = { - tag: 'OneOffQuery'; - value: __Infer; -}; -export type SubscribeSingle = { - tag: 'SubscribeSingle'; - value: __Infer; -}; -export type SubscribeMulti = { - tag: 'SubscribeMulti'; - value: __Infer; -}; -export type Unsubscribe = { - tag: 'Unsubscribe'; - value: __Infer; -}; -export type UnsubscribeMulti = { - tag: 'UnsubscribeMulti'; - value: __Infer; -}; -export type CallProcedure = { - tag: 'CallProcedure'; - value: __Infer; -}; diff --git a/crates/bindings-typescript/src/sdk/client_api/compressable_query_update_type.ts b/crates/bindings-typescript/src/sdk/client_api/compressable_query_update_type.ts index 287eb2364cc..fd07c71773b 100644 --- a/crates/bindings-typescript/src/sdk/client_api/compressable_query_update_type.ts +++ b/crates/bindings-typescript/src/sdk/client_api/compressable_query_update_type.ts @@ -11,8 +11,6 @@ import { } from '../../lib/type_builders'; import QueryUpdate from './query_update_type'; -import * as CompressableQueryUpdateVariants from './compressable_query_update_variants'; - // The tagged union or sum type for the algebraic type `CompressableQueryUpdate`. const CompressableQueryUpdate = __t.enum('CompressableQueryUpdate', { get Uncompressed() { diff --git a/crates/bindings-typescript/src/sdk/client_api/compressable_query_update_variants.ts b/crates/bindings-typescript/src/sdk/client_api/compressable_query_update_variants.ts deleted file mode 100644 index 8246811b00e..00000000000 --- a/crates/bindings-typescript/src/sdk/client_api/compressable_query_update_variants.ts +++ /dev/null @@ -1,19 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -/* eslint-disable */ -/* tslint:disable */ -import { - TypeBuilder as __TypeBuilder, - t as __t, - type AlgebraicTypeType as __AlgebraicTypeType, - type Infer as __Infer, -} from '../../lib/type_builders'; -import QueryUpdateType from './query_update_type'; - -export type Uncompressed = { - tag: 'Uncompressed'; - value: __Infer; -}; -export type Brotli = { tag: 'Brotli'; value: Uint8Array }; -export type Gzip = { tag: 'Gzip'; value: Uint8Array }; diff --git a/crates/bindings-typescript/src/sdk/client_api/procedure_status_type.ts b/crates/bindings-typescript/src/sdk/client_api/procedure_status_type.ts index f2750e88a29..29f444f66bd 100644 --- a/crates/bindings-typescript/src/sdk/client_api/procedure_status_type.ts +++ b/crates/bindings-typescript/src/sdk/client_api/procedure_status_type.ts @@ -9,7 +9,6 @@ import { type AlgebraicTypeType as __AlgebraicTypeType, type Infer as __Infer, } from '../../lib/type_builders'; -import * as ProcedureStatusVariants from './procedure_status_variants'; // The tagged union or sum type for the algebraic type `ProcedureStatus`. const ProcedureStatus = __t.enum('ProcedureStatus', { diff --git a/crates/bindings-typescript/src/sdk/client_api/procedure_status_variants.ts b/crates/bindings-typescript/src/sdk/client_api/procedure_status_variants.ts deleted file mode 100644 index 6652aab16d4..00000000000 --- a/crates/bindings-typescript/src/sdk/client_api/procedure_status_variants.ts +++ /dev/null @@ -1,15 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -/* eslint-disable */ -/* tslint:disable */ -import { - TypeBuilder as __TypeBuilder, - t as __t, - type AlgebraicTypeType as __AlgebraicTypeType, - type Infer as __Infer, -} from '../../lib/type_builders'; - -export type Returned = { tag: 'Returned'; value: Uint8Array }; -export type OutOfEnergy = { tag: 'OutOfEnergy' }; -export type InternalError = { tag: 'InternalError'; value: string }; diff --git a/crates/bindings-typescript/src/sdk/client_api/row_size_hint_type.ts b/crates/bindings-typescript/src/sdk/client_api/row_size_hint_type.ts index b5fcd506486..112417b2ac3 100644 --- a/crates/bindings-typescript/src/sdk/client_api/row_size_hint_type.ts +++ b/crates/bindings-typescript/src/sdk/client_api/row_size_hint_type.ts @@ -9,7 +9,6 @@ import { type AlgebraicTypeType as __AlgebraicTypeType, type Infer as __Infer, } from '../../lib/type_builders'; -import * as RowSizeHintVariants from './row_size_hint_variants'; // The tagged union or sum type for the algebraic type `RowSizeHint`. const RowSizeHint = __t.enum('RowSizeHint', { diff --git a/crates/bindings-typescript/src/sdk/client_api/row_size_hint_variants.ts b/crates/bindings-typescript/src/sdk/client_api/row_size_hint_variants.ts deleted file mode 100644 index 8c28ef824b9..00000000000 --- a/crates/bindings-typescript/src/sdk/client_api/row_size_hint_variants.ts +++ /dev/null @@ -1,14 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -/* eslint-disable */ -/* tslint:disable */ -import { - TypeBuilder as __TypeBuilder, - t as __t, - type AlgebraicTypeType as __AlgebraicTypeType, - type Infer as __Infer, -} from '../../lib/type_builders'; - -export type FixedSize = { tag: 'FixedSize'; value: number }; -export type RowOffsets = { tag: 'RowOffsets'; value: bigint[] }; diff --git a/crates/bindings-typescript/src/sdk/client_api/server_message_type.ts b/crates/bindings-typescript/src/sdk/client_api/server_message_type.ts index b670d6b69bc..cd9e0e2ea23 100644 --- a/crates/bindings-typescript/src/sdk/client_api/server_message_type.ts +++ b/crates/bindings-typescript/src/sdk/client_api/server_message_type.ts @@ -21,8 +21,6 @@ import SubscribeMultiApplied from './subscribe_multi_applied_type'; import UnsubscribeMultiApplied from './unsubscribe_multi_applied_type'; import ProcedureResult from './procedure_result_type'; -import * as ServerMessageVariants from './server_message_variants'; - // The tagged union or sum type for the algebraic type `ServerMessage`. const ServerMessage = __t.enum('ServerMessage', { get InitialSubscription() { diff --git a/crates/bindings-typescript/src/sdk/client_api/server_message_variants.ts b/crates/bindings-typescript/src/sdk/client_api/server_message_variants.ts deleted file mode 100644 index e27eb295f81..00000000000 --- a/crates/bindings-typescript/src/sdk/client_api/server_message_variants.ts +++ /dev/null @@ -1,67 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -/* eslint-disable */ -/* tslint:disable */ -import { - TypeBuilder as __TypeBuilder, - t as __t, - type AlgebraicTypeType as __AlgebraicTypeType, - type Infer as __Infer, -} from '../../lib/type_builders'; -import InitialSubscriptionType from './initial_subscription_type'; -import TransactionUpdateType from './transaction_update_type'; -import TransactionUpdateLightType from './transaction_update_light_type'; -import IdentityTokenType from './identity_token_type'; -import OneOffQueryResponseType from './one_off_query_response_type'; -import SubscribeAppliedType from './subscribe_applied_type'; -import UnsubscribeAppliedType from './unsubscribe_applied_type'; -import SubscriptionErrorType from './subscription_error_type'; -import SubscribeMultiAppliedType from './subscribe_multi_applied_type'; -import UnsubscribeMultiAppliedType from './unsubscribe_multi_applied_type'; -import ProcedureResultType from './procedure_result_type'; - -export type InitialSubscription = { - tag: 'InitialSubscription'; - value: __Infer; -}; -export type TransactionUpdate = { - tag: 'TransactionUpdate'; - value: __Infer; -}; -export type TransactionUpdateLight = { - tag: 'TransactionUpdateLight'; - value: __Infer; -}; -export type IdentityToken = { - tag: 'IdentityToken'; - value: __Infer; -}; -export type OneOffQueryResponse = { - tag: 'OneOffQueryResponse'; - value: __Infer; -}; -export type SubscribeApplied = { - tag: 'SubscribeApplied'; - value: __Infer; -}; -export type UnsubscribeApplied = { - tag: 'UnsubscribeApplied'; - value: __Infer; -}; -export type SubscriptionError = { - tag: 'SubscriptionError'; - value: __Infer; -}; -export type SubscribeMultiApplied = { - tag: 'SubscribeMultiApplied'; - value: __Infer; -}; -export type UnsubscribeMultiApplied = { - tag: 'UnsubscribeMultiApplied'; - value: __Infer; -}; -export type ProcedureResult = { - tag: 'ProcedureResult'; - value: __Infer; -}; diff --git a/crates/bindings-typescript/src/sdk/client_api/update_status_type.ts b/crates/bindings-typescript/src/sdk/client_api/update_status_type.ts index 0a666da5719..e5db16fc2e8 100644 --- a/crates/bindings-typescript/src/sdk/client_api/update_status_type.ts +++ b/crates/bindings-typescript/src/sdk/client_api/update_status_type.ts @@ -11,8 +11,6 @@ import { } from '../../lib/type_builders'; import DatabaseUpdate from './database_update_type'; -import * as UpdateStatusVariants from './update_status_variants'; - // The tagged union or sum type for the algebraic type `UpdateStatus`. const UpdateStatus = __t.enum('UpdateStatus', { get Committed() { diff --git a/crates/bindings-typescript/src/sdk/client_api/update_status_variants.ts b/crates/bindings-typescript/src/sdk/client_api/update_status_variants.ts deleted file mode 100644 index e2234e39e52..00000000000 --- a/crates/bindings-typescript/src/sdk/client_api/update_status_variants.ts +++ /dev/null @@ -1,19 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -/* eslint-disable */ -/* tslint:disable */ -import { - TypeBuilder as __TypeBuilder, - t as __t, - type AlgebraicTypeType as __AlgebraicTypeType, - type Infer as __Infer, -} from '../../lib/type_builders'; -import DatabaseUpdateType from './database_update_type'; - -export type Committed = { - tag: 'Committed'; - value: __Infer; -}; -export type Failed = { tag: 'Failed'; value: string }; -export type OutOfEnergy = { tag: 'OutOfEnergy' }; diff --git a/crates/bindings-typescript/src/sdk/client_cache.ts b/crates/bindings-typescript/src/sdk/client_cache.ts index afadb578a50..33c7bca6aa7 100644 --- a/crates/bindings-typescript/src/sdk/client_cache.ts +++ b/crates/bindings-typescript/src/sdk/client_cache.ts @@ -114,7 +114,7 @@ export class ClientCache { ): TableCacheForTableName { const name = tableDef.name as N; - let table = this.tables.get(name); + const table = this.tables.get(name); if (table) { return table; } diff --git a/crates/bindings-typescript/src/sdk/db_connection_builder.ts b/crates/bindings-typescript/src/sdk/db_connection_builder.ts index 1842f31fde2..efc32059ae9 100644 --- a/crates/bindings-typescript/src/sdk/db_connection_builder.ts +++ b/crates/bindings-typescript/src/sdk/db_connection_builder.ts @@ -5,7 +5,6 @@ import type { ErrorContextInterface, Identity, RemoteModuleOf, - SubscriptionEventContextInterface, } from '../'; import { ensureMinimumVersionOrThrow } from './version'; import { WebsocketDecompressAdapter } from './websocket_decompress_adapter'; diff --git a/crates/bindings-typescript/src/sdk/db_connection_impl.ts b/crates/bindings-typescript/src/sdk/db_connection_impl.ts index cae78d0564c..5b2a2187631 100644 --- a/crates/bindings-typescript/src/sdk/db_connection_impl.ts +++ b/crates/bindings-typescript/src/sdk/db_connection_impl.ts @@ -29,7 +29,6 @@ import type { } from './message_types.ts'; import type { ReducerEvent } from './reducer_event.ts'; import { - type RemoteModule, type UntypedRemoteModule, } from './spacetime_module.ts'; import { @@ -52,7 +51,6 @@ import type { ReducerEventInfo, ReducersView, SetReducerFlags, - UntypedReducersDef, } from './reducers.ts'; import type { ClientDbView } from './db_view.ts'; import type { UntypedTableDef } from '../lib/table.ts'; @@ -897,9 +895,9 @@ export class DbConnectionImpl params: object, flags: CallReducerFlags ) { - let writer = new BinaryWriter(1024); + const writer = new BinaryWriter(1024); ProductType.serializeValue(writer, paramsType, params); - let argsBuffer = writer.getBuffer(); + const argsBuffer = writer.getBuffer(); this.callReducer(reducerName, argsBuffer, flags); } diff --git a/crates/bindings-typescript/src/sdk/db_context.ts b/crates/bindings-typescript/src/sdk/db_context.ts index a991794594e..230170ac840 100644 --- a/crates/bindings-typescript/src/sdk/db_context.ts +++ b/crates/bindings-typescript/src/sdk/db_context.ts @@ -2,7 +2,6 @@ import type { ClientDbView } from './db_view'; import type { ReducersView, SetReducerFlags, - UntypedReducersDef, } from './reducers'; import type { UntypedRemoteModule } from './spacetime_module'; import type { SubscriptionBuilderImpl } from './subscription_builder_impl'; diff --git a/crates/bindings-typescript/src/sdk/message_types.ts b/crates/bindings-typescript/src/sdk/message_types.ts index 24e834a1ebe..6a7bdaa4dec 100644 --- a/crates/bindings-typescript/src/sdk/message_types.ts +++ b/crates/bindings-typescript/src/sdk/message_types.ts @@ -2,7 +2,7 @@ import { ConnectionId, type Infer } from '../'; import { Identity } from '../'; import type { TableUpdate } from './table_cache.ts'; import { Timestamp } from '../'; -import type { RowType, Table, UntypedTableDef } from '../lib/table.ts'; +import type { UntypedTableDef } from '../lib/table.ts'; import type UpdateStatus from './client_api/update_status_type.ts'; export type InitialSubscriptionMessage = { diff --git a/crates/bindings-typescript/src/sdk/table_cache.ts b/crates/bindings-typescript/src/sdk/table_cache.ts index 66e8330dc0b..2ff2a1ac194 100644 --- a/crates/bindings-typescript/src/sdk/table_cache.ts +++ b/crates/bindings-typescript/src/sdk/table_cache.ts @@ -4,12 +4,10 @@ import { stdbLogger } from './logger.ts'; import type { ComparablePrimitive } from '../'; import type { EventContextInterface, - ClientTable, TableDefForTableName, } from './index.ts'; -import type { RowType, Table, UntypedTableDef } from '../lib/table.ts'; +import type { RowType, UntypedTableDef } from '../lib/table.ts'; import type { - ClientTableCore, ClientTableCoreImplementable, } from './client_table.ts'; import type { UntypedRemoteModule } from './spacetime_module.ts'; diff --git a/crates/bindings-typescript/test-app/src/App.tsx b/crates/bindings-typescript/test-app/src/App.tsx index 3bbee2cbf27..720504f78d8 100644 --- a/crates/bindings-typescript/test-app/src/App.tsx +++ b/crates/bindings-typescript/test-app/src/App.tsx @@ -20,7 +20,6 @@ function App() { console.log('Player inserted:', row); }, }); - const x = players[0]; const createPlayer = useReducer(reducers.createPlayer); useEffect(() => { diff --git a/crates/bindings-typescript/test-app/src/module_bindings/index.ts b/crates/bindings-typescript/test-app/src/module_bindings/index.ts index fe0c2f4fbe0..fa5382b6be6 100644 --- a/crates/bindings-typescript/test-app/src/module_bindings/index.ts +++ b/crates/bindings-typescript/test-app/src/module_bindings/index.ts @@ -28,25 +28,25 @@ import { } from '../../../src/index'; // Import and reexport all reducer arg types -import CreatePlayer from './create_player_reducer.ts'; +import CreatePlayer from './create_player_reducer'; export { CreatePlayer }; // Import and reexport all table handle types -import PlayerRow from './player_table.ts'; +import PlayerRow from './player_table'; export { PlayerRow }; -import UnindexedPlayerRow from './unindexed_player_table.ts'; +import UnindexedPlayerRow from './unindexed_player_table'; export { UnindexedPlayerRow }; -import UserRow from './user_table.ts'; +import UserRow from './user_table'; export { UserRow }; // Import and reexport all types -import Player from './player_type.ts'; +import Player from './player_type'; export { Player }; -import Point from './point_type.ts'; +import Point from './point_type'; export { Point }; -import UnindexedPlayer from './unindexed_player_type.ts'; +import UnindexedPlayer from './unindexed_player_type'; export { UnindexedPlayer }; -import User from './user_type.ts'; +import User from './user_type'; export { User }; const tablesSchema = __schema( diff --git a/crates/bindings-typescript/test-react-router-app/package.json b/crates/bindings-typescript/test-react-router-app/package.json index babf93f8200..235f719db0e 100644 --- a/crates/bindings-typescript/test-react-router-app/package.json +++ b/crates/bindings-typescript/test-react-router-app/package.json @@ -26,6 +26,7 @@ "devDependencies": { "@types/react": "^18.3.3", "@types/react-dom": "^18.3.0", + "@types/react-router-dom": "^5.3.3", "@vitejs/plugin-react": "^4.3.1", "typescript": "^5.2.2", "vite": "^7.1.5" diff --git a/crates/bindings-typescript/test-react-router-app/server/src/lib.rs b/crates/bindings-typescript/test-react-router-app/server/src/lib.rs index 799eb5f91f3..520e68eeaec 100644 --- a/crates/bindings-typescript/test-react-router-app/server/src/lib.rs +++ b/crates/bindings-typescript/test-react-router-app/server/src/lib.rs @@ -59,6 +59,7 @@ fn increment_counter(ctx: &ReducerContext) -> Result<(), String> { fn clear_counter(ctx: &ReducerContext) { for row in ctx.db.counter().iter() { ctx.db.counter().id().delete(row.id); + ctx.db.counter().insert(Counter { id: 0, count: 0 }); } for row in ctx.db.user().iter() { diff --git a/crates/bindings-typescript/test-react-router-app/src/module_bindings/clear_counter_reducer.ts b/crates/bindings-typescript/test-react-router-app/src/module_bindings/clear_counter_reducer.ts index b05311785e6..2454b459929 100644 --- a/crates/bindings-typescript/test-react-router-app/src/module_bindings/clear_counter_reducer.ts +++ b/crates/bindings-typescript/test-react-router-app/src/module_bindings/clear_counter_reducer.ts @@ -4,64 +4,10 @@ /* eslint-disable */ /* tslint:disable */ import { - AlgebraicType as __AlgebraicTypeValue, - BinaryReader as __BinaryReader, - BinaryWriter as __BinaryWriter, - ClientCache as __ClientCache, - ConnectionId as __ConnectionId, - DbConnectionBuilder as __DbConnectionBuilder, - DbConnectionImpl as __DbConnectionImpl, - Identity as __Identity, - SubscriptionBuilderImpl as __SubscriptionBuilderImpl, - TableCache as __TableCache, - TimeDuration as __TimeDuration, - Timestamp as __Timestamp, - deepEqual as __deepEqual, - type AlgebraicType as __AlgebraicTypeType, - type AlgebraicTypeVariants as __AlgebraicTypeVariants, - type CallReducerFlags as __CallReducerFlags, - type ErrorContextInterface as __ErrorContextInterface, - type Event as __Event, - type EventContextInterface as __EventContextInterface, - type ReducerEventContextInterface as __ReducerEventContextInterface, - type SubscriptionEventContextInterface as __SubscriptionEventContextInterface, - type TableHandle as __TableHandle, + TypeBuilder as __TypeBuilder, + t as __t, + type AlgebraicTypeType as __AlgebraicTypeType, + type Infer as __Infer, } from '../../../src/index'; -export type ClearCounter = {}; -let _cached_ClearCounter_type_value: __AlgebraicTypeType | null = null; - -/** - * An object for generated helper functions. - */ -export const ClearCounter = { - /** - * A function which returns this type represented as an AlgebraicType. - * This function is derived from the AlgebraicType used to generate this type. - */ - getTypeScriptAlgebraicType(): __AlgebraicTypeType { - if (_cached_ClearCounter_type_value) return _cached_ClearCounter_type_value; - _cached_ClearCounter_type_value = __AlgebraicTypeValue.Product({ - elements: [], - }); - _cached_ClearCounter_type_value.value.elements.push(); - return _cached_ClearCounter_type_value; - }, - - serialize(writer: __BinaryWriter, value: ClearCounter): void { - __AlgebraicTypeValue.serializeValue( - writer, - ClearCounter.getTypeScriptAlgebraicType(), - value - ); - }, - - deserialize(reader: __BinaryReader): ClearCounter { - return __AlgebraicTypeValue.deserializeValue( - reader, - ClearCounter.getTypeScriptAlgebraicType() - ); - }, -}; - -export default ClearCounter; +export default {}; diff --git a/crates/bindings-typescript/test-react-router-app/src/module_bindings/client_connected_reducer.ts b/crates/bindings-typescript/test-react-router-app/src/module_bindings/client_connected_reducer.ts index ac7a7e2b90d..2454b459929 100644 --- a/crates/bindings-typescript/test-react-router-app/src/module_bindings/client_connected_reducer.ts +++ b/crates/bindings-typescript/test-react-router-app/src/module_bindings/client_connected_reducer.ts @@ -4,65 +4,10 @@ /* eslint-disable */ /* tslint:disable */ import { - AlgebraicType as __AlgebraicTypeValue, - BinaryReader as __BinaryReader, - BinaryWriter as __BinaryWriter, - ClientCache as __ClientCache, - ConnectionId as __ConnectionId, - DbConnectionBuilder as __DbConnectionBuilder, - DbConnectionImpl as __DbConnectionImpl, - Identity as __Identity, - SubscriptionBuilderImpl as __SubscriptionBuilderImpl, - TableCache as __TableCache, - TimeDuration as __TimeDuration, - Timestamp as __Timestamp, - deepEqual as __deepEqual, - type AlgebraicType as __AlgebraicTypeType, - type AlgebraicTypeVariants as __AlgebraicTypeVariants, - type CallReducerFlags as __CallReducerFlags, - type ErrorContextInterface as __ErrorContextInterface, - type Event as __Event, - type EventContextInterface as __EventContextInterface, - type ReducerEventContextInterface as __ReducerEventContextInterface, - type SubscriptionEventContextInterface as __SubscriptionEventContextInterface, - type TableHandle as __TableHandle, + TypeBuilder as __TypeBuilder, + t as __t, + type AlgebraicTypeType as __AlgebraicTypeType, + type Infer as __Infer, } from '../../../src/index'; -export type ClientConnected = {}; -let _cached_ClientConnected_type_value: __AlgebraicTypeType | null = null; - -/** - * An object for generated helper functions. - */ -export const ClientConnected = { - /** - * A function which returns this type represented as an AlgebraicType. - * This function is derived from the AlgebraicType used to generate this type. - */ - getTypeScriptAlgebraicType(): __AlgebraicTypeType { - if (_cached_ClientConnected_type_value) - return _cached_ClientConnected_type_value; - _cached_ClientConnected_type_value = __AlgebraicTypeValue.Product({ - elements: [], - }); - _cached_ClientConnected_type_value.value.elements.push(); - return _cached_ClientConnected_type_value; - }, - - serialize(writer: __BinaryWriter, value: ClientConnected): void { - __AlgebraicTypeValue.serializeValue( - writer, - ClientConnected.getTypeScriptAlgebraicType(), - value - ); - }, - - deserialize(reader: __BinaryReader): ClientConnected { - return __AlgebraicTypeValue.deserializeValue( - reader, - ClientConnected.getTypeScriptAlgebraicType() - ); - }, -}; - -export default ClientConnected; +export default {}; diff --git a/crates/bindings-typescript/test-react-router-app/src/module_bindings/client_disconnected_reducer.ts b/crates/bindings-typescript/test-react-router-app/src/module_bindings/client_disconnected_reducer.ts index d4369a3e513..2454b459929 100644 --- a/crates/bindings-typescript/test-react-router-app/src/module_bindings/client_disconnected_reducer.ts +++ b/crates/bindings-typescript/test-react-router-app/src/module_bindings/client_disconnected_reducer.ts @@ -4,65 +4,10 @@ /* eslint-disable */ /* tslint:disable */ import { - AlgebraicType as __AlgebraicTypeValue, - BinaryReader as __BinaryReader, - BinaryWriter as __BinaryWriter, - ClientCache as __ClientCache, - ConnectionId as __ConnectionId, - DbConnectionBuilder as __DbConnectionBuilder, - DbConnectionImpl as __DbConnectionImpl, - Identity as __Identity, - SubscriptionBuilderImpl as __SubscriptionBuilderImpl, - TableCache as __TableCache, - TimeDuration as __TimeDuration, - Timestamp as __Timestamp, - deepEqual as __deepEqual, - type AlgebraicType as __AlgebraicTypeType, - type AlgebraicTypeVariants as __AlgebraicTypeVariants, - type CallReducerFlags as __CallReducerFlags, - type ErrorContextInterface as __ErrorContextInterface, - type Event as __Event, - type EventContextInterface as __EventContextInterface, - type ReducerEventContextInterface as __ReducerEventContextInterface, - type SubscriptionEventContextInterface as __SubscriptionEventContextInterface, - type TableHandle as __TableHandle, + TypeBuilder as __TypeBuilder, + t as __t, + type AlgebraicTypeType as __AlgebraicTypeType, + type Infer as __Infer, } from '../../../src/index'; -export type ClientDisconnected = {}; -let _cached_ClientDisconnected_type_value: __AlgebraicTypeType | null = null; - -/** - * An object for generated helper functions. - */ -export const ClientDisconnected = { - /** - * A function which returns this type represented as an AlgebraicType. - * This function is derived from the AlgebraicType used to generate this type. - */ - getTypeScriptAlgebraicType(): __AlgebraicTypeType { - if (_cached_ClientDisconnected_type_value) - return _cached_ClientDisconnected_type_value; - _cached_ClientDisconnected_type_value = __AlgebraicTypeValue.Product({ - elements: [], - }); - _cached_ClientDisconnected_type_value.value.elements.push(); - return _cached_ClientDisconnected_type_value; - }, - - serialize(writer: __BinaryWriter, value: ClientDisconnected): void { - __AlgebraicTypeValue.serializeValue( - writer, - ClientDisconnected.getTypeScriptAlgebraicType(), - value - ); - }, - - deserialize(reader: __BinaryReader): ClientDisconnected { - return __AlgebraicTypeValue.deserializeValue( - reader, - ClientDisconnected.getTypeScriptAlgebraicType() - ); - }, -}; - -export default ClientDisconnected; +export default {}; diff --git a/crates/bindings-typescript/test-react-router-app/src/module_bindings/counter_table.ts b/crates/bindings-typescript/test-react-router-app/src/module_bindings/counter_table.ts index 9ffbf83d2c4..d492e387b23 100644 --- a/crates/bindings-typescript/test-react-router-app/src/module_bindings/counter_table.ts +++ b/crates/bindings-typescript/test-react-router-app/src/module_bindings/counter_table.ts @@ -4,115 +4,13 @@ /* eslint-disable */ /* tslint:disable */ import { - AlgebraicType as __AlgebraicTypeValue, - BinaryReader as __BinaryReader, - BinaryWriter as __BinaryWriter, - ClientCache as __ClientCache, - ConnectionId as __ConnectionId, - DbConnectionBuilder as __DbConnectionBuilder, - DbConnectionImpl as __DbConnectionImpl, - Identity as __Identity, - SubscriptionBuilderImpl as __SubscriptionBuilderImpl, - TableCache as __TableCache, - TimeDuration as __TimeDuration, - Timestamp as __Timestamp, - deepEqual as __deepEqual, - type AlgebraicType as __AlgebraicTypeType, - type AlgebraicTypeVariants as __AlgebraicTypeVariants, - type CallReducerFlags as __CallReducerFlags, - type ErrorContextInterface as __ErrorContextInterface, - type Event as __Event, - type EventContextInterface as __EventContextInterface, - type ReducerEventContextInterface as __ReducerEventContextInterface, - type SubscriptionEventContextInterface as __SubscriptionEventContextInterface, - type TableHandle as __TableHandle, + TypeBuilder as __TypeBuilder, + t as __t, + type AlgebraicTypeType as __AlgebraicTypeType, + type Infer as __Infer, } from '../../../src/index'; -import { Counter } from './counter_type'; -import { - type EventContext, - type Reducer, - RemoteReducers, - RemoteTables, -} from '.'; -declare type __keep = [EventContext, Reducer, RemoteReducers, RemoteTables]; - -/** - * Table handle for the table `counter`. - * - * Obtain a handle from the [`counter`] property on [`RemoteTables`], - * like `ctx.db.counter`. - * - * Users are encouraged not to explicitly reference this type, - * but to directly chain method calls, - * like `ctx.db.counter.on_insert(...)`. - */ -export class CounterTableHandle - implements __TableHandle -{ - // phantom type to track the table name - readonly tableName!: TableName; - tableCache: __TableCache; - - constructor(tableCache: __TableCache) { - this.tableCache = tableCache; - } - - count(): number { - return this.tableCache.count(); - } - - iter(): Iterable { - return this.tableCache.iter(); - } - /** - * Access to the `id` unique index on the table `counter`, - * which allows point queries on the field of the same name - * via the [`CounterIdUnique.find`] method. - * - * Users are encouraged not to explicitly reference this type, - * but to directly chain method calls, - * like `ctx.db.counter.id().find(...)`. - * - * Get a handle on the `id` unique index on the table `counter`. - */ - id = { - // Find the subscribed row whose `id` column value is equal to `colVal`, - // if such a row is present in the client cache. - find: (colVal: number): Counter | undefined => { - for (let row of this.tableCache.iter()) { - if (__deepEqual(row.id, colVal)) { - return row; - } - } - }, - }; - - onInsert = (cb: (ctx: EventContext, row: Counter) => void) => { - return this.tableCache.onInsert(cb); - }; - - removeOnInsert = (cb: (ctx: EventContext, row: Counter) => void) => { - return this.tableCache.removeOnInsert(cb); - }; - - onDelete = (cb: (ctx: EventContext, row: Counter) => void) => { - return this.tableCache.onDelete(cb); - }; - - removeOnDelete = (cb: (ctx: EventContext, row: Counter) => void) => { - return this.tableCache.removeOnDelete(cb); - }; - - // Updates are only defined for tables with primary keys. - onUpdate = ( - cb: (ctx: EventContext, oldRow: Counter, newRow: Counter) => void - ) => { - return this.tableCache.onUpdate(cb); - }; - removeOnUpdate = ( - cb: (ctx: EventContext, onRow: Counter, newRow: Counter) => void - ) => { - return this.tableCache.removeOnUpdate(cb); - }; -} +export default __t.row({ + id: __t.u32(), + count: __t.u32(), +}); diff --git a/crates/bindings-typescript/test-react-router-app/src/module_bindings/counter_type.ts b/crates/bindings-typescript/test-react-router-app/src/module_bindings/counter_type.ts index 9819fbb63e3..419b8dbfe5b 100644 --- a/crates/bindings-typescript/test-react-router-app/src/module_bindings/counter_type.ts +++ b/crates/bindings-typescript/test-react-router-app/src/module_bindings/counter_type.ts @@ -4,68 +4,13 @@ /* eslint-disable */ /* tslint:disable */ import { - AlgebraicType as __AlgebraicTypeValue, - BinaryReader as __BinaryReader, - BinaryWriter as __BinaryWriter, - ClientCache as __ClientCache, - ConnectionId as __ConnectionId, - DbConnectionBuilder as __DbConnectionBuilder, - DbConnectionImpl as __DbConnectionImpl, - Identity as __Identity, - SubscriptionBuilderImpl as __SubscriptionBuilderImpl, - TableCache as __TableCache, - TimeDuration as __TimeDuration, - Timestamp as __Timestamp, - deepEqual as __deepEqual, - type AlgebraicType as __AlgebraicTypeType, - type AlgebraicTypeVariants as __AlgebraicTypeVariants, - type CallReducerFlags as __CallReducerFlags, - type ErrorContextInterface as __ErrorContextInterface, - type Event as __Event, - type EventContextInterface as __EventContextInterface, - type ReducerEventContextInterface as __ReducerEventContextInterface, - type SubscriptionEventContextInterface as __SubscriptionEventContextInterface, - type TableHandle as __TableHandle, + TypeBuilder as __TypeBuilder, + t as __t, + type AlgebraicTypeType as __AlgebraicTypeType, + type Infer as __Infer, } from '../../../src/index'; -export type Counter = { - id: number; - count: number; -}; -let _cached_Counter_type_value: __AlgebraicTypeType | null = null; - -/** - * An object for generated helper functions. - */ -export const Counter = { - /** - * A function which returns this type represented as an AlgebraicType. - * This function is derived from the AlgebraicType used to generate this type. - */ - getTypeScriptAlgebraicType(): __AlgebraicTypeType { - if (_cached_Counter_type_value) return _cached_Counter_type_value; - _cached_Counter_type_value = __AlgebraicTypeValue.Product({ elements: [] }); - _cached_Counter_type_value.value.elements.push( - { name: 'id', algebraicType: __AlgebraicTypeValue.U32 }, - { name: 'count', algebraicType: __AlgebraicTypeValue.U32 } - ); - return _cached_Counter_type_value; - }, - - serialize(writer: __BinaryWriter, value: Counter): void { - __AlgebraicTypeValue.serializeValue( - writer, - Counter.getTypeScriptAlgebraicType(), - value - ); - }, - - deserialize(reader: __BinaryReader): Counter { - return __AlgebraicTypeValue.deserializeValue( - reader, - Counter.getTypeScriptAlgebraicType() - ); - }, -}; - -export default Counter; +export default __t.object('Counter', { + id: __t.u32(), + count: __t.u32(), +}); diff --git a/crates/bindings-typescript/test-react-router-app/src/module_bindings/increment_counter_reducer.ts b/crates/bindings-typescript/test-react-router-app/src/module_bindings/increment_counter_reducer.ts index 6fe15b551af..2454b459929 100644 --- a/crates/bindings-typescript/test-react-router-app/src/module_bindings/increment_counter_reducer.ts +++ b/crates/bindings-typescript/test-react-router-app/src/module_bindings/increment_counter_reducer.ts @@ -4,65 +4,10 @@ /* eslint-disable */ /* tslint:disable */ import { - AlgebraicType as __AlgebraicTypeValue, - BinaryReader as __BinaryReader, - BinaryWriter as __BinaryWriter, - ClientCache as __ClientCache, - ConnectionId as __ConnectionId, - DbConnectionBuilder as __DbConnectionBuilder, - DbConnectionImpl as __DbConnectionImpl, - Identity as __Identity, - SubscriptionBuilderImpl as __SubscriptionBuilderImpl, - TableCache as __TableCache, - TimeDuration as __TimeDuration, - Timestamp as __Timestamp, - deepEqual as __deepEqual, - type AlgebraicType as __AlgebraicTypeType, - type AlgebraicTypeVariants as __AlgebraicTypeVariants, - type CallReducerFlags as __CallReducerFlags, - type ErrorContextInterface as __ErrorContextInterface, - type Event as __Event, - type EventContextInterface as __EventContextInterface, - type ReducerEventContextInterface as __ReducerEventContextInterface, - type SubscriptionEventContextInterface as __SubscriptionEventContextInterface, - type TableHandle as __TableHandle, + TypeBuilder as __TypeBuilder, + t as __t, + type AlgebraicTypeType as __AlgebraicTypeType, + type Infer as __Infer, } from '../../../src/index'; -export type IncrementCounter = {}; -let _cached_IncrementCounter_type_value: __AlgebraicTypeType | null = null; - -/** - * An object for generated helper functions. - */ -export const IncrementCounter = { - /** - * A function which returns this type represented as an AlgebraicType. - * This function is derived from the AlgebraicType used to generate this type. - */ - getTypeScriptAlgebraicType(): __AlgebraicTypeType { - if (_cached_IncrementCounter_type_value) - return _cached_IncrementCounter_type_value; - _cached_IncrementCounter_type_value = __AlgebraicTypeValue.Product({ - elements: [], - }); - _cached_IncrementCounter_type_value.value.elements.push(); - return _cached_IncrementCounter_type_value; - }, - - serialize(writer: __BinaryWriter, value: IncrementCounter): void { - __AlgebraicTypeValue.serializeValue( - writer, - IncrementCounter.getTypeScriptAlgebraicType(), - value - ); - }, - - deserialize(reader: __BinaryReader): IncrementCounter { - return __AlgebraicTypeValue.deserializeValue( - reader, - IncrementCounter.getTypeScriptAlgebraicType() - ); - }, -}; - -export default IncrementCounter; +export default {}; diff --git a/crates/bindings-typescript/test-react-router-app/src/module_bindings/index.ts b/crates/bindings-typescript/test-react-router-app/src/module_bindings/index.ts index 07472dc2cf0..fa3f793bdb5 100644 --- a/crates/bindings-typescript/test-react-router-app/src/module_bindings/index.ts +++ b/crates/bindings-typescript/test-react-router-app/src/module_bindings/index.ts @@ -1,298 +1,125 @@ // THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE // WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. -// This was generated using ../../../src/index cli version 1.6.0 (commit 542d26d7ffecafe93e40ac1a991c2ef2b4e4d0cb). +// This was generated using ../../../src/index cli version 1.6.0 (commit 0b0b06d5f67fecff50eb7b1c79bff5dad686f5d2). /* eslint-disable */ /* tslint:disable */ import { - AlgebraicType as __AlgebraicTypeValue, - BinaryReader as __BinaryReader, - BinaryWriter as __BinaryWriter, - ClientCache as __ClientCache, - ConnectionId as __ConnectionId, DbConnectionBuilder as __DbConnectionBuilder, DbConnectionImpl as __DbConnectionImpl, - Identity as __Identity, SubscriptionBuilderImpl as __SubscriptionBuilderImpl, - TableCache as __TableCache, - TimeDuration as __TimeDuration, - Timestamp as __Timestamp, - deepEqual as __deepEqual, - type AlgebraicType as __AlgebraicTypeType, - type AlgebraicTypeVariants as __AlgebraicTypeVariants, - type CallReducerFlags as __CallReducerFlags, + TypeBuilder as __TypeBuilder, + convertToAccessorMap as __convertToAccessorMap, + reducerSchema as __reducerSchema, + reducers as __reducers, + schema as __schema, + t as __t, + table as __table, + type AlgebraicTypeType as __AlgebraicTypeType, + type DbConnectionConfig as __DbConnectionConfig, type ErrorContextInterface as __ErrorContextInterface, type Event as __Event, type EventContextInterface as __EventContextInterface, + type Infer as __Infer, type ReducerEventContextInterface as __ReducerEventContextInterface, + type RemoteModule as __RemoteModule, type SubscriptionEventContextInterface as __SubscriptionEventContextInterface, - type TableHandle as __TableHandle, } from '../../../src/index'; // Import and reexport all reducer arg types -import { ClearCounter } from './clear_counter_reducer.ts'; +import ClearCounter from './clear_counter_reducer'; export { ClearCounter }; -import { ClientConnected } from './client_connected_reducer.ts'; +import ClientConnected from './client_connected_reducer'; export { ClientConnected }; -import { ClientDisconnected } from './client_disconnected_reducer.ts'; +import ClientDisconnected from './client_disconnected_reducer'; export { ClientDisconnected }; -import { IncrementCounter } from './increment_counter_reducer.ts'; +import IncrementCounter from './increment_counter_reducer'; export { IncrementCounter }; // Import and reexport all table handle types -import { CounterTableHandle } from './counter_table.ts'; -export { CounterTableHandle }; -import { OfflineUserTableHandle } from './offline_user_table.ts'; -export { OfflineUserTableHandle }; -import { UserTableHandle } from './user_table.ts'; -export { UserTableHandle }; +import CounterRow from './counter_table'; +export { CounterRow }; +import OfflineUserRow from './offline_user_table'; +export { OfflineUserRow }; +import UserRow from './user_table'; +export { UserRow }; // Import and reexport all types -import { Counter } from './counter_type.ts'; +import Counter from './counter_type'; export { Counter }; -import { User } from './user_type.ts'; +import User from './user_type'; export { User }; -const REMOTE_MODULE = { - tables: { - counter: { - tableName: 'counter' as const, - rowType: Counter.getTypeScriptAlgebraicType(), - primaryKey: 'id', - primaryKeyInfo: { - colName: 'id', - colType: ( - Counter.getTypeScriptAlgebraicType() as __AlgebraicTypeVariants.Product - ).value.elements[0].algebraicType, - }, - }, - offline_user: { - tableName: 'offline_user' as const, - rowType: User.getTypeScriptAlgebraicType(), - primaryKey: 'identity', - primaryKeyInfo: { - colName: 'identity', - colType: ( - User.getTypeScriptAlgebraicType() as __AlgebraicTypeVariants.Product - ).value.elements[0].algebraicType, - }, +const tablesSchema = __schema( + __table( + { + name: 'counter', + indexes: [], }, - user: { - tableName: 'user' as const, - rowType: User.getTypeScriptAlgebraicType(), - primaryKey: 'identity', - primaryKeyInfo: { - colName: 'identity', - colType: ( - User.getTypeScriptAlgebraicType() as __AlgebraicTypeVariants.Product - ).value.elements[0].algebraicType, - }, - }, - }, - reducers: { - clear_counter: { - reducerName: 'clear_counter', - argsType: ClearCounter.getTypeScriptAlgebraicType(), + CounterRow + ), + __table( + { + name: 'offline_user', + indexes: [], }, - client_connected: { - reducerName: 'client_connected', - argsType: ClientConnected.getTypeScriptAlgebraicType(), + UserRow + ), + __table( + { + name: 'user', + indexes: [], }, - client_disconnected: { - reducerName: 'client_disconnected', - argsType: ClientDisconnected.getTypeScriptAlgebraicType(), - }, - increment_counter: { - reducerName: 'increment_counter', - argsType: IncrementCounter.getTypeScriptAlgebraicType(), - }, - }, - versionInfo: { - cliVersion: '1.6.0', - }, - // Constructors which are used by the DbConnectionImpl to - // extract type information from the generated RemoteModule. - // - // NOTE: This is not strictly necessary for `eventContextConstructor` because - // all we do is build a TypeScript object which we could have done inside the - // SDK, but if in the future we wanted to create a class this would be - // necessary because classes have methods, so we'll keep it. - eventContextConstructor: ( - imp: __DbConnectionImpl, - event: __Event - ) => { - return { - ...(imp as DbConnection), - event, - }; - }, - dbViewConstructor: (imp: __DbConnectionImpl) => { - return new RemoteTables(imp); - }, - reducersConstructor: ( - imp: __DbConnectionImpl, - setReducerFlags: SetReducerFlags - ) => { - return new RemoteReducers(imp, setReducerFlags); - }, - setReducerFlagsConstructor: () => { - return new SetReducerFlags(); - }, -}; - -// A type representing all the possible variants of a reducer. -export type Reducer = - | never - | { name: 'ClearCounter'; args: ClearCounter } - | { name: 'ClientConnected'; args: ClientConnected } - | { name: 'ClientDisconnected'; args: ClientDisconnected } - | { name: 'IncrementCounter'; args: IncrementCounter }; - -export class RemoteReducers { - constructor( - private connection: __DbConnectionImpl, - private setCallReducerFlags: SetReducerFlags - ) {} - - clearCounter() { - this.connection.callReducer( - 'clear_counter', - new Uint8Array(0), - this.setCallReducerFlags.clearCounterFlags - ); - } - - onClearCounter(callback: (ctx: ReducerEventContext) => void) { - this.connection.onReducer('clear_counter', callback); - } - - removeOnClearCounter(callback: (ctx: ReducerEventContext) => void) { - this.connection.offReducer('clear_counter', callback); - } - - onClientConnected(callback: (ctx: ReducerEventContext) => void) { - this.connection.onReducer('client_connected', callback); - } - - removeOnClientConnected(callback: (ctx: ReducerEventContext) => void) { - this.connection.offReducer('client_connected', callback); - } - - onClientDisconnected(callback: (ctx: ReducerEventContext) => void) { - this.connection.onReducer('client_disconnected', callback); - } - - removeOnClientDisconnected(callback: (ctx: ReducerEventContext) => void) { - this.connection.offReducer('client_disconnected', callback); - } - - incrementCounter() { - this.connection.callReducer( - 'increment_counter', - new Uint8Array(0), - this.setCallReducerFlags.incrementCounterFlags - ); - } - - onIncrementCounter(callback: (ctx: ReducerEventContext) => void) { - this.connection.onReducer('increment_counter', callback); - } + UserRow + ) +); - removeOnIncrementCounter(callback: (ctx: ReducerEventContext) => void) { - this.connection.offReducer('increment_counter', callback); - } -} - -export class SetReducerFlags { - clearCounterFlags: __CallReducerFlags = 'FullUpdate'; - clearCounter(flags: __CallReducerFlags) { - this.clearCounterFlags = flags; - } - - incrementCounterFlags: __CallReducerFlags = 'FullUpdate'; - incrementCounter(flags: __CallReducerFlags) { - this.incrementCounterFlags = flags; - } -} +const reducersSchema = __reducers( + __reducerSchema('clear_counter', ClearCounter), + __reducerSchema('increment_counter', IncrementCounter) +); -export class RemoteTables { - constructor(private connection: __DbConnectionImpl) {} - - get counter(): CounterTableHandle<'counter'> { - // clientCache is a private property - return new CounterTableHandle( - ( - this.connection as unknown as { clientCache: __ClientCache } - ).clientCache.getOrCreateTable(REMOTE_MODULE.tables.counter) - ); - } +const REMOTE_MODULE = { + versionInfo: { + cliVersion: '1.6.0' as const, + }, + tables: tablesSchema.schemaType.tables, + reducers: reducersSchema.reducersType.reducers, +} satisfies __RemoteModule< + typeof tablesSchema.schemaType, + typeof reducersSchema.reducersType +>; - get offlineUser(): OfflineUserTableHandle<'offline_user'> { - // clientCache is a private property - return new OfflineUserTableHandle( - ( - this.connection as unknown as { clientCache: __ClientCache } - ).clientCache.getOrCreateTable(REMOTE_MODULE.tables.offline_user) - ); - } +export const tables = __convertToAccessorMap(tablesSchema.schemaType.tables); +export const reducers = __convertToAccessorMap( + reducersSchema.reducersType.reducers +); - get user(): UserTableHandle<'user'> { - // clientCache is a private property - return new UserTableHandle( - ( - this.connection as unknown as { clientCache: __ClientCache } - ).clientCache.getOrCreateTable(REMOTE_MODULE.tables.user) - ); - } -} +export type EventContext = __EventContextInterface; +export type ReducerEventContext = __ReducerEventContextInterface< + typeof REMOTE_MODULE +>; +export type SubscriptionEventContext = __SubscriptionEventContextInterface< + typeof REMOTE_MODULE +>; +export type ErrorContext = __ErrorContextInterface; export class SubscriptionBuilder extends __SubscriptionBuilderImpl< - RemoteTables, - RemoteReducers, - SetReducerFlags + typeof REMOTE_MODULE > {} -export class DbConnection extends __DbConnectionImpl< - RemoteTables, - RemoteReducers, - SetReducerFlags -> { - static builder = (): __DbConnectionBuilder< - DbConnection, - ErrorContext, - SubscriptionEventContext - > => { - return new __DbConnectionBuilder< - DbConnection, - ErrorContext, - SubscriptionEventContext - >(REMOTE_MODULE, (imp: __DbConnectionImpl) => imp as DbConnection); +export class DbConnectionBuilder extends __DbConnectionBuilder {} + +export class DbConnection extends __DbConnectionImpl { + static builder = (): DbConnectionBuilder => { + return new DbConnectionBuilder( + REMOTE_MODULE, + (config: __DbConnectionConfig) => + new DbConnection(config) + ); }; subscriptionBuilder = (): SubscriptionBuilder => { return new SubscriptionBuilder(this); }; } - -export type EventContext = __EventContextInterface< - RemoteTables, - RemoteReducers, - SetReducerFlags, - Reducer ->; -export type ReducerEventContext = __ReducerEventContextInterface< - RemoteTables, - RemoteReducers, - SetReducerFlags, - Reducer ->; -export type SubscriptionEventContext = __SubscriptionEventContextInterface< - RemoteTables, - RemoteReducers, - SetReducerFlags ->; -export type ErrorContext = __ErrorContextInterface< - RemoteTables, - RemoteReducers, - SetReducerFlags ->; diff --git a/crates/bindings-typescript/test-react-router-app/src/module_bindings/offline_user_table.ts b/crates/bindings-typescript/test-react-router-app/src/module_bindings/offline_user_table.ts index cb526e2dee8..7a83afcebf0 100644 --- a/crates/bindings-typescript/test-react-router-app/src/module_bindings/offline_user_table.ts +++ b/crates/bindings-typescript/test-react-router-app/src/module_bindings/offline_user_table.ts @@ -4,113 +4,13 @@ /* eslint-disable */ /* tslint:disable */ import { - AlgebraicType as __AlgebraicTypeValue, - BinaryReader as __BinaryReader, - BinaryWriter as __BinaryWriter, - ClientCache as __ClientCache, - ConnectionId as __ConnectionId, - DbConnectionBuilder as __DbConnectionBuilder, - DbConnectionImpl as __DbConnectionImpl, - Identity as __Identity, - SubscriptionBuilderImpl as __SubscriptionBuilderImpl, - TableCache as __TableCache, - TimeDuration as __TimeDuration, - Timestamp as __Timestamp, - deepEqual as __deepEqual, - type AlgebraicType as __AlgebraicTypeType, - type AlgebraicTypeVariants as __AlgebraicTypeVariants, - type CallReducerFlags as __CallReducerFlags, - type ErrorContextInterface as __ErrorContextInterface, - type Event as __Event, - type EventContextInterface as __EventContextInterface, - type ReducerEventContextInterface as __ReducerEventContextInterface, - type SubscriptionEventContextInterface as __SubscriptionEventContextInterface, - type TableHandle as __TableHandle, + TypeBuilder as __TypeBuilder, + t as __t, + type AlgebraicTypeType as __AlgebraicTypeType, + type Infer as __Infer, } from '../../../src/index'; -import { User } from './user_type'; -import { - type EventContext, - type Reducer, - RemoteReducers, - RemoteTables, -} from '.'; -declare type __keep = [EventContext, Reducer, RemoteReducers, RemoteTables]; - -/** - * Table handle for the table `offline_user`. - * - * Obtain a handle from the [`offlineUser`] property on [`RemoteTables`], - * like `ctx.db.offlineUser`. - * - * Users are encouraged not to explicitly reference this type, - * but to directly chain method calls, - * like `ctx.db.offlineUser.on_insert(...)`. - */ -export class OfflineUserTableHandle - implements __TableHandle -{ - // phantom type to track the table name - readonly tableName!: TableName; - tableCache: __TableCache; - - constructor(tableCache: __TableCache) { - this.tableCache = tableCache; - } - - count(): number { - return this.tableCache.count(); - } - - iter(): Iterable { - return this.tableCache.iter(); - } - /** - * Access to the `identity` unique index on the table `offline_user`, - * which allows point queries on the field of the same name - * via the [`OfflineUserIdentityUnique.find`] method. - * - * Users are encouraged not to explicitly reference this type, - * but to directly chain method calls, - * like `ctx.db.offlineUser.identity().find(...)`. - * - * Get a handle on the `identity` unique index on the table `offline_user`. - */ - identity = { - // Find the subscribed row whose `identity` column value is equal to `colVal`, - // if such a row is present in the client cache. - find: (colVal: __Identity): User | undefined => { - for (let row of this.tableCache.iter()) { - if (__deepEqual(row.identity, colVal)) { - return row; - } - } - }, - }; - - onInsert = (cb: (ctx: EventContext, row: User) => void) => { - return this.tableCache.onInsert(cb); - }; - - removeOnInsert = (cb: (ctx: EventContext, row: User) => void) => { - return this.tableCache.removeOnInsert(cb); - }; - - onDelete = (cb: (ctx: EventContext, row: User) => void) => { - return this.tableCache.onDelete(cb); - }; - - removeOnDelete = (cb: (ctx: EventContext, row: User) => void) => { - return this.tableCache.removeOnDelete(cb); - }; - - // Updates are only defined for tables with primary keys. - onUpdate = (cb: (ctx: EventContext, oldRow: User, newRow: User) => void) => { - return this.tableCache.onUpdate(cb); - }; - removeOnUpdate = ( - cb: (ctx: EventContext, onRow: User, newRow: User) => void - ) => { - return this.tableCache.removeOnUpdate(cb); - }; -} +export default __t.row({ + identity: __t.identity(), + hasIncrementedCount: __t.u32(), +}); diff --git a/crates/bindings-typescript/test-react-router-app/src/module_bindings/user_table.ts b/crates/bindings-typescript/test-react-router-app/src/module_bindings/user_table.ts index e8364a92e8f..7a83afcebf0 100644 --- a/crates/bindings-typescript/test-react-router-app/src/module_bindings/user_table.ts +++ b/crates/bindings-typescript/test-react-router-app/src/module_bindings/user_table.ts @@ -4,113 +4,13 @@ /* eslint-disable */ /* tslint:disable */ import { - AlgebraicType as __AlgebraicTypeValue, - BinaryReader as __BinaryReader, - BinaryWriter as __BinaryWriter, - ClientCache as __ClientCache, - ConnectionId as __ConnectionId, - DbConnectionBuilder as __DbConnectionBuilder, - DbConnectionImpl as __DbConnectionImpl, - Identity as __Identity, - SubscriptionBuilderImpl as __SubscriptionBuilderImpl, - TableCache as __TableCache, - TimeDuration as __TimeDuration, - Timestamp as __Timestamp, - deepEqual as __deepEqual, - type AlgebraicType as __AlgebraicTypeType, - type AlgebraicTypeVariants as __AlgebraicTypeVariants, - type CallReducerFlags as __CallReducerFlags, - type ErrorContextInterface as __ErrorContextInterface, - type Event as __Event, - type EventContextInterface as __EventContextInterface, - type ReducerEventContextInterface as __ReducerEventContextInterface, - type SubscriptionEventContextInterface as __SubscriptionEventContextInterface, - type TableHandle as __TableHandle, + TypeBuilder as __TypeBuilder, + t as __t, + type AlgebraicTypeType as __AlgebraicTypeType, + type Infer as __Infer, } from '../../../src/index'; -import { User } from './user_type'; -import { - type EventContext, - type Reducer, - RemoteReducers, - RemoteTables, -} from '.'; -declare type __keep = [EventContext, Reducer, RemoteReducers, RemoteTables]; - -/** - * Table handle for the table `user`. - * - * Obtain a handle from the [`user`] property on [`RemoteTables`], - * like `ctx.db.user`. - * - * Users are encouraged not to explicitly reference this type, - * but to directly chain method calls, - * like `ctx.db.user.on_insert(...)`. - */ -export class UserTableHandle - implements __TableHandle -{ - // phantom type to track the table name - readonly tableName!: TableName; - tableCache: __TableCache; - - constructor(tableCache: __TableCache) { - this.tableCache = tableCache; - } - - count(): number { - return this.tableCache.count(); - } - - iter(): Iterable { - return this.tableCache.iter(); - } - /** - * Access to the `identity` unique index on the table `user`, - * which allows point queries on the field of the same name - * via the [`UserIdentityUnique.find`] method. - * - * Users are encouraged not to explicitly reference this type, - * but to directly chain method calls, - * like `ctx.db.user.identity().find(...)`. - * - * Get a handle on the `identity` unique index on the table `user`. - */ - identity = { - // Find the subscribed row whose `identity` column value is equal to `colVal`, - // if such a row is present in the client cache. - find: (colVal: __Identity): User | undefined => { - for (let row of this.tableCache.iter()) { - if (__deepEqual(row.identity, colVal)) { - return row; - } - } - }, - }; - - onInsert = (cb: (ctx: EventContext, row: User) => void) => { - return this.tableCache.onInsert(cb); - }; - - removeOnInsert = (cb: (ctx: EventContext, row: User) => void) => { - return this.tableCache.removeOnInsert(cb); - }; - - onDelete = (cb: (ctx: EventContext, row: User) => void) => { - return this.tableCache.onDelete(cb); - }; - - removeOnDelete = (cb: (ctx: EventContext, row: User) => void) => { - return this.tableCache.removeOnDelete(cb); - }; - - // Updates are only defined for tables with primary keys. - onUpdate = (cb: (ctx: EventContext, oldRow: User, newRow: User) => void) => { - return this.tableCache.onUpdate(cb); - }; - removeOnUpdate = ( - cb: (ctx: EventContext, onRow: User, newRow: User) => void - ) => { - return this.tableCache.removeOnUpdate(cb); - }; -} +export default __t.row({ + identity: __t.identity(), + hasIncrementedCount: __t.u32(), +}); diff --git a/crates/bindings-typescript/test-react-router-app/src/module_bindings/user_type.ts b/crates/bindings-typescript/test-react-router-app/src/module_bindings/user_type.ts index bd12911fa23..ad6fb447e3c 100644 --- a/crates/bindings-typescript/test-react-router-app/src/module_bindings/user_type.ts +++ b/crates/bindings-typescript/test-react-router-app/src/module_bindings/user_type.ts @@ -4,71 +4,13 @@ /* eslint-disable */ /* tslint:disable */ import { - AlgebraicType as __AlgebraicTypeValue, - BinaryReader as __BinaryReader, - BinaryWriter as __BinaryWriter, - ClientCache as __ClientCache, - ConnectionId as __ConnectionId, - DbConnectionBuilder as __DbConnectionBuilder, - DbConnectionImpl as __DbConnectionImpl, - Identity as __Identity, - SubscriptionBuilderImpl as __SubscriptionBuilderImpl, - TableCache as __TableCache, - TimeDuration as __TimeDuration, - Timestamp as __Timestamp, - deepEqual as __deepEqual, - type AlgebraicType as __AlgebraicTypeType, - type AlgebraicTypeVariants as __AlgebraicTypeVariants, - type CallReducerFlags as __CallReducerFlags, - type ErrorContextInterface as __ErrorContextInterface, - type Event as __Event, - type EventContextInterface as __EventContextInterface, - type ReducerEventContextInterface as __ReducerEventContextInterface, - type SubscriptionEventContextInterface as __SubscriptionEventContextInterface, - type TableHandle as __TableHandle, + TypeBuilder as __TypeBuilder, + t as __t, + type AlgebraicTypeType as __AlgebraicTypeType, + type Infer as __Infer, } from '../../../src/index'; -export type User = { - identity: __Identity; - hasIncrementedCount: number; -}; -let _cached_User_type_value: __AlgebraicTypeType | null = null; - -/** - * An object for generated helper functions. - */ -export const User = { - /** - * A function which returns this type represented as an AlgebraicType. - * This function is derived from the AlgebraicType used to generate this type. - */ - getTypeScriptAlgebraicType(): __AlgebraicTypeType { - if (_cached_User_type_value) return _cached_User_type_value; - _cached_User_type_value = __AlgebraicTypeValue.Product({ elements: [] }); - _cached_User_type_value.value.elements.push( - { - name: 'identity', - algebraicType: __AlgebraicTypeValue.createIdentityType(), - }, - { name: 'hasIncrementedCount', algebraicType: __AlgebraicTypeValue.U32 } - ); - return _cached_User_type_value; - }, - - serialize(writer: __BinaryWriter, value: User): void { - __AlgebraicTypeValue.serializeValue( - writer, - User.getTypeScriptAlgebraicType(), - value - ); - }, - - deserialize(reader: __BinaryReader): User { - return __AlgebraicTypeValue.deserializeValue( - reader, - User.getTypeScriptAlgebraicType() - ); - }, -}; - -export default User; +export default __t.object('User', { + identity: __t.identity(), + hasIncrementedCount: __t.u32(), +}); diff --git a/crates/bindings-typescript/test-react-router-app/src/pages/CounterPage.tsx b/crates/bindings-typescript/test-react-router-app/src/pages/CounterPage.tsx index bc7d5674131..d5787e39620 100644 --- a/crates/bindings-typescript/test-react-router-app/src/pages/CounterPage.tsx +++ b/crates/bindings-typescript/test-react-router-app/src/pages/CounterPage.tsx @@ -1,9 +1,10 @@ -import { useSpacetimeDB, useTable } from '../../../src/react'; -import { DbConnection, Counter } from '../module_bindings'; +import { useReducer, useTable } from '../../../src/react'; +import { tables, reducers } from '../module_bindings'; export default function CounterPage() { - const stdb = useSpacetimeDB(); - const { rows: counter } = useTable('counter'); + const counter = useTable(tables.counter); + const incrementCounter = useReducer(reducers.incrementCounter); + const clearCounter = useReducer(reducers.clearCounter); console.log('Rendering CounterPage, current counter:', counter); @@ -11,13 +12,13 @@ export default function CounterPage() { <>

Counter

-

Click above to increment the count, click below to clear the count.

-
diff --git a/crates/bindings-typescript/test-react-router-app/src/pages/UserPage.tsx b/crates/bindings-typescript/test-react-router-app/src/pages/UserPage.tsx index 67eccc256e0..b73e004f791 100644 --- a/crates/bindings-typescript/test-react-router-app/src/pages/UserPage.tsx +++ b/crates/bindings-typescript/test-react-router-app/src/pages/UserPage.tsx @@ -1,28 +1,14 @@ -import { useEffect } from 'react'; import { useSpacetimeDB, useTable } from '../../../src/react'; -import { DbConnection, User } from '../module_bindings'; +import { tables, User } from '../module_bindings'; +import { Infer } from '../../../src'; export default function UserPage() { - const stdb = useSpacetimeDB(); - const { rows: users } = useTable('user'); + const connection = useSpacetimeDB(); + const users = useTable(tables.user); - useEffect(() => { - if (!stdb.isActive) return; - - const sub = stdb - .subscriptionBuilder() - .onError((err: any) => console.error('User subscription error:', err)) - .onApplied(() => console.log('User subscription applied')) - .subscribe('SELECT * FROM user'); - - return () => { - sub.unsubscribeThen(() => console.log('User subscription cleaned up')); - }; - }, [stdb.isActive]); - - const identityHex = stdb.identity?.toHexString(); + const identityHex = connection.identity?.toHexString(); const currentUser = users.find( - (u: User) => u.identity.toHexString() === identityHex + (u: Infer) => u.identity.toHexString() === identityHex ); return ( diff --git a/crates/codegen/src/typescript.rs b/crates/codegen/src/typescript.rs index 704ccb6069f..d6bd510dd0a 100644 --- a/crates/codegen/src/typescript.rs +++ b/crates/codegen/src/typescript.rs @@ -1,7 +1,7 @@ use crate::util::{ - is_reducer_invokable, iter_indexes, iter_reducers, iter_tables, iter_types, print_auto_generated_version_comment + is_reducer_invokable, iter_indexes, iter_reducers, iter_tables, iter_types, print_auto_generated_version_comment, }; -use crate::{OutputFile}; +use crate::OutputFile; use super::util::{collect_case, print_auto_generated_file_comment, type_ref_name}; @@ -13,7 +13,9 @@ use convert_case::{Case, Casing}; use spacetimedb_lib::sats::layout::PrimitiveType; use spacetimedb_lib::sats::AlgebraicTypeRef; use spacetimedb_primitives::ColId; -use spacetimedb_schema::def::{BTreeAlgorithm, IndexAlgorithm, ModuleDef, ReducerDef, ScopedTypeName, TableDef, TypeDef}; +use spacetimedb_schema::def::{ + BTreeAlgorithm, IndexAlgorithm, ModuleDef, ReducerDef, ScopedTypeName, TableDef, TypeDef, +}; use spacetimedb_schema::identifier::Identifier; use spacetimedb_schema::type_for_generate::{AlgebraicTypeDef, AlgebraicTypeUse, ProductTypeDef}; @@ -46,34 +48,12 @@ impl Lang for TypeScript { } }; - let define_variants_for_sum = |variants: &[(Identifier, AlgebraicTypeUse)]| { - let mut output = CodeIndenter::new(String::new(), INDENT); - let out = &mut output; - - print_file_header(out, false, true); - // Note that the current type is not included in dont_import below. - gen_and_print_imports(module, out, variants, &[], Some("Type")); - writeln!(out); - write_variant_types(module, out, variants); - out.newline(); - OutputFile { - filename: variants_module_name(&typ.name) + ".ts", - code: output.into_inner(), - } - }; - let define_type_for_sum = |variants: &[(Identifier, AlgebraicTypeUse)]| { let mut output = CodeIndenter::new(String::new(), INDENT); let out = &mut output; print_file_header(out, false, true); gen_and_print_imports(module, out, variants, &[typ.ty], None); - writeln!( - out, - "import * as {}Variants from './{}'", - type_name, - variants_module_name(&typ.name) - ); writeln!(out); // For the purpose of bootstrapping AlgebraicType, if the name of the type // is `AlgebraicType`, we need to use an alias. @@ -90,10 +70,7 @@ impl Lang for TypeScript { vec![define_type_for_product(product)] } AlgebraicTypeDef::Sum(sum) => { - vec![ - define_variants_for_sum(&sum.variants), - define_type_for_sum(&sum.variants), - ] + vec![define_type_for_sum(&sum.variants)] } AlgebraicTypeDef::PlainEnum(plain_enum) => { let variants = plain_enum @@ -102,7 +79,7 @@ impl Lang for TypeScript { .cloned() .map(|var| (var, AlgebraicTypeUse::Unit)) .collect::>(); - vec![define_variants_for_sum(&variants), define_type_for_sum(&variants)] + vec![define_type_for_sum(&variants)] } } } @@ -112,7 +89,7 @@ impl Lang for TypeScript { /// table({ /// name: 'player', /// indexes: [ - /// { name: 'this_is_an_index', algorithm: "btree", columns: [ "ownerId" ] } + /// { name: 'this_is_an_index', algorithm: "btree", columns: [ "ownerId" ] } /// ], /// }, t.row({ /// id: t.u32().primaryKey(), @@ -190,7 +167,7 @@ impl Lang for TypeScript { writeln!(out, "// Import and reexport all reducer arg types"); for reducer in iter_reducers(module) { let reducer_name = &reducer.name; - let reducer_module_name = reducer_module_name(reducer_name) + ".ts"; + let reducer_module_name = reducer_module_name(reducer_name); let args_type = reducer_args_type_name(&reducer.name); writeln!(out, "import {args_type} from \"./{reducer_module_name}\";"); writeln!(out, "export {{ {args_type} }};"); @@ -200,7 +177,7 @@ impl Lang for TypeScript { writeln!(out, "// Import and reexport all table handle types"); for table in iter_tables(module) { let table_name = &table.name; - let table_module_name = table_module_name(table_name) + ".ts"; + let table_module_name = table_module_name(table_name); let table_name_pascalcase = table.name.deref().to_case(Case::Pascal); // TODO: This really shouldn't be necessary. We could also have `table()` accept // `__t.object(...)`s. @@ -212,13 +189,13 @@ impl Lang for TypeScript { writeln!(out, "// Import and reexport all types"); for ty in iter_types(module) { let type_name = collect_case(Case::Pascal, ty.name.name_segments()); - let type_module_name = type_module_name(&ty.name) + ".ts"; + let type_module_name = type_module_name(&ty.name); writeln!(out, "import {type_name} from \"./{type_module_name}\";"); writeln!(out, "export {{ {type_name} }};"); } out.newline(); - + writeln!(out); writeln!(out, "const tablesSchema = __schema("); out.indent(1); @@ -271,8 +248,14 @@ impl Lang for TypeScript { out.dedent(1); writeln!(out); - writeln!(out, "export const tables = __convertToAccessorMap(tablesSchema.schemaType.tables);"); - writeln!(out, "export const reducers = __convertToAccessorMap(reducersSchema.reducersType.reducers);"); + writeln!( + out, + "export const tables = __convertToAccessorMap(tablesSchema.schemaType.tables);" + ); + writeln!( + out, + "export const reducers = __convertToAccessorMap(reducersSchema.reducersType.reducers);" + ); writeln!(out); out.newline(); @@ -297,7 +280,10 @@ impl Lang for TypeScript { writeln!(out); - writeln!(out, "export class SubscriptionBuilder extends __SubscriptionBuilderImpl<"); + writeln!( + out, + "export class SubscriptionBuilder extends __SubscriptionBuilderImpl<" + ); out.indent(1); writeln!(out, "typeof REMOTE_MODULE"); out.dedent(1); @@ -316,10 +302,7 @@ impl Lang for TypeScript { "export class DbConnection extends __DbConnectionImpl {{" ); out.indent(1); - writeln!( - out, - "static builder = (): DbConnectionBuilder => {{" - ); + writeln!(out, "static builder = (): DbConnectionBuilder => {{"); out.indent(1); writeln!( out, @@ -327,13 +310,10 @@ impl Lang for TypeScript { ); out.dedent(1); writeln!(out, "}};"); - writeln!( - out, - "subscriptionBuilder = (): SubscriptionBuilder => {{" - ); + writeln!(out, "subscriptionBuilder = (): SubscriptionBuilder => {{"); out.indent(1); writeln!(out, "return new SubscriptionBuilder(this);"); - + out.dedent(1); writeln!(out, "}};"); out.dedent(1); @@ -350,7 +330,7 @@ impl Lang for TypeScript { fn print_index_imports(out: &mut Indenter) { // All library imports are prefixed with `__` to avoid // clashing with the names of user generated types. - let mut types = [ + let mut types = [ "TypeBuilder as __TypeBuilder", "type AlgebraicTypeType as __AlgebraicTypeType", "DbConnectionBuilder as __DbConnectionBuilder", @@ -384,7 +364,7 @@ fn print_index_imports(out: &mut Indenter) { fn print_type_builder_imports(out: &mut Indenter) { // All library imports are prefixed with `__` to avoid // clashing with the names of user generated types. - let mut types = [ + let mut types = [ "TypeBuilder as __TypeBuilder", "type AlgebraicTypeType as __AlgebraicTypeType", "type Infer as __Infer", @@ -426,15 +406,11 @@ fn print_lint_suppression(output: &mut Indenter) { /// fooBar: __t.string(), /// }; /// ``` -fn define_body_for_reducer( - module: &ModuleDef, - out: &mut Indenter, - params: &[(Identifier, AlgebraicTypeUse)], -) { +fn define_body_for_reducer(module: &ModuleDef, out: &mut Indenter, params: &[(Identifier, AlgebraicTypeUse)]) { write!(out, "export default {{"); if params.is_empty() { writeln!(out, "}};"); - } else { + } else { writeln!(out); out.with_indent(|out| write_object_type_builder_fields(module, out, params, true).unwrap()); writeln!(out, "}};"); @@ -455,7 +431,6 @@ fn define_body_for_product( name: &str, elements: &[(Identifier, AlgebraicTypeUse)], ) { - write!(out, "export default __t.object(\"{name}\", {{"); if elements.is_empty() { writeln!(out, "}});"); @@ -470,11 +445,7 @@ fn define_body_for_product( fn write_table_opts(module: &ModuleDef, out: &mut Indenter, table: &TableDef) { let type_ref = table.product_type_ref; let product_def = module.typespace_for_generate()[type_ref].as_product().unwrap(); - writeln!( - out, - "name: '{}',", - table.name.deref() - ); + writeln!(out, "name: '{}',", table.name.deref()); writeln!(out, "indexes: ["); out.indent(1); for index_def in iter_indexes(table) { @@ -533,12 +504,7 @@ fn write_object_type_builder_fields( Ok(()) } -fn write_type_builder_field( - module: &ModuleDef, - out: &mut Indenter, - name: &str, - ty: &AlgebraicTypeUse, -) -> fmt::Result { +fn write_type_builder_field(module: &ModuleDef, out: &mut Indenter, name: &str, ty: &AlgebraicTypeUse) -> fmt::Result { // Do we need a getter? (Option/Array only if their inner is a Ref) let needs_getter = match ty { AlgebraicTypeUse::Ref(_) => true, @@ -579,7 +545,7 @@ fn write_type_builder(module: &ModuleDef, out: &mut W, ty: &AlgebraicT write!(out, "__t.option(")?; write_type_builder(module, out, inner_ty)?; write!(out, ")")?; - }, + } AlgebraicTypeUse::Primitive(prim) => match prim { PrimitiveType::Bool => write!(out, "__t.bool()")?, PrimitiveType::I8 => write!(out, "__t.i8()")?, @@ -605,59 +571,14 @@ fn write_type_builder(module: &ModuleDef, out: &mut W, ty: &AlgebraicT write!(out, "__t.array(")?; write_type_builder(module, out, elem_ty)?; write!(out, ")")?; - }, + } AlgebraicTypeUse::Ref(r) => { write!(out, "{}", type_ref_name(module, *r))?; - }, + } } Ok(()) } -fn write_sum_variant_type(module: &ModuleDef, out: &mut Indenter, ident: &Identifier, ty: &AlgebraicTypeUse) { - let name = ident.deref().to_case(Case::Pascal); - write!(out, "export type {name} = "); - - // If the contained type is the unit type, i.e. this variant has no members, - // write only the tag. - // ``` - // { tag: "Foo" } - // ``` - write!(out, "{{ "); - write!(out, "tag: \"{name}\""); - - // If the contained type is not the unit type, write the tag and the value. - // ``` - // { tag: "Bar", value: Infer } - // { tag: "Bar", value: number } - // { tag: "Bar", value: string } - // ``` - // Note you could alternatively do: - // ``` - // { tag: "Bar" } & Infer - // ``` - // for non-primitive types but that doesn't extend to primitives. - // Another alternative would be to name the value field the same as the tag field, but lowercased - // ``` - // { tag: "Bar", bar: Infer } - // { tag: "Bar", bar: number } - // { tag: "Bar", bar: string } - // ``` - // but this is a departure from our previous convention and is not much different. - if !matches!(ty, AlgebraicTypeUse::Unit) { - write!(out, ", value: "); - write_type(module, out, ty, None, Some("Type")).unwrap(); - } - - writeln!(out, " }};"); -} - -fn write_variant_types(module: &ModuleDef, out: &mut Indenter, variants: &[(Identifier, AlgebraicTypeUse)]) { - // Write all the variant types. - for (ident, ty) in variants { - write_sum_variant_type(module, out, ident, ty); - } -} - /// e.g. /// ```ts /// // The tagged union or sum type for the algebraic type `Option`. @@ -694,34 +615,18 @@ fn type_module_name(type_name: &ScopedTypeName) -> String { collect_case(Case::Snake, type_name.name_segments()) + "_type" } -fn variants_module_name(type_name: &ScopedTypeName) -> String { - collect_case(Case::Snake, type_name.name_segments()) + "_variants" -} - fn table_module_name(table_name: &Identifier) -> String { table_name.deref().to_case(Case::Snake) + "_table" } -fn table_method_name(table_name: &Identifier) -> String { - table_name.deref().to_case(Case::Camel) -} - fn reducer_args_type_name(reducer_name: &Identifier) -> String { reducer_name.deref().to_case(Case::Pascal) } -fn reducer_variant_name(reducer_name: &Identifier) -> String { - reducer_name.deref().to_case(Case::Pascal) -} - fn reducer_module_name(reducer_name: &Identifier) -> String { reducer_name.deref().to_case(Case::Snake) + "_reducer" } -fn reducer_function_name(reducer: &ReducerDef) -> String { - reducer.name.deref().to_case(Case::Camel) -} - pub fn type_name(module: &ModuleDef, ty: &AlgebraicTypeUse) -> String { let mut s = String::new(); write_type(module, &mut s, ty, None, None).unwrap(); @@ -827,10 +732,7 @@ fn print_imports(module: &ModuleDef, out: &mut Indenter, imports: Imports, suffi let module_name = type_ref_module_name(module, typeref); let type_name = type_ref_name(module, typeref); if let Some(suffix) = suffix { - writeln!( - out, - "import {type_name}{suffix} from \"./{module_name}\";" - ); + writeln!(out, "import {type_name}{suffix} from \"./{module_name}\";"); } else { writeln!(out, "import {type_name} from \"./{module_name}\";"); } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index bd66da9016c..5a173665ccb 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -57,8 +57,8 @@ importers: specifier: ^3.3.3 version: 3.6.2 react: - specifier: ^18.0.0 || ^19.0.0-0 || ^19.0.0 - version: 18.3.1 + specifier: ^19.0.0 + version: 19.2.0 undici: specifier: ^6.19.2 version: 6.21.3 @@ -204,6 +204,37 @@ importers: specifier: ^7.1.5 version: 7.1.5(@types/node@24.3.0)(jiti@2.5.1)(terser@5.43.1)(tsx@4.20.4) + crates/bindings-typescript/test-react-router-app: + dependencies: + react: + specifier: ^18.3.1 + version: 18.3.1 + react-dom: + specifier: ^18.3.1 + version: 18.3.1(react@18.3.1) + react-router-dom: + specifier: ^7.9.4 + version: 7.9.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + devDependencies: + '@types/react': + specifier: ^18.3.3 + version: 18.3.23 + '@types/react-dom': + specifier: ^18.3.0 + version: 18.3.7(@types/react@18.3.23) + '@types/react-router-dom': + specifier: ^5.3.3 + version: 5.3.3 + '@vitejs/plugin-react': + specifier: ^4.3.1 + version: 4.7.0(vite@7.1.5(@types/node@24.3.0)(jiti@2.5.1)(terser@5.43.1)(tsx@4.20.4)) + typescript: + specifier: ^5.2.2 + version: 5.9.3 + vite: + specifier: ^7.1.5 + version: 7.1.5(@types/node@24.3.0)(jiti@2.5.1)(terser@5.43.1)(tsx@4.20.4) + docs: dependencies: '@docusaurus/core': @@ -211,7 +242,7 @@ importers: version: 3.9.1(@mdx-js/react@3.1.1(@types/react@19.2.0)(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.6.3) '@docusaurus/plugin-content-docs': specifier: ^3.9.2 - version: 3.9.2(@mdx-js/react@3.1.1(@types/react@19.2.0)(react@19.2.0))(debug@4.4.3)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.6.3) + version: 3.9.2(@mdx-js/react@3.1.1(@types/react@19.2.0)(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.6.3) '@docusaurus/preset-classic': specifier: 3.9.1 version: 3.9.1(@algolia/client-search@5.39.0)(@mdx-js/react@3.1.1(@types/react@19.2.0)(react@19.2.0))(@types/react@19.2.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(search-insights@2.17.3)(typescript@5.6.3) @@ -4522,6 +4553,10 @@ packages: resolution: {integrity: sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==} engines: {node: '>= 0.6'} + cookie@1.0.2: + resolution: {integrity: sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==} + engines: {node: '>=18'} + copy-webpack-plugin@11.0.0: resolution: {integrity: sha512-fX2MWpamkW0hZxMEg0+mYnA40LTosOSa5TqZ9GYIBzyJa9C3QUaMPSE2xAi/buNr8u89SfD9wHSQVBzrRa/SOQ==} engines: {node: '>= 14.15.0'} @@ -7511,11 +7546,28 @@ packages: peerDependencies: react: '>=15' + react-router-dom@7.9.5: + resolution: {integrity: sha512-mkEmq/K8tKN63Ae2M7Xgz3c9l9YNbY+NHH6NNeUmLA3kDkhKXRsNb/ZpxaEunvGo2/3YXdk5EJU3Hxp3ocaBPw==} + engines: {node: '>=20.0.0'} + peerDependencies: + react: '>=18' + react-dom: '>=18' + react-router@5.3.4: resolution: {integrity: sha512-Ys9K+ppnJah3QuaRiLxk+jDWOR1MekYQrlytiXxC1RyfbdsZkS5pvKAzCCr031xHixZwpnsYNT5xysdFHQaYsA==} peerDependencies: react: '>=15' + react-router@7.9.5: + resolution: {integrity: sha512-JmxqrnBZ6E9hWmf02jzNn9Jm3UqyeimyiwzD69NjxGySG6lIz/1LVPsoTCwN7NBX2XjCEa1LIX5EMz1j2b6u6A==} + engines: {node: '>=20.0.0'} + peerDependencies: + react: '>=18' + react-dom: '>=18' + peerDependenciesMeta: + react-dom: + optional: true + react-style-singleton@2.2.3: resolution: {integrity: sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==} engines: {node: '>=10'} @@ -7827,6 +7879,9 @@ packages: resolution: {integrity: sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==} engines: {node: '>= 0.8.0'} + set-cookie-parser@2.7.2: + resolution: {integrity: sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==} + set-function-length@1.2.2: resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} engines: {node: '>= 0.4'} @@ -9131,10 +9186,10 @@ snapshots: '@babel/helper-compilation-targets': 7.27.2 '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.3) '@babel/helpers': 7.28.3 - '@babel/parser': 7.28.3 + '@babel/parser': 7.28.4 '@babel/template': 7.27.2 - '@babel/traverse': 7.28.3 - '@babel/types': 7.28.2 + '@babel/traverse': 7.28.4 + '@babel/types': 7.28.4 convert-source-map: 2.0.0 debug: 4.4.3 gensync: 1.0.0-beta.2 @@ -9145,8 +9200,8 @@ snapshots: '@babel/generator@7.28.3': dependencies: - '@babel/parser': 7.28.3 - '@babel/types': 7.28.2 + '@babel/parser': 7.28.4 + '@babel/types': 7.28.4 '@jridgewell/gen-mapping': 0.3.13 '@jridgewell/trace-mapping': 0.3.30 jsesc: 3.1.0 @@ -9206,7 +9261,7 @@ snapshots: '@babel/helper-module-imports@7.27.1': dependencies: '@babel/traverse': 7.28.4 - '@babel/types': 7.28.2 + '@babel/types': 7.28.4 transitivePeerDependencies: - supports-color @@ -9215,7 +9270,7 @@ snapshots: '@babel/core': 7.28.3 '@babel/helper-module-imports': 7.27.1 '@babel/helper-validator-identifier': 7.27.1 - '@babel/traverse': 7.28.3 + '@babel/traverse': 7.28.4 transitivePeerDependencies: - supports-color @@ -9267,7 +9322,7 @@ snapshots: '@babel/helpers@7.28.3': dependencies: '@babel/template': 7.27.2 - '@babel/types': 7.28.2 + '@babel/types': 7.28.4 '@babel/parser@7.28.3': dependencies: @@ -9862,8 +9917,8 @@ snapshots: '@babel/template@7.27.2': dependencies: '@babel/code-frame': 7.27.1 - '@babel/parser': 7.28.3 - '@babel/types': 7.28.2 + '@babel/parser': 7.28.4 + '@babel/types': 7.28.4 '@babel/traverse@7.28.3': dependencies: @@ -10711,6 +10766,46 @@ snapshots: - webpack-cli '@docusaurus/plugin-content-docs@3.9.2(@mdx-js/react@3.1.1(@types/react@19.2.0)(react@19.2.0))(debug@4.4.3)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.6.3)': + dependencies: + '@docusaurus/core': 3.9.2(@mdx-js/react@3.1.1(@types/react@19.2.0)(react@19.2.0))(debug@4.4.3)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.6.3) + '@docusaurus/logger': 3.9.2 + '@docusaurus/mdx-loader': 3.9.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@docusaurus/module-type-aliases': 3.9.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@docusaurus/theme-common': 3.9.2(@docusaurus/plugin-content-docs@3.9.2(@mdx-js/react@3.1.1(@types/react@19.2.0)(react@19.2.0))(debug@4.4.3)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.6.3))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@docusaurus/types': 3.9.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@docusaurus/utils': 3.9.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@docusaurus/utils-common': 3.9.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@docusaurus/utils-validation': 3.9.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@types/react-router-config': 5.0.11 + combine-promises: 1.2.0 + fs-extra: 11.3.2 + js-yaml: 4.1.0 + lodash: 4.17.21 + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + schema-dts: 1.1.5 + tslib: 2.8.1 + utility-types: 3.11.0 + webpack: 5.102.0 + transitivePeerDependencies: + - '@docusaurus/faster' + - '@mdx-js/react' + - '@parcel/css' + - '@rspack/core' + - '@swc/core' + - '@swc/css' + - bufferutil + - csso + - debug + - esbuild + - lightningcss + - supports-color + - typescript + - uglify-js + - utf-8-validate + - webpack-cli + + '@docusaurus/plugin-content-docs@3.9.2(@mdx-js/react@3.1.1(@types/react@19.2.0)(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.6.3)': dependencies: '@docusaurus/core': 3.9.2(@mdx-js/react@3.1.1(@types/react@19.2.0)(react@19.2.0))(debug@4.4.3)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.6.3) '@docusaurus/logger': 3.9.2 @@ -11095,7 +11190,7 @@ snapshots: dependencies: '@docusaurus/mdx-loader': 3.9.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@docusaurus/module-type-aliases': 3.9.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@docusaurus/plugin-content-docs': 3.9.2(@mdx-js/react@3.1.1(@types/react@19.2.0)(react@19.2.0))(debug@4.4.3)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.6.3) + '@docusaurus/plugin-content-docs': 3.9.2(@mdx-js/react@3.1.1(@types/react@19.2.0)(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.6.3) '@docusaurus/utils': 3.9.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@docusaurus/utils-common': 3.9.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@types/history': 4.7.11 @@ -11115,7 +11210,7 @@ snapshots: - uglify-js - webpack-cli - '@docusaurus/theme-common@3.9.2(@docusaurus/plugin-content-docs@3.9.2(@mdx-js/react@3.1.1(@types/react@19.2.0)(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.6.3))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + '@docusaurus/theme-common@3.9.2(@docusaurus/plugin-content-docs@3.9.2(@mdx-js/react@3.1.1(@types/react@19.2.0)(react@19.2.0))(debug@4.4.3)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.6.3))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': dependencies: '@docusaurus/mdx-loader': 3.9.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@docusaurus/module-type-aliases': 3.9.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0) @@ -11139,6 +11234,30 @@ snapshots: - uglify-js - webpack-cli + '@docusaurus/theme-common@3.9.2(@docusaurus/plugin-content-docs@3.9.2(@mdx-js/react@3.1.1(@types/react@19.2.0)(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.6.3))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@docusaurus/mdx-loader': 3.9.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@docusaurus/module-type-aliases': 3.9.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@docusaurus/plugin-content-docs': 3.9.2(@mdx-js/react@3.1.1(@types/react@19.2.0)(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.6.3) + '@docusaurus/utils': 3.9.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@docusaurus/utils-common': 3.9.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@types/history': 4.7.11 + '@types/react': 18.3.23 + '@types/react-router-config': 5.0.11 + clsx: 2.1.1 + parse-numeric-range: 1.3.0 + prism-react-renderer: 2.4.1(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + tslib: 2.8.1 + utility-types: 3.11.0 + transitivePeerDependencies: + - '@swc/core' + - esbuild + - supports-color + - uglify-js + - webpack-cli + '@docusaurus/theme-search-algolia@3.9.1(@algolia/client-search@5.39.0)(@mdx-js/react@3.1.1(@types/react@19.2.0)(react@19.2.0))(@types/react@19.2.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(search-insights@2.17.3)(typescript@5.6.3)': dependencies: '@docsearch/react': 4.2.0(@algolia/client-search@5.39.0)(@types/react@19.2.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(search-insights@2.17.3) @@ -13175,24 +13294,24 @@ snapshots: '@types/babel__core@7.20.5': dependencies: - '@babel/parser': 7.28.3 - '@babel/types': 7.28.2 + '@babel/parser': 7.28.4 + '@babel/types': 7.28.4 '@types/babel__generator': 7.27.0 '@types/babel__template': 7.4.4 '@types/babel__traverse': 7.28.0 '@types/babel__generator@7.27.0': dependencies: - '@babel/types': 7.28.2 + '@babel/types': 7.28.4 '@types/babel__template@7.4.4': dependencies: - '@babel/parser': 7.28.3 - '@babel/types': 7.28.2 + '@babel/parser': 7.28.4 + '@babel/types': 7.28.4 '@types/babel__traverse@7.28.0': dependencies: - '@babel/types': 7.28.2 + '@babel/types': 7.28.4 '@types/body-parser@1.19.6': dependencies: @@ -15280,6 +15399,8 @@ snapshots: cookie@0.7.1: {} + cookie@1.0.2: {} + copy-webpack-plugin@11.0.0(webpack@5.102.0): dependencies: fast-glob: 3.3.3 @@ -18813,6 +18934,12 @@ snapshots: tiny-invariant: 1.3.3 tiny-warning: 1.0.3 + react-router-dom@7.9.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + dependencies: + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + react-router: 7.9.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + react-router@5.3.4(react@19.2.0): dependencies: '@babel/runtime': 7.28.4 @@ -18826,6 +18953,14 @@ snapshots: tiny-invariant: 1.3.3 tiny-warning: 1.0.3 + react-router@7.9.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + dependencies: + cookie: 1.0.2 + react: 18.3.1 + set-cookie-parser: 2.7.2 + optionalDependencies: + react-dom: 18.3.1(react@18.3.1) + react-style-singleton@2.2.3(@types/react@19.2.0)(react@19.2.0): dependencies: get-nonce: 1.0.1 @@ -19262,6 +19397,8 @@ snapshots: transitivePeerDependencies: - supports-color + set-cookie-parser@2.7.2: {} + set-function-length@1.2.2: dependencies: define-data-property: 1.1.4 From d398d25d044a837e6e517713ef267b15453dfcaa Mon Sep 17 00:00:00 2001 From: = Date: Sun, 9 Nov 2025 16:26:12 -0500 Subject: [PATCH 20/49] pnpm format --- crates/bindings-typescript/src/lib/indexes.ts | 2 +- crates/bindings-typescript/src/lib/schema.ts | 7 ++++++- crates/bindings-typescript/src/lib/util.ts | 7 +++++-- crates/bindings-typescript/src/react/useReducer.ts | 10 ++++------ .../bindings-typescript/src/sdk/db_connection_impl.ts | 4 +--- crates/bindings-typescript/src/sdk/db_context.ts | 5 +---- crates/bindings-typescript/src/sdk/table_cache.ts | 9 ++------- crates/bindings-typescript/src/server/runtime.ts | 7 ++++++- .../test-react-router-app/src/pages/CounterPage.tsx | 4 +--- 9 files changed, 27 insertions(+), 28 deletions(-) diff --git a/crates/bindings-typescript/src/lib/indexes.ts b/crates/bindings-typescript/src/lib/indexes.ts index 9ac54cdd83c..75e0b0a0b8d 100644 --- a/crates/bindings-typescript/src/lib/indexes.ts +++ b/crates/bindings-typescript/src/lib/indexes.ts @@ -97,7 +97,7 @@ export interface UniqueIndex< > extends ReadonlyUniqueIndex { delete(colVal: IndexVal): boolean; update(colVal: RowType): RowType; -}; +} /** * A type representing a read-only ranged index on a database table. diff --git a/crates/bindings-typescript/src/lib/schema.ts b/crates/bindings-typescript/src/lib/schema.ts index d5bc6fdbe45..367a0018929 100644 --- a/crates/bindings-typescript/src/lib/schema.ts +++ b/crates/bindings-typescript/src/lib/schema.ts @@ -33,7 +33,12 @@ import type RawScopedTypeNameV9 from './autogen/raw_scoped_type_name_v_9_type'; import type { CamelCase } from './type_util'; import type { TableSchema } from './table_schema'; import { toCamelCase } from './util'; -import { defineView, type AnonymousViewFn, type ViewFn, type ViewReturnTypeBuilder } from './views'; +import { + defineView, + type AnonymousViewFn, + type ViewFn, + type ViewReturnTypeBuilder, +} from './views'; export type TableNamesOf = S['tables'][number]['name']; diff --git a/crates/bindings-typescript/src/lib/util.ts b/crates/bindings-typescript/src/lib/util.ts index 83822e6c760..c13a90b0e53 100644 --- a/crates/bindings-typescript/src/lib/util.ts +++ b/crates/bindings-typescript/src/lib/util.ts @@ -113,7 +113,10 @@ import type { AlgebraicType } from './algebraic_type'; import type Typespace from './autogen/typespace_type'; import type { Infer } from './type_builders'; -export function bsatnBaseSize(typespace: Infer, ty: AlgebraicType): number { +export function bsatnBaseSize( + typespace: Infer, + ty: AlgebraicType +): number { const assumedArrayLength = 4; while (ty.tag === 'Ref') ty = typespace.types[ty.value]; if (ty.tag === 'Product') { @@ -152,4 +155,4 @@ export function bsatnBaseSize(typespace: Infer, ty: AlgebraicT I256: 32, U256: 32, }[ty.tag]; -} \ No newline at end of file +} diff --git a/crates/bindings-typescript/src/react/useReducer.ts b/crates/bindings-typescript/src/react/useReducer.ts index dc93ae01b58..742f456ae31 100644 --- a/crates/bindings-typescript/src/react/useReducer.ts +++ b/crates/bindings-typescript/src/react/useReducer.ts @@ -7,9 +7,9 @@ import type { Prettify } from '../lib/type_util'; type IsEmptyObject = [keyof T] extends [never] ? true : false; type MaybeParams = IsEmptyObject extends true ? [] : [params: T]; -type ParamsType = MaybeParams ->>; +type ParamsType = MaybeParams< + Prettify> +>; export function useReducer( reducerDef: ReducerDef @@ -18,9 +18,7 @@ export function useReducer( const reducerName = reducerDef.accessorName; // Holds calls made before the connection exists - const queueRef = useRef< - ParamsType[] - >([]); + const queueRef = useRef[]>([]); // Flush when we finally have a connection useEffect(() => { diff --git a/crates/bindings-typescript/src/sdk/db_connection_impl.ts b/crates/bindings-typescript/src/sdk/db_connection_impl.ts index ddfaac3b0b1..1e250548738 100644 --- a/crates/bindings-typescript/src/sdk/db_connection_impl.ts +++ b/crates/bindings-typescript/src/sdk/db_connection_impl.ts @@ -28,9 +28,7 @@ import type { UnsubscribeAppliedMessage, } from './message_types.ts'; import type { ReducerEvent } from './reducer_event.ts'; -import { - type UntypedRemoteModule, -} from './spacetime_module.ts'; +import { type UntypedRemoteModule } from './spacetime_module.ts'; import { TableCache, type Operation, diff --git a/crates/bindings-typescript/src/sdk/db_context.ts b/crates/bindings-typescript/src/sdk/db_context.ts index 230170ac840..f34bf4a95ed 100644 --- a/crates/bindings-typescript/src/sdk/db_context.ts +++ b/crates/bindings-typescript/src/sdk/db_context.ts @@ -1,8 +1,5 @@ import type { ClientDbView } from './db_view'; -import type { - ReducersView, - SetReducerFlags, -} from './reducers'; +import type { ReducersView, SetReducerFlags } from './reducers'; import type { UntypedRemoteModule } from './spacetime_module'; import type { SubscriptionBuilderImpl } from './subscription_builder_impl'; diff --git a/crates/bindings-typescript/src/sdk/table_cache.ts b/crates/bindings-typescript/src/sdk/table_cache.ts index 2ff2a1ac194..abc4fb147d5 100644 --- a/crates/bindings-typescript/src/sdk/table_cache.ts +++ b/crates/bindings-typescript/src/sdk/table_cache.ts @@ -2,14 +2,9 @@ import { EventEmitter } from './event_emitter.ts'; import { stdbLogger } from './logger.ts'; import type { ComparablePrimitive } from '../'; -import type { - EventContextInterface, - TableDefForTableName, -} from './index.ts'; +import type { EventContextInterface, TableDefForTableName } from './index.ts'; import type { RowType, UntypedTableDef } from '../lib/table.ts'; -import type { - ClientTableCoreImplementable, -} from './client_table.ts'; +import type { ClientTableCoreImplementable } from './client_table.ts'; import type { UntypedRemoteModule } from './spacetime_module.ts'; import type { TableNamesOf } from '../lib/schema.ts'; diff --git a/crates/bindings-typescript/src/server/runtime.ts b/crates/bindings-typescript/src/server/runtime.ts index a6a02308d23..92b50768052 100644 --- a/crates/bindings-typescript/src/server/runtime.ts +++ b/crates/bindings-typescript/src/server/runtime.ts @@ -32,7 +32,12 @@ import type { DbView } from './db_view'; import { toCamelCase } from '../lib/util'; import type { Infer } from '../lib/type_builders'; import { bsatnBaseSize } from '../lib/util'; -import { ANON_VIEWS, VIEWS, type AnonymousViewCtx, type ViewCtx } from '../lib/views'; +import { + ANON_VIEWS, + VIEWS, + type AnonymousViewCtx, + type ViewCtx, +} from '../lib/views'; const { freeze } = Object; diff --git a/crates/bindings-typescript/test-react-router-app/src/pages/CounterPage.tsx b/crates/bindings-typescript/test-react-router-app/src/pages/CounterPage.tsx index d5787e39620..034ba900866 100644 --- a/crates/bindings-typescript/test-react-router-app/src/pages/CounterPage.tsx +++ b/crates/bindings-typescript/test-react-router-app/src/pages/CounterPage.tsx @@ -18,9 +18,7 @@ export default function CounterPage() {

Click above to increment the count, click below to clear the count.

- + ); From c61fae717081900187abc1ad39ac841af540346c Mon Sep 17 00:00:00 2001 From: = Date: Sun, 9 Nov 2025 16:26:27 -0500 Subject: [PATCH 21/49] cargo fmt --- crates/codegen/src/typescript.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/crates/codegen/src/typescript.rs b/crates/codegen/src/typescript.rs index ba1872a7be5..c3aa847b7e4 100644 --- a/crates/codegen/src/typescript.rs +++ b/crates/codegen/src/typescript.rs @@ -99,7 +99,12 @@ impl Lang for TypeScript { /// location: pointType, /// })) /// ``` - fn generate_table_file_from_schema(&self, module: &ModuleDef, table: &TableDef, _schema: TableSchema) -> OutputFile { + fn generate_table_file_from_schema( + &self, + module: &ModuleDef, + table: &TableDef, + _schema: TableSchema, + ) -> OutputFile { let mut output = CodeIndenter::new(String::new(), INDENT); let out = &mut output; From 64b3404f9829fa9825cb1b460c912621d493a8d4 Mon Sep 17 00:00:00 2001 From: = Date: Sun, 9 Nov 2025 16:28:38 -0500 Subject: [PATCH 22/49] misconfigured import --- crates/bindings-typescript/src/server/runtime.ts | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/crates/bindings-typescript/src/server/runtime.ts b/crates/bindings-typescript/src/server/runtime.ts index 92b50768052..a6a02308d23 100644 --- a/crates/bindings-typescript/src/server/runtime.ts +++ b/crates/bindings-typescript/src/server/runtime.ts @@ -32,12 +32,7 @@ import type { DbView } from './db_view'; import { toCamelCase } from '../lib/util'; import type { Infer } from '../lib/type_builders'; import { bsatnBaseSize } from '../lib/util'; -import { - ANON_VIEWS, - VIEWS, - type AnonymousViewCtx, - type ViewCtx, -} from '../lib/views'; +import { ANON_VIEWS, VIEWS, type AnonymousViewCtx, type ViewCtx } from '../lib/views'; const { freeze } = Object; From 31243a71da6b5b921f89507411e20fa9f2e575ee Mon Sep 17 00:00:00 2001 From: = Date: Sun, 9 Nov 2025 16:29:52 -0500 Subject: [PATCH 23/49] Fixed broken type tests --- crates/bindings-typescript/src/server/schema.test-d.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/bindings-typescript/src/server/schema.test-d.ts b/crates/bindings-typescript/src/server/schema.test-d.ts index 8ffc6f50656..c1846ca1716 100644 --- a/crates/bindings-typescript/src/server/schema.test-d.ts +++ b/crates/bindings-typescript/src/server/schema.test-d.ts @@ -1,6 +1,6 @@ -import { schema } from './schema'; -import { table } from './table'; -import t from './type_builders'; +import { schema } from '../lib/schema'; +import { table } from '../lib/table'; +import t from '../lib/type_builders'; const person = table( { From 57bd49bec937a3ae060c1c9af85979525fdb839d Mon Sep 17 00:00:00 2001 From: = Date: Sun, 9 Nov 2025 20:11:25 -0500 Subject: [PATCH 24/49] Fixed up the API a bit to have fewer breaking changes --- .../src/lib/autogen/algebraic_type_type.ts | 2 +- .../src/lib/autogen/index_type_type.ts | 2 +- .../src/lib/autogen/lifecycle_type.ts | 2 +- .../lib/autogen/misc_module_export_type.ts | 2 +- .../lib/autogen/product_type_element_type.ts | 2 +- .../src/lib/autogen/product_type_type.ts | 2 +- .../lib/autogen/raw_column_def_v_8_type.ts | 2 +- .../raw_column_default_value_v_9_type.ts | 2 +- .../autogen/raw_constraint_data_v_9_type.ts | 2 +- .../autogen/raw_constraint_def_v_8_type.ts | 2 +- .../autogen/raw_constraint_def_v_9_type.ts | 2 +- .../lib/autogen/raw_index_algorithm_type.ts | 2 +- .../src/lib/autogen/raw_index_def_v_8_type.ts | 2 +- .../src/lib/autogen/raw_index_def_v_9_type.ts | 2 +- .../raw_misc_module_export_v_9_type.ts | 2 +- .../src/lib/autogen/raw_module_def_type.ts | 2 +- .../lib/autogen/raw_module_def_v_8_type.ts | 2 +- .../lib/autogen/raw_module_def_v_9_type.ts | 2 +- .../lib/autogen/raw_procedure_def_v_9_type.ts | 2 +- .../lib/autogen/raw_reducer_def_v_9_type.ts | 2 +- .../raw_row_level_security_def_v_9_type.ts | 2 +- .../lib/autogen/raw_schedule_def_v_9_type.ts | 2 +- .../autogen/raw_scoped_type_name_v_9_type.ts | 2 +- .../lib/autogen/raw_sequence_def_v_8_type.ts | 2 +- .../lib/autogen/raw_sequence_def_v_9_type.ts | 2 +- .../src/lib/autogen/raw_table_def_v_8_type.ts | 2 +- .../src/lib/autogen/raw_table_def_v_9_type.ts | 2 +- .../src/lib/autogen/raw_type_def_v_9_type.ts | 2 +- .../raw_unique_constraint_data_v_9_type.ts | 2 +- .../src/lib/autogen/raw_view_def_v_9_type.ts | 2 +- .../src/lib/autogen/reducer_def_type.ts | 2 +- .../src/lib/autogen/sum_type_type.ts | 2 +- .../src/lib/autogen/sum_type_variant_type.ts | 2 +- .../src/lib/autogen/table_access_type.ts | 2 +- .../src/lib/autogen/table_desc_type.ts | 2 +- .../src/lib/autogen/table_type_type.ts | 2 +- .../src/lib/autogen/type_alias_type.ts | 2 +- .../src/lib/autogen/typespace_type.ts | 2 +- .../bindings-typescript/src/lib/reducers.ts | 6 +- crates/bindings-typescript/src/lib/table.ts | 4 +- .../src/lib/type_builders.ts | 704 +++++++++--------- .../src/sdk/client_api/index.ts | 150 ++++ .../src/sdk/db_connection_impl.ts | 6 +- .../bindings-typescript/src/server/runtime.ts | 2 +- .../tests/algebraic_type.test.ts | 2 +- .../tests/binary_read_write.test.ts | 34 +- .../bindings-typescript/tests/index.test.ts | 4 +- .../tests/table_cache.test.ts | 199 +++-- crates/bindings-typescript/tests/utils.ts | 11 +- .../examples/regen-typescript-moduledef.rs | 2 +- 50 files changed, 691 insertions(+), 509 deletions(-) create mode 100644 crates/bindings-typescript/src/sdk/client_api/index.ts diff --git a/crates/bindings-typescript/src/lib/autogen/algebraic_type_type.ts b/crates/bindings-typescript/src/lib/autogen/algebraic_type_type.ts index 8ec644f676b..3fe9bb3bbe1 100644 --- a/crates/bindings-typescript/src/lib/autogen/algebraic_type_type.ts +++ b/crates/bindings-typescript/src/lib/autogen/algebraic_type_type.ts @@ -8,7 +8,7 @@ import { t as __t, type AlgebraicTypeType as __AlgebraicTypeType, type Infer as __Infer, -} from '../../index'; +} from '../../lib/type_builders'; import SumType from './sum_type_type'; import ProductType from './product_type_type'; diff --git a/crates/bindings-typescript/src/lib/autogen/index_type_type.ts b/crates/bindings-typescript/src/lib/autogen/index_type_type.ts index 4c2c4d6f3fc..4bcfdb5933a 100644 --- a/crates/bindings-typescript/src/lib/autogen/index_type_type.ts +++ b/crates/bindings-typescript/src/lib/autogen/index_type_type.ts @@ -8,7 +8,7 @@ import { t as __t, type AlgebraicTypeType as __AlgebraicTypeType, type Infer as __Infer, -} from '../../index'; +} from '../../lib/type_builders'; // The tagged union or sum type for the algebraic type `IndexType`. const IndexType = __t.enum('IndexType', { diff --git a/crates/bindings-typescript/src/lib/autogen/lifecycle_type.ts b/crates/bindings-typescript/src/lib/autogen/lifecycle_type.ts index 8de101313f0..f1aa730d73c 100644 --- a/crates/bindings-typescript/src/lib/autogen/lifecycle_type.ts +++ b/crates/bindings-typescript/src/lib/autogen/lifecycle_type.ts @@ -8,7 +8,7 @@ import { t as __t, type AlgebraicTypeType as __AlgebraicTypeType, type Infer as __Infer, -} from '../../index'; +} from '../../lib/type_builders'; // The tagged union or sum type for the algebraic type `Lifecycle`. const Lifecycle = __t.enum('Lifecycle', { diff --git a/crates/bindings-typescript/src/lib/autogen/misc_module_export_type.ts b/crates/bindings-typescript/src/lib/autogen/misc_module_export_type.ts index 753169f2831..9c0589c2c5e 100644 --- a/crates/bindings-typescript/src/lib/autogen/misc_module_export_type.ts +++ b/crates/bindings-typescript/src/lib/autogen/misc_module_export_type.ts @@ -8,7 +8,7 @@ import { t as __t, type AlgebraicTypeType as __AlgebraicTypeType, type Infer as __Infer, -} from '../../index'; +} from '../../lib/type_builders'; import TypeAlias from './type_alias_type'; // The tagged union or sum type for the algebraic type `MiscModuleExport`. diff --git a/crates/bindings-typescript/src/lib/autogen/product_type_element_type.ts b/crates/bindings-typescript/src/lib/autogen/product_type_element_type.ts index 62a8e3649db..fec88e755fe 100644 --- a/crates/bindings-typescript/src/lib/autogen/product_type_element_type.ts +++ b/crates/bindings-typescript/src/lib/autogen/product_type_element_type.ts @@ -8,7 +8,7 @@ import { t as __t, type AlgebraicTypeType as __AlgebraicTypeType, type Infer as __Infer, -} from '../../index'; +} from '../../lib/type_builders'; import AlgebraicType from './algebraic_type_type'; export default __t.object('ProductTypeElement', { diff --git a/crates/bindings-typescript/src/lib/autogen/product_type_type.ts b/crates/bindings-typescript/src/lib/autogen/product_type_type.ts index 202f0d07617..64416a77874 100644 --- a/crates/bindings-typescript/src/lib/autogen/product_type_type.ts +++ b/crates/bindings-typescript/src/lib/autogen/product_type_type.ts @@ -8,7 +8,7 @@ import { t as __t, type AlgebraicTypeType as __AlgebraicTypeType, type Infer as __Infer, -} from '../../index'; +} from '../../lib/type_builders'; import ProductTypeElement from './product_type_element_type'; export default __t.object('ProductType', { diff --git a/crates/bindings-typescript/src/lib/autogen/raw_column_def_v_8_type.ts b/crates/bindings-typescript/src/lib/autogen/raw_column_def_v_8_type.ts index 8cfffad67c1..b8606b3a96d 100644 --- a/crates/bindings-typescript/src/lib/autogen/raw_column_def_v_8_type.ts +++ b/crates/bindings-typescript/src/lib/autogen/raw_column_def_v_8_type.ts @@ -8,7 +8,7 @@ import { t as __t, type AlgebraicTypeType as __AlgebraicTypeType, type Infer as __Infer, -} from '../../index'; +} from '../../lib/type_builders'; import AlgebraicType from './algebraic_type_type'; export default __t.object('RawColumnDefV8', { diff --git a/crates/bindings-typescript/src/lib/autogen/raw_column_default_value_v_9_type.ts b/crates/bindings-typescript/src/lib/autogen/raw_column_default_value_v_9_type.ts index 8e6ba6cc96d..3915ca92c5a 100644 --- a/crates/bindings-typescript/src/lib/autogen/raw_column_default_value_v_9_type.ts +++ b/crates/bindings-typescript/src/lib/autogen/raw_column_default_value_v_9_type.ts @@ -8,7 +8,7 @@ import { t as __t, type AlgebraicTypeType as __AlgebraicTypeType, type Infer as __Infer, -} from '../../index'; +} from '../../lib/type_builders'; export default __t.object('RawColumnDefaultValueV9', { table: __t.string(), diff --git a/crates/bindings-typescript/src/lib/autogen/raw_constraint_data_v_9_type.ts b/crates/bindings-typescript/src/lib/autogen/raw_constraint_data_v_9_type.ts index dafe670e956..39812e52b83 100644 --- a/crates/bindings-typescript/src/lib/autogen/raw_constraint_data_v_9_type.ts +++ b/crates/bindings-typescript/src/lib/autogen/raw_constraint_data_v_9_type.ts @@ -8,7 +8,7 @@ import { t as __t, type AlgebraicTypeType as __AlgebraicTypeType, type Infer as __Infer, -} from '../../index'; +} from '../../lib/type_builders'; import RawUniqueConstraintDataV9 from './raw_unique_constraint_data_v_9_type'; // The tagged union or sum type for the algebraic type `RawConstraintDataV9`. diff --git a/crates/bindings-typescript/src/lib/autogen/raw_constraint_def_v_8_type.ts b/crates/bindings-typescript/src/lib/autogen/raw_constraint_def_v_8_type.ts index 95a37ba403a..93c76509ed2 100644 --- a/crates/bindings-typescript/src/lib/autogen/raw_constraint_def_v_8_type.ts +++ b/crates/bindings-typescript/src/lib/autogen/raw_constraint_def_v_8_type.ts @@ -8,7 +8,7 @@ import { t as __t, type AlgebraicTypeType as __AlgebraicTypeType, type Infer as __Infer, -} from '../../index'; +} from '../../lib/type_builders'; export default __t.object('RawConstraintDefV8', { constraintName: __t.string(), diff --git a/crates/bindings-typescript/src/lib/autogen/raw_constraint_def_v_9_type.ts b/crates/bindings-typescript/src/lib/autogen/raw_constraint_def_v_9_type.ts index b4af353d9ee..ac0144c50d5 100644 --- a/crates/bindings-typescript/src/lib/autogen/raw_constraint_def_v_9_type.ts +++ b/crates/bindings-typescript/src/lib/autogen/raw_constraint_def_v_9_type.ts @@ -8,7 +8,7 @@ import { t as __t, type AlgebraicTypeType as __AlgebraicTypeType, type Infer as __Infer, -} from '../../index'; +} from '../../lib/type_builders'; import RawConstraintDataV9 from './raw_constraint_data_v_9_type'; export default __t.object('RawConstraintDefV9', { diff --git a/crates/bindings-typescript/src/lib/autogen/raw_index_algorithm_type.ts b/crates/bindings-typescript/src/lib/autogen/raw_index_algorithm_type.ts index f70c8992c68..a1c1cda01a5 100644 --- a/crates/bindings-typescript/src/lib/autogen/raw_index_algorithm_type.ts +++ b/crates/bindings-typescript/src/lib/autogen/raw_index_algorithm_type.ts @@ -8,7 +8,7 @@ import { t as __t, type AlgebraicTypeType as __AlgebraicTypeType, type Infer as __Infer, -} from '../../index'; +} from '../../lib/type_builders'; // The tagged union or sum type for the algebraic type `RawIndexAlgorithm`. const RawIndexAlgorithm = __t.enum('RawIndexAlgorithm', { diff --git a/crates/bindings-typescript/src/lib/autogen/raw_index_def_v_8_type.ts b/crates/bindings-typescript/src/lib/autogen/raw_index_def_v_8_type.ts index 043c14554a1..52fff2ef4ac 100644 --- a/crates/bindings-typescript/src/lib/autogen/raw_index_def_v_8_type.ts +++ b/crates/bindings-typescript/src/lib/autogen/raw_index_def_v_8_type.ts @@ -8,7 +8,7 @@ import { t as __t, type AlgebraicTypeType as __AlgebraicTypeType, type Infer as __Infer, -} from '../../index'; +} from '../../lib/type_builders'; import IndexType from './index_type_type'; export default __t.object('RawIndexDefV8', { diff --git a/crates/bindings-typescript/src/lib/autogen/raw_index_def_v_9_type.ts b/crates/bindings-typescript/src/lib/autogen/raw_index_def_v_9_type.ts index 890afd29f98..d29a62e93dc 100644 --- a/crates/bindings-typescript/src/lib/autogen/raw_index_def_v_9_type.ts +++ b/crates/bindings-typescript/src/lib/autogen/raw_index_def_v_9_type.ts @@ -8,7 +8,7 @@ import { t as __t, type AlgebraicTypeType as __AlgebraicTypeType, type Infer as __Infer, -} from '../../index'; +} from '../../lib/type_builders'; import RawIndexAlgorithm from './raw_index_algorithm_type'; export default __t.object('RawIndexDefV9', { diff --git a/crates/bindings-typescript/src/lib/autogen/raw_misc_module_export_v_9_type.ts b/crates/bindings-typescript/src/lib/autogen/raw_misc_module_export_v_9_type.ts index 81612d985f9..60ca04525da 100644 --- a/crates/bindings-typescript/src/lib/autogen/raw_misc_module_export_v_9_type.ts +++ b/crates/bindings-typescript/src/lib/autogen/raw_misc_module_export_v_9_type.ts @@ -8,7 +8,7 @@ import { t as __t, type AlgebraicTypeType as __AlgebraicTypeType, type Infer as __Infer, -} from '../../index'; +} from '../../lib/type_builders'; import RawColumnDefaultValueV9 from './raw_column_default_value_v_9_type'; import RawProcedureDefV9 from './raw_procedure_def_v_9_type'; import RawViewDefV9 from './raw_view_def_v_9_type'; diff --git a/crates/bindings-typescript/src/lib/autogen/raw_module_def_type.ts b/crates/bindings-typescript/src/lib/autogen/raw_module_def_type.ts index ac92d10fa65..e0f91b646ff 100644 --- a/crates/bindings-typescript/src/lib/autogen/raw_module_def_type.ts +++ b/crates/bindings-typescript/src/lib/autogen/raw_module_def_type.ts @@ -8,7 +8,7 @@ import { t as __t, type AlgebraicTypeType as __AlgebraicTypeType, type Infer as __Infer, -} from '../../index'; +} from '../../lib/type_builders'; import RawModuleDefV8 from './raw_module_def_v_8_type'; import RawModuleDefV9 from './raw_module_def_v_9_type'; diff --git a/crates/bindings-typescript/src/lib/autogen/raw_module_def_v_8_type.ts b/crates/bindings-typescript/src/lib/autogen/raw_module_def_v_8_type.ts index 3d7f8432636..cdfee338f0b 100644 --- a/crates/bindings-typescript/src/lib/autogen/raw_module_def_v_8_type.ts +++ b/crates/bindings-typescript/src/lib/autogen/raw_module_def_v_8_type.ts @@ -8,7 +8,7 @@ import { t as __t, type AlgebraicTypeType as __AlgebraicTypeType, type Infer as __Infer, -} from '../../index'; +} from '../../lib/type_builders'; import Typespace from './typespace_type'; import TableDesc from './table_desc_type'; import ReducerDef from './reducer_def_type'; diff --git a/crates/bindings-typescript/src/lib/autogen/raw_module_def_v_9_type.ts b/crates/bindings-typescript/src/lib/autogen/raw_module_def_v_9_type.ts index 91be3311621..42c05970fdb 100644 --- a/crates/bindings-typescript/src/lib/autogen/raw_module_def_v_9_type.ts +++ b/crates/bindings-typescript/src/lib/autogen/raw_module_def_v_9_type.ts @@ -8,7 +8,7 @@ import { t as __t, type AlgebraicTypeType as __AlgebraicTypeType, type Infer as __Infer, -} from '../../index'; +} from '../../lib/type_builders'; import Typespace from './typespace_type'; import RawTableDefV9 from './raw_table_def_v_9_type'; import RawReducerDefV9 from './raw_reducer_def_v_9_type'; diff --git a/crates/bindings-typescript/src/lib/autogen/raw_procedure_def_v_9_type.ts b/crates/bindings-typescript/src/lib/autogen/raw_procedure_def_v_9_type.ts index e19d2456f03..37b9c4b2c42 100644 --- a/crates/bindings-typescript/src/lib/autogen/raw_procedure_def_v_9_type.ts +++ b/crates/bindings-typescript/src/lib/autogen/raw_procedure_def_v_9_type.ts @@ -8,7 +8,7 @@ import { t as __t, type AlgebraicTypeType as __AlgebraicTypeType, type Infer as __Infer, -} from '../../index'; +} from '../../lib/type_builders'; import AlgebraicType from './algebraic_type_type'; import ProductType from './product_type_type'; diff --git a/crates/bindings-typescript/src/lib/autogen/raw_reducer_def_v_9_type.ts b/crates/bindings-typescript/src/lib/autogen/raw_reducer_def_v_9_type.ts index 9dc29e31c59..abfa8cf3e68 100644 --- a/crates/bindings-typescript/src/lib/autogen/raw_reducer_def_v_9_type.ts +++ b/crates/bindings-typescript/src/lib/autogen/raw_reducer_def_v_9_type.ts @@ -8,7 +8,7 @@ import { t as __t, type AlgebraicTypeType as __AlgebraicTypeType, type Infer as __Infer, -} from '../../index'; +} from '../../lib/type_builders'; import ProductType from './product_type_type'; import Lifecycle from './lifecycle_type'; diff --git a/crates/bindings-typescript/src/lib/autogen/raw_row_level_security_def_v_9_type.ts b/crates/bindings-typescript/src/lib/autogen/raw_row_level_security_def_v_9_type.ts index d32a79f32f4..919a32affe9 100644 --- a/crates/bindings-typescript/src/lib/autogen/raw_row_level_security_def_v_9_type.ts +++ b/crates/bindings-typescript/src/lib/autogen/raw_row_level_security_def_v_9_type.ts @@ -8,7 +8,7 @@ import { t as __t, type AlgebraicTypeType as __AlgebraicTypeType, type Infer as __Infer, -} from '../../index'; +} from '../../lib/type_builders'; export default __t.object('RawRowLevelSecurityDefV9', { sql: __t.string(), diff --git a/crates/bindings-typescript/src/lib/autogen/raw_schedule_def_v_9_type.ts b/crates/bindings-typescript/src/lib/autogen/raw_schedule_def_v_9_type.ts index 8c1463607dd..cc48e22fc21 100644 --- a/crates/bindings-typescript/src/lib/autogen/raw_schedule_def_v_9_type.ts +++ b/crates/bindings-typescript/src/lib/autogen/raw_schedule_def_v_9_type.ts @@ -8,7 +8,7 @@ import { t as __t, type AlgebraicTypeType as __AlgebraicTypeType, type Infer as __Infer, -} from '../../index'; +} from '../../lib/type_builders'; export default __t.object('RawScheduleDefV9', { name: __t.option(__t.string()), diff --git a/crates/bindings-typescript/src/lib/autogen/raw_scoped_type_name_v_9_type.ts b/crates/bindings-typescript/src/lib/autogen/raw_scoped_type_name_v_9_type.ts index b6ddc65622d..8a524df9ea4 100644 --- a/crates/bindings-typescript/src/lib/autogen/raw_scoped_type_name_v_9_type.ts +++ b/crates/bindings-typescript/src/lib/autogen/raw_scoped_type_name_v_9_type.ts @@ -8,7 +8,7 @@ import { t as __t, type AlgebraicTypeType as __AlgebraicTypeType, type Infer as __Infer, -} from '../../index'; +} from '../../lib/type_builders'; export default __t.object('RawScopedTypeNameV9', { scope: __t.array(__t.string()), diff --git a/crates/bindings-typescript/src/lib/autogen/raw_sequence_def_v_8_type.ts b/crates/bindings-typescript/src/lib/autogen/raw_sequence_def_v_8_type.ts index 05d5b54daff..eb0a866fa76 100644 --- a/crates/bindings-typescript/src/lib/autogen/raw_sequence_def_v_8_type.ts +++ b/crates/bindings-typescript/src/lib/autogen/raw_sequence_def_v_8_type.ts @@ -8,7 +8,7 @@ import { t as __t, type AlgebraicTypeType as __AlgebraicTypeType, type Infer as __Infer, -} from '../../index'; +} from '../../lib/type_builders'; export default __t.object('RawSequenceDefV8', { sequenceName: __t.string(), diff --git a/crates/bindings-typescript/src/lib/autogen/raw_sequence_def_v_9_type.ts b/crates/bindings-typescript/src/lib/autogen/raw_sequence_def_v_9_type.ts index 5c506094b3f..5095291e292 100644 --- a/crates/bindings-typescript/src/lib/autogen/raw_sequence_def_v_9_type.ts +++ b/crates/bindings-typescript/src/lib/autogen/raw_sequence_def_v_9_type.ts @@ -8,7 +8,7 @@ import { t as __t, type AlgebraicTypeType as __AlgebraicTypeType, type Infer as __Infer, -} from '../../index'; +} from '../../lib/type_builders'; export default __t.object('RawSequenceDefV9', { name: __t.option(__t.string()), diff --git a/crates/bindings-typescript/src/lib/autogen/raw_table_def_v_8_type.ts b/crates/bindings-typescript/src/lib/autogen/raw_table_def_v_8_type.ts index be8ef6b922a..c504720d916 100644 --- a/crates/bindings-typescript/src/lib/autogen/raw_table_def_v_8_type.ts +++ b/crates/bindings-typescript/src/lib/autogen/raw_table_def_v_8_type.ts @@ -8,7 +8,7 @@ import { t as __t, type AlgebraicTypeType as __AlgebraicTypeType, type Infer as __Infer, -} from '../../index'; +} from '../../lib/type_builders'; import RawColumnDefV8 from './raw_column_def_v_8_type'; import RawIndexDefV8 from './raw_index_def_v_8_type'; import RawConstraintDefV8 from './raw_constraint_def_v_8_type'; diff --git a/crates/bindings-typescript/src/lib/autogen/raw_table_def_v_9_type.ts b/crates/bindings-typescript/src/lib/autogen/raw_table_def_v_9_type.ts index b3fcb11dccb..8d6df28be85 100644 --- a/crates/bindings-typescript/src/lib/autogen/raw_table_def_v_9_type.ts +++ b/crates/bindings-typescript/src/lib/autogen/raw_table_def_v_9_type.ts @@ -8,7 +8,7 @@ import { t as __t, type AlgebraicTypeType as __AlgebraicTypeType, type Infer as __Infer, -} from '../../index'; +} from '../../lib/type_builders'; import RawIndexDefV9 from './raw_index_def_v_9_type'; import RawConstraintDefV9 from './raw_constraint_def_v_9_type'; import RawSequenceDefV9 from './raw_sequence_def_v_9_type'; diff --git a/crates/bindings-typescript/src/lib/autogen/raw_type_def_v_9_type.ts b/crates/bindings-typescript/src/lib/autogen/raw_type_def_v_9_type.ts index ecfc9fcab81..5a8b4c54725 100644 --- a/crates/bindings-typescript/src/lib/autogen/raw_type_def_v_9_type.ts +++ b/crates/bindings-typescript/src/lib/autogen/raw_type_def_v_9_type.ts @@ -8,7 +8,7 @@ import { t as __t, type AlgebraicTypeType as __AlgebraicTypeType, type Infer as __Infer, -} from '../../index'; +} from '../../lib/type_builders'; import RawScopedTypeNameV9 from './raw_scoped_type_name_v_9_type'; export default __t.object('RawTypeDefV9', { diff --git a/crates/bindings-typescript/src/lib/autogen/raw_unique_constraint_data_v_9_type.ts b/crates/bindings-typescript/src/lib/autogen/raw_unique_constraint_data_v_9_type.ts index 89b24676cf7..38ebe81001b 100644 --- a/crates/bindings-typescript/src/lib/autogen/raw_unique_constraint_data_v_9_type.ts +++ b/crates/bindings-typescript/src/lib/autogen/raw_unique_constraint_data_v_9_type.ts @@ -8,7 +8,7 @@ import { t as __t, type AlgebraicTypeType as __AlgebraicTypeType, type Infer as __Infer, -} from '../../index'; +} from '../../lib/type_builders'; export default __t.object('RawUniqueConstraintDataV9', { columns: __t.array(__t.u16()), diff --git a/crates/bindings-typescript/src/lib/autogen/raw_view_def_v_9_type.ts b/crates/bindings-typescript/src/lib/autogen/raw_view_def_v_9_type.ts index 7469342bd41..d58d89a1a03 100644 --- a/crates/bindings-typescript/src/lib/autogen/raw_view_def_v_9_type.ts +++ b/crates/bindings-typescript/src/lib/autogen/raw_view_def_v_9_type.ts @@ -8,7 +8,7 @@ import { t as __t, type AlgebraicTypeType as __AlgebraicTypeType, type Infer as __Infer, -} from '../../index'; +} from '../../lib/type_builders'; import AlgebraicType from './algebraic_type_type'; import ProductType from './product_type_type'; diff --git a/crates/bindings-typescript/src/lib/autogen/reducer_def_type.ts b/crates/bindings-typescript/src/lib/autogen/reducer_def_type.ts index 8a23f6854b4..7086f7848a1 100644 --- a/crates/bindings-typescript/src/lib/autogen/reducer_def_type.ts +++ b/crates/bindings-typescript/src/lib/autogen/reducer_def_type.ts @@ -8,7 +8,7 @@ import { t as __t, type AlgebraicTypeType as __AlgebraicTypeType, type Infer as __Infer, -} from '../../index'; +} from '../../lib/type_builders'; import ProductTypeElement from './product_type_element_type'; export default __t.object('ReducerDef', { diff --git a/crates/bindings-typescript/src/lib/autogen/sum_type_type.ts b/crates/bindings-typescript/src/lib/autogen/sum_type_type.ts index 7345998cc7f..8ce504461db 100644 --- a/crates/bindings-typescript/src/lib/autogen/sum_type_type.ts +++ b/crates/bindings-typescript/src/lib/autogen/sum_type_type.ts @@ -8,7 +8,7 @@ import { t as __t, type AlgebraicTypeType as __AlgebraicTypeType, type Infer as __Infer, -} from '../../index'; +} from '../../lib/type_builders'; import SumTypeVariant from './sum_type_variant_type'; export default __t.object('SumType', { diff --git a/crates/bindings-typescript/src/lib/autogen/sum_type_variant_type.ts b/crates/bindings-typescript/src/lib/autogen/sum_type_variant_type.ts index 8adc80e7bc1..72fac38f3d6 100644 --- a/crates/bindings-typescript/src/lib/autogen/sum_type_variant_type.ts +++ b/crates/bindings-typescript/src/lib/autogen/sum_type_variant_type.ts @@ -8,7 +8,7 @@ import { t as __t, type AlgebraicTypeType as __AlgebraicTypeType, type Infer as __Infer, -} from '../../index'; +} from '../../lib/type_builders'; import AlgebraicType from './algebraic_type_type'; export default __t.object('SumTypeVariant', { diff --git a/crates/bindings-typescript/src/lib/autogen/table_access_type.ts b/crates/bindings-typescript/src/lib/autogen/table_access_type.ts index 80d87d447c0..fe49768d987 100644 --- a/crates/bindings-typescript/src/lib/autogen/table_access_type.ts +++ b/crates/bindings-typescript/src/lib/autogen/table_access_type.ts @@ -8,7 +8,7 @@ import { t as __t, type AlgebraicTypeType as __AlgebraicTypeType, type Infer as __Infer, -} from '../../index'; +} from '../../lib/type_builders'; // The tagged union or sum type for the algebraic type `TableAccess`. const TableAccess = __t.enum('TableAccess', { diff --git a/crates/bindings-typescript/src/lib/autogen/table_desc_type.ts b/crates/bindings-typescript/src/lib/autogen/table_desc_type.ts index 626b04864bb..963baf7f87b 100644 --- a/crates/bindings-typescript/src/lib/autogen/table_desc_type.ts +++ b/crates/bindings-typescript/src/lib/autogen/table_desc_type.ts @@ -8,7 +8,7 @@ import { t as __t, type AlgebraicTypeType as __AlgebraicTypeType, type Infer as __Infer, -} from '../../index'; +} from '../../lib/type_builders'; import RawTableDefV8 from './raw_table_def_v_8_type'; export default __t.object('TableDesc', { diff --git a/crates/bindings-typescript/src/lib/autogen/table_type_type.ts b/crates/bindings-typescript/src/lib/autogen/table_type_type.ts index b5d1071151c..5f03aa6f678 100644 --- a/crates/bindings-typescript/src/lib/autogen/table_type_type.ts +++ b/crates/bindings-typescript/src/lib/autogen/table_type_type.ts @@ -8,7 +8,7 @@ import { t as __t, type AlgebraicTypeType as __AlgebraicTypeType, type Infer as __Infer, -} from '../../index'; +} from '../../lib/type_builders'; // The tagged union or sum type for the algebraic type `TableType`. const TableType = __t.enum('TableType', { diff --git a/crates/bindings-typescript/src/lib/autogen/type_alias_type.ts b/crates/bindings-typescript/src/lib/autogen/type_alias_type.ts index 815cce037f9..b0b4b2bd900 100644 --- a/crates/bindings-typescript/src/lib/autogen/type_alias_type.ts +++ b/crates/bindings-typescript/src/lib/autogen/type_alias_type.ts @@ -8,7 +8,7 @@ import { t as __t, type AlgebraicTypeType as __AlgebraicTypeType, type Infer as __Infer, -} from '../../index'; +} from '../../lib/type_builders'; export default __t.object('TypeAlias', { name: __t.string(), diff --git a/crates/bindings-typescript/src/lib/autogen/typespace_type.ts b/crates/bindings-typescript/src/lib/autogen/typespace_type.ts index 32cdea5d607..b2215b5af73 100644 --- a/crates/bindings-typescript/src/lib/autogen/typespace_type.ts +++ b/crates/bindings-typescript/src/lib/autogen/typespace_type.ts @@ -8,7 +8,7 @@ import { t as __t, type AlgebraicTypeType as __AlgebraicTypeType, type Infer as __Infer, -} from '../../index'; +} from '../../lib/type_builders'; import AlgebraicType from './algebraic_type_type'; export default __t.object('Typespace', { diff --git a/crates/bindings-typescript/src/lib/reducers.ts b/crates/bindings-typescript/src/lib/reducers.ts index 1411e26e1d6..f8b32bd1313 100644 --- a/crates/bindings-typescript/src/lib/reducers.ts +++ b/crates/bindings-typescript/src/lib/reducers.ts @@ -218,7 +218,7 @@ export function init( params: Params, fn: Reducer ): void { - pushReducer(name, params, fn, Lifecycle.create('Init')); + pushReducer(name, params, fn, Lifecycle.Init); } /** @@ -234,7 +234,7 @@ export function clientConnected< S extends UntypedSchemaDef, Params extends ParamsObj, >(name: string, params: Params, fn: Reducer): void { - pushReducer(name, params, fn, Lifecycle.create('OnConnect')); + pushReducer(name, params, fn, Lifecycle.OnConnect); } /** @@ -260,7 +260,7 @@ export function clientDisconnected< S extends UntypedSchemaDef, Params extends ParamsObj, >(name: string, params: Params, fn: Reducer): void { - pushReducer(name, params, fn, Lifecycle.create('OnDisconnect')); + pushReducer(name, params, fn, Lifecycle.OnDisconnect); } class Reducers { diff --git a/crates/bindings-typescript/src/lib/table.ts b/crates/bindings-typescript/src/lib/table.ts index 59f48823832..6f18b2603ae 100644 --- a/crates/bindings-typescript/src/lib/table.ts +++ b/crates/bindings-typescript/src/lib/table.ts @@ -247,10 +247,10 @@ export function table>( let algorithm: Infer; switch (algo) { case 'btree': - algorithm = RawIndexAlgorithm.create('BTree', [id]); + algorithm = RawIndexAlgorithm.BTree([id]); break; case 'direct': - algorithm = RawIndexAlgorithm.create('Direct', id); + algorithm = RawIndexAlgorithm.Direct(id); break; } indexes.push({ diff --git a/crates/bindings-typescript/src/lib/type_builders.ts b/crates/bindings-typescript/src/lib/type_builders.ts index 690646443b5..ebd8ff36795 100644 --- a/crates/bindings-typescript/src/lib/type_builders.ts +++ b/crates/bindings-typescript/src/lib/type_builders.ts @@ -1,4 +1,6 @@ import { AlgebraicType, type AlgebraicTypeVariants } from './algebraic_type'; +import type BinaryReader from './binary_reader'; +import type BinaryWriter from './binary_writer'; import { ConnectionId, type ConnectionIdAlgebraicType } from './connection_id'; import { Identity, type IdentityAlgebraicType } from './identity'; import { Option, type OptionAlgebraicType } from './option'; @@ -117,8 +119,8 @@ type IsUnit = B extends UnitBuilder ? true : false; */ type EnumType = { [K in keyof Variants & string]: IsUnit extends true - ? { tag: K } - : { tag: K; value: InferTypeOfTypeBuilder }; + ? { tag: K } + : { tag: K; value: InferTypeOfTypeBuilder }; }[keyof Variants & string]; /** @@ -134,8 +136,7 @@ type VariantsArrayFromVariantsObj = { * and the corresponding `AlgebraicType`. */ export class TypeBuilder - implements Optional -{ + implements Optional { /** * The TypeScript phantom type. This is not stored at runtime, * but is visible to the compiler @@ -160,6 +161,14 @@ export class TypeBuilder optional(): OptionBuilder { return new OptionBuilder(this); } + + serialize(writer: BinaryWriter, value: Type): void { + AlgebraicType.serializeValue(writer, this.algebraicType, value); + } + + deserialize(reader: BinaryReader): Type { + return AlgebraicType.deserializeValue(reader, this.algebraicType); + } } /** @@ -345,12 +354,11 @@ interface Defaultable< export class U8Builder extends TypeBuilder implements - Indexable, - Uniqueable, - PrimaryKeyable, - AutoIncrementable, - Defaultable -{ + Indexable, + Uniqueable, + PrimaryKeyable, + AutoIncrementable, + Defaultable { constructor() { super(AlgebraicType.U8); } @@ -398,12 +406,11 @@ export class U8Builder export class U16Builder extends TypeBuilder implements - Indexable, - Uniqueable, - PrimaryKeyable, - AutoIncrementable, - Defaultable -{ + Indexable, + Uniqueable, + PrimaryKeyable, + AutoIncrementable, + Defaultable { constructor() { super(AlgebraicType.U16); } @@ -451,12 +458,11 @@ export class U16Builder export class U32Builder extends TypeBuilder implements - Indexable, - Uniqueable, - PrimaryKeyable, - AutoIncrementable, - Defaultable -{ + Indexable, + Uniqueable, + PrimaryKeyable, + AutoIncrementable, + Defaultable { constructor() { super(AlgebraicType.U32); } @@ -504,12 +510,11 @@ export class U32Builder export class U64Builder extends TypeBuilder implements - Indexable, - Uniqueable, - PrimaryKeyable, - AutoIncrementable, - Defaultable -{ + Indexable, + Uniqueable, + PrimaryKeyable, + AutoIncrementable, + Defaultable { constructor() { super(AlgebraicType.U64); } @@ -557,12 +562,11 @@ export class U64Builder export class U128Builder extends TypeBuilder implements - Indexable, - Uniqueable, - PrimaryKeyable, - AutoIncrementable, - Defaultable -{ + Indexable, + Uniqueable, + PrimaryKeyable, + AutoIncrementable, + Defaultable { constructor() { super(AlgebraicType.U128); } @@ -613,12 +617,11 @@ export class U128Builder export class U256Builder extends TypeBuilder implements - Indexable, - Uniqueable, - PrimaryKeyable, - AutoIncrementable, - Defaultable -{ + Indexable, + Uniqueable, + PrimaryKeyable, + AutoIncrementable, + Defaultable { constructor() { super(AlgebraicType.U256); } @@ -669,12 +672,11 @@ export class U256Builder export class I8Builder extends TypeBuilder implements - Indexable, - Uniqueable, - PrimaryKeyable, - AutoIncrementable, - Defaultable -{ + Indexable, + Uniqueable, + PrimaryKeyable, + AutoIncrementable, + Defaultable { constructor() { super(AlgebraicType.I8); } @@ -722,12 +724,11 @@ export class I8Builder export class I16Builder extends TypeBuilder implements - Indexable, - Uniqueable, - PrimaryKeyable, - AutoIncrementable, - Defaultable -{ + Indexable, + Uniqueable, + PrimaryKeyable, + AutoIncrementable, + Defaultable { constructor() { super(AlgebraicType.I16); } @@ -775,13 +776,12 @@ export class I16Builder export class I32Builder extends TypeBuilder implements - TypeBuilder, - Indexable, - Uniqueable, - PrimaryKeyable, - AutoIncrementable, - Defaultable -{ + TypeBuilder, + Indexable, + Uniqueable, + PrimaryKeyable, + AutoIncrementable, + Defaultable { constructor() { super(AlgebraicType.I32); } @@ -829,12 +829,11 @@ export class I32Builder export class I64Builder extends TypeBuilder implements - Indexable, - Uniqueable, - PrimaryKeyable, - AutoIncrementable, - Defaultable -{ + Indexable, + Uniqueable, + PrimaryKeyable, + AutoIncrementable, + Defaultable { constructor() { super(AlgebraicType.I64); } @@ -882,12 +881,11 @@ export class I64Builder export class I128Builder extends TypeBuilder implements - Indexable, - Uniqueable, - PrimaryKeyable, - AutoIncrementable, - Defaultable -{ + Indexable, + Uniqueable, + PrimaryKeyable, + AutoIncrementable, + Defaultable { constructor() { super(AlgebraicType.I128); } @@ -938,12 +936,11 @@ export class I128Builder export class I256Builder extends TypeBuilder implements - Indexable, - Uniqueable, - PrimaryKeyable, - AutoIncrementable, - Defaultable -{ + Indexable, + Uniqueable, + PrimaryKeyable, + AutoIncrementable, + Defaultable { constructor() { super(AlgebraicType.I256); } @@ -993,8 +990,7 @@ export class I256Builder export class F32Builder extends TypeBuilder - implements Defaultable -{ + implements Defaultable { constructor() { super(AlgebraicType.F32); } @@ -1010,8 +1006,7 @@ export class F32Builder export class F64Builder extends TypeBuilder - implements Defaultable -{ + implements Defaultable { constructor() { super(AlgebraicType.F64); } @@ -1028,11 +1023,10 @@ export class F64Builder export class BoolBuilder extends TypeBuilder implements - Indexable, - Uniqueable, - PrimaryKeyable, - Defaultable -{ + Indexable, + Uniqueable, + PrimaryKeyable, + Defaultable { constructor() { super(AlgebraicType.Bool); } @@ -1075,11 +1069,10 @@ export class BoolBuilder export class StringBuilder extends TypeBuilder implements - Indexable, - Uniqueable, - PrimaryKeyable, - Defaultable -{ + Indexable, + Uniqueable, + PrimaryKeyable, + Defaultable { constructor() { super(AlgebraicType.String); } @@ -1124,8 +1117,7 @@ export class ArrayBuilder> Array>, { tag: 'Array'; value: InferSpacetimeTypeOfTypeBuilder } > - implements Defaultable>, any> -{ + implements Defaultable>, any> { /** * The phantom element type of the array for TypeScript */ @@ -1152,8 +1144,7 @@ export class ByteArrayBuilder Uint8Array, { tag: 'Array'; value: AlgebraicTypeVariants.U8 } > - implements Defaultable -{ + implements Defaultable { constructor() { super(AlgebraicType.Array(AlgebraicType.U8)); } @@ -1172,11 +1163,10 @@ export class OptionBuilder> OptionAlgebraicType> > implements - Defaultable< - InferTypeOfTypeBuilder | undefined, - OptionAlgebraicType> - > -{ + Defaultable< + InferTypeOfTypeBuilder | undefined, + OptionAlgebraicType> + > { /** * The phantom value type of the option for TypeScript */ @@ -1216,8 +1206,7 @@ export class ProductBuilder value: { elements: ElementsArrayFromElementsObj }; } > - implements Defaultable, any> -{ + implements Defaultable, any> { readonly typeName: string | undefined; readonly elements: Elements; constructor(elements: Elements, name?: string) { @@ -1281,15 +1270,30 @@ export class RowBuilder extends TypeBuilder< // Value type produced for a given variant key + builder type EnumValue> = IsUnit extends true - ? { tag: K } - : { tag: K; value: InferTypeOfTypeBuilder }; + ? { tag: K } + : { tag: K; value: InferTypeOfTypeBuilder }; + +type VariantConstructor< + K extends string, + V extends TypeBuilder +> = IsUnit extends true + ? EnumValue + : (value: InferTypeOfTypeBuilder) => EnumValue; + +type SumBuilderVariantConstructors = { + [K in keyof Variants & string]: VariantConstructor; +}; -export class SumBuilder extends TypeBuilder< +export type SumBuilder = SumBuilderImpl & + SumBuilderVariantConstructors; + +class SumBuilderImpl extends TypeBuilder< EnumType, { tag: 'Sum'; value: { variants: VariantsArrayFromVariantsObj } } > { readonly variants: Variants; readonly typeName: string | undefined; + constructor(variants: Variants, name?: string) { function variantsArrayFromVariantsObj( variants: Variants @@ -1299,13 +1303,54 @@ export class SumBuilder extends TypeBuilder< algebraicType: value.algebraicType, })); } + super( AlgebraicType.Sum({ variants: variantsArrayFromVariantsObj(variants), }) ); + this.variants = variants; this.typeName = name; + + // ---- Runtime unit detection ---- + // Adjust this to your real shape if needed. + // From your code, you have `value.algebraicType` available. + function isUnitRuntime(v: any): boolean { + // common patterns — tweak as necessary: + if (!v || !v.algebraicType) return false; + const t = v.algebraicType; + return t.tag === 'Unit' || t.kind === 'Unit' || t.type === 'Unit'; + } + + // wire dynamic per-variant methods + // e.g. mySumBuilder.Foo(value) + for (const key of Object.keys(variants) as Array) { + const variant = variants[key]; + + if (isUnitRuntime(variant)) { + // Unit: expose a read-only VALUE (no call) + const constant = this.create(key as any) as EnumValue; + Object.defineProperty(this, key, { + value: constant, + writable: false, + enumerable: true, + configurable: false, + }); + } else { + // Payload: expose a function(value) -> EnumValue + const fn = ((value: any) => this.create(key as any, value)) as VariantConstructor< + typeof key & string, + Variants[typeof key] + >; + Object.defineProperty(this, key, { + value: fn, + writable: false, + enumerable: true, + configurable: false, + }); + } + } } /** @@ -1313,17 +1358,13 @@ export class SumBuilder extends TypeBuilder< * - Unit variants: create('bar') * - Payload variants: create('foo', value) */ - create( - ...args: IsUnit extends true - ? [tag: K] // unit variant: only the tag - : [tag: K, value: InferTypeOfTypeBuilder] // payload variant: tag + value - ): EnumValue { - const [tag, value] = args as [K, unknown]; - // just return the shape, types guarantee correctness - return (value === undefined ? { tag } : { tag, value }) as EnumValue< - K, - Variants[K] - >; + private create(tag: K): EnumValue; + private create( + tag: K, + value: InferTypeOfTypeBuilder + ): EnumValue; + private create(tag: string, value?: unknown) { + return (value === undefined ? { tag } : { tag, value }); } default( @@ -1339,24 +1380,30 @@ export class SumBuilder extends TypeBuilder< } } -export class SimpleSumBuilder - extends SumBuilder +export const SumBuilder: { + new ( + variants: Variants, + name?: string + ): SumBuilderImpl & SumBuilderVariantConstructors; +} = SumBuilderImpl as any; + +class SimpleSumBuilderImpl + extends SumBuilderImpl implements - Indexable< - EnumType, - { - tag: 'Sum'; - value: { variants: VariantsArrayFromVariantsObj }; - } - >, - PrimaryKeyable< - EnumType, - { - tag: 'Sum'; - value: { variants: VariantsArrayFromVariantsObj }; - } - > -{ + Indexable< + EnumType, + { + tag: 'Sum'; + value: { variants: VariantsArrayFromVariantsObj }; + } + >, + PrimaryKeyable< + EnumType, + { + tag: 'Sum'; + value: { variants: VariantsArrayFromVariantsObj }; + } + > { index(): SimpleSumColumnBuilder< Variants, SetField @@ -1389,14 +1436,23 @@ export class SimpleSumBuilder } } +export const SimpleSumBuilder: { + new ( + variants: Variants, + name?: string + ): SimpleSumBuilderImpl & SumBuilderVariantConstructors; +} = SimpleSumBuilderImpl as any; + +export type SimpleSumBuilder = + SimpleSumBuilderImpl & SumBuilderVariantConstructors; + export class IdentityBuilder extends TypeBuilder implements - Indexable, - Uniqueable, - PrimaryKeyable, - Defaultable -{ + Indexable, + Uniqueable, + PrimaryKeyable, + Defaultable { constructor() { super(Identity.getAlgebraicType()); } @@ -1451,11 +1507,10 @@ export class IdentityBuilder export class ConnectionIdBuilder extends TypeBuilder implements - Indexable, - Uniqueable, - PrimaryKeyable, - Defaultable -{ + Indexable, + Uniqueable, + PrimaryKeyable, + Defaultable { constructor() { super(ConnectionId.getAlgebraicType()); } @@ -1514,11 +1569,10 @@ export class ConnectionIdBuilder export class TimestampBuilder extends TypeBuilder implements - Indexable, - Uniqueable, - PrimaryKeyable, - Defaultable -{ + Indexable, + Uniqueable, + PrimaryKeyable, + Defaultable { constructor() { super(Timestamp.getAlgebraicType()); } @@ -1577,11 +1631,10 @@ export class TimestampBuilder export class TimeDurationBuilder extends TypeBuilder implements - Indexable, - Uniqueable, - PrimaryKeyable, - Defaultable -{ + Indexable, + Uniqueable, + PrimaryKeyable, + Defaultable { constructor() { super(TimeDuration.getAlgebraicType()); } @@ -1689,17 +1742,24 @@ export class ColumnBuilder< this.typeBuilder = typeBuilder; this.columnMetadata = metadata; } + + serialize(writer: BinaryWriter, value: Type): void { + AlgebraicType.serializeValue(writer, this.typeBuilder.algebraicType, value); + } + + deserialize(reader: BinaryReader): Type { + return AlgebraicType.deserializeValue(reader, this.typeBuilder.algebraicType); + } } export class U8ColumnBuilder = DefaultMetadata> extends ColumnBuilder implements - Indexable, - Uniqueable, - PrimaryKeyable, - AutoIncrementable, - Defaultable -{ + Indexable, + Uniqueable, + PrimaryKeyable, + AutoIncrementable, + Defaultable { index(): U8ColumnBuilder>; index>( algorithm: N @@ -1741,16 +1801,15 @@ export class U8ColumnBuilder = DefaultMetadata> } export class U16ColumnBuilder< - M extends ColumnMetadata = DefaultMetadata, - > + M extends ColumnMetadata = DefaultMetadata, +> extends ColumnBuilder implements - Indexable, - Uniqueable, - PrimaryKeyable, - AutoIncrementable, - Defaultable -{ + Indexable, + Uniqueable, + PrimaryKeyable, + AutoIncrementable, + Defaultable { index(): U16ColumnBuilder>; index>( algorithm: N @@ -1794,16 +1853,15 @@ export class U16ColumnBuilder< } export class U32ColumnBuilder< - M extends ColumnMetadata = DefaultMetadata, - > + M extends ColumnMetadata = DefaultMetadata, +> extends ColumnBuilder implements - Indexable, - Uniqueable, - PrimaryKeyable, - AutoIncrementable, - Defaultable -{ + Indexable, + Uniqueable, + PrimaryKeyable, + AutoIncrementable, + Defaultable { index(): U32ColumnBuilder>; index>( algorithm: N @@ -1847,16 +1905,15 @@ export class U32ColumnBuilder< } export class U64ColumnBuilder< - M extends ColumnMetadata = DefaultMetadata, - > + M extends ColumnMetadata = DefaultMetadata, +> extends ColumnBuilder implements - Indexable, - Uniqueable, - PrimaryKeyable, - AutoIncrementable, - Defaultable -{ + Indexable, + Uniqueable, + PrimaryKeyable, + AutoIncrementable, + Defaultable { index(): U64ColumnBuilder>; index>( algorithm: N @@ -1900,16 +1957,15 @@ export class U64ColumnBuilder< } export class U128ColumnBuilder< - M extends ColumnMetadata = DefaultMetadata, - > + M extends ColumnMetadata = DefaultMetadata, +> extends ColumnBuilder implements - Indexable, - Uniqueable, - PrimaryKeyable, - AutoIncrementable, - Defaultable -{ + Indexable, + Uniqueable, + PrimaryKeyable, + AutoIncrementable, + Defaultable { index(): U128ColumnBuilder>; index>( algorithm: N @@ -1953,16 +2009,15 @@ export class U128ColumnBuilder< } export class U256ColumnBuilder< - M extends ColumnMetadata = DefaultMetadata, - > + M extends ColumnMetadata = DefaultMetadata, +> extends ColumnBuilder implements - Indexable, - Uniqueable, - PrimaryKeyable, - AutoIncrementable, - Defaultable -{ + Indexable, + Uniqueable, + PrimaryKeyable, + AutoIncrementable, + Defaultable { index(): U256ColumnBuilder>; index>( algorithm: N @@ -2008,12 +2063,11 @@ export class U256ColumnBuilder< export class I8ColumnBuilder = DefaultMetadata> extends ColumnBuilder implements - Indexable, - Uniqueable, - PrimaryKeyable, - AutoIncrementable, - Defaultable -{ + Indexable, + Uniqueable, + PrimaryKeyable, + AutoIncrementable, + Defaultable { index(): I8ColumnBuilder>; index>( algorithm: N @@ -2055,16 +2109,15 @@ export class I8ColumnBuilder = DefaultMetadata> } export class I16ColumnBuilder< - M extends ColumnMetadata = DefaultMetadata, - > + M extends ColumnMetadata = DefaultMetadata, +> extends ColumnBuilder implements - Indexable, - Uniqueable, - PrimaryKeyable, - AutoIncrementable, - Defaultable -{ + Indexable, + Uniqueable, + PrimaryKeyable, + AutoIncrementable, + Defaultable { index(): I16ColumnBuilder>; index>( algorithm: N @@ -2108,16 +2161,15 @@ export class I16ColumnBuilder< } export class I32ColumnBuilder< - M extends ColumnMetadata = DefaultMetadata, - > + M extends ColumnMetadata = DefaultMetadata, +> extends ColumnBuilder implements - Indexable, - Uniqueable, - PrimaryKeyable, - AutoIncrementable, - Defaultable -{ + Indexable, + Uniqueable, + PrimaryKeyable, + AutoIncrementable, + Defaultable { index(): I32ColumnBuilder>; index>( algorithm: N @@ -2161,16 +2213,15 @@ export class I32ColumnBuilder< } export class I64ColumnBuilder< - M extends ColumnMetadata = DefaultMetadata, - > + M extends ColumnMetadata = DefaultMetadata, +> extends ColumnBuilder implements - Indexable, - Uniqueable, - PrimaryKeyable, - AutoIncrementable, - Defaultable -{ + Indexable, + Uniqueable, + PrimaryKeyable, + AutoIncrementable, + Defaultable { index(): I64ColumnBuilder>; index>( algorithm: N @@ -2214,16 +2265,15 @@ export class I64ColumnBuilder< } export class I128ColumnBuilder< - M extends ColumnMetadata = DefaultMetadata, - > + M extends ColumnMetadata = DefaultMetadata, +> extends ColumnBuilder implements - Indexable, - Uniqueable, - PrimaryKeyable, - AutoIncrementable, - Defaultable -{ + Indexable, + Uniqueable, + PrimaryKeyable, + AutoIncrementable, + Defaultable { index(): I128ColumnBuilder>; index>( algorithm: N @@ -2267,16 +2317,15 @@ export class I128ColumnBuilder< } export class I256ColumnBuilder< - M extends ColumnMetadata = DefaultMetadata, - > + M extends ColumnMetadata = DefaultMetadata, +> extends ColumnBuilder implements - Indexable, - Uniqueable, - PrimaryKeyable, - AutoIncrementable, - Defaultable -{ + Indexable, + Uniqueable, + PrimaryKeyable, + AutoIncrementable, + Defaultable { index(): I256ColumnBuilder>; index>( algorithm: N @@ -2320,11 +2369,10 @@ export class I256ColumnBuilder< } export class F32ColumnBuilder< - M extends ColumnMetadata = DefaultMetadata, - > + M extends ColumnMetadata = DefaultMetadata, +> extends ColumnBuilder - implements Defaultable -{ + implements Defaultable { default( value: number ): F32ColumnBuilder> { @@ -2338,11 +2386,10 @@ export class F32ColumnBuilder< } export class F64ColumnBuilder< - M extends ColumnMetadata = DefaultMetadata, - > + M extends ColumnMetadata = DefaultMetadata, +> extends ColumnBuilder - implements Defaultable -{ + implements Defaultable { default( value: number ): F64ColumnBuilder> { @@ -2356,15 +2403,14 @@ export class F64ColumnBuilder< } export class BoolColumnBuilder< - M extends ColumnMetadata = DefaultMetadata, - > + M extends ColumnMetadata = DefaultMetadata, +> extends ColumnBuilder implements - Indexable, - Uniqueable, - PrimaryKeyable, - Defaultable -{ + Indexable, + Uniqueable, + PrimaryKeyable, + Defaultable { index(): BoolColumnBuilder>; index>( algorithm: N @@ -2402,15 +2448,14 @@ export class BoolColumnBuilder< } export class StringColumnBuilder< - M extends ColumnMetadata = DefaultMetadata, - > + M extends ColumnMetadata = DefaultMetadata, +> extends ColumnBuilder implements - Indexable, - Uniqueable, - PrimaryKeyable, - Defaultable -{ + Indexable, + Uniqueable, + PrimaryKeyable, + Defaultable { index(): StringColumnBuilder>; index>( algorithm: N @@ -2448,22 +2493,21 @@ export class StringColumnBuilder< } export class ArrayColumnBuilder< - Element extends TypeBuilder, - M extends ColumnMetadata< - Array> - > = DefaultMetadata, - > + Element extends TypeBuilder, + M extends ColumnMetadata< + Array> + > = DefaultMetadata, +> extends ColumnBuilder< Array>, { tag: 'Array'; value: InferSpacetimeTypeOfTypeBuilder }, M > implements - Defaultable< - Array>, - AlgebraicTypeVariants.Array - > -{ + Defaultable< + Array>, + AlgebraicTypeVariants.Array + > { default( value: Array> ): ArrayColumnBuilder< @@ -2495,22 +2539,21 @@ export class ByteArrayColumnBuilder< } export class OptionColumnBuilder< - Value extends TypeBuilder, - M extends ColumnMetadata< - InferTypeOfTypeBuilder | undefined - > = DefaultMetadata, - > + Value extends TypeBuilder, + M extends ColumnMetadata< + InferTypeOfTypeBuilder | undefined + > = DefaultMetadata, +> extends ColumnBuilder< InferTypeOfTypeBuilder | undefined, OptionAlgebraicType>, M > implements - Defaultable< - InferTypeOfTypeBuilder | undefined, - OptionAlgebraicType> - > -{ + Defaultable< + InferTypeOfTypeBuilder | undefined, + OptionAlgebraicType> + > { default( value: InferTypeOfTypeBuilder | undefined ): OptionColumnBuilder< @@ -2527,9 +2570,9 @@ export class OptionColumnBuilder< } export class ProductColumnBuilder< - Elements extends ElementsObj, - M extends ColumnMetadata> = DefaultMetadata, - > + Elements extends ElementsObj, + M extends ColumnMetadata> = DefaultMetadata, +> extends ColumnBuilder< ObjectType, { @@ -2538,8 +2581,7 @@ export class ProductColumnBuilder< }, M > - implements Defaultable, AlgebraicTypeVariants.Product> -{ + implements Defaultable, AlgebraicTypeVariants.Product> { default( value: ObjectType ): ProductColumnBuilder< @@ -2554,16 +2596,15 @@ export class ProductColumnBuilder< } export class SumColumnBuilder< - Variants extends VariantsObj, - M extends ColumnMetadata> = DefaultMetadata, - > + Variants extends VariantsObj, + M extends ColumnMetadata> = DefaultMetadata, +> extends ColumnBuilder< EnumType, { tag: 'Sum'; value: { variants: VariantsArrayFromVariantsObj } }, M > - implements Defaultable, AlgebraicTypeVariants.Sum> -{ + implements Defaultable, AlgebraicTypeVariants.Sum> { default( value: EnumType ): SumColumnBuilder< @@ -2578,14 +2619,13 @@ export class SumColumnBuilder< } export class SimpleSumColumnBuilder< - Variants extends VariantsObj, - M extends ColumnMetadata> = DefaultMetadata, - > + Variants extends VariantsObj, + M extends ColumnMetadata> = DefaultMetadata, +> extends SumColumnBuilder implements - Indexable, AlgebraicTypeVariants.Sum>, - PrimaryKeyable, AlgebraicTypeVariants.Sum> -{ + Indexable, AlgebraicTypeVariants.Sum>, + PrimaryKeyable, AlgebraicTypeVariants.Sum> { index(): SimpleSumColumnBuilder< Variants, SetField @@ -2619,15 +2659,14 @@ export class SimpleSumColumnBuilder< } export class IdentityColumnBuilder< - M extends ColumnMetadata = DefaultMetadata, - > + M extends ColumnMetadata = DefaultMetadata, +> extends ColumnBuilder implements - Indexable, - Uniqueable, - PrimaryKeyable, - Defaultable -{ + Indexable, + Uniqueable, + PrimaryKeyable, + Defaultable { index(): IdentityColumnBuilder>; index>( algorithm: N @@ -2663,15 +2702,14 @@ export class IdentityColumnBuilder< } export class ConnectionIdColumnBuilder< - M extends ColumnMetadata = DefaultMetadata, - > + M extends ColumnMetadata = DefaultMetadata, +> extends ColumnBuilder implements - Indexable, - Uniqueable, - PrimaryKeyable, - Defaultable -{ + Indexable, + Uniqueable, + PrimaryKeyable, + Defaultable { index(): ConnectionIdColumnBuilder>; index>( algorithm: N @@ -2707,15 +2745,14 @@ export class ConnectionIdColumnBuilder< } export class TimestampColumnBuilder< - M extends ColumnMetadata = DefaultMetadata, - > + M extends ColumnMetadata = DefaultMetadata, +> extends ColumnBuilder implements - Indexable, - Uniqueable, - PrimaryKeyable, - Defaultable -{ + Indexable, + Uniqueable, + PrimaryKeyable, + Defaultable { index(): TimestampColumnBuilder>; index>( algorithm: N @@ -2751,15 +2788,14 @@ export class TimestampColumnBuilder< } export class TimeDurationColumnBuilder< - M extends ColumnMetadata = DefaultMetadata, - > + M extends ColumnMetadata = DefaultMetadata, +> extends ColumnBuilder implements - Indexable, - Uniqueable, - PrimaryKeyable, - Defaultable -{ + Indexable, + Uniqueable, + PrimaryKeyable, + Defaultable { index(): TimeDurationColumnBuilder>; index>( algorithm: N @@ -2815,7 +2851,7 @@ interface EnumFn { ( name: string, cases: readonly [Case, ...Case[]] - ): SimpleSumBuilder>; + ): SimpleSumBuilderImpl>; /** * Creates an empty simple sum type (no cases, equivalent to `never`). @@ -2825,7 +2861,7 @@ interface EnumFn { * t.enum("Never", []); * ``` */ - (name: string, cases: []): SimpleSumBuilder>; + (name: string, cases: []): SimpleSumBuilderImpl>; /** * Creates a full sum type, where each case can have a payload. @@ -2859,7 +2895,7 @@ const enumImpl = ((nameOrObj: any, maybeObj?: any) => { for (const variant of obj) { simpleVariantsObj[variant] = new ProductBuilder({}); } - return new SimpleSumBuilder(simpleVariantsObj, name); + return new SimpleSumBuilderImpl(simpleVariantsObj, name); } // Regular sum (object form) diff --git a/crates/bindings-typescript/src/sdk/client_api/index.ts b/crates/bindings-typescript/src/sdk/client_api/index.ts new file mode 100644 index 00000000000..8548380f1dd --- /dev/null +++ b/crates/bindings-typescript/src/sdk/client_api/index.ts @@ -0,0 +1,150 @@ +// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE +// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. + +// This was generated using spacetimedb cli version 1.7.0 (commit cb16789be729954a7c47b87fb40b35baa0bd1029). + +/* eslint-disable */ +/* tslint:disable */ +import { + DbConnectionBuilder as __DbConnectionBuilder, + DbConnectionImpl as __DbConnectionImpl, + SubscriptionBuilderImpl as __SubscriptionBuilderImpl, + TypeBuilder as __TypeBuilder, + convertToAccessorMap as __convertToAccessorMap, + reducerSchema as __reducerSchema, + reducers as __reducers, + schema as __schema, + t as __t, + table as __table, + type AlgebraicTypeType as __AlgebraicTypeType, + type DbConnectionConfig as __DbConnectionConfig, + type ErrorContextInterface as __ErrorContextInterface, + type Event as __Event, + type EventContextInterface as __EventContextInterface, + type Infer as __Infer, + type ReducerEventContextInterface as __ReducerEventContextInterface, + type RemoteModule as __RemoteModule, + type SubscriptionEventContextInterface as __SubscriptionEventContextInterface, +} from '../../index'; + +// Import and reexport all reducer arg types + +// Import and reexport all table handle types + +// Import and reexport all types +import BsatnRowList from './bsatn_row_list_type'; +export { BsatnRowList }; +import CallProcedure from './call_procedure_type'; +export { CallProcedure }; +import CallReducer from './call_reducer_type'; +export { CallReducer }; +import ClientMessage from './client_message_type'; +export { ClientMessage }; +import CompressableQueryUpdate from './compressable_query_update_type'; +export { CompressableQueryUpdate }; +import DatabaseUpdate from './database_update_type'; +export { DatabaseUpdate }; +import EnergyQuanta from './energy_quanta_type'; +export { EnergyQuanta }; +import IdentityToken from './identity_token_type'; +export { IdentityToken }; +import InitialSubscription from './initial_subscription_type'; +export { InitialSubscription }; +import OneOffQuery from './one_off_query_type'; +export { OneOffQuery }; +import OneOffQueryResponse from './one_off_query_response_type'; +export { OneOffQueryResponse }; +import OneOffTable from './one_off_table_type'; +export { OneOffTable }; +import ProcedureResult from './procedure_result_type'; +export { ProcedureResult }; +import ProcedureStatus from './procedure_status_type'; +export { ProcedureStatus }; +import QueryId from './query_id_type'; +export { QueryId }; +import QueryUpdate from './query_update_type'; +export { QueryUpdate }; +import ReducerCallInfo from './reducer_call_info_type'; +export { ReducerCallInfo }; +import RowSizeHint from './row_size_hint_type'; +export { RowSizeHint }; +import ServerMessage from './server_message_type'; +export { ServerMessage }; +import Subscribe from './subscribe_type'; +export { Subscribe }; +import SubscribeApplied from './subscribe_applied_type'; +export { SubscribeApplied }; +import SubscribeMulti from './subscribe_multi_type'; +export { SubscribeMulti }; +import SubscribeMultiApplied from './subscribe_multi_applied_type'; +export { SubscribeMultiApplied }; +import SubscribeRows from './subscribe_rows_type'; +export { SubscribeRows }; +import SubscribeSingle from './subscribe_single_type'; +export { SubscribeSingle }; +import SubscriptionError from './subscription_error_type'; +export { SubscriptionError }; +import TableUpdate from './table_update_type'; +export { TableUpdate }; +import TransactionUpdate from './transaction_update_type'; +export { TransactionUpdate }; +import TransactionUpdateLight from './transaction_update_light_type'; +export { TransactionUpdateLight }; +import Unsubscribe from './unsubscribe_type'; +export { Unsubscribe }; +import UnsubscribeApplied from './unsubscribe_applied_type'; +export { UnsubscribeApplied }; +import UnsubscribeMulti from './unsubscribe_multi_type'; +export { UnsubscribeMulti }; +import UnsubscribeMultiApplied from './unsubscribe_multi_applied_type'; +export { UnsubscribeMultiApplied }; +import UpdateStatus from './update_status_type'; +export { UpdateStatus }; + +const tablesSchema = __schema(); + +const reducersSchema = __reducers(); + +const REMOTE_MODULE = { + versionInfo: { + cliVersion: '1.7.0' as const, + }, + tables: tablesSchema.schemaType.tables, + reducers: reducersSchema.reducersType.reducers, +} satisfies __RemoteModule< + typeof tablesSchema.schemaType, + typeof reducersSchema.reducersType +>; + +export const tables = __convertToAccessorMap(tablesSchema.schemaType.tables); +export const reducers = __convertToAccessorMap( + reducersSchema.reducersType.reducers +); + +export type EventContext = __EventContextInterface; +export type ReducerEventContext = __ReducerEventContextInterface< + typeof REMOTE_MODULE +>; +export type SubscriptionEventContext = __SubscriptionEventContextInterface< + typeof REMOTE_MODULE +>; +export type ErrorContext = __ErrorContextInterface; + +export class SubscriptionBuilder extends __SubscriptionBuilderImpl< + typeof REMOTE_MODULE +> {} + +export class DbConnectionBuilder extends __DbConnectionBuilder {} + +export class DbConnection extends __DbConnectionImpl { + static builder = (): DbConnectionBuilder => { + return new DbConnectionBuilder( + REMOTE_MODULE, + (config: __DbConnectionConfig) => + new DbConnection(config) + ); + }; + subscriptionBuilder = (): SubscriptionBuilder => { + return new SubscriptionBuilder(this); + }; +} diff --git a/crates/bindings-typescript/src/sdk/db_connection_impl.ts b/crates/bindings-typescript/src/sdk/db_connection_impl.ts index 1e250548738..7a6daf50324 100644 --- a/crates/bindings-typescript/src/sdk/db_connection_impl.ts +++ b/crates/bindings-typescript/src/sdk/db_connection_impl.ts @@ -337,7 +337,7 @@ export class DbConnectionImpl emitter: handleEmitter, }); this.#sendMessage( - ClientMessage.create('SubscribeMulti', { + ClientMessage.SubscribeMulti({ queryStrings: querySql, queryId: { id: queryId }, // The TypeScript SDK doesn't currently track `request_id`s, @@ -350,7 +350,7 @@ export class DbConnectionImpl unregisterSubscription(queryId: number): void { this.#sendMessage( - ClientMessage.create('UnsubscribeMulti', { + ClientMessage.UnsubscribeMulti({ queryId: { id: queryId }, // The TypeScript SDK doesn't currently track `request_id`s, // so always use 0. @@ -869,7 +869,7 @@ export class DbConnectionImpl argsBuffer: Uint8Array, flags: CallReducerFlags ): void { - const message = ClientMessage.create('CallReducer', { + const message = ClientMessage.CallReducer({ reducer: reducerName, args: argsBuffer, // The TypeScript SDK doesn't currently track `request_id`s, diff --git a/crates/bindings-typescript/src/server/runtime.ts b/crates/bindings-typescript/src/server/runtime.ts index a6a02308d23..bb364994f4d 100644 --- a/crates/bindings-typescript/src/server/runtime.ts +++ b/crates/bindings-typescript/src/server/runtime.ts @@ -182,7 +182,7 @@ export const hooks: ModuleHooks = { AlgebraicType.serializeValue( writer, RawModuleDef.algebraicType, - RawModuleDef.create('V9', MODULE_DEF) + RawModuleDef.V9(MODULE_DEF) ); return writer.getBuffer(); }, diff --git a/crates/bindings-typescript/tests/algebraic_type.test.ts b/crates/bindings-typescript/tests/algebraic_type.test.ts index 126b21a7a05..c993f1f0e5f 100644 --- a/crates/bindings-typescript/tests/algebraic_type.test.ts +++ b/crates/bindings-typescript/tests/algebraic_type.test.ts @@ -1,5 +1,5 @@ import { describe, expect, test } from 'vitest'; -import { AlgebraicType } from '../src/index'; +import { AlgebraicType } from '../src/lib/algebraic_type'; describe('AlgebraicType', () => { test('intoMapKey handles all primitive types', () => { diff --git a/crates/bindings-typescript/tests/binary_read_write.test.ts b/crates/bindings-typescript/tests/binary_read_write.test.ts index ecf316b56b7..77a9b024f4c 100644 --- a/crates/bindings-typescript/tests/binary_read_write.test.ts +++ b/crates/bindings-typescript/tests/binary_read_write.test.ts @@ -1,13 +1,4 @@ import { describe, expect, test } from 'vitest'; -import { - AlgebraicType, - BinaryReader, - BinaryWriter, - ConnectionId, - TimeDuration, - Timestamp, -} from '../src/index'; -import * as ws from '../src/sdk/client_api'; import { anIdentity, bobIdentity, @@ -15,7 +6,16 @@ import { encodeUser, sallyIdentity, } from './utils'; -import { ServerMessage } from '../src/sdk/client_api'; +import ServerMessage from '../src/sdk/client_api/server_message_type'; +import UpdateStatus from '../src/sdk/client_api/update_status_type'; +import CompressableQueryUpdate from '../src/sdk/client_api/compressable_query_update_type'; +import RowSizeHint from '../src/sdk/client_api/row_size_hint_type'; +import BinaryReader from '../src/lib/binary_reader'; +import BinaryWriter from '../src/lib/binary_writer'; +import { Timestamp } from '../src/lib/timestamp'; +import { ConnectionId } from '../src/lib/connection_id'; +import { TimeDuration } from '../src/lib/time_duration'; +import { AlgebraicType } from '../src/lib/algebraic_type'; /* // Generated by the following Rust code: @@ -131,22 +131,22 @@ describe('BinaryReader/Writer', () => { username: 'sally', }; const binary = [...encodeUser(user1)].concat([...encodeUser(user2)]); - const transactionUpdate = ws.ServerMessage.TransactionUpdate({ - status: ws.UpdateStatus.Committed({ + const transactionUpdate = ServerMessage.create('TransactionUpdate', { + status: UpdateStatus.create('Committed', { tables: [ { tableId: 35, tableName: 'user', numRows: BigInt(1), updates: [ - ws.CompressableQueryUpdate.Uncompressed({ + CompressableQueryUpdate.create('Uncompressed', { deletes: { - sizeHint: ws.RowSizeHint.FixedSize(0), // not used + sizeHint: RowSizeHint.create('FixedSize', 0), // not used rowsData: new Uint8Array([]), }, // FIXME: this test is evil: an initial subscription can never contain deletes or updates. inserts: { - sizeHint: ws.RowSizeHint.FixedSize(0), // not used + sizeHint: RowSizeHint.create('FixedSize', 0), // not used rowsData: new Uint8Array(binary), }, }), @@ -169,14 +169,14 @@ describe('BinaryReader/Writer', () => { const writer = new BinaryWriter(1024); AlgebraicType.serializeValue( writer, - ServerMessage.getTypeScriptAlgebraicType(), + ServerMessage.algebraicType, transactionUpdate ); const rawBytes = writer.getBuffer(); const deserializedTransactionUpdate = AlgebraicType.deserializeValue( new BinaryReader(rawBytes), - ServerMessage.getTypeScriptAlgebraicType() + ServerMessage.algebraicType ); expect(deserializedTransactionUpdate).toEqual(transactionUpdate); }); diff --git a/crates/bindings-typescript/tests/index.test.ts b/crates/bindings-typescript/tests/index.test.ts index 90be9efc2c0..9062b69b478 100644 --- a/crates/bindings-typescript/tests/index.test.ts +++ b/crates/bindings-typescript/tests/index.test.ts @@ -15,7 +15,7 @@ describe('TypeBuilder', () => { y: t.f64(), z: t.f64(), }); - expect(point.resolveType()).toEqual({ + expect(point.algebraicType).toEqual({ tag: 'Product', value: { elements: [ @@ -32,7 +32,7 @@ describe('TypeBuilder', () => { a: t.string(), b: t.number(), }); - expect(sumType.resolveType()).toEqual({ + expect(sumType.algebraicType).toEqual({ tag: 'Sum', value: { variants: [ diff --git a/crates/bindings-typescript/tests/table_cache.test.ts b/crates/bindings-typescript/tests/table_cache.test.ts index f5961e9a4fd..5c7f0afb372 100644 --- a/crates/bindings-typescript/tests/table_cache.test.ts +++ b/crates/bindings-typescript/tests/table_cache.test.ts @@ -1,9 +1,8 @@ import { type Operation, TableCache } from '../src/sdk/table_cache'; import { describe, expect, test } from 'vitest'; - -import { Player } from '../test-app/src/module_bindings/player_type.ts'; - -import { AlgebraicType, type AlgebraicTypeVariants } from 'spacetimedb'; +import Player from '../test-app/src/module_bindings/player_type.ts'; +import { AlgebraicType, Identity, type Infer } from 'spacetimedb'; +import { tables } from '../test-app/src/module_bindings/index.ts'; interface ApplyOperations { ops: Operation[]; @@ -44,7 +43,7 @@ function deleteEvent(row: any, ctx: any = {}): CallbackEvent { interface AssertionInput { // The state of the table cache. - tableCache: TableCache; + tableCache: TableCache; // The sequence of callbacks that were fired from the last applyOperations. callbackHistory: CallbackEvent[]; } @@ -58,7 +57,7 @@ interface TestStep { assertions: Assertion[]; } -function runTest(tableCache: TableCache, testSteps: TestStep[]) { +function runTest(tableCache: TableCache, testSteps: TestStep[]) { const callbackHistory: CallbackEvent[] = []; tableCache.onInsert((ctx, row) => { callbackHistory.push({ @@ -111,13 +110,9 @@ describe('TableCache', () => { { name: 'location', algebraicType: pointType }, ], }); - const tableTypeInfo: TableRuntimeTypeInfo = { - tableName: 'player', - rowType: playerType, - }; - const newTable = () => new TableCache(tableTypeInfo); - const mkOperation = (type: 'insert' | 'delete', row: Player) => { - const rowId = AlgebraicType.intoMapKey(tableTypeInfo.rowType, row); + const newTable = () => new TableCache(tables.unindexedPlayer); + const mkOperation = (type: 'insert' | 'delete', row: Infer) => { + const rowId = AlgebraicType.intoMapKey({ tag: 'Product', value: tables.unindexedPlayer.rowType }, row); return { type, rowId, @@ -129,7 +124,8 @@ describe('TableCache', () => { const tableCache = newTable(); const steps: TestStep[] = []; const player = { - ownerId: '1', + id: 1, + userId: Identity.zero(), name: 'Player 1', location: { x: 1, @@ -143,9 +139,9 @@ describe('TableCache', () => { }, assertions: [ ({ tableCache, callbackHistory }) => { - expect(tableCache.count()).toBe(1); - expect(tableCache.iter().length).toBe(1); - expect(tableCache.iter()[0]).toEqual(player); + expect(tableCache.count()).toBe(1n); + expect(Array.from(tableCache.iter()).length).toBe(1); + expect(Array.from(tableCache.iter())[0]).toEqual(player); expect(callbackHistory.length).toBe(1); expect(callbackHistory[0].type).toBe('insert'); expect(callbackHistory[0].row).toEqual(player); @@ -159,7 +155,8 @@ describe('TableCache', () => { const tableCache = newTable(); const steps: TestStep[] = []; const player = { - ownerId: '1', + id: 1, + userId: Identity.zero(), name: 'Player 1', location: { x: 1, @@ -173,9 +170,9 @@ describe('TableCache', () => { }, assertions: [ ({ tableCache, callbackHistory }) => { - expect(tableCache.count()).toBe(1); - expect(tableCache.iter().length).toBe(1); - expect(tableCache.iter()[0]).toEqual(player); + expect(tableCache.count()).toBe(1n); + expect(Array.from(tableCache.iter()).length).toBe(1); + expect(Array.from(tableCache.iter())[0]).toEqual(player); expect(callbackHistory.length).toBe(1); expect(callbackHistory[0].type).toBe('insert'); expect(callbackHistory[0].row).toEqual(player); @@ -189,7 +186,8 @@ describe('TableCache', () => { const tableCache = newTable(); const steps: TestStep[] = []; const player = { - ownerId: '1', + id: 1, + userId: Identity.zero(), name: 'Player 1', location: { x: 1, @@ -203,9 +201,9 @@ describe('TableCache', () => { }, assertions: [ ({ tableCache, callbackHistory }) => { - expect(tableCache.count()).toBe(1); - expect(tableCache.iter().length).toBe(1); - expect(tableCache.iter()[0]).toEqual(player); + expect(tableCache.count()).toBe(1n); + expect(Array.from(tableCache.iter()).length).toBe(1); + expect(Array.from(tableCache.iter())[0]).toEqual(player); expect(callbackHistory.length).toBe(1); expect(callbackHistory[0].type).toBe('insert'); expect(callbackHistory[0].row).toEqual(player); @@ -219,9 +217,9 @@ describe('TableCache', () => { }, assertions: [ ({ tableCache, callbackHistory }) => { - expect(tableCache.count()).toBe(1); - expect(tableCache.iter().length).toBe(1); - expect(tableCache.iter()[0]).toEqual(player); + expect(tableCache.count()).toBe(1n); + expect(Array.from(tableCache.iter()).length).toBe(1); + expect(Array.from(tableCache.iter())[0]).toEqual(player); expect(callbackHistory.length).toBe(0); }, ], @@ -233,7 +231,8 @@ describe('TableCache', () => { const tableCache = newTable(); const steps: TestStep[] = []; const player = { - ownerId: '1', + id: 1, + userId: Identity.zero(), name: 'Player 1', location: { x: 1, @@ -247,8 +246,8 @@ describe('TableCache', () => { }, assertions: [ ({ tableCache, callbackHistory }) => { - expect(tableCache.count()).toBe(1); - expect(tableCache.iter()[0]).toEqual(player); + expect(tableCache.count()).toBe(1n); + expect(Array.from(tableCache.iter())[0]).toEqual(player); expect(callbackHistory.length).toBe(1); expect(callbackHistory[0].type).toBe('insert'); expect(callbackHistory[0].row).toEqual(player); @@ -276,7 +275,8 @@ describe('TableCache', () => { const tableCache = newTable(); const steps: TestStep[] = []; const mkPlayer = () => ({ - ownerId: '1', + id: 1, + userId: Identity.zero(), name: 'Player 1', location: { x: 1, @@ -284,7 +284,8 @@ describe('TableCache', () => { }, }); const player = { - ownerId: '1', + id: 1, + userId: Identity.zero(), name: 'Player 1', location: { x: 1, @@ -301,8 +302,8 @@ describe('TableCache', () => { }, assertions: [ ({ tableCache, callbackHistory }) => { - expect(tableCache.count()).toBe(1); - expect(tableCache.iter()[0]).toEqual(player); + expect(tableCache.count()).toBe(1n); + expect(Array.from(tableCache.iter())[0]).toEqual(player); expect(callbackHistory.length).toBe(1); expect(callbackHistory[0].type).toBe('insert'); expect(callbackHistory[0].row).toEqual(player); @@ -317,8 +318,8 @@ describe('TableCache', () => { assertions: [ ({ tableCache, callbackHistory }) => { // We still have one reference left, so it isn't actually deleted. - expect(tableCache.count()).toBe(1); - expect(tableCache.iter()[0]).toEqual(player); + expect(tableCache.count()).toBe(1n); + expect(Array.from(tableCache.iter())[0]).toEqual(player); expect(callbackHistory.length).toBe(0); }, ], @@ -346,8 +347,8 @@ describe('TableCache', () => { }, assertions: [ ({ tableCache, callbackHistory }) => { - expect(tableCache.count()).toBe(1); - expect(tableCache.iter()[0]).toEqual(player); + expect(tableCache.count()).toBe(1n); + expect(Array.from(tableCache.iter())[0]).toEqual(player); expect(callbackHistory).toEqual([insertEvent(player)]); }, ], @@ -359,8 +360,8 @@ describe('TableCache', () => { }, assertions: [ ({ tableCache, callbackHistory }) => { - expect(tableCache.count()).toBe(1); - expect(tableCache.iter()[0]).toEqual(player); + expect(tableCache.count()).toBe(1n); + expect(Array.from(tableCache.iter())[0]).toEqual(player); expect(callbackHistory).toEqual([]); }, ], @@ -383,7 +384,8 @@ describe('TableCache', () => { test('Insert one', () => { const tableCache = newTable(); const op = mkOperation('insert', { - ownerId: '1', + id: 1, + userId: Identity.zero(), name: 'Player 1', location: { x: 1, @@ -397,7 +399,7 @@ describe('TableCache', () => { expect(row).toEqual(op.row); }); expect(callbacks.length).toBe(1); - expect(tableCache.count()).toBe(1); + expect(tableCache.count()).toBe(1n); callbacks.forEach(cb => { cb.cb(); }); @@ -413,25 +415,17 @@ describe('TableCache', () => { }); const playerType: AlgebraicType = AlgebraicType.Product({ elements: [ - { name: 'ownerId', algebraicType: AlgebraicType.String }, + { name: 'id', algebraicType: AlgebraicType.U32 }, + { name: 'userId', algebraicType: AlgebraicType.Product({ elements: [{ name: '__identity__', algebraicType: AlgebraicType.U256 }] }) }, { name: 'name', algebraicType: AlgebraicType.String }, { name: 'location', algebraicType: pointType }, ], }); - const tableTypeInfo: TableRuntimeTypeInfo = { - tableName: 'player', - rowType: playerType, - primaryKeyInfo: { - colName: 'ownerId', - colType: (playerType as AlgebraicTypeVariants.Product).value.elements[0] - .algebraicType, - }, - }; - const newTable = () => new TableCache(tableTypeInfo); - const mkOperation = (type: 'insert' | 'delete', row: Player) => { + const newTable = () => new TableCache(tables.player); + const mkOperation = (type: 'insert' | 'delete', row: Infer) => { const rowId = AlgebraicType.intoMapKey( - tableTypeInfo.primaryKeyInfo!.colType, - row['ownerId'] + { tag: 'Product', value: tables.player.rowType }, + row['id'] ); return { type, @@ -444,7 +438,8 @@ describe('TableCache', () => { const tableCache = newTable(); const steps: TestStep[] = []; const player = { - ownerId: '1', + id: 1, + userId: Identity.zero(), name: 'Player 1', location: { x: 1, @@ -458,9 +453,9 @@ describe('TableCache', () => { }, assertions: [ ({ tableCache, callbackHistory }) => { - expect(tableCache.count()).toBe(1); - expect(tableCache.iter().length).toBe(1); - expect(tableCache.iter()[0]).toEqual(player); + expect(tableCache.count()).toBe(1n); + expect(Array.from(tableCache.iter()).length).toBe(1); + expect(Array.from(tableCache.iter())[0]).toEqual(player); expect(callbackHistory.length).toBe(1); expect(callbackHistory[0].type).toBe('insert'); expect(callbackHistory[0].row).toEqual(player); @@ -474,7 +469,8 @@ describe('TableCache', () => { const tableCache = newTable(); const steps: TestStep[] = []; const player = { - ownerId: '1', + id: 1, + userId: Identity.zero(), name: 'Player 1', location: { x: 1, @@ -488,9 +484,9 @@ describe('TableCache', () => { }, assertions: [ ({ tableCache, callbackHistory }) => { - expect(tableCache.count()).toBe(1); - expect(tableCache.iter().length).toBe(1); - expect(tableCache.iter()[0]).toEqual(player); + expect(tableCache.count()).toBe(1n); + expect(Array.from(tableCache.iter()).length).toBe(1); + expect(Array.from(tableCache.iter())[0]).toEqual(player); expect(callbackHistory.length).toBe(1); expect(callbackHistory[0].type).toBe('insert'); expect(callbackHistory[0].row).toEqual(player); @@ -504,7 +500,8 @@ describe('TableCache', () => { const tableCache = newTable(); const steps: TestStep[] = []; const player = { - ownerId: '1', + id: 1, + userId: Identity.zero(), name: 'Player 1', location: { x: 1, @@ -518,9 +515,9 @@ describe('TableCache', () => { }, assertions: [ ({ tableCache, callbackHistory }) => { - expect(tableCache.count()).toBe(1); - expect(tableCache.iter().length).toBe(1); - expect(tableCache.iter()[0]).toEqual(player); + expect(tableCache.count()).toBe(1n); + expect(Array.from(tableCache.iter()).length).toBe(1); + expect(Array.from(tableCache.iter())[0]).toEqual(player); expect(callbackHistory.length).toBe(1); expect(callbackHistory[0].type).toBe('insert'); expect(callbackHistory[0].row).toEqual(player); @@ -534,9 +531,9 @@ describe('TableCache', () => { }, assertions: [ ({ tableCache, callbackHistory }) => { - expect(tableCache.count()).toBe(1); - expect(tableCache.iter().length).toBe(1); - expect(tableCache.iter()[0]).toEqual(player); + expect(tableCache.count()).toBe(1n); + expect(Array.from(tableCache.iter()).length).toBe(1); + expect(Array.from(tableCache.iter())[0]).toEqual(player); expect(callbackHistory.length).toBe(0); }, ], @@ -548,7 +545,8 @@ describe('TableCache', () => { const tableCache = newTable(); const steps: TestStep[] = []; const player = { - ownerId: '1', + id: 1, + userId: Identity.zero(), name: 'Player 1', location: { x: 1, @@ -562,8 +560,8 @@ describe('TableCache', () => { }, assertions: [ ({ tableCache, callbackHistory }) => { - expect(tableCache.count()).toBe(1); - expect(tableCache.iter()[0]).toEqual(player); + expect(tableCache.count()).toBe(1n); + expect(Array.from(tableCache.iter())[0]).toEqual(player); expect(callbackHistory.length).toBe(1); expect(callbackHistory[0].type).toBe('insert'); expect(callbackHistory[0].row).toEqual(player); @@ -591,7 +589,8 @@ describe('TableCache', () => { const tableCache = newTable(); const steps: TestStep[] = []; const mkPlayer = (name: string) => ({ - ownerId: '1', + id: 1, + userId: Identity.zero(), name: name, location: { x: 1, @@ -605,8 +604,8 @@ describe('TableCache', () => { }, assertions: [ ({ tableCache, callbackHistory }) => { - expect(tableCache.count()).toBe(1); - expect(tableCache.iter()[0]).toEqual(mkPlayer('jeff')); + expect(tableCache.count()).toBe(1n); + expect(Array.from(tableCache.iter())[0]).toEqual(mkPlayer('jeff')); expect(callbackHistory).toEqual([insertEvent(mkPlayer('jeff'))]); }, ], @@ -621,8 +620,8 @@ describe('TableCache', () => { }, assertions: [ ({ tableCache, callbackHistory }) => { - expect(tableCache.count()).toBe(1); - expect(tableCache.iter()[0]).toEqual(mkPlayer('jeffv2')); + expect(tableCache.count()).toBe(1n); + expect(Array.from(tableCache.iter())[0]).toEqual(mkPlayer('jeffv2')); expect(callbackHistory).toEqual([ updateEvent(mkPlayer('jeff'), mkPlayer('jeffv2')), ]); @@ -636,7 +635,8 @@ describe('TableCache', () => { const tableCache = newTable(); const steps: TestStep[] = []; const mkPlayer = () => ({ - ownerId: '1', + id: 1, + userId: Identity.zero(), name: 'Player 1', location: { x: 1, @@ -644,7 +644,8 @@ describe('TableCache', () => { }, }); const player = { - ownerId: '1', + id: 1, + userId: Identity.zero(), name: 'Player 1', location: { x: 1, @@ -661,8 +662,8 @@ describe('TableCache', () => { }, assertions: [ ({ tableCache, callbackHistory }) => { - expect(tableCache.count()).toBe(1); - expect(tableCache.iter()[0]).toEqual(player); + expect(tableCache.count()).toBe(1n); + expect(Array.from(tableCache.iter())[0]).toEqual(player); expect(callbackHistory.length).toBe(1); expect(callbackHistory[0].type).toBe('insert'); expect(callbackHistory[0].row).toEqual(player); @@ -677,8 +678,8 @@ describe('TableCache', () => { assertions: [ ({ tableCache, callbackHistory }) => { // We still have one reference left, so it isn't actually deleted. - expect(tableCache.count()).toBe(1); - expect(tableCache.iter()[0]).toEqual(player); + expect(tableCache.count()).toBe(1n); + expect(Array.from(tableCache.iter())[0]).toEqual(player); expect(callbackHistory.length).toBe(0); }, ], @@ -706,8 +707,8 @@ describe('TableCache', () => { }, assertions: [ ({ tableCache, callbackHistory }) => { - expect(tableCache.count()).toBe(1); - expect(tableCache.iter()[0]).toEqual(player); + expect(tableCache.count()).toBe(1n); + expect(Array.from(tableCache.iter())[0]).toEqual(player); expect(callbackHistory).toEqual([insertEvent(player)]); }, ], @@ -719,8 +720,8 @@ describe('TableCache', () => { }, assertions: [ ({ tableCache, callbackHistory }) => { - expect(tableCache.count()).toBe(1); - expect(tableCache.iter()[0]).toEqual(player); + expect(tableCache.count()).toBe(1n); + expect(Array.from(tableCache.iter())[0]).toEqual(player); expect(callbackHistory).toEqual([]); }, ], @@ -743,7 +744,8 @@ describe('TableCache', () => { test('Insert one', () => { const tableCache = newTable(); const op = mkOperation('insert', { - ownerId: '1', + id: 1, + userId: Identity.zero(), name: 'Player 1', location: { x: 1, @@ -757,7 +759,7 @@ describe('TableCache', () => { expect(row).toEqual(op.row); }); expect(callbacks.length).toBe(1); - expect(tableCache.count()).toBe(1); + expect(tableCache.count()).toBe(1n); callbacks.forEach(cb => { cb.cb(); }); @@ -780,16 +782,7 @@ describe('TableCache', () => { }); test('should be empty on creation', () => { - const tableTypeInfo: TableRuntimeTypeInfo = { - tableName: 'player', - rowType: playerType, - primaryKeyInfo: { - colName: 'ownerId', - colType: (playerType as AlgebraicTypeVariants.Product).value.elements[0] - .algebraicType, - }, - }; - const tableCache = new TableCache(tableTypeInfo); - expect(tableCache.count()).toBe(0); + const tableCache = new TableCache(tables.player); + expect(tableCache.count()).toBe(0n); }); }); diff --git a/crates/bindings-typescript/tests/utils.ts b/crates/bindings-typescript/tests/utils.ts index 19461b384cf..4ed63d7e2ed 100644 --- a/crates/bindings-typescript/tests/utils.ts +++ b/crates/bindings-typescript/tests/utils.ts @@ -1,4 +1,7 @@ -import { AlgebraicType, BinaryWriter, Identity } from '../src'; +import { AlgebraicType } from '../src/lib/algebraic_type'; +import BinaryWriter from '../src/lib/binary_writer'; +import { Identity } from '../src/lib/identity'; +import type { Infer } from '../src/lib/type_builders'; import { Player, Point, User } from '../test-app/src/module_bindings'; export const anIdentity = Identity.fromString( @@ -11,13 +14,13 @@ export const sallyIdentity = Identity.fromString( '000000000000000000000000000000000000000000000000000000000006a111' ); -export function encodePlayer(value: Player): Uint8Array { +export function encodePlayer(value: Infer): Uint8Array { const writer = new BinaryWriter(1024); Player.serialize(writer, value); return writer.getBuffer(); } -export function encodeUser(value: User): Uint8Array { +export function encodeUser(value: Infer): Uint8Array { const writer = new BinaryWriter(1024); User.serialize(writer, value); return writer.getBuffer(); @@ -25,7 +28,7 @@ export function encodeUser(value: User): Uint8Array { export function encodeCreatePlayerArgs( name: string, - location: Point + location: Infer ): Uint8Array { const writer = new BinaryWriter(1024); AlgebraicType.serializeValue(writer, AlgebraicType.String, name); diff --git a/crates/codegen/examples/regen-typescript-moduledef.rs b/crates/codegen/examples/regen-typescript-moduledef.rs index 67d83892187..a5f76e64be4 100644 --- a/crates/codegen/examples/regen-typescript-moduledef.rs +++ b/crates/codegen/examples/regen-typescript-moduledef.rs @@ -39,7 +39,7 @@ fn main() -> anyhow::Result<()> { if filename == "index.ts" { return Ok(()); } - let code = regex_replace!(&code, r#"from "spacetimedb";"#, r#"from "../../index";"#); + let code = regex_replace!(&code, r#"from "spacetimedb";"#, r#"from "../../lib/type_builders";"#); // Elide types which are related to client-side only things let code = regex_replace!(&code, r"type CallReducerFlags as __CallReducerFlags,", r""); From dadd620df518611a0c371e0ab399f218d77c18bb Mon Sep 17 00:00:00 2001 From: Tyler Cloutier Date: Mon, 10 Nov 2025 21:25:16 -0500 Subject: [PATCH 25/49] Implemented all the index stuff --- .../bindings-typescript/src/lib/reducers.ts | 22 +- crates/bindings-typescript/src/lib/schema.ts | 17 +- crates/bindings-typescript/src/lib/table.ts | 11 +- .../src/lib/type_builders.ts | 623 ++++++++++-------- .../bindings-typescript/src/lib/type_util.ts | 13 + crates/bindings-typescript/src/lib/util.ts | 5 + crates/bindings-typescript/src/lib/views.ts | 3 +- .../src/react/SpacetimeDBProvider.ts | 1 - .../src/sdk/client_cache.ts | 6 +- .../src/sdk/db_connection_impl.ts | 46 +- .../src/sdk/event_context.ts | 10 +- .../bindings-typescript/src/sdk/reducers.ts | 72 +- .../src/sdk/table_cache.ts | 150 ++++- .../bindings-typescript/src/server/runtime.ts | 7 +- .../test-app/src/module_bindings/index.ts | 27 +- .../src/module_bindings/player_table.ts | 2 +- .../module_bindings/unindexed_player_table.ts | 2 +- .../src/module_bindings/user_table.ts | 2 +- .../tests/algebraic_type.test.ts | 10 +- .../tests/db_connection.test.ts | 79 +-- .../bindings-typescript/tests/index.test.ts | 52 +- .../tests/table_cache.test.ts | 223 +++---- crates/codegen/src/typescript.rs | 66 +- pnpm-lock.yaml | 145 +--- 24 files changed, 914 insertions(+), 680 deletions(-) diff --git a/crates/bindings-typescript/src/lib/reducers.ts b/crates/bindings-typescript/src/lib/reducers.ts index f8b32bd1313..c7ec2b06aba 100644 --- a/crates/bindings-typescript/src/lib/reducers.ts +++ b/crates/bindings-typescript/src/lib/reducers.ts @@ -8,6 +8,7 @@ import type { UntypedReducersDef } from '../sdk/reducers'; import type { DbView } from '../server/db_view'; import { MODULE_DEF, type UntypedSchemaDef } from './schema'; import { + ColumnBuilder, RowBuilder, type Infer, type InferTypeOfRow, @@ -21,13 +22,15 @@ import type { CamelCase } from './type_util'; /** * Helper to extract the parameter types from an object type */ -export type ParamsObj = Record>; +export type ParamsObj = Record< + string, + TypeBuilder | ColumnBuilder +>; /** * Helper to convert a ParamsObj or RowObj into an object type */ -type ParamsAsObject = - InferTypeOfRow; +type ParamsAsObject = InferTypeOfRow; /** * Defines a SpacetimeDB reducer function. @@ -55,10 +58,7 @@ type ParamsAsObject = * ); * ``` */ -export type Reducer< - S extends UntypedSchemaDef, - Params extends ParamsObj | RowObj, -> = ( +export type Reducer = ( ctx: ReducerCtx, payload: ParamsAsObject ) => void | { tag: 'ok' } | { tag: 'err'; value: string }; @@ -190,10 +190,7 @@ export const REDUCERS: Reducer[] = []; * ); * ``` */ -export function reducer< - S extends UntypedSchemaDef, - Params extends ParamsObj | RowObj, ->( +export function reducer( name: string, params: Params, fn: (ctx: ReducerCtx, payload: ParamsAsObject) => void @@ -353,7 +350,8 @@ export function reducerSchema< const paramType: ProductType = { elements: Object.entries(params).map(([n, c]) => ({ name: n, - algebraicType: c.algebraicType, + algebraicType: + 'typeBuilder' in c ? c.typeBuilder.algebraicType : c.algebraicType, })), }; return { diff --git a/crates/bindings-typescript/src/lib/schema.ts b/crates/bindings-typescript/src/lib/schema.ts index 367a0018929..cd65a1b43d0 100644 --- a/crates/bindings-typescript/src/lib/schema.ts +++ b/crates/bindings-typescript/src/lib/schema.ts @@ -39,6 +39,8 @@ import { type ViewFn, type ViewReturnTypeBuilder, } from './views'; +import RawIndexDefV9 from './autogen/raw_index_def_v_9_type'; +import type { Index, IndexOpts } from './indexes'; export type TableNamesOf = S['tables'][number]['name']; @@ -77,7 +79,16 @@ export function tablesToSchema< columns: schema.rowType.row, // typed as T[i]['rowType']['row'] under TablesToSchema rowType: schema.rowSpacetimeType, // UntypedTableDef expects mutable array; idxs are readonly, spread to copy. - indexes: [...schema.idxs], + indexes: [ + ...schema.idxs.map( + (idx: Infer): IndexOpts => + ({ + name: idx.name, + algorithm: idx.algorithm.tag.toLowerCase() as 'btree', + // TODO: columns + }) as IndexOpts + ), + ], } as const; }) as { // preserve tuple indices so the return type matches `[i in keyof T]` @@ -298,13 +309,13 @@ class Schema { * ); * ``` */ - reducer( + reducer( name: string, params: Params, fn: Reducer ): Reducer; reducer(name: string, fn: Reducer): Reducer; - reducer( + reducer( name: string, paramsOrFn: Params | Reducer, fn?: Reducer diff --git a/crates/bindings-typescript/src/lib/table.ts b/crates/bindings-typescript/src/lib/table.ts index 6f18b2603ae..ccc2a6e8a21 100644 --- a/crates/bindings-typescript/src/lib/table.ts +++ b/crates/bindings-typescript/src/lib/table.ts @@ -254,8 +254,8 @@ export function table>( break; } indexes.push({ - name: undefined, - accessorName: name, + name: undefined, // Unnamed indexes will be assigned a globally unique name + accessorName: name, // The name of this column will be used as the accessor name algorithm, }); } @@ -297,6 +297,13 @@ export function table>( algorithm = { tag: 'Direct', value: colIds.get(indexOpts.column)! }; break; } + // unnamed indexes will be assigned a globally unique name + // The name users supply is actually the accessor name which will be used + // in TypeScript to access the index. This will be used verbatim. + // This is confusing because it is not the index name and there is + // no actual way for the user to set the actual index name. + // I think we should standardize: name and accessorName as the way to set + // the name and accessor name of an index across all SDKs. indexes.push({ name: undefined, accessorName: indexOpts.name, algorithm }); } diff --git a/crates/bindings-typescript/src/lib/type_builders.ts b/crates/bindings-typescript/src/lib/type_builders.ts index ebd8ff36795..0ecfdd8b6f6 100644 --- a/crates/bindings-typescript/src/lib/type_builders.ts +++ b/crates/bindings-typescript/src/lib/type_builders.ts @@ -28,7 +28,12 @@ export type InferSpacetimeTypeOfTypeBuilder> = /** * Helper type to extract the TypeScript type from a TypeBuilder */ -export type Infer> = InferTypeOfTypeBuilder; +export type Infer = + T extends TypeBuilder + ? InferTypeOfTypeBuilder + : T extends RowObj + ? InferTypeOfRow + : never; /** * Helper type to extract the type of a row from an object. @@ -119,8 +124,8 @@ type IsUnit = B extends UnitBuilder ? true : false; */ type EnumType = { [K in keyof Variants & string]: IsUnit extends true - ? { tag: K } - : { tag: K; value: InferTypeOfTypeBuilder }; + ? { tag: K } + : { tag: K; value: InferTypeOfTypeBuilder }; }[keyof Variants & string]; /** @@ -136,7 +141,8 @@ type VariantsArrayFromVariantsObj = { * and the corresponding `AlgebraicType`. */ export class TypeBuilder - implements Optional { + implements Optional +{ /** * The TypeScript phantom type. This is not stored at runtime, * but is visible to the compiler @@ -354,11 +360,12 @@ interface Defaultable< export class U8Builder extends TypeBuilder implements - Indexable, - Uniqueable, - PrimaryKeyable, - AutoIncrementable, - Defaultable { + Indexable, + Uniqueable, + PrimaryKeyable, + AutoIncrementable, + Defaultable +{ constructor() { super(AlgebraicType.U8); } @@ -406,11 +413,12 @@ export class U8Builder export class U16Builder extends TypeBuilder implements - Indexable, - Uniqueable, - PrimaryKeyable, - AutoIncrementable, - Defaultable { + Indexable, + Uniqueable, + PrimaryKeyable, + AutoIncrementable, + Defaultable +{ constructor() { super(AlgebraicType.U16); } @@ -458,11 +466,12 @@ export class U16Builder export class U32Builder extends TypeBuilder implements - Indexable, - Uniqueable, - PrimaryKeyable, - AutoIncrementable, - Defaultable { + Indexable, + Uniqueable, + PrimaryKeyable, + AutoIncrementable, + Defaultable +{ constructor() { super(AlgebraicType.U32); } @@ -510,11 +519,12 @@ export class U32Builder export class U64Builder extends TypeBuilder implements - Indexable, - Uniqueable, - PrimaryKeyable, - AutoIncrementable, - Defaultable { + Indexable, + Uniqueable, + PrimaryKeyable, + AutoIncrementable, + Defaultable +{ constructor() { super(AlgebraicType.U64); } @@ -562,11 +572,12 @@ export class U64Builder export class U128Builder extends TypeBuilder implements - Indexable, - Uniqueable, - PrimaryKeyable, - AutoIncrementable, - Defaultable { + Indexable, + Uniqueable, + PrimaryKeyable, + AutoIncrementable, + Defaultable +{ constructor() { super(AlgebraicType.U128); } @@ -617,11 +628,12 @@ export class U128Builder export class U256Builder extends TypeBuilder implements - Indexable, - Uniqueable, - PrimaryKeyable, - AutoIncrementable, - Defaultable { + Indexable, + Uniqueable, + PrimaryKeyable, + AutoIncrementable, + Defaultable +{ constructor() { super(AlgebraicType.U256); } @@ -672,11 +684,12 @@ export class U256Builder export class I8Builder extends TypeBuilder implements - Indexable, - Uniqueable, - PrimaryKeyable, - AutoIncrementable, - Defaultable { + Indexable, + Uniqueable, + PrimaryKeyable, + AutoIncrementable, + Defaultable +{ constructor() { super(AlgebraicType.I8); } @@ -724,11 +737,12 @@ export class I8Builder export class I16Builder extends TypeBuilder implements - Indexable, - Uniqueable, - PrimaryKeyable, - AutoIncrementable, - Defaultable { + Indexable, + Uniqueable, + PrimaryKeyable, + AutoIncrementable, + Defaultable +{ constructor() { super(AlgebraicType.I16); } @@ -776,12 +790,13 @@ export class I16Builder export class I32Builder extends TypeBuilder implements - TypeBuilder, - Indexable, - Uniqueable, - PrimaryKeyable, - AutoIncrementable, - Defaultable { + TypeBuilder, + Indexable, + Uniqueable, + PrimaryKeyable, + AutoIncrementable, + Defaultable +{ constructor() { super(AlgebraicType.I32); } @@ -829,11 +844,12 @@ export class I32Builder export class I64Builder extends TypeBuilder implements - Indexable, - Uniqueable, - PrimaryKeyable, - AutoIncrementable, - Defaultable { + Indexable, + Uniqueable, + PrimaryKeyable, + AutoIncrementable, + Defaultable +{ constructor() { super(AlgebraicType.I64); } @@ -881,11 +897,12 @@ export class I64Builder export class I128Builder extends TypeBuilder implements - Indexable, - Uniqueable, - PrimaryKeyable, - AutoIncrementable, - Defaultable { + Indexable, + Uniqueable, + PrimaryKeyable, + AutoIncrementable, + Defaultable +{ constructor() { super(AlgebraicType.I128); } @@ -936,11 +953,12 @@ export class I128Builder export class I256Builder extends TypeBuilder implements - Indexable, - Uniqueable, - PrimaryKeyable, - AutoIncrementable, - Defaultable { + Indexable, + Uniqueable, + PrimaryKeyable, + AutoIncrementable, + Defaultable +{ constructor() { super(AlgebraicType.I256); } @@ -990,7 +1008,8 @@ export class I256Builder export class F32Builder extends TypeBuilder - implements Defaultable { + implements Defaultable +{ constructor() { super(AlgebraicType.F32); } @@ -1006,7 +1025,8 @@ export class F32Builder export class F64Builder extends TypeBuilder - implements Defaultable { + implements Defaultable +{ constructor() { super(AlgebraicType.F64); } @@ -1023,10 +1043,11 @@ export class F64Builder export class BoolBuilder extends TypeBuilder implements - Indexable, - Uniqueable, - PrimaryKeyable, - Defaultable { + Indexable, + Uniqueable, + PrimaryKeyable, + Defaultable +{ constructor() { super(AlgebraicType.Bool); } @@ -1069,10 +1090,11 @@ export class BoolBuilder export class StringBuilder extends TypeBuilder implements - Indexable, - Uniqueable, - PrimaryKeyable, - Defaultable { + Indexable, + Uniqueable, + PrimaryKeyable, + Defaultable +{ constructor() { super(AlgebraicType.String); } @@ -1117,7 +1139,8 @@ export class ArrayBuilder> Array>, { tag: 'Array'; value: InferSpacetimeTypeOfTypeBuilder } > - implements Defaultable>, any> { + implements Defaultable>, any> +{ /** * The phantom element type of the array for TypeScript */ @@ -1144,7 +1167,8 @@ export class ByteArrayBuilder Uint8Array, { tag: 'Array'; value: AlgebraicTypeVariants.U8 } > - implements Defaultable { + implements Defaultable +{ constructor() { super(AlgebraicType.Array(AlgebraicType.U8)); } @@ -1163,10 +1187,11 @@ export class OptionBuilder> OptionAlgebraicType> > implements - Defaultable< - InferTypeOfTypeBuilder | undefined, - OptionAlgebraicType> - > { + Defaultable< + InferTypeOfTypeBuilder | undefined, + OptionAlgebraicType> + > +{ /** * The phantom value type of the option for TypeScript */ @@ -1206,7 +1231,8 @@ export class ProductBuilder value: { elements: ElementsArrayFromElementsObj }; } > - implements Defaultable, any> { + implements Defaultable, any> +{ readonly typeName: string | undefined; readonly elements: Elements; constructor(elements: Elements, name?: string) { @@ -1270,22 +1296,20 @@ export class RowBuilder extends TypeBuilder< // Value type produced for a given variant key + builder type EnumValue> = IsUnit extends true - ? { tag: K } - : { tag: K; value: InferTypeOfTypeBuilder }; + ? { tag: K } + : { tag: K; value: InferTypeOfTypeBuilder }; -type VariantConstructor< - K extends string, - V extends TypeBuilder -> = IsUnit extends true - ? EnumValue - : (value: InferTypeOfTypeBuilder) => EnumValue; +type VariantConstructor> = + IsUnit extends true + ? EnumValue + : (value: InferTypeOfTypeBuilder) => EnumValue; type SumBuilderVariantConstructors = { [K in keyof Variants & string]: VariantConstructor; }; -export type SumBuilder = SumBuilderImpl & - SumBuilderVariantConstructors; +export type SumBuilder = + SumBuilderImpl & SumBuilderVariantConstructors; class SumBuilderImpl extends TypeBuilder< EnumType, @@ -1330,7 +1354,10 @@ class SumBuilderImpl extends TypeBuilder< if (isUnitRuntime(variant)) { // Unit: expose a read-only VALUE (no call) - const constant = this.create(key as any) as EnumValue; + const constant = this.create(key as any) as EnumValue< + typeof key, + Variants[typeof key] + >; Object.defineProperty(this, key, { value: constant, writable: false, @@ -1339,7 +1366,8 @@ class SumBuilderImpl extends TypeBuilder< }); } else { // Payload: expose a function(value) -> EnumValue - const fn = ((value: any) => this.create(key as any, value)) as VariantConstructor< + const fn = ((value: any) => + this.create(key as any, value)) as VariantConstructor< typeof key & string, Variants[typeof key] >; @@ -1358,13 +1386,15 @@ class SumBuilderImpl extends TypeBuilder< * - Unit variants: create('bar') * - Payload variants: create('foo', value) */ - private create(tag: K): EnumValue; + private create( + tag: K + ): EnumValue; private create( tag: K, value: InferTypeOfTypeBuilder ): EnumValue; private create(tag: string, value?: unknown) { - return (value === undefined ? { tag } : { tag, value }); + return value === undefined ? { tag } : { tag, value }; } default( @@ -1390,20 +1420,21 @@ export const SumBuilder: { class SimpleSumBuilderImpl extends SumBuilderImpl implements - Indexable< - EnumType, - { - tag: 'Sum'; - value: { variants: VariantsArrayFromVariantsObj }; - } - >, - PrimaryKeyable< - EnumType, - { - tag: 'Sum'; - value: { variants: VariantsArrayFromVariantsObj }; - } - > { + Indexable< + EnumType, + { + tag: 'Sum'; + value: { variants: VariantsArrayFromVariantsObj }; + } + >, + PrimaryKeyable< + EnumType, + { + tag: 'Sum'; + value: { variants: VariantsArrayFromVariantsObj }; + } + > +{ index(): SimpleSumColumnBuilder< Variants, SetField @@ -1449,10 +1480,11 @@ export type SimpleSumBuilder = export class IdentityBuilder extends TypeBuilder implements - Indexable, - Uniqueable, - PrimaryKeyable, - Defaultable { + Indexable, + Uniqueable, + PrimaryKeyable, + Defaultable +{ constructor() { super(Identity.getAlgebraicType()); } @@ -1507,10 +1539,11 @@ export class IdentityBuilder export class ConnectionIdBuilder extends TypeBuilder implements - Indexable, - Uniqueable, - PrimaryKeyable, - Defaultable { + Indexable, + Uniqueable, + PrimaryKeyable, + Defaultable +{ constructor() { super(ConnectionId.getAlgebraicType()); } @@ -1569,10 +1602,11 @@ export class ConnectionIdBuilder export class TimestampBuilder extends TypeBuilder implements - Indexable, - Uniqueable, - PrimaryKeyable, - Defaultable { + Indexable, + Uniqueable, + PrimaryKeyable, + Defaultable +{ constructor() { super(Timestamp.getAlgebraicType()); } @@ -1631,10 +1665,11 @@ export class TimestampBuilder export class TimeDurationBuilder extends TypeBuilder implements - Indexable, - Uniqueable, - PrimaryKeyable, - Defaultable { + Indexable, + Uniqueable, + PrimaryKeyable, + Defaultable +{ constructor() { super(TimeDuration.getAlgebraicType()); } @@ -1748,18 +1783,22 @@ export class ColumnBuilder< } deserialize(reader: BinaryReader): Type { - return AlgebraicType.deserializeValue(reader, this.typeBuilder.algebraicType); + return AlgebraicType.deserializeValue( + reader, + this.typeBuilder.algebraicType + ); } } export class U8ColumnBuilder = DefaultMetadata> extends ColumnBuilder implements - Indexable, - Uniqueable, - PrimaryKeyable, - AutoIncrementable, - Defaultable { + Indexable, + Uniqueable, + PrimaryKeyable, + AutoIncrementable, + Defaultable +{ index(): U8ColumnBuilder>; index>( algorithm: N @@ -1801,15 +1840,16 @@ export class U8ColumnBuilder = DefaultMetadata> } export class U16ColumnBuilder< - M extends ColumnMetadata = DefaultMetadata, -> + M extends ColumnMetadata = DefaultMetadata, + > extends ColumnBuilder implements - Indexable, - Uniqueable, - PrimaryKeyable, - AutoIncrementable, - Defaultable { + Indexable, + Uniqueable, + PrimaryKeyable, + AutoIncrementable, + Defaultable +{ index(): U16ColumnBuilder>; index>( algorithm: N @@ -1853,15 +1893,16 @@ export class U16ColumnBuilder< } export class U32ColumnBuilder< - M extends ColumnMetadata = DefaultMetadata, -> + M extends ColumnMetadata = DefaultMetadata, + > extends ColumnBuilder implements - Indexable, - Uniqueable, - PrimaryKeyable, - AutoIncrementable, - Defaultable { + Indexable, + Uniqueable, + PrimaryKeyable, + AutoIncrementable, + Defaultable +{ index(): U32ColumnBuilder>; index>( algorithm: N @@ -1905,15 +1946,16 @@ export class U32ColumnBuilder< } export class U64ColumnBuilder< - M extends ColumnMetadata = DefaultMetadata, -> + M extends ColumnMetadata = DefaultMetadata, + > extends ColumnBuilder implements - Indexable, - Uniqueable, - PrimaryKeyable, - AutoIncrementable, - Defaultable { + Indexable, + Uniqueable, + PrimaryKeyable, + AutoIncrementable, + Defaultable +{ index(): U64ColumnBuilder>; index>( algorithm: N @@ -1957,15 +1999,16 @@ export class U64ColumnBuilder< } export class U128ColumnBuilder< - M extends ColumnMetadata = DefaultMetadata, -> + M extends ColumnMetadata = DefaultMetadata, + > extends ColumnBuilder implements - Indexable, - Uniqueable, - PrimaryKeyable, - AutoIncrementable, - Defaultable { + Indexable, + Uniqueable, + PrimaryKeyable, + AutoIncrementable, + Defaultable +{ index(): U128ColumnBuilder>; index>( algorithm: N @@ -2009,15 +2052,16 @@ export class U128ColumnBuilder< } export class U256ColumnBuilder< - M extends ColumnMetadata = DefaultMetadata, -> + M extends ColumnMetadata = DefaultMetadata, + > extends ColumnBuilder implements - Indexable, - Uniqueable, - PrimaryKeyable, - AutoIncrementable, - Defaultable { + Indexable, + Uniqueable, + PrimaryKeyable, + AutoIncrementable, + Defaultable +{ index(): U256ColumnBuilder>; index>( algorithm: N @@ -2063,11 +2107,12 @@ export class U256ColumnBuilder< export class I8ColumnBuilder = DefaultMetadata> extends ColumnBuilder implements - Indexable, - Uniqueable, - PrimaryKeyable, - AutoIncrementable, - Defaultable { + Indexable, + Uniqueable, + PrimaryKeyable, + AutoIncrementable, + Defaultable +{ index(): I8ColumnBuilder>; index>( algorithm: N @@ -2109,15 +2154,16 @@ export class I8ColumnBuilder = DefaultMetadata> } export class I16ColumnBuilder< - M extends ColumnMetadata = DefaultMetadata, -> + M extends ColumnMetadata = DefaultMetadata, + > extends ColumnBuilder implements - Indexable, - Uniqueable, - PrimaryKeyable, - AutoIncrementable, - Defaultable { + Indexable, + Uniqueable, + PrimaryKeyable, + AutoIncrementable, + Defaultable +{ index(): I16ColumnBuilder>; index>( algorithm: N @@ -2161,15 +2207,16 @@ export class I16ColumnBuilder< } export class I32ColumnBuilder< - M extends ColumnMetadata = DefaultMetadata, -> + M extends ColumnMetadata = DefaultMetadata, + > extends ColumnBuilder implements - Indexable, - Uniqueable, - PrimaryKeyable, - AutoIncrementable, - Defaultable { + Indexable, + Uniqueable, + PrimaryKeyable, + AutoIncrementable, + Defaultable +{ index(): I32ColumnBuilder>; index>( algorithm: N @@ -2213,15 +2260,16 @@ export class I32ColumnBuilder< } export class I64ColumnBuilder< - M extends ColumnMetadata = DefaultMetadata, -> + M extends ColumnMetadata = DefaultMetadata, + > extends ColumnBuilder implements - Indexable, - Uniqueable, - PrimaryKeyable, - AutoIncrementable, - Defaultable { + Indexable, + Uniqueable, + PrimaryKeyable, + AutoIncrementable, + Defaultable +{ index(): I64ColumnBuilder>; index>( algorithm: N @@ -2265,15 +2313,16 @@ export class I64ColumnBuilder< } export class I128ColumnBuilder< - M extends ColumnMetadata = DefaultMetadata, -> + M extends ColumnMetadata = DefaultMetadata, + > extends ColumnBuilder implements - Indexable, - Uniqueable, - PrimaryKeyable, - AutoIncrementable, - Defaultable { + Indexable, + Uniqueable, + PrimaryKeyable, + AutoIncrementable, + Defaultable +{ index(): I128ColumnBuilder>; index>( algorithm: N @@ -2317,15 +2366,16 @@ export class I128ColumnBuilder< } export class I256ColumnBuilder< - M extends ColumnMetadata = DefaultMetadata, -> + M extends ColumnMetadata = DefaultMetadata, + > extends ColumnBuilder implements - Indexable, - Uniqueable, - PrimaryKeyable, - AutoIncrementable, - Defaultable { + Indexable, + Uniqueable, + PrimaryKeyable, + AutoIncrementable, + Defaultable +{ index(): I256ColumnBuilder>; index>( algorithm: N @@ -2369,10 +2419,11 @@ export class I256ColumnBuilder< } export class F32ColumnBuilder< - M extends ColumnMetadata = DefaultMetadata, -> + M extends ColumnMetadata = DefaultMetadata, + > extends ColumnBuilder - implements Defaultable { + implements Defaultable +{ default( value: number ): F32ColumnBuilder> { @@ -2386,10 +2437,11 @@ export class F32ColumnBuilder< } export class F64ColumnBuilder< - M extends ColumnMetadata = DefaultMetadata, -> + M extends ColumnMetadata = DefaultMetadata, + > extends ColumnBuilder - implements Defaultable { + implements Defaultable +{ default( value: number ): F64ColumnBuilder> { @@ -2403,14 +2455,15 @@ export class F64ColumnBuilder< } export class BoolColumnBuilder< - M extends ColumnMetadata = DefaultMetadata, -> + M extends ColumnMetadata = DefaultMetadata, + > extends ColumnBuilder implements - Indexable, - Uniqueable, - PrimaryKeyable, - Defaultable { + Indexable, + Uniqueable, + PrimaryKeyable, + Defaultable +{ index(): BoolColumnBuilder>; index>( algorithm: N @@ -2448,14 +2501,15 @@ export class BoolColumnBuilder< } export class StringColumnBuilder< - M extends ColumnMetadata = DefaultMetadata, -> + M extends ColumnMetadata = DefaultMetadata, + > extends ColumnBuilder implements - Indexable, - Uniqueable, - PrimaryKeyable, - Defaultable { + Indexable, + Uniqueable, + PrimaryKeyable, + Defaultable +{ index(): StringColumnBuilder>; index>( algorithm: N @@ -2493,21 +2547,22 @@ export class StringColumnBuilder< } export class ArrayColumnBuilder< - Element extends TypeBuilder, - M extends ColumnMetadata< - Array> - > = DefaultMetadata, -> + Element extends TypeBuilder, + M extends ColumnMetadata< + Array> + > = DefaultMetadata, + > extends ColumnBuilder< Array>, { tag: 'Array'; value: InferSpacetimeTypeOfTypeBuilder }, M > implements - Defaultable< - Array>, - AlgebraicTypeVariants.Array - > { + Defaultable< + Array>, + AlgebraicTypeVariants.Array + > +{ default( value: Array> ): ArrayColumnBuilder< @@ -2539,21 +2594,22 @@ export class ByteArrayColumnBuilder< } export class OptionColumnBuilder< - Value extends TypeBuilder, - M extends ColumnMetadata< - InferTypeOfTypeBuilder | undefined - > = DefaultMetadata, -> + Value extends TypeBuilder, + M extends ColumnMetadata< + InferTypeOfTypeBuilder | undefined + > = DefaultMetadata, + > extends ColumnBuilder< InferTypeOfTypeBuilder | undefined, OptionAlgebraicType>, M > implements - Defaultable< - InferTypeOfTypeBuilder | undefined, - OptionAlgebraicType> - > { + Defaultable< + InferTypeOfTypeBuilder | undefined, + OptionAlgebraicType> + > +{ default( value: InferTypeOfTypeBuilder | undefined ): OptionColumnBuilder< @@ -2570,9 +2626,9 @@ export class OptionColumnBuilder< } export class ProductColumnBuilder< - Elements extends ElementsObj, - M extends ColumnMetadata> = DefaultMetadata, -> + Elements extends ElementsObj, + M extends ColumnMetadata> = DefaultMetadata, + > extends ColumnBuilder< ObjectType, { @@ -2581,7 +2637,8 @@ export class ProductColumnBuilder< }, M > - implements Defaultable, AlgebraicTypeVariants.Product> { + implements Defaultable, AlgebraicTypeVariants.Product> +{ default( value: ObjectType ): ProductColumnBuilder< @@ -2596,15 +2653,16 @@ export class ProductColumnBuilder< } export class SumColumnBuilder< - Variants extends VariantsObj, - M extends ColumnMetadata> = DefaultMetadata, -> + Variants extends VariantsObj, + M extends ColumnMetadata> = DefaultMetadata, + > extends ColumnBuilder< EnumType, { tag: 'Sum'; value: { variants: VariantsArrayFromVariantsObj } }, M > - implements Defaultable, AlgebraicTypeVariants.Sum> { + implements Defaultable, AlgebraicTypeVariants.Sum> +{ default( value: EnumType ): SumColumnBuilder< @@ -2619,13 +2677,14 @@ export class SumColumnBuilder< } export class SimpleSumColumnBuilder< - Variants extends VariantsObj, - M extends ColumnMetadata> = DefaultMetadata, -> + Variants extends VariantsObj, + M extends ColumnMetadata> = DefaultMetadata, + > extends SumColumnBuilder implements - Indexable, AlgebraicTypeVariants.Sum>, - PrimaryKeyable, AlgebraicTypeVariants.Sum> { + Indexable, AlgebraicTypeVariants.Sum>, + PrimaryKeyable, AlgebraicTypeVariants.Sum> +{ index(): SimpleSumColumnBuilder< Variants, SetField @@ -2659,14 +2718,15 @@ export class SimpleSumColumnBuilder< } export class IdentityColumnBuilder< - M extends ColumnMetadata = DefaultMetadata, -> + M extends ColumnMetadata = DefaultMetadata, + > extends ColumnBuilder implements - Indexable, - Uniqueable, - PrimaryKeyable, - Defaultable { + Indexable, + Uniqueable, + PrimaryKeyable, + Defaultable +{ index(): IdentityColumnBuilder>; index>( algorithm: N @@ -2702,14 +2762,15 @@ export class IdentityColumnBuilder< } export class ConnectionIdColumnBuilder< - M extends ColumnMetadata = DefaultMetadata, -> + M extends ColumnMetadata = DefaultMetadata, + > extends ColumnBuilder implements - Indexable, - Uniqueable, - PrimaryKeyable, - Defaultable { + Indexable, + Uniqueable, + PrimaryKeyable, + Defaultable +{ index(): ConnectionIdColumnBuilder>; index>( algorithm: N @@ -2745,14 +2806,15 @@ export class ConnectionIdColumnBuilder< } export class TimestampColumnBuilder< - M extends ColumnMetadata = DefaultMetadata, -> + M extends ColumnMetadata = DefaultMetadata, + > extends ColumnBuilder implements - Indexable, - Uniqueable, - PrimaryKeyable, - Defaultable { + Indexable, + Uniqueable, + PrimaryKeyable, + Defaultable +{ index(): TimestampColumnBuilder>; index>( algorithm: N @@ -2788,14 +2850,15 @@ export class TimestampColumnBuilder< } export class TimeDurationColumnBuilder< - M extends ColumnMetadata = DefaultMetadata, -> + M extends ColumnMetadata = DefaultMetadata, + > extends ColumnBuilder implements - Indexable, - Uniqueable, - PrimaryKeyable, - Defaultable { + Indexable, + Uniqueable, + PrimaryKeyable, + Defaultable +{ index(): TimeDurationColumnBuilder>; index>( algorithm: N diff --git a/crates/bindings-typescript/src/lib/type_util.ts b/crates/bindings-typescript/src/lib/type_util.ts index 55aa63ec162..35efb5740d8 100644 --- a/crates/bindings-typescript/src/lib/type_util.ts +++ b/crates/bindings-typescript/src/lib/type_util.ts @@ -60,3 +60,16 @@ type CamelCaseImpl = S extends `${infer Head}_${infer Tail}` * - Normalizes the *first* character to lowercase (e.g. "User_Name" -> "userName") */ export type CamelCase = Uncapitalize>; + +type PascalCaseImpl = S extends `${infer Head}_${infer Tail}` + ? `${Capitalize}${PascalCaseImpl}` + : S extends `${infer Head}-${infer Tail}` + ? `${Capitalize}${PascalCaseImpl}` + : Capitalize; + +/** + * Convert "some_identifier-name" -> "SomeIdentifierName" + * - No spaces; allowed separators: "_" and "-" + * - Normalizes the *first* character to uppercase (e.g. "user_name" -> "UserName") + */ +export type PascalCase = PascalCaseImpl; diff --git a/crates/bindings-typescript/src/lib/util.ts b/crates/bindings-typescript/src/lib/util.ts index c13a90b0e53..025b9c70bf3 100644 --- a/crates/bindings-typescript/src/lib/util.ts +++ b/crates/bindings-typescript/src/lib/util.ts @@ -2,6 +2,11 @@ import BinaryReader from './binary_reader'; import BinaryWriter from './binary_writer'; import type { CamelCase } from './type_util'; +/** + * Converts a string to PascalCase (UpperCamelCase). + * @param str The string to convert + * @returns The converted string + */ export function toPascalCase(s: string): string { const str = s.replace(/([-_][a-z])/gi, $1 => { return $1.toUpperCase().replace('-', '').replace('_', ''); diff --git a/crates/bindings-typescript/src/lib/views.ts b/crates/bindings-typescript/src/lib/views.ts index b4a5fbd0b23..27858467b2c 100644 --- a/crates/bindings-typescript/src/lib/views.ts +++ b/crates/bindings-typescript/src/lib/views.ts @@ -63,7 +63,8 @@ export function defineView< const paramType = { elements: Object.entries(params).map(([n, c]) => ({ name: n, - algebraicType: c.algebraicType, + algebraicType: + 'typeBuilder' in c ? c.typeBuilder.algebraicType : c.algebraicType, })), }; diff --git a/crates/bindings-typescript/src/react/SpacetimeDBProvider.ts b/crates/bindings-typescript/src/react/SpacetimeDBProvider.ts index 5c10b2aed8c..299b069cc1d 100644 --- a/crates/bindings-typescript/src/react/SpacetimeDBProvider.ts +++ b/crates/bindings-typescript/src/react/SpacetimeDBProvider.ts @@ -40,7 +40,6 @@ export function SpacetimeDBProvider< if (!connRef.current) { connRef.current = connectionBuilder.build(); } - console.log('HAPPPP'); // Register callback for onConnect to update state const onConnect = (conn: DbConnection) => { setState(s => ({ diff --git a/crates/bindings-typescript/src/sdk/client_cache.ts b/crates/bindings-typescript/src/sdk/client_cache.ts index 33c7bca6aa7..1016cb76e8b 100644 --- a/crates/bindings-typescript/src/sdk/client_cache.ts +++ b/crates/bindings-typescript/src/sdk/client_cache.ts @@ -1,7 +1,7 @@ import type { TableNamesOf, UntypedSchemaDef } from '../lib/schema.ts'; import type { UntypedTableDef } from '../lib/table.ts'; import type { UntypedRemoteModule } from './spacetime_module.ts'; -import { TableCache } from './table_cache.ts'; +import { type TableCache, TableCacheImpl } from './table_cache.ts'; type TableName = [SchemaDef] extends [UntypedSchemaDef] ? TableNamesOf @@ -119,7 +119,9 @@ export class ClientCache { return table; } - const newTable = new TableCache(tableDef); + const newTable = new TableCacheImpl( + tableDef + ) as TableCache; this.tables.set(name, newTable); return newTable; } diff --git a/crates/bindings-typescript/src/sdk/db_connection_impl.ts b/crates/bindings-typescript/src/sdk/db_connection_impl.ts index 7a6daf50324..a7e3a1082e8 100644 --- a/crates/bindings-typescript/src/sdk/db_connection_impl.ts +++ b/crates/bindings-typescript/src/sdk/db_connection_impl.ts @@ -30,7 +30,7 @@ import type { import type { ReducerEvent } from './reducer_event.ts'; import { type UntypedRemoteModule } from './spacetime_module.ts'; import { - TableCache, + type TableCache, type Operation, type PendingCallback, type TableUpdate as CacheTableUpdate, @@ -46,15 +46,22 @@ import { import { stdbLogger } from './logger.ts'; import { fromByteArray } from 'base64-js'; import type { + ReducerEventCallback, ReducerEventInfo, ReducersView, SetReducerFlags, + SubscriptionEventCallback, } from './reducers.ts'; import type { ClientDbView } from './db_view.ts'; import type { UntypedTableDef } from '../lib/table.ts'; -import { toCamelCase } from '../lib/util.ts'; +import { toCamelCase, toPascalCase } from '../lib/util.ts'; -export { DbConnectionBuilder, SubscriptionBuilderImpl, TableCache, type Event }; +export { + DbConnectionBuilder, + SubscriptionBuilderImpl, + type TableCache, + type Event, +}; export type RemoteModuleOf = C extends DbConnectionImpl ? RM : never; @@ -71,18 +78,6 @@ export type { export type ConnectionEvent = 'connect' | 'disconnect' | 'connectError'; export type CallReducerFlags = 'FullUpdate' | 'NoSuccessNotify'; -type ReducerEventCallback< - RemoteModule extends UntypedRemoteModule, - ReducerArgs extends any[] = any[], -> = ( - ctx: ReducerEventContextInterface, - ...args: ReducerArgs -) => void; - -type SubscriptionEventCallback = ( - ctx: SubscriptionEventContextInterface -) => void; - function callReducerFlagsToNumber(flags: CallReducerFlags): number { switch (flags) { case 'FullUpdate': @@ -273,6 +268,26 @@ export class DbConnectionImpl flags ); }; + + const onReducerEventKey = `on${toPascalCase(reducer.name)}`; + (out as any)[onReducerEventKey] = ( + callback: ReducerEventCallback< + RemoteModule, + InferTypeOfRow + > + ) => { + this.onReducer(reducer.name, callback); + }; + + const offReducerEventKey = `removeOn${toPascalCase(reducer.name)}`; + (out as any)[offReducerEventKey] = ( + callback: ReducerEventCallback< + RemoteModule, + InferTypeOfRow + > + ) => { + this.offReducer(reducer.name, callback); + }; } return out as ReducersView; @@ -296,6 +311,7 @@ export class DbConnectionImpl #makeEventContext( event: Event< ReducerEventInfo< + RemoteModule['reducers'][number]['name'], InferTypeOfRow > > diff --git a/crates/bindings-typescript/src/sdk/event_context.ts b/crates/bindings-typescript/src/sdk/event_context.ts index 677adcac90d..093243d4c1a 100644 --- a/crates/bindings-typescript/src/sdk/event_context.ts +++ b/crates/bindings-typescript/src/sdk/event_context.ts @@ -11,7 +11,10 @@ export interface EventContextInterface extends DbContext { /** Enum with variants for all possible events. */ event: Event< - ReducerEventInfo> + ReducerEventInfo< + RemoteModule['reducers'][number]['name'], + InferTypeOfRow + > >; } @@ -20,7 +23,10 @@ export interface ReducerEventContextInterface< > extends DbContext { /** Enum with variants for all possible events. */ event: ReducerEvent< - ReducerEventInfo> + ReducerEventInfo< + RemoteModule['reducers'][number]['name'], + InferTypeOfRow + > >; } diff --git a/crates/bindings-typescript/src/sdk/reducers.ts b/crates/bindings-typescript/src/sdk/reducers.ts index e8bf048e868..2b4dcd801b8 100644 --- a/crates/bindings-typescript/src/sdk/reducers.ts +++ b/crates/bindings-typescript/src/sdk/reducers.ts @@ -2,17 +2,75 @@ import type { ProductType } from '../lib/algebraic_type'; import type { ParamsObj } from '../lib/reducers'; import type { CoerceRow } from '../lib/table'; import type { InferTypeOfRow } from '../lib/type_builders'; -import type { CamelCase } from '../lib/type_util'; +import type { CamelCase, PascalCase } from '../lib/type_util'; import type { CallReducerFlags } from './db_connection_impl'; +import type { UntypedRemoteModule } from './spacetime_module'; +import type { + ReducerEventContextInterface, + SubscriptionEventContextInterface, +} from './event_context'; -export type ReducersView = { - [I in keyof R['reducers'] as CamelCase< - R['reducers'][number]['accessorName'] - >]: (params: InferTypeOfRow) => void; +export type ReducerEventCallback< + RemoteModule extends UntypedRemoteModule, + ReducerArgs extends object = object, +> = ( + ctx: ReducerEventContextInterface, + args: ReducerArgs +) => void; + +export type SubscriptionEventCallback< + RemoteModule extends UntypedRemoteModule, +> = (ctx: SubscriptionEventContextInterface) => void; + +// Utility: detect 'any' +type IfAny = 0 extends 1 & T ? Y : N; + +// Loose shape that allows all three families even when key names are unknown +type ReducersViewLoose = { + // call: camelCase(name) + [k: string]: (params: any) => void; +} & { + // onX + [k: `on${string}`]: (callback: ReducerEventCallback) => void; +} & { + // removeOnX + [k: `removeOn${string}`]: (callback: ReducerEventCallback) => void; }; -export type ReducerEventInfo = { - name: string; +export type ReducersView = IfAny< + RemoteModule, + ReducersViewLoose, + RemoteModule extends UntypedRemoteModule + ? // x: camelCase(name) + { + [K in RemoteModule['reducers'][number] as CamelCase< + K['accessorName'] + >]: (params: InferTypeOfRow) => void; + } & // onX: `on${PascalCase(name)}` + { + [K in RemoteModule['reducers'][number] as `on${PascalCase}`]: ( + callback: ReducerEventCallback< + RemoteModule, + InferTypeOfRow + > + ) => void; + } & // removeOnX: `removeOn${PascalCase(name)}` + { + [K in RemoteModule['reducers'][number] as `removeOn${PascalCase}`]: ( + callback: ReducerEventCallback< + RemoteModule, + InferTypeOfRow + > + ) => void; + } + : never +>; + +export type ReducerEventInfo< + Name extends string = string, + Args extends object = object, +> = { + name: Name; args: Args; }; diff --git a/crates/bindings-typescript/src/sdk/table_cache.ts b/crates/bindings-typescript/src/sdk/table_cache.ts index abc4fb147d5..999b2632289 100644 --- a/crates/bindings-typescript/src/sdk/table_cache.ts +++ b/crates/bindings-typescript/src/sdk/table_cache.ts @@ -1,12 +1,20 @@ import { EventEmitter } from './event_emitter.ts'; import { stdbLogger } from './logger.ts'; -import type { ComparablePrimitive } from '../'; +import { deepEqual, type ComparablePrimitive } from '../'; import type { EventContextInterface, TableDefForTableName } from './index.ts'; -import type { RowType, UntypedTableDef } from '../lib/table.ts'; +import type { RowType, TableIndexes, UntypedTableDef } from '../lib/table.ts'; import type { ClientTableCoreImplementable } from './client_table.ts'; import type { UntypedRemoteModule } from './spacetime_module.ts'; import type { TableNamesOf } from '../lib/schema.ts'; +import type { + ReadonlyIndex, + ReadonlyIndexes, + ReadonlyRangedIndex, + ReadonlyUniqueIndex, + UntypedIndex, +} from '../lib/indexes.ts'; +import type { Bound } from '../server/range.ts'; export type Operation< RowType extends Record = Record, @@ -29,10 +37,31 @@ export type PendingCallback = { cb: () => void; }; +// Strict scalar compare for index term values. +const scalarCompare = (x: any, y: any): number => { + if (x === y) return 0; + // Compare booleans/numbers/bigints/strings with JS ordering. + return x < y ? -1 : 1; +}; + +export type TableIndexView< + RemoteModule extends UntypedRemoteModule, + TableName extends TableNamesOf, +> = ReadonlyIndexes< + TableDefForTableName, + TableIndexes> +>; + +export type TableCache< + RemoteModule extends UntypedRemoteModule, + TableName extends TableNamesOf, +> = TableCacheImpl & + TableIndexView; + /** * Builder to generate calls to query a `table` in the database */ -export class TableCache< +export class TableCacheImpl< RemoteModule extends UntypedRemoteModule, TableName extends TableNamesOf, > implements ClientTableCoreImplementable @@ -54,6 +83,121 @@ export class TableCache< this.tableDef = tableDef; this.rows = new Map(); this.emitter = new EventEmitter(); + // Build indexes + const indexesDef = this.tableDef.indexes || {}; + for (const idx of indexesDef) { + const idxDef = idx as UntypedIndex< + keyof TableDefForTableName['columns'] & string + >; + const index = this.#makeReadonlyIndex(idxDef); + (this as any)[idx.name!] = index; + } + } + + // TODO: this just scans the whole table; we should build proper index structures + #makeReadonlyIndex< + I extends UntypedIndex< + keyof TableDefForTableName['columns'] & string + >, + >(idx: I): ReadonlyIndex, I> { + type TableDef = TableDefForTableName; + type Row = RowType; + + // We do not yet support non-btree indexes + if (idx.algorithm !== 'btree') { + throw new Error('Only btree indexes are supported in TableCacheImpl'); + } + + const columns = idx.columns as readonly (keyof Row & string)[]; + + // Extract the tuple key for this btree index (column order preserved) + const getKey = (row: Row): readonly unknown[] => columns.map(c => row[c]); + + // The server’s ranged scan fixes all prefix cols to equality and applies + // the bound only to the *last* term. We mirror that. + // + // rangeArg for multi-col index is: + // [...prefixEqualValues, (lastTerm | Range)] + // + // If only one element is provided, it’s the last term (scalar or Range). + const matchRange = (row: Row, rangeArg: any): boolean => { + const key = getKey(row); + + // Normalize rangeArg into an array. + // With multi-col b-tree, IndexScanRangeBounds always yields at least one element. + const arr = Array.isArray(rangeArg) ? rangeArg : [rangeArg]; + + const prefixLen = Math.max(0, arr.length - 1); + // Check equality over the prefix (all but the last provided element) + for (let i = 0; i < prefixLen; i++) { + if (!deepEqual(key[i], arr[i])) return false; + } + + const lastProvided = arr[arr.length - 1]; + const kLast = key[prefixLen]; + + // If the last provided is a Range, apply bounds; otherwise equality. + if ( + lastProvided && + typeof lastProvided === 'object' && + 'from' in lastProvided && + 'to' in lastProvided + ) { + // Range + const from = lastProvided.from as Bound; + const to = lastProvided.to as Bound; + + // Lower bound + if (from.tag !== 'unbounded') { + const c = scalarCompare(kLast, from.value); + if (c < 0) return false; + if (c === 0 && from.tag === 'excluded') return false; + } + + // Upper bound + if (to.tag !== 'unbounded') { + const c = scalarCompare(kLast, to.value); + if (c > 0) return false; + if (c === 0 && to.tag === 'excluded') return false; + } + + // All good on last term; any remaining columns (if any) are unconstrained, + // which matches server behavior for a prefix scan. + return true; + } else { + // Equality on the last provided element + if (!deepEqual(kLast, lastProvided)) return false; + // Any remaining columns are unconstrained (prefix equality only). + return true; + } + }; + + const isUnique = idx.unique === true; + + // eslint-disable-next-line @typescript-eslint/no-this-alias + const self = this; + if (isUnique) { + const impl: ReadonlyUniqueIndex = { + find: (colVal: any): Row | null => { + // For unique btree, caller supplies the *full* key (tuple if multi-col). + const expected = Array.isArray(colVal) ? colVal : [colVal]; + for (const row of self.iter()) { + if (deepEqual(getKey(row), expected)) return row; + } + return null; + }, + }; + return impl as ReadonlyIndex; + } else { + const impl: ReadonlyRangedIndex = { + *filter(range: any): IterableIterator { + for (const row of self.iter()) { + if (matchRange(row, range)) yield row; + } + }, + }; + return impl as ReadonlyIndex; + } } /** diff --git a/crates/bindings-typescript/src/server/runtime.ts b/crates/bindings-typescript/src/server/runtime.ts index bb364994f4d..581f35ddd7f 100644 --- a/crates/bindings-typescript/src/server/runtime.ts +++ b/crates/bindings-typescript/src/server/runtime.ts @@ -32,7 +32,12 @@ import type { DbView } from './db_view'; import { toCamelCase } from '../lib/util'; import type { Infer } from '../lib/type_builders'; import { bsatnBaseSize } from '../lib/util'; -import { ANON_VIEWS, VIEWS, type AnonymousViewCtx, type ViewCtx } from '../lib/views'; +import { + ANON_VIEWS, + VIEWS, + type AnonymousViewCtx, + type ViewCtx, +} from '../lib/views'; const { freeze } = Object; diff --git a/crates/bindings-typescript/test-app/src/module_bindings/index.ts b/crates/bindings-typescript/test-app/src/module_bindings/index.ts index 24ce38c5708..2f42fe19a15 100644 --- a/crates/bindings-typescript/test-app/src/module_bindings/index.ts +++ b/crates/bindings-typescript/test-app/src/module_bindings/index.ts @@ -1,7 +1,7 @@ // THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE // WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. -// This was generated using ../../../src/index cli version 1.7.0 (commit cb16789be729954a7c47b87fb40b35baa0bd1029). +// This was generated using ../../../src/index cli version 1.7.0 (commit 57bd49bec937a3ae060c1c9af85979525fdb839d). /* eslint-disable */ /* tslint:disable */ @@ -53,21 +53,40 @@ const tablesSchema = __schema( __table( { name: 'player', - indexes: [], + indexes: [{ name: 'id', algorithm: 'btree', columns: ['id'] }], + constraints: [ + { name: 'player_id_key', constraint: 'unique', columns: ['id'] }, + ], }, PlayerRow ), __table( { name: 'unindexed_player', - indexes: [], + indexes: [{ name: 'id', algorithm: 'btree', columns: ['id'] }], + constraints: [ + { + name: 'unindexed_player_id_key', + constraint: 'unique', + columns: ['id'], + }, + ], }, UnindexedPlayerRow ), __table( { name: 'user', - indexes: [], + indexes: [ + { name: 'identity', algorithm: 'btree', columns: ['identity'] }, + ], + constraints: [ + { + name: 'user_identity_key', + constraint: 'unique', + columns: ['identity'], + }, + ], }, UserRow ) diff --git a/crates/bindings-typescript/test-app/src/module_bindings/player_table.ts b/crates/bindings-typescript/test-app/src/module_bindings/player_table.ts index ee98682e78b..8a17e720c5a 100644 --- a/crates/bindings-typescript/test-app/src/module_bindings/player_table.ts +++ b/crates/bindings-typescript/test-app/src/module_bindings/player_table.ts @@ -12,7 +12,7 @@ import { import Point from './point_type'; export default __t.row({ - id: __t.u32(), + id: __t.u32().primaryKey(), userId: __t.identity(), name: __t.string(), get location() { diff --git a/crates/bindings-typescript/test-app/src/module_bindings/unindexed_player_table.ts b/crates/bindings-typescript/test-app/src/module_bindings/unindexed_player_table.ts index 96f056baeb7..6f6457a7a52 100644 --- a/crates/bindings-typescript/test-app/src/module_bindings/unindexed_player_table.ts +++ b/crates/bindings-typescript/test-app/src/module_bindings/unindexed_player_table.ts @@ -12,7 +12,7 @@ import { import Point from './point_type'; export default __t.row({ - id: __t.u32(), + id: __t.u32().primaryKey(), ownerId: __t.identity(), name: __t.string(), get location() { diff --git a/crates/bindings-typescript/test-app/src/module_bindings/user_table.ts b/crates/bindings-typescript/test-app/src/module_bindings/user_table.ts index efa159d1988..086fe07ad63 100644 --- a/crates/bindings-typescript/test-app/src/module_bindings/user_table.ts +++ b/crates/bindings-typescript/test-app/src/module_bindings/user_table.ts @@ -11,6 +11,6 @@ import { } from '../../../src/index'; export default __t.row({ - identity: __t.identity(), + identity: __t.identity().primaryKey(), username: __t.string(), }); diff --git a/crates/bindings-typescript/tests/algebraic_type.test.ts b/crates/bindings-typescript/tests/algebraic_type.test.ts index c993f1f0e5f..351275e9beb 100644 --- a/crates/bindings-typescript/tests/algebraic_type.test.ts +++ b/crates/bindings-typescript/tests/algebraic_type.test.ts @@ -25,7 +25,7 @@ describe('AlgebraicType', () => { for (const [tag, value] of primitiveTypes) { const algebraicType = { tag, value: undefined }; const mapKey = AlgebraicType.intoMapKey(algebraicType, value); - expect(mapKey).toBe(value); + expect(mapKey).foundUser(value); } }); @@ -37,9 +37,9 @@ describe('AlgebraicType', () => { const mapKey = AlgebraicType.intoMapKey(productType, productValue); // Fallback for complex types is base64 encoding of serialized value - expect(typeof mapKey).toBe('string'); + expect(typeof mapKey).foundUser('string'); // 42 as i32 little-endian is 2A000000, which is KgAAAA== in base64 - expect(mapKey).toBe('KgAAAA=='); + expect(mapKey).foundUser('KgAAAA=='); }); test('intoMapKey fallback serializes array types', () => { @@ -47,8 +47,8 @@ describe('AlgebraicType', () => { const arrayValue = [1, 2, 3]; const mapKey = AlgebraicType.intoMapKey(arrayType, arrayValue); - expect(typeof mapKey).toBe('string'); + expect(typeof mapKey).foundUser('string'); // Serialized as: [len (u32), val1 (u16), val2 (u16), val3 (u16)] - expect(mapKey).toBe('AwAAAAEAAgADAA=='); + expect(mapKey).foundUser('AwAAAAEAAgADAA=='); }); }); diff --git a/crates/bindings-typescript/tests/db_connection.test.ts b/crates/bindings-typescript/tests/db_connection.test.ts index 02dff03d690..b4c92ed8274 100644 --- a/crates/bindings-typescript/tests/db_connection.test.ts +++ b/crates/bindings-typescript/tests/db_connection.test.ts @@ -2,11 +2,10 @@ import { CreatePlayer, DbConnection, Player, - Point, User, } from '../test-app/src/module_bindings'; import { beforeEach, describe, expect, test } from 'vitest'; -import { ConnectionId } from '../src'; +import { ConnectionId, type Infer } from '../src'; import { Timestamp } from '../src'; import { TimeDuration } from '../src'; import * as ws from '../src/sdk/client_api'; @@ -149,11 +148,11 @@ describe('DbConnection', () => { const inserts: { reducerEvent: | ReducerEvent<{ - name: 'CreatePlayer'; - args: CreatePlayer; + name: 'create_player'; + args: Infer; }> | undefined; - player: Player; + player: Infer; }[] = []; const insert1Promise = new Deferred(); @@ -176,20 +175,22 @@ describe('DbConnection', () => { const reducerCallbackLog: { reducerEvent: ReducerEvent<{ - name: 'CreatePlayer'; - args: CreatePlayer; + name: 'create_player'; + args: Infer; }>; reducerArgs: any[]; }[] = []; - client.reducers.onCreatePlayer((ctx, name: string, location: Point) => { - const reducerEvent = ctx.event; - reducerCallbackLog.push({ - reducerEvent, - reducerArgs: [name, location], - }); - }); + client.reducers.onCreatePlayer( + (ctx, { name, location }: Infer) => { + const reducerEvent = ctx.event; + reducerCallbackLog.push({ + reducerEvent, + reducerArgs: [name, location], + }); + } + ); - const subscriptionMessage: ws.ServerMessage = + const subscriptionMessage: Infer = ws.ServerMessage.InitialSubscription({ databaseUpdate: { tables: [ @@ -206,7 +207,8 @@ describe('DbConnection', () => { inserts: { sizeHint: ws.RowSizeHint.FixedSize(0), // not used rowsData: encodePlayer({ - ownerId: 'player-1', + id: 1, + userId: anIdentity, name: 'drogus', location: { x: 0, y: 0 }, }), @@ -230,8 +232,8 @@ describe('DbConnection', () => { ]); expect(inserts).toHaveLength(1); - expect(inserts[0].player.ownerId).toBe('player-1'); - expect(inserts[0].reducerEvent).toBe(undefined); + expect(inserts[0].player.id).toEqual(1); + expect(inserts[0].reducerEvent).toEqual(undefined); const transactionUpdate = ws.ServerMessage.TransactionUpdate({ status: ws.UpdateStatus.Committed({ @@ -249,7 +251,8 @@ describe('DbConnection', () => { inserts: { sizeHint: ws.RowSizeHint.FixedSize(0), // not used rowsData: encodePlayer({ - ownerId: 'player-2', + id: 2, + userId: anIdentity, name: 'drogus', location: { x: 2, y: 3 }, }), @@ -281,9 +284,9 @@ describe('DbConnection', () => { ]); expect(inserts).toHaveLength(2); - expect(inserts[1].player.ownerId).toBe('player-2'); - expect(inserts[1].reducerEvent?.reducer.name).toBe('create_player'); - expect(inserts[1].reducerEvent?.status.tag).toBe('Committed'); + expect(inserts[1].player.id).toEqual(2); + expect(inserts[1].reducerEvent?.reducer.name).toEqual('create_player'); + expect(inserts[1].reducerEvent?.status.tag).toEqual('Committed'); expect(inserts[1].reducerEvent?.callerIdentity).toEqual(anIdentity); expect(inserts[1].reducerEvent?.reducer.args).toEqual({ name: 'A Player', @@ -311,10 +314,10 @@ describe('DbConnection', () => { const updatePromise = new Deferred(); - expect(client.db.player.count()).toBe(0); + expect(client.db.player.count()).toEqual(0); client.reducers.onCreatePlayer(() => { - expect(client.db.player.count()).toBe(1); + expect(client.db.player.count()).toEqual(1); updatePromise.resolve(); }); @@ -336,7 +339,8 @@ describe('DbConnection', () => { sizeHint: ws.RowSizeHint.FixedSize(0), // not used rowsData: new Uint8Array([ ...encodePlayer({ - ownerId: 'player-2', + id: 1, + userId: anIdentity, name: 'foo', location: { x: 0, y: 0 }, }), @@ -411,7 +415,8 @@ describe('DbConnection', () => { sizeHint: ws.RowSizeHint.FixedSize(0), // not used rowsData: new Uint8Array([ ...encodePlayer({ - ownerId: 'player-2', + id: 2, + userId: anIdentity, name: 'foo', location: { x: 0, y: 0 }, }), @@ -468,18 +473,18 @@ describe('DbConnection', () => { '41db74c20cdda916dd2637e5a11b9f31eb1672249aa7172f7e22b4043a6a9008' ); - const initialUser: User = { + const initialUser: Infer = { identity: userIdentity, username: 'originalName', }; - const updatedUser: User = { + const updatedUser: Infer = { identity: userIdentity, username: 'newName', }; const updates: { - oldUser: User; - newUser: User; + oldUser: Infer; + newUser: Infer; }[] = []; client.db.user.onInsert(() => { initialInsertPromise.resolve(); @@ -568,11 +573,11 @@ describe('DbConnection', () => { await update1Promise.promise; expect(updates).toHaveLength(1); - expect(updates[0]['oldUser'].username).toBe(initialUser.username); - expect(updates[0]['newUser'].username).toBe(updatedUser.username); + expect(updates[0]['oldUser'].username).toEqual(initialUser.username); + expect(updates[0]['newUser'].username).toEqual(updatedUser.username); console.log('Users: ', [...client.db.user.iter()]); - expect(client.db.user.count()).toBe(1); + expect(client.db.user.count()).toEqual(1); }); test('Filtering works', async () => { @@ -635,9 +640,9 @@ describe('DbConnection', () => { wsAdapter.sendToClient(transactionUpdate); await gotAllInserts.promise; - const filteredUser = client.db.user.identity.find(sallyIdentity); - expect(filteredUser).not.toBeUndefined(); - expect(filteredUser!.username).toBe('sally'); - expect(client.db.user.count()).toBe(2); + const foundUser = client.db.user.identity.find(sallyIdentity); + expect(foundUser).not.toBeUndefined(); + expect(foundUser!.username).toEqual('sally'); + expect(client.db.user.count()).toEqual(2); }); }); diff --git a/crates/bindings-typescript/tests/index.test.ts b/crates/bindings-typescript/tests/index.test.ts index 9062b69b478..e99970274af 100644 --- a/crates/bindings-typescript/tests/index.test.ts +++ b/crates/bindings-typescript/tests/index.test.ts @@ -52,11 +52,11 @@ describe('TypeBuilder', () => { expect(col.typeBuilder.algebraicType).toEqual({ tag: 'I32', }); - expect(col.columnMetadata.isPrimaryKey).toBe(true); - expect(col.columnMetadata.isUnique).toBe(true); - expect(col.columnMetadata.indexType).toBe('btree'); - expect(col.columnMetadata.isAutoIncrement).toBe(undefined); - expect(col.columnMetadata.isScheduleAt).toBe(undefined); + expect(col.columnMetadata.isPrimaryKey).foundUser(true); + expect(col.columnMetadata.isUnique).foundUser(true); + expect(col.columnMetadata.indexType).foundUser('btree'); + expect(col.columnMetadata.isAutoIncrement).foundUser(undefined); + expect(col.columnMetadata.isScheduleAt).foundUser(undefined); }); it('builds ColumnBuilders with the correct metadata', () => { @@ -68,38 +68,38 @@ describe('TypeBuilder', () => { expect(indexCol.typeBuilder.algebraicType).toEqual({ tag: 'I32', }); - expect(indexCol.columnMetadata.isPrimaryKey).toBe(undefined); - expect(indexCol.columnMetadata.isUnique).toBe(undefined); - expect(indexCol.columnMetadata.indexType).toBe('btree'); - expect(indexCol.columnMetadata.isAutoIncrement).toBe(undefined); - expect(indexCol.columnMetadata.isScheduleAt).toBe(undefined); + expect(indexCol.columnMetadata.isPrimaryKey).foundUser(undefined); + expect(indexCol.columnMetadata.isUnique).foundUser(undefined); + expect(indexCol.columnMetadata.indexType).foundUser('btree'); + expect(indexCol.columnMetadata.isAutoIncrement).foundUser(undefined); + expect(indexCol.columnMetadata.isScheduleAt).foundUser(undefined); expect(uniqueCol.typeBuilder.algebraicType).toEqual({ tag: 'I32', }); - expect(uniqueCol.columnMetadata.isPrimaryKey).toBe(undefined); - expect(uniqueCol.columnMetadata.isUnique).toBe(true); - expect(uniqueCol.columnMetadata.indexType).toBe(undefined); - expect(uniqueCol.columnMetadata.isAutoIncrement).toBe(undefined); - expect(uniqueCol.columnMetadata.isScheduleAt).toBe(undefined); + expect(uniqueCol.columnMetadata.isPrimaryKey).foundUser(undefined); + expect(uniqueCol.columnMetadata.isUnique).foundUser(true); + expect(uniqueCol.columnMetadata.indexType).foundUser(undefined); + expect(uniqueCol.columnMetadata.isAutoIncrement).foundUser(undefined); + expect(uniqueCol.columnMetadata.isScheduleAt).foundUser(undefined); expect(primaryKeyCol.typeBuilder.algebraicType).toEqual({ tag: 'I32', }); - expect(primaryKeyCol.columnMetadata.isPrimaryKey).toBe(true); - expect(primaryKeyCol.columnMetadata.isUnique).toBe(undefined); - expect(primaryKeyCol.columnMetadata.indexType).toBe(undefined); - expect(primaryKeyCol.columnMetadata.isAutoIncrement).toBe(undefined); - expect(primaryKeyCol.columnMetadata.isScheduleAt).toBe(undefined); + expect(primaryKeyCol.columnMetadata.isPrimaryKey).foundUser(true); + expect(primaryKeyCol.columnMetadata.isUnique).foundUser(undefined); + expect(primaryKeyCol.columnMetadata.indexType).foundUser(undefined); + expect(primaryKeyCol.columnMetadata.isAutoIncrement).foundUser(undefined); + expect(primaryKeyCol.columnMetadata.isScheduleAt).foundUser(undefined); expect(autoIncCol.typeBuilder.algebraicType).toEqual({ tag: 'I32', }); - expect(autoIncCol.columnMetadata.isPrimaryKey).toBe(undefined); - expect(autoIncCol.columnMetadata.isUnique).toBe(undefined); - expect(autoIncCol.columnMetadata.indexType).toBe(undefined); - expect(autoIncCol.columnMetadata.isAutoIncrement).toBe(true); - expect(autoIncCol.columnMetadata.isScheduleAt).toBe(undefined); + expect(autoIncCol.columnMetadata.isPrimaryKey).foundUser(undefined); + expect(autoIncCol.columnMetadata.isUnique).foundUser(undefined); + expect(autoIncCol.columnMetadata.indexType).foundUser(undefined); + expect(autoIncCol.columnMetadata.isAutoIncrement).foundUser(true); + expect(autoIncCol.columnMetadata.isScheduleAt).foundUser(undefined); }); it('builds a ScheduleAt column with the correct type and metadata', () => { @@ -139,7 +139,7 @@ describe('TypeBuilder', () => { ], }, }); - expect(col.columnMetadata.isScheduleAt).toBe(true); + expect(col.columnMetadata.isScheduleAt).foundUser(true); }); }); diff --git a/crates/bindings-typescript/tests/table_cache.test.ts b/crates/bindings-typescript/tests/table_cache.test.ts index 5c7f0afb372..67436113bfb 100644 --- a/crates/bindings-typescript/tests/table_cache.test.ts +++ b/crates/bindings-typescript/tests/table_cache.test.ts @@ -1,7 +1,7 @@ -import { type Operation, TableCache } from '../src/sdk/table_cache'; +import { type Operation, TableCacheImpl } from '../src/sdk/table_cache'; import { describe, expect, test } from 'vitest'; import Player from '../test-app/src/module_bindings/player_type.ts'; -import { AlgebraicType, Identity, type Infer } from 'spacetimedb'; +import { AlgebraicType, Identity, type Infer } from '../src'; import { tables } from '../test-app/src/module_bindings/index.ts'; interface ApplyOperations { @@ -43,7 +43,7 @@ function deleteEvent(row: any, ctx: any = {}): CallbackEvent { interface AssertionInput { // The state of the table cache. - tableCache: TableCache; + tableCache: TableCacheImpl; // The sequence of callbacks that were fired from the last applyOperations. callbackHistory: CallbackEvent[]; } @@ -57,7 +57,10 @@ interface TestStep { assertions: Assertion[]; } -function runTest(tableCache: TableCache, testSteps: TestStep[]) { +function runTest( + tableCache: TableCacheImpl, + testSteps: TestStep[] +) { const callbackHistory: CallbackEvent[] = []; tableCache.onInsert((ctx, row) => { callbackHistory.push({ @@ -97,22 +100,15 @@ function runTest(tableCache: TableCache, testSteps: TestStep[]) { describe('TableCache', () => { describe('Unindexed player table', () => { - const pointType = AlgebraicType.Product({ - elements: [ - { name: 'x', algebraicType: AlgebraicType.U16 }, - { name: 'y', algebraicType: AlgebraicType.U16 }, - ], - }); - const playerType = AlgebraicType.Product({ - elements: [ - { name: 'ownerId', algebraicType: AlgebraicType.String }, - { name: 'name', algebraicType: AlgebraicType.String }, - { name: 'location', algebraicType: pointType }, - ], - }); - const newTable = () => new TableCache(tables.unindexedPlayer); - const mkOperation = (type: 'insert' | 'delete', row: Infer) => { - const rowId = AlgebraicType.intoMapKey({ tag: 'Product', value: tables.unindexedPlayer.rowType }, row); + const newTable = () => new TableCacheImpl(tables.unindexedPlayer); + const mkOperation = ( + type: 'insert' | 'delete', + row: Infer + ) => { + const rowId = AlgebraicType.intoMapKey( + { tag: 'Product', value: tables.unindexedPlayer.rowType }, + row + ); return { type, rowId, @@ -139,11 +135,11 @@ describe('TableCache', () => { }, assertions: [ ({ tableCache, callbackHistory }) => { - expect(tableCache.count()).toBe(1n); - expect(Array.from(tableCache.iter()).length).toBe(1); + expect(tableCache.count()).foundUser(1n); + expect(Array.from(tableCache.iter()).length).foundUser(1); expect(Array.from(tableCache.iter())[0]).toEqual(player); - expect(callbackHistory.length).toBe(1); - expect(callbackHistory[0].type).toBe('insert'); + expect(callbackHistory.length).foundUser(1); + expect(callbackHistory[0].type).foundUser('insert'); expect(callbackHistory[0].row).toEqual(player); }, ], @@ -170,11 +166,11 @@ describe('TableCache', () => { }, assertions: [ ({ tableCache, callbackHistory }) => { - expect(tableCache.count()).toBe(1n); - expect(Array.from(tableCache.iter()).length).toBe(1); + expect(tableCache.count()).foundUser(1n); + expect(Array.from(tableCache.iter()).length).foundUser(1); expect(Array.from(tableCache.iter())[0]).toEqual(player); - expect(callbackHistory.length).toBe(1); - expect(callbackHistory[0].type).toBe('insert'); + expect(callbackHistory.length).foundUser(1); + expect(callbackHistory[0].type).foundUser('insert'); expect(callbackHistory[0].row).toEqual(player); }, ], @@ -201,11 +197,11 @@ describe('TableCache', () => { }, assertions: [ ({ tableCache, callbackHistory }) => { - expect(tableCache.count()).toBe(1n); - expect(Array.from(tableCache.iter()).length).toBe(1); + expect(tableCache.count()).foundUser(1n); + expect(Array.from(tableCache.iter()).length).foundUser(1); expect(Array.from(tableCache.iter())[0]).toEqual(player); - expect(callbackHistory.length).toBe(1); - expect(callbackHistory[0].type).toBe('insert'); + expect(callbackHistory.length).foundUser(1); + expect(callbackHistory[0].type).foundUser('insert'); expect(callbackHistory[0].row).toEqual(player); }, ], @@ -217,10 +213,10 @@ describe('TableCache', () => { }, assertions: [ ({ tableCache, callbackHistory }) => { - expect(tableCache.count()).toBe(1n); - expect(Array.from(tableCache.iter()).length).toBe(1); + expect(tableCache.count()).foundUser(1n); + expect(Array.from(tableCache.iter()).length).foundUser(1); expect(Array.from(tableCache.iter())[0]).toEqual(player); - expect(callbackHistory.length).toBe(0); + expect(callbackHistory.length).foundUser(0); }, ], }); @@ -246,10 +242,10 @@ describe('TableCache', () => { }, assertions: [ ({ tableCache, callbackHistory }) => { - expect(tableCache.count()).toBe(1n); + expect(tableCache.count()).foundUser(1n); expect(Array.from(tableCache.iter())[0]).toEqual(player); - expect(callbackHistory.length).toBe(1); - expect(callbackHistory[0].type).toBe('insert'); + expect(callbackHistory.length).foundUser(1); + expect(callbackHistory[0].type).foundUser('insert'); expect(callbackHistory[0].row).toEqual(player); }, ], @@ -261,9 +257,9 @@ describe('TableCache', () => { }, assertions: [ ({ tableCache, callbackHistory }) => { - expect(tableCache.count()).toBe(0); - expect(callbackHistory.length).toBe(1); - expect(callbackHistory[0].type).toBe('delete'); + expect(tableCache.count()).foundUser(0); + expect(callbackHistory.length).foundUser(1); + expect(callbackHistory[0].type).foundUser('delete'); expect(callbackHistory[0].row).toEqual(player); }, ], @@ -302,10 +298,10 @@ describe('TableCache', () => { }, assertions: [ ({ tableCache, callbackHistory }) => { - expect(tableCache.count()).toBe(1n); + expect(tableCache.count()).foundUser(1n); expect(Array.from(tableCache.iter())[0]).toEqual(player); - expect(callbackHistory.length).toBe(1); - expect(callbackHistory[0].type).toBe('insert'); + expect(callbackHistory.length).foundUser(1); + expect(callbackHistory[0].type).foundUser('insert'); expect(callbackHistory[0].row).toEqual(player); }, ], @@ -318,9 +314,9 @@ describe('TableCache', () => { assertions: [ ({ tableCache, callbackHistory }) => { // We still have one reference left, so it isn't actually deleted. - expect(tableCache.count()).toBe(1n); + expect(tableCache.count()).foundUser(1n); expect(Array.from(tableCache.iter())[0]).toEqual(player); - expect(callbackHistory.length).toBe(0); + expect(callbackHistory.length).foundUser(0); }, ], }); @@ -332,9 +328,9 @@ describe('TableCache', () => { assertions: [ ({ tableCache, callbackHistory }) => { // Now it is actually deleted. - expect(tableCache.count()).toBe(0); - expect(callbackHistory.length).toBe(1); - expect(callbackHistory[0].type).toBe('delete'); + expect(tableCache.count()).foundUser(0); + expect(callbackHistory.length).foundUser(1); + expect(callbackHistory[0].type).foundUser('delete'); expect(callbackHistory[0].row).toEqual(player); }, ], @@ -347,7 +343,7 @@ describe('TableCache', () => { }, assertions: [ ({ tableCache, callbackHistory }) => { - expect(tableCache.count()).toBe(1n); + expect(tableCache.count()).foundUser(1n); expect(Array.from(tableCache.iter())[0]).toEqual(player); expect(callbackHistory).toEqual([insertEvent(player)]); }, @@ -360,7 +356,7 @@ describe('TableCache', () => { }, assertions: [ ({ tableCache, callbackHistory }) => { - expect(tableCache.count()).toBe(1n); + expect(tableCache.count()).foundUser(1n); expect(Array.from(tableCache.iter())[0]).toEqual(player); expect(callbackHistory).toEqual([]); }, @@ -373,7 +369,7 @@ describe('TableCache', () => { }, assertions: [ ({ tableCache, callbackHistory }) => { - expect(tableCache.count()).toBe(0); + expect(tableCache.count()).foundUser(0); expect(callbackHistory).toEqual([deleteEvent(mkPlayer())]); }, ], @@ -398,31 +394,20 @@ describe('TableCache', () => { rowsInserted++; expect(row).toEqual(op.row); }); - expect(callbacks.length).toBe(1); - expect(tableCache.count()).toBe(1n); + expect(callbacks.length).foundUser(1); + expect(tableCache.count()).foundUser(1n); callbacks.forEach(cb => { cb.cb(); }); - expect(rowsInserted).toBe(1); + expect(rowsInserted).foundUser(1); }); }); describe('Indexed player table', () => { - const pointType = AlgebraicType.Product({ - elements: [ - { name: 'x', algebraicType: AlgebraicType.U16 }, - { name: 'y', algebraicType: AlgebraicType.U16 }, - ], - }); - const playerType: AlgebraicType = AlgebraicType.Product({ - elements: [ - { name: 'id', algebraicType: AlgebraicType.U32 }, - { name: 'userId', algebraicType: AlgebraicType.Product({ elements: [{ name: '__identity__', algebraicType: AlgebraicType.U256 }] }) }, - { name: 'name', algebraicType: AlgebraicType.String }, - { name: 'location', algebraicType: pointType }, - ], - }); - const newTable = () => new TableCache(tables.player); - const mkOperation = (type: 'insert' | 'delete', row: Infer) => { + const newTable = () => new TableCacheImpl(tables.player); + const mkOperation = ( + type: 'insert' | 'delete', + row: Infer + ) => { const rowId = AlgebraicType.intoMapKey( { tag: 'Product', value: tables.player.rowType }, row['id'] @@ -453,11 +438,11 @@ describe('TableCache', () => { }, assertions: [ ({ tableCache, callbackHistory }) => { - expect(tableCache.count()).toBe(1n); - expect(Array.from(tableCache.iter()).length).toBe(1); + expect(tableCache.count()).foundUser(1n); + expect(Array.from(tableCache.iter()).length).foundUser(1); expect(Array.from(tableCache.iter())[0]).toEqual(player); - expect(callbackHistory.length).toBe(1); - expect(callbackHistory[0].type).toBe('insert'); + expect(callbackHistory.length).foundUser(1); + expect(callbackHistory[0].type).foundUser('insert'); expect(callbackHistory[0].row).toEqual(player); }, ], @@ -484,11 +469,11 @@ describe('TableCache', () => { }, assertions: [ ({ tableCache, callbackHistory }) => { - expect(tableCache.count()).toBe(1n); - expect(Array.from(tableCache.iter()).length).toBe(1); + expect(tableCache.count()).foundUser(1n); + expect(Array.from(tableCache.iter()).length).foundUser(1); expect(Array.from(tableCache.iter())[0]).toEqual(player); - expect(callbackHistory.length).toBe(1); - expect(callbackHistory[0].type).toBe('insert'); + expect(callbackHistory.length).foundUser(1); + expect(callbackHistory[0].type).foundUser('insert'); expect(callbackHistory[0].row).toEqual(player); }, ], @@ -515,11 +500,11 @@ describe('TableCache', () => { }, assertions: [ ({ tableCache, callbackHistory }) => { - expect(tableCache.count()).toBe(1n); - expect(Array.from(tableCache.iter()).length).toBe(1); + expect(tableCache.count()).foundUser(1n); + expect(Array.from(tableCache.iter()).length).foundUser(1); expect(Array.from(tableCache.iter())[0]).toEqual(player); - expect(callbackHistory.length).toBe(1); - expect(callbackHistory[0].type).toBe('insert'); + expect(callbackHistory.length).foundUser(1); + expect(callbackHistory[0].type).foundUser('insert'); expect(callbackHistory[0].row).toEqual(player); }, ], @@ -531,10 +516,10 @@ describe('TableCache', () => { }, assertions: [ ({ tableCache, callbackHistory }) => { - expect(tableCache.count()).toBe(1n); - expect(Array.from(tableCache.iter()).length).toBe(1); + expect(tableCache.count()).foundUser(1n); + expect(Array.from(tableCache.iter()).length).foundUser(1); expect(Array.from(tableCache.iter())[0]).toEqual(player); - expect(callbackHistory.length).toBe(0); + expect(callbackHistory.length).foundUser(0); }, ], }); @@ -560,10 +545,10 @@ describe('TableCache', () => { }, assertions: [ ({ tableCache, callbackHistory }) => { - expect(tableCache.count()).toBe(1n); + expect(tableCache.count()).foundUser(1n); expect(Array.from(tableCache.iter())[0]).toEqual(player); - expect(callbackHistory.length).toBe(1); - expect(callbackHistory[0].type).toBe('insert'); + expect(callbackHistory.length).foundUser(1); + expect(callbackHistory[0].type).foundUser('insert'); expect(callbackHistory[0].row).toEqual(player); }, ], @@ -575,9 +560,9 @@ describe('TableCache', () => { }, assertions: [ ({ tableCache, callbackHistory }) => { - expect(tableCache.count()).toBe(0); - expect(callbackHistory.length).toBe(1); - expect(callbackHistory[0].type).toBe('delete'); + expect(tableCache.count()).foundUser(0); + expect(callbackHistory.length).foundUser(1); + expect(callbackHistory[0].type).foundUser('delete'); expect(callbackHistory[0].row).toEqual(player); }, ], @@ -604,7 +589,7 @@ describe('TableCache', () => { }, assertions: [ ({ tableCache, callbackHistory }) => { - expect(tableCache.count()).toBe(1n); + expect(tableCache.count()).foundUser(1n); expect(Array.from(tableCache.iter())[0]).toEqual(mkPlayer('jeff')); expect(callbackHistory).toEqual([insertEvent(mkPlayer('jeff'))]); }, @@ -620,8 +605,10 @@ describe('TableCache', () => { }, assertions: [ ({ tableCache, callbackHistory }) => { - expect(tableCache.count()).toBe(1n); - expect(Array.from(tableCache.iter())[0]).toEqual(mkPlayer('jeffv2')); + expect(tableCache.count()).foundUser(1n); + expect(Array.from(tableCache.iter())[0]).toEqual( + mkPlayer('jeffv2') + ); expect(callbackHistory).toEqual([ updateEvent(mkPlayer('jeff'), mkPlayer('jeffv2')), ]); @@ -662,10 +649,10 @@ describe('TableCache', () => { }, assertions: [ ({ tableCache, callbackHistory }) => { - expect(tableCache.count()).toBe(1n); + expect(tableCache.count()).foundUser(1n); expect(Array.from(tableCache.iter())[0]).toEqual(player); - expect(callbackHistory.length).toBe(1); - expect(callbackHistory[0].type).toBe('insert'); + expect(callbackHistory.length).foundUser(1); + expect(callbackHistory[0].type).foundUser('insert'); expect(callbackHistory[0].row).toEqual(player); }, ], @@ -678,9 +665,9 @@ describe('TableCache', () => { assertions: [ ({ tableCache, callbackHistory }) => { // We still have one reference left, so it isn't actually deleted. - expect(tableCache.count()).toBe(1n); + expect(tableCache.count()).foundUser(1n); expect(Array.from(tableCache.iter())[0]).toEqual(player); - expect(callbackHistory.length).toBe(0); + expect(callbackHistory.length).foundUser(0); }, ], }); @@ -692,9 +679,9 @@ describe('TableCache', () => { assertions: [ ({ tableCache, callbackHistory }) => { // Now it is actually deleted. - expect(tableCache.count()).toBe(0); - expect(callbackHistory.length).toBe(1); - expect(callbackHistory[0].type).toBe('delete'); + expect(tableCache.count()).foundUser(0); + expect(callbackHistory.length).foundUser(1); + expect(callbackHistory[0].type).foundUser('delete'); expect(callbackHistory[0].row).toEqual(player); }, ], @@ -707,7 +694,7 @@ describe('TableCache', () => { }, assertions: [ ({ tableCache, callbackHistory }) => { - expect(tableCache.count()).toBe(1n); + expect(tableCache.count()).foundUser(1n); expect(Array.from(tableCache.iter())[0]).toEqual(player); expect(callbackHistory).toEqual([insertEvent(player)]); }, @@ -720,7 +707,7 @@ describe('TableCache', () => { }, assertions: [ ({ tableCache, callbackHistory }) => { - expect(tableCache.count()).toBe(1n); + expect(tableCache.count()).foundUser(1n); expect(Array.from(tableCache.iter())[0]).toEqual(player); expect(callbackHistory).toEqual([]); }, @@ -733,7 +720,7 @@ describe('TableCache', () => { }, assertions: [ ({ tableCache, callbackHistory }) => { - expect(tableCache.count()).toBe(0); + expect(tableCache.count()).foundUser(0); expect(callbackHistory).toEqual([deleteEvent(mkPlayer())]); }, ], @@ -758,31 +745,17 @@ describe('TableCache', () => { rowsInserted++; expect(row).toEqual(op.row); }); - expect(callbacks.length).toBe(1); - expect(tableCache.count()).toBe(1n); + expect(callbacks.length).foundUser(1); + expect(tableCache.count()).foundUser(1n); callbacks.forEach(cb => { cb.cb(); }); - expect(rowsInserted).toBe(1); + expect(rowsInserted).foundUser(1); }); }); - const pointType = AlgebraicType.Product({ - elements: [ - { name: 'x', algebraicType: AlgebraicType.U16 }, - { name: 'y', algebraicType: AlgebraicType.U16 }, - ], - }); - const playerType = AlgebraicType.Product({ - elements: [ - { name: 'ownerId', algebraicType: AlgebraicType.String }, - { name: 'name', algebraicType: AlgebraicType.String }, - { name: 'location', algebraicType: pointType }, - ], - }); - test('should be empty on creation', () => { - const tableCache = new TableCache(tables.player); - expect(tableCache.count()).toBe(0n); + const tableCache = new TableCacheImpl(tables.player); + expect(tableCache.count()).foundUser(0n); }); }); diff --git a/crates/codegen/src/typescript.rs b/crates/codegen/src/typescript.rs index c3aa847b7e4..21a3887104a 100644 --- a/crates/codegen/src/typescript.rs +++ b/crates/codegen/src/typescript.rs @@ -128,7 +128,7 @@ impl Lang for TypeScript { writeln!(out, "export default __t.row({{"); out.indent(1); - write_object_type_builder_fields(module, out, &product_def.elements, true).unwrap(); + write_object_type_builder_fields(module, out, &product_def.elements, table.primary_key, true).unwrap(); out.dedent(1); writeln!(out, "}});"); OutputFile { @@ -418,7 +418,7 @@ fn define_body_for_reducer(module: &ModuleDef, out: &mut Indenter, params: &[(Id writeln!(out, "}};"); } else { writeln!(out); - out.with_indent(|out| write_object_type_builder_fields(module, out, params, true).unwrap()); + out.with_indent(|out| write_object_type_builder_fields(module, out, params, None, true).unwrap()); writeln!(out, "}};"); } } @@ -442,7 +442,7 @@ fn define_body_for_product( writeln!(out, "}});"); } else { writeln!(out); - out.with_indent(|out| write_object_type_builder_fields(module, out, elements, true).unwrap()); + out.with_indent(|out| write_object_type_builder_fields(module, out, elements, None, true).unwrap()); writeln!(out, "}});"); } out.newline(); @@ -455,7 +455,7 @@ fn write_table_opts(module: &ModuleDef, out: &mut Indenter, table: &TableDef) { writeln!(out, "indexes: ["); out.indent(1); for index_def in iter_indexes(table) { - if !index_def.generated() { + if index_def.generated() { // Skip system-defined indexes continue; } @@ -466,7 +466,18 @@ fn write_table_opts(module: &ModuleDef, out: &mut Indenter, table: &TableDef) { let name_camel = field_name.deref().to_case(Case::Camel); (name_camel, field_type) }; - writeln!(out, "{{ name: '{}', algorithm: 'btree', columns: [", index_def.name); + // TODO(cloutiertyler): + // The name users supply is actually the accessor name which will be used + // in TypeScript to access the index. This will be used verbatim. + // This is confusing because it is not the index name and there is + // no actual way for the user to set the actual index name. + // I think we should standardize: name and accessorName as the way to set + // the name and accessor name of an index across all SDKs. + if let Some(accessor_name) = &index_def.accessor_name { + writeln!(out, "{{ name: '{}', algorithm: 'btree', columns: [", accessor_name); + } else { + writeln!(out, "{{ name: '{}', algorithm: 'btree', columns: [", index_def.name); + } out.indent(1); for col_id in columns.iter() { writeln!(out, "'{}',", get_name_and_type(col_id).0); @@ -483,11 +494,35 @@ fn write_table_opts(module: &ModuleDef, out: &mut Indenter, table: &TableDef) { } out.dedent(1); writeln!(out, "],"); + writeln!(out, "constraints: ["); + out.indent(1); + // Unique constraints + for (_, constraint) in &table.constraints { + let columns: Vec<_> = constraint + .data + .unique_columns() // Option<&ColSet> + .into_iter() // Iterator over 0 or 1 item (&ColSet) + .flat_map(|cs| cs.iter()) // Iterator over the ColIds inside the set + .map(|col_id| { + let (field_name, _field_type) = &product_def.elements[col_id.idx()]; + format!("'{}'", field_name) + }) + .collect(); + + writeln!( + out, + "{{ name: '{}', constraint: 'unique', columns: [{}] }},", + constraint.name, + columns.join(", ") + ); + } + out.dedent(1); + writeln!(out, "],"); } /// e.g. /// ```ts -/// x: __t.f32(), +/// x: __t.f32().primaryKey(), /// y: __t.f32(), /// fooBar: __t.string(), /// ``` @@ -495,22 +530,27 @@ fn write_object_type_builder_fields( module: &ModuleDef, out: &mut Indenter, elements: &[(Identifier, AlgebraicTypeUse)], + primary_key: Option, convert_case: bool, ) -> anyhow::Result<()> { - for (ident, ty) in elements { + for (i, (ident, ty)) in elements.iter().enumerate() { let name = if convert_case { ident.deref().to_case(Case::Camel) } else { ident.deref().into() }; - write_type_builder_field(module, out, &name, ty)?; + let is_primary_key = match primary_key { + Some(pk) => pk.idx() == i, + None => false, + }; + write_type_builder_field(module, out, &name, ty, is_primary_key)?; } Ok(()) } -fn write_type_builder_field(module: &ModuleDef, out: &mut Indenter, name: &str, ty: &AlgebraicTypeUse) -> fmt::Result { +fn write_type_builder_field(module: &ModuleDef, out: &mut Indenter, name: &str, ty: &AlgebraicTypeUse, is_primary_key: bool) -> fmt::Result { // Do we need a getter? (Option/Array only if their inner is a Ref) let needs_getter = match ty { AlgebraicTypeUse::Ref(_) => true, @@ -525,12 +565,18 @@ fn write_type_builder_field(module: &ModuleDef, out: &mut Indenter, name: &str, out.indent(1); write!(out, "return "); write_type_builder(module, out, ty)?; + if is_primary_key { + write!(out, ".primaryKey()"); + } writeln!(out, ";"); out.dedent(1); writeln!(out, "}},"); } else { write!(out, "{name}: "); write_type_builder(module, out, ty)?; + if is_primary_key { + write!(out, ".primaryKey()"); + } writeln!(out, ","); } @@ -605,7 +651,7 @@ fn define_body_for_sum( write!(out, ": __TypeBuilder<__AlgebraicTypeType, __AlgebraicTypeType>"); } write!(out, " = __t.enum(\"{name}\", {{"); - out.with_indent(|out| write_object_type_builder_fields(module, out, variants, false).unwrap()); + out.with_indent(|out| write_object_type_builder_fields(module, out, variants, None, false).unwrap()); writeln!(out, "}});"); out.newline(); writeln!(out, "export default {name};"); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5a173665ccb..97fbd3cc06f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -57,7 +57,7 @@ importers: specifier: ^3.3.3 version: 3.6.2 react: - specifier: ^19.0.0 + specifier: ^18.0.0 || ^19.0.0-0 || ^19.0.0 version: 19.2.0 undici: specifier: ^6.19.2 @@ -204,37 +204,6 @@ importers: specifier: ^7.1.5 version: 7.1.5(@types/node@24.3.0)(jiti@2.5.1)(terser@5.43.1)(tsx@4.20.4) - crates/bindings-typescript/test-react-router-app: - dependencies: - react: - specifier: ^18.3.1 - version: 18.3.1 - react-dom: - specifier: ^18.3.1 - version: 18.3.1(react@18.3.1) - react-router-dom: - specifier: ^7.9.4 - version: 7.9.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - devDependencies: - '@types/react': - specifier: ^18.3.3 - version: 18.3.23 - '@types/react-dom': - specifier: ^18.3.0 - version: 18.3.7(@types/react@18.3.23) - '@types/react-router-dom': - specifier: ^5.3.3 - version: 5.3.3 - '@vitejs/plugin-react': - specifier: ^4.3.1 - version: 4.7.0(vite@7.1.5(@types/node@24.3.0)(jiti@2.5.1)(terser@5.43.1)(tsx@4.20.4)) - typescript: - specifier: ^5.2.2 - version: 5.9.3 - vite: - specifier: ^7.1.5 - version: 7.1.5(@types/node@24.3.0)(jiti@2.5.1)(terser@5.43.1)(tsx@4.20.4) - docs: dependencies: '@docusaurus/core': @@ -242,7 +211,7 @@ importers: version: 3.9.1(@mdx-js/react@3.1.1(@types/react@19.2.0)(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.6.3) '@docusaurus/plugin-content-docs': specifier: ^3.9.2 - version: 3.9.2(@mdx-js/react@3.1.1(@types/react@19.2.0)(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.6.3) + version: 3.9.2(@mdx-js/react@3.1.1(@types/react@19.2.0)(react@19.2.0))(debug@4.4.3)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.6.3) '@docusaurus/preset-classic': specifier: 3.9.1 version: 3.9.1(@algolia/client-search@5.39.0)(@mdx-js/react@3.1.1(@types/react@19.2.0)(react@19.2.0))(@types/react@19.2.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(search-insights@2.17.3)(typescript@5.6.3) @@ -4553,10 +4522,6 @@ packages: resolution: {integrity: sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==} engines: {node: '>= 0.6'} - cookie@1.0.2: - resolution: {integrity: sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==} - engines: {node: '>=18'} - copy-webpack-plugin@11.0.0: resolution: {integrity: sha512-fX2MWpamkW0hZxMEg0+mYnA40LTosOSa5TqZ9GYIBzyJa9C3QUaMPSE2xAi/buNr8u89SfD9wHSQVBzrRa/SOQ==} engines: {node: '>= 14.15.0'} @@ -7546,28 +7511,11 @@ packages: peerDependencies: react: '>=15' - react-router-dom@7.9.5: - resolution: {integrity: sha512-mkEmq/K8tKN63Ae2M7Xgz3c9l9YNbY+NHH6NNeUmLA3kDkhKXRsNb/ZpxaEunvGo2/3YXdk5EJU3Hxp3ocaBPw==} - engines: {node: '>=20.0.0'} - peerDependencies: - react: '>=18' - react-dom: '>=18' - react-router@5.3.4: resolution: {integrity: sha512-Ys9K+ppnJah3QuaRiLxk+jDWOR1MekYQrlytiXxC1RyfbdsZkS5pvKAzCCr031xHixZwpnsYNT5xysdFHQaYsA==} peerDependencies: react: '>=15' - react-router@7.9.5: - resolution: {integrity: sha512-JmxqrnBZ6E9hWmf02jzNn9Jm3UqyeimyiwzD69NjxGySG6lIz/1LVPsoTCwN7NBX2XjCEa1LIX5EMz1j2b6u6A==} - engines: {node: '>=20.0.0'} - peerDependencies: - react: '>=18' - react-dom: '>=18' - peerDependenciesMeta: - react-dom: - optional: true - react-style-singleton@2.2.3: resolution: {integrity: sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==} engines: {node: '>=10'} @@ -7879,9 +7827,6 @@ packages: resolution: {integrity: sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==} engines: {node: '>= 0.8.0'} - set-cookie-parser@2.7.2: - resolution: {integrity: sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==} - set-function-length@1.2.2: resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} engines: {node: '>= 0.4'} @@ -10766,46 +10711,6 @@ snapshots: - webpack-cli '@docusaurus/plugin-content-docs@3.9.2(@mdx-js/react@3.1.1(@types/react@19.2.0)(react@19.2.0))(debug@4.4.3)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.6.3)': - dependencies: - '@docusaurus/core': 3.9.2(@mdx-js/react@3.1.1(@types/react@19.2.0)(react@19.2.0))(debug@4.4.3)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.6.3) - '@docusaurus/logger': 3.9.2 - '@docusaurus/mdx-loader': 3.9.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@docusaurus/module-type-aliases': 3.9.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@docusaurus/theme-common': 3.9.2(@docusaurus/plugin-content-docs@3.9.2(@mdx-js/react@3.1.1(@types/react@19.2.0)(react@19.2.0))(debug@4.4.3)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.6.3))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@docusaurus/types': 3.9.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@docusaurus/utils': 3.9.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@docusaurus/utils-common': 3.9.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@docusaurus/utils-validation': 3.9.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@types/react-router-config': 5.0.11 - combine-promises: 1.2.0 - fs-extra: 11.3.2 - js-yaml: 4.1.0 - lodash: 4.17.21 - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) - schema-dts: 1.1.5 - tslib: 2.8.1 - utility-types: 3.11.0 - webpack: 5.102.0 - transitivePeerDependencies: - - '@docusaurus/faster' - - '@mdx-js/react' - - '@parcel/css' - - '@rspack/core' - - '@swc/core' - - '@swc/css' - - bufferutil - - csso - - debug - - esbuild - - lightningcss - - supports-color - - typescript - - uglify-js - - utf-8-validate - - webpack-cli - - '@docusaurus/plugin-content-docs@3.9.2(@mdx-js/react@3.1.1(@types/react@19.2.0)(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.6.3)': dependencies: '@docusaurus/core': 3.9.2(@mdx-js/react@3.1.1(@types/react@19.2.0)(react@19.2.0))(debug@4.4.3)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.6.3) '@docusaurus/logger': 3.9.2 @@ -11190,7 +11095,7 @@ snapshots: dependencies: '@docusaurus/mdx-loader': 3.9.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@docusaurus/module-type-aliases': 3.9.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@docusaurus/plugin-content-docs': 3.9.2(@mdx-js/react@3.1.1(@types/react@19.2.0)(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.6.3) + '@docusaurus/plugin-content-docs': 3.9.2(@mdx-js/react@3.1.1(@types/react@19.2.0)(react@19.2.0))(debug@4.4.3)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.6.3) '@docusaurus/utils': 3.9.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@docusaurus/utils-common': 3.9.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@types/history': 4.7.11 @@ -11210,35 +11115,11 @@ snapshots: - uglify-js - webpack-cli - '@docusaurus/theme-common@3.9.2(@docusaurus/plugin-content-docs@3.9.2(@mdx-js/react@3.1.1(@types/react@19.2.0)(react@19.2.0))(debug@4.4.3)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.6.3))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': - dependencies: - '@docusaurus/mdx-loader': 3.9.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@docusaurus/module-type-aliases': 3.9.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@docusaurus/plugin-content-docs': 3.9.2(@mdx-js/react@3.1.1(@types/react@19.2.0)(react@19.2.0))(debug@4.4.3)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.6.3) - '@docusaurus/utils': 3.9.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@docusaurus/utils-common': 3.9.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@types/history': 4.7.11 - '@types/react': 18.3.23 - '@types/react-router-config': 5.0.11 - clsx: 2.1.1 - parse-numeric-range: 1.3.0 - prism-react-renderer: 2.4.1(react@19.2.0) - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) - tslib: 2.8.1 - utility-types: 3.11.0 - transitivePeerDependencies: - - '@swc/core' - - esbuild - - supports-color - - uglify-js - - webpack-cli - '@docusaurus/theme-common@3.9.2(@docusaurus/plugin-content-docs@3.9.2(@mdx-js/react@3.1.1(@types/react@19.2.0)(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.6.3))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': dependencies: '@docusaurus/mdx-loader': 3.9.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@docusaurus/module-type-aliases': 3.9.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@docusaurus/plugin-content-docs': 3.9.2(@mdx-js/react@3.1.1(@types/react@19.2.0)(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.6.3) + '@docusaurus/plugin-content-docs': 3.9.2(@mdx-js/react@3.1.1(@types/react@19.2.0)(react@19.2.0))(debug@4.4.3)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.6.3) '@docusaurus/utils': 3.9.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@docusaurus/utils-common': 3.9.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@types/history': 4.7.11 @@ -15399,8 +15280,6 @@ snapshots: cookie@0.7.1: {} - cookie@1.0.2: {} - copy-webpack-plugin@11.0.0(webpack@5.102.0): dependencies: fast-glob: 3.3.3 @@ -18934,12 +18813,6 @@ snapshots: tiny-invariant: 1.3.3 tiny-warning: 1.0.3 - react-router-dom@7.9.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1): - dependencies: - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - react-router: 7.9.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react-router@5.3.4(react@19.2.0): dependencies: '@babel/runtime': 7.28.4 @@ -18953,14 +18826,6 @@ snapshots: tiny-invariant: 1.3.3 tiny-warning: 1.0.3 - react-router@7.9.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1): - dependencies: - cookie: 1.0.2 - react: 18.3.1 - set-cookie-parser: 2.7.2 - optionalDependencies: - react-dom: 18.3.1(react@18.3.1) - react-style-singleton@2.2.3(@types/react@19.2.0)(react@19.2.0): dependencies: get-nonce: 1.0.1 @@ -19397,8 +19262,6 @@ snapshots: transitivePeerDependencies: - supports-color - set-cookie-parser@2.7.2: {} - set-function-length@1.2.2: dependencies: define-data-property: 1.1.4 From ffa5336c7635304abfc5a9fcb69c01a15c2a3822 Mon Sep 17 00:00:00 2001 From: Tyler Cloutier Date: Mon, 10 Nov 2025 22:43:44 -0500 Subject: [PATCH 26/49] Good Heavens all the tests pass --- .../src/lib/constraints.ts | 1 - crates/bindings-typescript/src/lib/indexes.ts | 1 - crates/bindings-typescript/src/lib/schema.ts | 56 ++++-- crates/bindings-typescript/src/lib/table.ts | 5 +- .../src/lib/table_schema.ts | 9 + .../src/lib/type_builders.ts | 10 +- .../src/sdk/client_table.ts | 16 +- .../src/sdk/table_cache.ts | 31 ++-- .../tests/algebraic_type.test.ts | 10 +- .../tests/db_connection.test.ts | 8 +- .../bindings-typescript/tests/index.test.ts | 52 +++--- .../tests/table_cache.test.ts | 166 +++++++++--------- 12 files changed, 204 insertions(+), 161 deletions(-) diff --git a/crates/bindings-typescript/src/lib/constraints.ts b/crates/bindings-typescript/src/lib/constraints.ts index 5bd2936ad62..0c4134cc40a 100644 --- a/crates/bindings-typescript/src/lib/constraints.ts +++ b/crates/bindings-typescript/src/lib/constraints.ts @@ -47,5 +47,4 @@ export type ConstraintOpts = { name?: string; } & ( | { constraint: 'unique'; columns: [AllowedCol] } - | { constraint: 'primaryKey'; columns: [AllowedCol] } ); diff --git a/crates/bindings-typescript/src/lib/indexes.ts b/crates/bindings-typescript/src/lib/indexes.ts index 75e0b0a0b8d..993789e09a5 100644 --- a/crates/bindings-typescript/src/lib/indexes.ts +++ b/crates/bindings-typescript/src/lib/indexes.ts @@ -20,7 +20,6 @@ export type IndexOpts = { */ export type UntypedIndex = { name: string; - unique: boolean; algorithm: 'btree' | 'direct'; columns: readonly AllowedCol[]; }; diff --git a/crates/bindings-typescript/src/lib/schema.ts b/crates/bindings-typescript/src/lib/schema.ts index cd65a1b43d0..ccc02f5f0f9 100644 --- a/crates/bindings-typescript/src/lib/schema.ts +++ b/crates/bindings-typescript/src/lib/schema.ts @@ -40,7 +40,7 @@ import { type ViewReturnTypeBuilder, } from './views'; import RawIndexDefV9 from './autogen/raw_index_def_v_9_type'; -import type { Index, IndexOpts } from './indexes'; +import type { IndexOpts } from './indexes'; export type TableNamesOf = S['tables'][number]['name']; @@ -64,6 +64,7 @@ type TablesToSchema[]> = { columns: T[i]['rowType']['row']; rowType: T[i]['rowSpacetimeType']; indexes: T[i]['idxs']; + constraints: T[i]['constraints']; }; }; }; @@ -73,33 +74,62 @@ export function tablesToSchema< >(tables: T): TablesToSchema { const result = { tables: tables.map(schema => { + const colNameList: string[] = []; + schema.rowType.algebraicType.value.elements.forEach(elem => { + colNameList.push(elem.name); + }); + return { name: schema.tableName, accessorName: toCamelCase(schema.tableName), columns: schema.rowType.row, // typed as T[i]['rowType']['row'] under TablesToSchema rowType: schema.rowSpacetimeType, + constraints: [...schema.tableDef.constraints.map(c => ({ + name: c.name, + constraint: 'unique' as const, + columns: c.data.value.columns.map(i => colNameList[i]), + }))], // UntypedTableDef expects mutable array; idxs are readonly, spread to copy. indexes: [ ...schema.idxs.map( (idx: Infer): IndexOpts => ({ - name: idx.name, + name: idx.accessorName, + unique: schema.tableDef.constraints.map(c => { + if (idx.algorithm.tag == 'BTree') { + return c.data.value.columns.every(col => { + const idxColumns = idx.algorithm.value; + if (Array.isArray(idxColumns)) { + return idxColumns.includes(col); + } else { + return col === idxColumns; + } + }); + } + }).includes(true), algorithm: idx.algorithm.tag.toLowerCase() as 'btree', - // TODO: columns + columns: (() => { + const cols = + idx.algorithm.tag === 'Direct' + ? [idx.algorithm.value] + : idx.algorithm.value; + return cols.map(i => colNameList[i]); + })(), }) as IndexOpts ), ], } as const; }) as { - // preserve tuple indices so the return type matches `[i in keyof T]` - readonly [I in keyof T]: { - name: T[I]['tableName']; - accessorName: CamelCase; - columns: T[I]['rowType']['row']; - rowType: T[I]['rowSpacetimeType']; - indexes: T[I]['idxs']; - }; - }, + // preserve tuple indices so the return type matches `[i in keyof T]` + readonly [I in keyof T]: { + name: T[I]['tableName']; + accessorName: CamelCase; + columns: T[I]['rowType']['row']; + rowType: T[I]['rowSpacetimeType']; + indexes: T[I]['idxs']; + constraints: T[I]['constraints']; + }; + }, } satisfies TablesToSchema; return result; } @@ -557,7 +587,7 @@ export function schema[]>( type HasAccessor = { accessorName: PropertyKey }; export type ConvertToAccessorMap = { - [Tbl in TableDefs[number] as Tbl['accessorName']]: Tbl; + [Tbl in TableDefs[number]as Tbl['accessorName']]: Tbl; }; export function convertToAccessorMap( diff --git a/crates/bindings-typescript/src/lib/table.ts b/crates/bindings-typescript/src/lib/table.ts index ccc2a6e8a21..b4a286f073d 100644 --- a/crates/bindings-typescript/src/lib/table.ts +++ b/crates/bindings-typescript/src/lib/table.ts @@ -72,6 +72,7 @@ export type UntypedTableDef = { columns: Record>>; rowType: ProductType; indexes: readonly IndexOpts[]; + constraints: readonly ConstraintOpts[]; }; /** @@ -242,6 +243,7 @@ export function table>( // implicit 1‑column indexes if (meta.indexType || isUnique) { + console.log("GAAAAAAH", name); const algo = meta.indexType ?? 'btree'; const id = colIds.get(name)!; let algorithm: Infer; @@ -317,9 +319,6 @@ export function table>( constraints.push({ name: constraintOpts.name, data }); continue; } - if (constraintOpts.constraint === 'primaryKey') { - pk.push(...constraintOpts.columns.map(c => colIds.get(c)!)); - } } for (const index of indexes) { diff --git a/crates/bindings-typescript/src/lib/table_schema.ts b/crates/bindings-typescript/src/lib/table_schema.ts index 540af16673a..8cb5e01444c 100644 --- a/crates/bindings-typescript/src/lib/table_schema.ts +++ b/crates/bindings-typescript/src/lib/table_schema.ts @@ -35,4 +35,13 @@ export type TableSchema< * The indexes defined on the table. */ readonly idxs: Idx; + + /** + * The constraints defined on the table. + */ + readonly constraints: readonly { + name: string | undefined; + constraint: 'unique'; + columns: readonly string[]; + }[]; }; diff --git a/crates/bindings-typescript/src/lib/type_builders.ts b/crates/bindings-typescript/src/lib/type_builders.ts index 0ecfdd8b6f6..ddaf013af9f 100644 --- a/crates/bindings-typescript/src/lib/type_builders.ts +++ b/crates/bindings-typescript/src/lib/type_builders.ts @@ -29,11 +29,11 @@ export type InferSpacetimeTypeOfTypeBuilder> = * Helper type to extract the TypeScript type from a TypeBuilder */ export type Infer = - T extends TypeBuilder - ? InferTypeOfTypeBuilder - : T extends RowObj - ? InferTypeOfRow - : never; + T extends RowObj + ? InferTypeOfRow + : T extends TypeBuilder + ? InferTypeOfTypeBuilder + : never; /** * Helper type to extract the type of a row from an object. diff --git a/crates/bindings-typescript/src/sdk/client_table.ts b/crates/bindings-typescript/src/sdk/client_table.ts index ac20b83decf..2e4e102301b 100644 --- a/crates/bindings-typescript/src/sdk/client_table.ts +++ b/crates/bindings-typescript/src/sdk/client_table.ts @@ -24,8 +24,8 @@ export type ClientTablePrimaryKeyMethods< onUpdate( cb: ( ctx: EventContextInterface, - oldRow: RowType>, - newRow: RowType> + oldRow: Prettify>>, + newRow: Prettify>> ) => void ): void; @@ -36,8 +36,8 @@ export type ClientTablePrimaryKeyMethods< removeOnUpdate( cb: ( ctx: EventContextInterface, - oldRow: RowType>, - newRow: RowType> + oldRow: Prettify>>, + newRow: Prettify>> ) => void ): void; }; @@ -52,7 +52,7 @@ export type ClientTableMethods< onInsert( cb: ( ctx: EventContextInterface, - row: RowType> + row: Prettify>> ) => void ): void; @@ -63,7 +63,7 @@ export type ClientTableMethods< removeOnInsert( cb: ( ctx: EventContextInterface, - row: RowType> + row: Prettify>> ) => void ): void; @@ -73,7 +73,7 @@ export type ClientTableMethods< onDelete( cb: ( ctx: EventContextInterface, - row: RowType> + row: Prettify>> ) => void ): void; @@ -84,7 +84,7 @@ export type ClientTableMethods< removeOnDelete( cb: ( ctx: EventContextInterface, - row: RowType> + row: Prettify>> ) => void ): void; }; diff --git a/crates/bindings-typescript/src/sdk/table_cache.ts b/crates/bindings-typescript/src/sdk/table_cache.ts index 999b2632289..d1281732961 100644 --- a/crates/bindings-typescript/src/sdk/table_cache.ts +++ b/crates/bindings-typescript/src/sdk/table_cache.ts @@ -15,6 +15,7 @@ import type { UntypedIndex, } from '../lib/indexes.ts'; import type { Bound } from '../server/range.ts'; +import type { Prettify } from '../lib/type_util.ts'; export type Operation< RowType extends Record = Record, @@ -89,7 +90,7 @@ export class TableCacheImpl< const idxDef = idx as UntypedIndex< keyof TableDefForTableName['columns'] & string >; - const index = this.#makeReadonlyIndex(idxDef); + const index = this.#makeReadonlyIndex(this.tableDef, idxDef); (this as any)[idx.name!] = index; } } @@ -99,7 +100,7 @@ export class TableCacheImpl< I extends UntypedIndex< keyof TableDefForTableName['columns'] & string >, - >(idx: I): ReadonlyIndex, I> { + >(tableDef: TableDefForTableName, idx: I): ReadonlyIndex, I> { type TableDef = TableDefForTableName; type Row = RowType; @@ -108,7 +109,7 @@ export class TableCacheImpl< throw new Error('Only btree indexes are supported in TableCacheImpl'); } - const columns = idx.columns as readonly (keyof Row & string)[]; + const columns = idx.columns; // Extract the tuple key for this btree index (column order preserved) const getKey = (row: Row): readonly unknown[] => columns.map(c => row[c]); @@ -172,7 +173,13 @@ export class TableCacheImpl< } }; - const isUnique = idx.unique === true; + // An index is unique if it shares all columns with a unique constraint + const isUnique = tableDef.constraints.some(constraint => { + if (constraint.constraint !== 'unique') { + return false; + } + return deepEqual(constraint.columns, idx.columns); + }); // eslint-disable-next-line @typescript-eslint/no-this-alias const self = this; @@ -445,7 +452,7 @@ export class TableCacheImpl< onInsert = ( cb: ( ctx: EventContextInterface, - row: RowType> + row: Prettify>> ) => void ): void => { this.emitter.on('insert', cb); @@ -469,7 +476,7 @@ export class TableCacheImpl< onDelete = ( cb: ( ctx: EventContextInterface, - row: RowType> + row: Prettify>> ) => void ): void => { this.emitter.on('delete', cb); @@ -493,8 +500,8 @@ export class TableCacheImpl< onUpdate = ( cb: ( ctx: EventContextInterface, - oldRow: RowType>, - row: RowType> + oldRow: Prettify>>, + row: Prettify>> ) => void ): void => { this.emitter.on('update', cb); @@ -508,7 +515,7 @@ export class TableCacheImpl< removeOnInsert = ( cb: ( ctx: EventContextInterface, - row: RowType> + row: Prettify>> ) => void ): void => { this.emitter.off('insert', cb); @@ -522,7 +529,7 @@ export class TableCacheImpl< removeOnDelete = ( cb: ( ctx: EventContextInterface, - row: RowType> + row: Prettify>> ) => void ): void => { this.emitter.off('delete', cb); @@ -536,8 +543,8 @@ export class TableCacheImpl< removeOnUpdate = ( cb: ( ctx: EventContextInterface, - oldRow: RowType>, - row: RowType> + oldRow: Prettify>>, + row: Prettify>> ) => void ): void => { this.emitter.off('update', cb); diff --git a/crates/bindings-typescript/tests/algebraic_type.test.ts b/crates/bindings-typescript/tests/algebraic_type.test.ts index 351275e9beb..22eb8f8a0fe 100644 --- a/crates/bindings-typescript/tests/algebraic_type.test.ts +++ b/crates/bindings-typescript/tests/algebraic_type.test.ts @@ -25,7 +25,7 @@ describe('AlgebraicType', () => { for (const [tag, value] of primitiveTypes) { const algebraicType = { tag, value: undefined }; const mapKey = AlgebraicType.intoMapKey(algebraicType, value); - expect(mapKey).foundUser(value); + expect(mapKey).toEqual(value); } }); @@ -37,9 +37,9 @@ describe('AlgebraicType', () => { const mapKey = AlgebraicType.intoMapKey(productType, productValue); // Fallback for complex types is base64 encoding of serialized value - expect(typeof mapKey).foundUser('string'); + expect(typeof mapKey).toEqual('string'); // 42 as i32 little-endian is 2A000000, which is KgAAAA== in base64 - expect(mapKey).foundUser('KgAAAA=='); + expect(mapKey).toEqual('KgAAAA=='); }); test('intoMapKey fallback serializes array types', () => { @@ -47,8 +47,8 @@ describe('AlgebraicType', () => { const arrayValue = [1, 2, 3]; const mapKey = AlgebraicType.intoMapKey(arrayType, arrayValue); - expect(typeof mapKey).foundUser('string'); + expect(typeof mapKey).toEqual('string'); // Serialized as: [len (u32), val1 (u16), val2 (u16), val3 (u16)] - expect(mapKey).foundUser('AwAAAAEAAgADAA=='); + expect(mapKey).toEqual('AwAAAAEAAgADAA=='); }); }); diff --git a/crates/bindings-typescript/tests/db_connection.test.ts b/crates/bindings-typescript/tests/db_connection.test.ts index b4c92ed8274..6f7193fc175 100644 --- a/crates/bindings-typescript/tests/db_connection.test.ts +++ b/crates/bindings-typescript/tests/db_connection.test.ts @@ -314,10 +314,10 @@ describe('DbConnection', () => { const updatePromise = new Deferred(); - expect(client.db.player.count()).toEqual(0); + expect(client.db.player.count()).toEqual(0n); client.reducers.onCreatePlayer(() => { - expect(client.db.player.count()).toEqual(1); + expect(client.db.player.count()).toEqual(1n); updatePromise.resolve(); }); @@ -577,7 +577,7 @@ describe('DbConnection', () => { expect(updates[0]['newUser'].username).toEqual(updatedUser.username); console.log('Users: ', [...client.db.user.iter()]); - expect(client.db.user.count()).toEqual(1); + expect(client.db.user.count()).toEqual(1n); }); test('Filtering works', async () => { @@ -643,6 +643,6 @@ describe('DbConnection', () => { const foundUser = client.db.user.identity.find(sallyIdentity); expect(foundUser).not.toBeUndefined(); expect(foundUser!.username).toEqual('sally'); - expect(client.db.user.count()).toEqual(2); + expect(client.db.user.count()).toEqual(2n); }); }); diff --git a/crates/bindings-typescript/tests/index.test.ts b/crates/bindings-typescript/tests/index.test.ts index e99970274af..5e009d7d75b 100644 --- a/crates/bindings-typescript/tests/index.test.ts +++ b/crates/bindings-typescript/tests/index.test.ts @@ -52,11 +52,11 @@ describe('TypeBuilder', () => { expect(col.typeBuilder.algebraicType).toEqual({ tag: 'I32', }); - expect(col.columnMetadata.isPrimaryKey).foundUser(true); - expect(col.columnMetadata.isUnique).foundUser(true); - expect(col.columnMetadata.indexType).foundUser('btree'); - expect(col.columnMetadata.isAutoIncrement).foundUser(undefined); - expect(col.columnMetadata.isScheduleAt).foundUser(undefined); + expect(col.columnMetadata.isPrimaryKey).toEqual(true); + expect(col.columnMetadata.isUnique).toEqual(true); + expect(col.columnMetadata.indexType).toEqual('btree'); + expect(col.columnMetadata.isAutoIncrement).toEqual(undefined); + expect(col.columnMetadata.isScheduleAt).toEqual(undefined); }); it('builds ColumnBuilders with the correct metadata', () => { @@ -68,38 +68,38 @@ describe('TypeBuilder', () => { expect(indexCol.typeBuilder.algebraicType).toEqual({ tag: 'I32', }); - expect(indexCol.columnMetadata.isPrimaryKey).foundUser(undefined); - expect(indexCol.columnMetadata.isUnique).foundUser(undefined); - expect(indexCol.columnMetadata.indexType).foundUser('btree'); - expect(indexCol.columnMetadata.isAutoIncrement).foundUser(undefined); - expect(indexCol.columnMetadata.isScheduleAt).foundUser(undefined); + expect(indexCol.columnMetadata.isPrimaryKey).toEqual(undefined); + expect(indexCol.columnMetadata.isUnique).toEqual(undefined); + expect(indexCol.columnMetadata.indexType).toEqual('btree'); + expect(indexCol.columnMetadata.isAutoIncrement).toEqual(undefined); + expect(indexCol.columnMetadata.isScheduleAt).toEqual(undefined); expect(uniqueCol.typeBuilder.algebraicType).toEqual({ tag: 'I32', }); - expect(uniqueCol.columnMetadata.isPrimaryKey).foundUser(undefined); - expect(uniqueCol.columnMetadata.isUnique).foundUser(true); - expect(uniqueCol.columnMetadata.indexType).foundUser(undefined); - expect(uniqueCol.columnMetadata.isAutoIncrement).foundUser(undefined); - expect(uniqueCol.columnMetadata.isScheduleAt).foundUser(undefined); + expect(uniqueCol.columnMetadata.isPrimaryKey).toEqual(undefined); + expect(uniqueCol.columnMetadata.isUnique).toEqual(true); + expect(uniqueCol.columnMetadata.indexType).toEqual(undefined); + expect(uniqueCol.columnMetadata.isAutoIncrement).toEqual(undefined); + expect(uniqueCol.columnMetadata.isScheduleAt).toEqual(undefined); expect(primaryKeyCol.typeBuilder.algebraicType).toEqual({ tag: 'I32', }); - expect(primaryKeyCol.columnMetadata.isPrimaryKey).foundUser(true); - expect(primaryKeyCol.columnMetadata.isUnique).foundUser(undefined); - expect(primaryKeyCol.columnMetadata.indexType).foundUser(undefined); - expect(primaryKeyCol.columnMetadata.isAutoIncrement).foundUser(undefined); - expect(primaryKeyCol.columnMetadata.isScheduleAt).foundUser(undefined); + expect(primaryKeyCol.columnMetadata.isPrimaryKey).toEqual(true); + expect(primaryKeyCol.columnMetadata.isUnique).toEqual(undefined); + expect(primaryKeyCol.columnMetadata.indexType).toEqual(undefined); + expect(primaryKeyCol.columnMetadata.isAutoIncrement).toEqual(undefined); + expect(primaryKeyCol.columnMetadata.isScheduleAt).toEqual(undefined); expect(autoIncCol.typeBuilder.algebraicType).toEqual({ tag: 'I32', }); - expect(autoIncCol.columnMetadata.isPrimaryKey).foundUser(undefined); - expect(autoIncCol.columnMetadata.isUnique).foundUser(undefined); - expect(autoIncCol.columnMetadata.indexType).foundUser(undefined); - expect(autoIncCol.columnMetadata.isAutoIncrement).foundUser(true); - expect(autoIncCol.columnMetadata.isScheduleAt).foundUser(undefined); + expect(autoIncCol.columnMetadata.isPrimaryKey).toEqual(undefined); + expect(autoIncCol.columnMetadata.isUnique).toEqual(undefined); + expect(autoIncCol.columnMetadata.indexType).toEqual(undefined); + expect(autoIncCol.columnMetadata.isAutoIncrement).toEqual(true); + expect(autoIncCol.columnMetadata.isScheduleAt).toEqual(undefined); }); it('builds a ScheduleAt column with the correct type and metadata', () => { @@ -139,7 +139,7 @@ describe('TypeBuilder', () => { ], }, }); - expect(col.columnMetadata.isScheduleAt).foundUser(true); + expect(col.columnMetadata.isScheduleAt).toEqual(true); }); }); diff --git a/crates/bindings-typescript/tests/table_cache.test.ts b/crates/bindings-typescript/tests/table_cache.test.ts index 67436113bfb..939303e7287 100644 --- a/crates/bindings-typescript/tests/table_cache.test.ts +++ b/crates/bindings-typescript/tests/table_cache.test.ts @@ -2,7 +2,7 @@ import { type Operation, TableCacheImpl } from '../src/sdk/table_cache'; import { describe, expect, test } from 'vitest'; import Player from '../test-app/src/module_bindings/player_type.ts'; import { AlgebraicType, Identity, type Infer } from '../src'; -import { tables } from '../test-app/src/module_bindings/index.ts'; +import { tables, UnindexedPlayer } from '../test-app/src/module_bindings/index.ts'; interface ApplyOperations { ops: Operation[]; @@ -103,7 +103,7 @@ describe('TableCache', () => { const newTable = () => new TableCacheImpl(tables.unindexedPlayer); const mkOperation = ( type: 'insert' | 'delete', - row: Infer + row: Infer ) => { const rowId = AlgebraicType.intoMapKey( { tag: 'Product', value: tables.unindexedPlayer.rowType }, @@ -121,7 +121,7 @@ describe('TableCache', () => { const steps: TestStep[] = []; const player = { id: 1, - userId: Identity.zero(), + ownerId: Identity.zero(), name: 'Player 1', location: { x: 1, @@ -135,11 +135,11 @@ describe('TableCache', () => { }, assertions: [ ({ tableCache, callbackHistory }) => { - expect(tableCache.count()).foundUser(1n); - expect(Array.from(tableCache.iter()).length).foundUser(1); + expect(tableCache.count()).toEqual(1n); + expect(Array.from(tableCache.iter()).length).toEqual(1); expect(Array.from(tableCache.iter())[0]).toEqual(player); - expect(callbackHistory.length).foundUser(1); - expect(callbackHistory[0].type).foundUser('insert'); + expect(callbackHistory.length).toEqual(1); + expect(callbackHistory[0].type).toEqual('insert'); expect(callbackHistory[0].row).toEqual(player); }, ], @@ -152,7 +152,7 @@ describe('TableCache', () => { const steps: TestStep[] = []; const player = { id: 1, - userId: Identity.zero(), + ownerId: Identity.zero(), name: 'Player 1', location: { x: 1, @@ -166,11 +166,11 @@ describe('TableCache', () => { }, assertions: [ ({ tableCache, callbackHistory }) => { - expect(tableCache.count()).foundUser(1n); - expect(Array.from(tableCache.iter()).length).foundUser(1); + expect(tableCache.count()).toEqual(1n); + expect(Array.from(tableCache.iter()).length).toEqual(1); expect(Array.from(tableCache.iter())[0]).toEqual(player); - expect(callbackHistory.length).foundUser(1); - expect(callbackHistory[0].type).foundUser('insert'); + expect(callbackHistory.length).toEqual(1); + expect(callbackHistory[0].type).toEqual('insert'); expect(callbackHistory[0].row).toEqual(player); }, ], @@ -183,7 +183,7 @@ describe('TableCache', () => { const steps: TestStep[] = []; const player = { id: 1, - userId: Identity.zero(), + ownerId: Identity.zero(), name: 'Player 1', location: { x: 1, @@ -197,11 +197,11 @@ describe('TableCache', () => { }, assertions: [ ({ tableCache, callbackHistory }) => { - expect(tableCache.count()).foundUser(1n); - expect(Array.from(tableCache.iter()).length).foundUser(1); + expect(tableCache.count()).toEqual(1n); + expect(Array.from(tableCache.iter()).length).toEqual(1); expect(Array.from(tableCache.iter())[0]).toEqual(player); - expect(callbackHistory.length).foundUser(1); - expect(callbackHistory[0].type).foundUser('insert'); + expect(callbackHistory.length).toEqual(1); + expect(callbackHistory[0].type).toEqual('insert'); expect(callbackHistory[0].row).toEqual(player); }, ], @@ -213,10 +213,10 @@ describe('TableCache', () => { }, assertions: [ ({ tableCache, callbackHistory }) => { - expect(tableCache.count()).foundUser(1n); - expect(Array.from(tableCache.iter()).length).foundUser(1); + expect(tableCache.count()).toEqual(1n); + expect(Array.from(tableCache.iter()).length).toEqual(1); expect(Array.from(tableCache.iter())[0]).toEqual(player); - expect(callbackHistory.length).foundUser(0); + expect(callbackHistory.length).toEqual(0); }, ], }); @@ -228,7 +228,7 @@ describe('TableCache', () => { const steps: TestStep[] = []; const player = { id: 1, - userId: Identity.zero(), + ownerId: Identity.zero(), name: 'Player 1', location: { x: 1, @@ -242,10 +242,10 @@ describe('TableCache', () => { }, assertions: [ ({ tableCache, callbackHistory }) => { - expect(tableCache.count()).foundUser(1n); + expect(tableCache.count()).toEqual(1n); expect(Array.from(tableCache.iter())[0]).toEqual(player); - expect(callbackHistory.length).foundUser(1); - expect(callbackHistory[0].type).foundUser('insert'); + expect(callbackHistory.length).toEqual(1); + expect(callbackHistory[0].type).toEqual('insert'); expect(callbackHistory[0].row).toEqual(player); }, ], @@ -257,9 +257,9 @@ describe('TableCache', () => { }, assertions: [ ({ tableCache, callbackHistory }) => { - expect(tableCache.count()).foundUser(0); - expect(callbackHistory.length).foundUser(1); - expect(callbackHistory[0].type).foundUser('delete'); + expect(tableCache.count()).toEqual(0n); + expect(callbackHistory.length).toEqual(1); + expect(callbackHistory[0].type).toEqual('delete'); expect(callbackHistory[0].row).toEqual(player); }, ], @@ -272,7 +272,7 @@ describe('TableCache', () => { const steps: TestStep[] = []; const mkPlayer = () => ({ id: 1, - userId: Identity.zero(), + ownerId: Identity.zero(), name: 'Player 1', location: { x: 1, @@ -281,7 +281,7 @@ describe('TableCache', () => { }); const player = { id: 1, - userId: Identity.zero(), + ownerId: Identity.zero(), name: 'Player 1', location: { x: 1, @@ -298,10 +298,10 @@ describe('TableCache', () => { }, assertions: [ ({ tableCache, callbackHistory }) => { - expect(tableCache.count()).foundUser(1n); + expect(tableCache.count()).toEqual(1n); expect(Array.from(tableCache.iter())[0]).toEqual(player); - expect(callbackHistory.length).foundUser(1); - expect(callbackHistory[0].type).foundUser('insert'); + expect(callbackHistory.length).toEqual(1); + expect(callbackHistory[0].type).toEqual('insert'); expect(callbackHistory[0].row).toEqual(player); }, ], @@ -314,9 +314,9 @@ describe('TableCache', () => { assertions: [ ({ tableCache, callbackHistory }) => { // We still have one reference left, so it isn't actually deleted. - expect(tableCache.count()).foundUser(1n); + expect(tableCache.count()).toEqual(1n); expect(Array.from(tableCache.iter())[0]).toEqual(player); - expect(callbackHistory.length).foundUser(0); + expect(callbackHistory.length).toEqual(0); }, ], }); @@ -328,9 +328,9 @@ describe('TableCache', () => { assertions: [ ({ tableCache, callbackHistory }) => { // Now it is actually deleted. - expect(tableCache.count()).foundUser(0); - expect(callbackHistory.length).foundUser(1); - expect(callbackHistory[0].type).foundUser('delete'); + expect(tableCache.count()).toEqual(0n); + expect(callbackHistory.length).toEqual(1); + expect(callbackHistory[0].type).toEqual('delete'); expect(callbackHistory[0].row).toEqual(player); }, ], @@ -343,7 +343,7 @@ describe('TableCache', () => { }, assertions: [ ({ tableCache, callbackHistory }) => { - expect(tableCache.count()).foundUser(1n); + expect(tableCache.count()).toEqual(1n); expect(Array.from(tableCache.iter())[0]).toEqual(player); expect(callbackHistory).toEqual([insertEvent(player)]); }, @@ -356,7 +356,7 @@ describe('TableCache', () => { }, assertions: [ ({ tableCache, callbackHistory }) => { - expect(tableCache.count()).foundUser(1n); + expect(tableCache.count()).toEqual(1n); expect(Array.from(tableCache.iter())[0]).toEqual(player); expect(callbackHistory).toEqual([]); }, @@ -369,7 +369,7 @@ describe('TableCache', () => { }, assertions: [ ({ tableCache, callbackHistory }) => { - expect(tableCache.count()).foundUser(0); + expect(tableCache.count()).toEqual(0n); expect(callbackHistory).toEqual([deleteEvent(mkPlayer())]); }, ], @@ -381,7 +381,7 @@ describe('TableCache', () => { const tableCache = newTable(); const op = mkOperation('insert', { id: 1, - userId: Identity.zero(), + ownerId: Identity.zero(), name: 'Player 1', location: { x: 1, @@ -394,12 +394,12 @@ describe('TableCache', () => { rowsInserted++; expect(row).toEqual(op.row); }); - expect(callbacks.length).foundUser(1); - expect(tableCache.count()).foundUser(1n); + expect(callbacks.length).toEqual(1); + expect(tableCache.count()).toEqual(1n); callbacks.forEach(cb => { cb.cb(); }); - expect(rowsInserted).foundUser(1); + expect(rowsInserted).toEqual(1); }); }); describe('Indexed player table', () => { @@ -409,7 +409,7 @@ describe('TableCache', () => { row: Infer ) => { const rowId = AlgebraicType.intoMapKey( - { tag: 'Product', value: tables.player.rowType }, + Player.elements['id'].algebraicType, row['id'] ); return { @@ -438,11 +438,11 @@ describe('TableCache', () => { }, assertions: [ ({ tableCache, callbackHistory }) => { - expect(tableCache.count()).foundUser(1n); - expect(Array.from(tableCache.iter()).length).foundUser(1); + expect(tableCache.count()).toEqual(1n); + expect(Array.from(tableCache.iter()).length).toEqual(1); expect(Array.from(tableCache.iter())[0]).toEqual(player); - expect(callbackHistory.length).foundUser(1); - expect(callbackHistory[0].type).foundUser('insert'); + expect(callbackHistory.length).toEqual(1); + expect(callbackHistory[0].type).toEqual('insert'); expect(callbackHistory[0].row).toEqual(player); }, ], @@ -469,11 +469,11 @@ describe('TableCache', () => { }, assertions: [ ({ tableCache, callbackHistory }) => { - expect(tableCache.count()).foundUser(1n); - expect(Array.from(tableCache.iter()).length).foundUser(1); + expect(tableCache.count()).toEqual(1n); + expect(Array.from(tableCache.iter()).length).toEqual(1); expect(Array.from(tableCache.iter())[0]).toEqual(player); - expect(callbackHistory.length).foundUser(1); - expect(callbackHistory[0].type).foundUser('insert'); + expect(callbackHistory.length).toEqual(1); + expect(callbackHistory[0].type).toEqual('insert'); expect(callbackHistory[0].row).toEqual(player); }, ], @@ -500,11 +500,11 @@ describe('TableCache', () => { }, assertions: [ ({ tableCache, callbackHistory }) => { - expect(tableCache.count()).foundUser(1n); - expect(Array.from(tableCache.iter()).length).foundUser(1); + expect(tableCache.count()).toEqual(1n); + expect(Array.from(tableCache.iter()).length).toEqual(1); expect(Array.from(tableCache.iter())[0]).toEqual(player); - expect(callbackHistory.length).foundUser(1); - expect(callbackHistory[0].type).foundUser('insert'); + expect(callbackHistory.length).toEqual(1); + expect(callbackHistory[0].type).toEqual('insert'); expect(callbackHistory[0].row).toEqual(player); }, ], @@ -516,10 +516,10 @@ describe('TableCache', () => { }, assertions: [ ({ tableCache, callbackHistory }) => { - expect(tableCache.count()).foundUser(1n); - expect(Array.from(tableCache.iter()).length).foundUser(1); + expect(tableCache.count()).toEqual(1n); + expect(Array.from(tableCache.iter()).length).toEqual(1); expect(Array.from(tableCache.iter())[0]).toEqual(player); - expect(callbackHistory.length).foundUser(0); + expect(callbackHistory.length).toEqual(0); }, ], }); @@ -545,10 +545,10 @@ describe('TableCache', () => { }, assertions: [ ({ tableCache, callbackHistory }) => { - expect(tableCache.count()).foundUser(1n); + expect(tableCache.count()).toEqual(1n); expect(Array.from(tableCache.iter())[0]).toEqual(player); - expect(callbackHistory.length).foundUser(1); - expect(callbackHistory[0].type).foundUser('insert'); + expect(callbackHistory.length).toEqual(1); + expect(callbackHistory[0].type).toEqual('insert'); expect(callbackHistory[0].row).toEqual(player); }, ], @@ -560,9 +560,9 @@ describe('TableCache', () => { }, assertions: [ ({ tableCache, callbackHistory }) => { - expect(tableCache.count()).foundUser(0); - expect(callbackHistory.length).foundUser(1); - expect(callbackHistory[0].type).foundUser('delete'); + expect(tableCache.count()).toEqual(0n); + expect(callbackHistory.length).toEqual(1); + expect(callbackHistory[0].type).toEqual('delete'); expect(callbackHistory[0].row).toEqual(player); }, ], @@ -589,7 +589,7 @@ describe('TableCache', () => { }, assertions: [ ({ tableCache, callbackHistory }) => { - expect(tableCache.count()).foundUser(1n); + expect(tableCache.count()).toEqual(1n); expect(Array.from(tableCache.iter())[0]).toEqual(mkPlayer('jeff')); expect(callbackHistory).toEqual([insertEvent(mkPlayer('jeff'))]); }, @@ -605,7 +605,7 @@ describe('TableCache', () => { }, assertions: [ ({ tableCache, callbackHistory }) => { - expect(tableCache.count()).foundUser(1n); + expect(tableCache.count()).toEqual(1n); expect(Array.from(tableCache.iter())[0]).toEqual( mkPlayer('jeffv2') ); @@ -649,10 +649,10 @@ describe('TableCache', () => { }, assertions: [ ({ tableCache, callbackHistory }) => { - expect(tableCache.count()).foundUser(1n); + expect(tableCache.count()).toEqual(1n); expect(Array.from(tableCache.iter())[0]).toEqual(player); - expect(callbackHistory.length).foundUser(1); - expect(callbackHistory[0].type).foundUser('insert'); + expect(callbackHistory.length).toEqual(1); + expect(callbackHistory[0].type).toEqual('insert'); expect(callbackHistory[0].row).toEqual(player); }, ], @@ -665,9 +665,9 @@ describe('TableCache', () => { assertions: [ ({ tableCache, callbackHistory }) => { // We still have one reference left, so it isn't actually deleted. - expect(tableCache.count()).foundUser(1n); + expect(tableCache.count()).toEqual(1n); expect(Array.from(tableCache.iter())[0]).toEqual(player); - expect(callbackHistory.length).foundUser(0); + expect(callbackHistory.length).toEqual(0); }, ], }); @@ -679,9 +679,9 @@ describe('TableCache', () => { assertions: [ ({ tableCache, callbackHistory }) => { // Now it is actually deleted. - expect(tableCache.count()).foundUser(0); - expect(callbackHistory.length).foundUser(1); - expect(callbackHistory[0].type).foundUser('delete'); + expect(tableCache.count()).toEqual(0n); + expect(callbackHistory.length).toEqual(1); + expect(callbackHistory[0].type).toEqual('delete'); expect(callbackHistory[0].row).toEqual(player); }, ], @@ -694,7 +694,7 @@ describe('TableCache', () => { }, assertions: [ ({ tableCache, callbackHistory }) => { - expect(tableCache.count()).foundUser(1n); + expect(tableCache.count()).toEqual(1n); expect(Array.from(tableCache.iter())[0]).toEqual(player); expect(callbackHistory).toEqual([insertEvent(player)]); }, @@ -707,7 +707,7 @@ describe('TableCache', () => { }, assertions: [ ({ tableCache, callbackHistory }) => { - expect(tableCache.count()).foundUser(1n); + expect(tableCache.count()).toEqual(1n); expect(Array.from(tableCache.iter())[0]).toEqual(player); expect(callbackHistory).toEqual([]); }, @@ -720,7 +720,7 @@ describe('TableCache', () => { }, assertions: [ ({ tableCache, callbackHistory }) => { - expect(tableCache.count()).foundUser(0); + expect(tableCache.count()).toEqual(0n); expect(callbackHistory).toEqual([deleteEvent(mkPlayer())]); }, ], @@ -745,17 +745,17 @@ describe('TableCache', () => { rowsInserted++; expect(row).toEqual(op.row); }); - expect(callbacks.length).foundUser(1); - expect(tableCache.count()).foundUser(1n); + expect(callbacks.length).toEqual(1); + expect(tableCache.count()).toEqual(1n); callbacks.forEach(cb => { cb.cb(); }); - expect(rowsInserted).foundUser(1); + expect(rowsInserted).toEqual(1); }); }); test('should be empty on creation', () => { const tableCache = new TableCacheImpl(tables.player); - expect(tableCache.count()).foundUser(0n); + expect(tableCache.count()).toEqual(0n); }); }); From 4d2aff439735588cdb7020e359c9a7f90f53872e Mon Sep 17 00:00:00 2001 From: Tyler Cloutier Date: Mon, 10 Nov 2025 22:43:59 -0500 Subject: [PATCH 27/49] pnpm format --- .../src/lib/constraints.ts | 4 +- crates/bindings-typescript/src/lib/schema.ts | 60 ++++++++++--------- crates/bindings-typescript/src/lib/table.ts | 2 +- .../src/lib/type_builders.ts | 11 ++-- .../bindings-typescript/src/sdk/reducers.ts | 6 +- .../src/sdk/table_cache.ts | 5 +- .../tests/table_cache.test.ts | 5 +- 7 files changed, 49 insertions(+), 44 deletions(-) diff --git a/crates/bindings-typescript/src/lib/constraints.ts b/crates/bindings-typescript/src/lib/constraints.ts index 0c4134cc40a..862e75ae7ea 100644 --- a/crates/bindings-typescript/src/lib/constraints.ts +++ b/crates/bindings-typescript/src/lib/constraints.ts @@ -45,6 +45,4 @@ export type ColumnIsUnique> = M extends */ export type ConstraintOpts = { name?: string; -} & ( - | { constraint: 'unique'; columns: [AllowedCol] } -); +} & { constraint: 'unique'; columns: [AllowedCol] }; diff --git a/crates/bindings-typescript/src/lib/schema.ts b/crates/bindings-typescript/src/lib/schema.ts index ccc02f5f0f9..f01ad323aac 100644 --- a/crates/bindings-typescript/src/lib/schema.ts +++ b/crates/bindings-typescript/src/lib/schema.ts @@ -84,29 +84,33 @@ export function tablesToSchema< accessorName: toCamelCase(schema.tableName), columns: schema.rowType.row, // typed as T[i]['rowType']['row'] under TablesToSchema rowType: schema.rowSpacetimeType, - constraints: [...schema.tableDef.constraints.map(c => ({ - name: c.name, - constraint: 'unique' as const, - columns: c.data.value.columns.map(i => colNameList[i]), - }))], + constraints: [ + ...schema.tableDef.constraints.map(c => ({ + name: c.name, + constraint: 'unique' as const, + columns: c.data.value.columns.map(i => colNameList[i]), + })), + ], // UntypedTableDef expects mutable array; idxs are readonly, spread to copy. indexes: [ ...schema.idxs.map( (idx: Infer): IndexOpts => ({ name: idx.accessorName, - unique: schema.tableDef.constraints.map(c => { - if (idx.algorithm.tag == 'BTree') { - return c.data.value.columns.every(col => { - const idxColumns = idx.algorithm.value; - if (Array.isArray(idxColumns)) { - return idxColumns.includes(col); - } else { - return col === idxColumns; - } - }); - } - }).includes(true), + unique: schema.tableDef.constraints + .map(c => { + if (idx.algorithm.tag == 'BTree') { + return c.data.value.columns.every(col => { + const idxColumns = idx.algorithm.value; + if (Array.isArray(idxColumns)) { + return idxColumns.includes(col); + } else { + return col === idxColumns; + } + }); + } + }) + .includes(true), algorithm: idx.algorithm.tag.toLowerCase() as 'btree', columns: (() => { const cols = @@ -120,16 +124,16 @@ export function tablesToSchema< ], } as const; }) as { - // preserve tuple indices so the return type matches `[i in keyof T]` - readonly [I in keyof T]: { - name: T[I]['tableName']; - accessorName: CamelCase; - columns: T[I]['rowType']['row']; - rowType: T[I]['rowSpacetimeType']; - indexes: T[I]['idxs']; - constraints: T[I]['constraints']; - }; - }, + // preserve tuple indices so the return type matches `[i in keyof T]` + readonly [I in keyof T]: { + name: T[I]['tableName']; + accessorName: CamelCase; + columns: T[I]['rowType']['row']; + rowType: T[I]['rowSpacetimeType']; + indexes: T[I]['idxs']; + constraints: T[I]['constraints']; + }; + }, } satisfies TablesToSchema; return result; } @@ -587,7 +591,7 @@ export function schema[]>( type HasAccessor = { accessorName: PropertyKey }; export type ConvertToAccessorMap = { - [Tbl in TableDefs[number]as Tbl['accessorName']]: Tbl; + [Tbl in TableDefs[number] as Tbl['accessorName']]: Tbl; }; export function convertToAccessorMap( diff --git a/crates/bindings-typescript/src/lib/table.ts b/crates/bindings-typescript/src/lib/table.ts index b4a286f073d..2da1fcb7cc8 100644 --- a/crates/bindings-typescript/src/lib/table.ts +++ b/crates/bindings-typescript/src/lib/table.ts @@ -243,7 +243,7 @@ export function table>( // implicit 1‑column indexes if (meta.indexType || isUnique) { - console.log("GAAAAAAH", name); + console.log('GAAAAAAH', name); const algo = meta.indexType ?? 'btree'; const id = colIds.get(name)!; let algorithm: Infer; diff --git a/crates/bindings-typescript/src/lib/type_builders.ts b/crates/bindings-typescript/src/lib/type_builders.ts index ddaf013af9f..86b51032fd5 100644 --- a/crates/bindings-typescript/src/lib/type_builders.ts +++ b/crates/bindings-typescript/src/lib/type_builders.ts @@ -28,12 +28,11 @@ export type InferSpacetimeTypeOfTypeBuilder> = /** * Helper type to extract the TypeScript type from a TypeBuilder */ -export type Infer = - T extends RowObj - ? InferTypeOfRow - : T extends TypeBuilder - ? InferTypeOfTypeBuilder - : never; +export type Infer = T extends RowObj + ? InferTypeOfRow + : T extends TypeBuilder + ? InferTypeOfTypeBuilder + : never; /** * Helper type to extract the type of a row from an object. diff --git a/crates/bindings-typescript/src/sdk/reducers.ts b/crates/bindings-typescript/src/sdk/reducers.ts index 2b4dcd801b8..602e426539f 100644 --- a/crates/bindings-typescript/src/sdk/reducers.ts +++ b/crates/bindings-typescript/src/sdk/reducers.ts @@ -46,16 +46,14 @@ export type ReducersView = IfAny< [K in RemoteModule['reducers'][number] as CamelCase< K['accessorName'] >]: (params: InferTypeOfRow) => void; - } & // onX: `on${PascalCase(name)}` - { + } & { // onX: `on${PascalCase(name)}` [K in RemoteModule['reducers'][number] as `on${PascalCase}`]: ( callback: ReducerEventCallback< RemoteModule, InferTypeOfRow > ) => void; - } & // removeOnX: `removeOn${PascalCase(name)}` - { + } & { // removeOnX: `removeOn${PascalCase(name)}` [K in RemoteModule['reducers'][number] as `removeOn${PascalCase}`]: ( callback: ReducerEventCallback< RemoteModule, diff --git a/crates/bindings-typescript/src/sdk/table_cache.ts b/crates/bindings-typescript/src/sdk/table_cache.ts index d1281732961..ffc55702514 100644 --- a/crates/bindings-typescript/src/sdk/table_cache.ts +++ b/crates/bindings-typescript/src/sdk/table_cache.ts @@ -100,7 +100,10 @@ export class TableCacheImpl< I extends UntypedIndex< keyof TableDefForTableName['columns'] & string >, - >(tableDef: TableDefForTableName, idx: I): ReadonlyIndex, I> { + >( + tableDef: TableDefForTableName, + idx: I + ): ReadonlyIndex, I> { type TableDef = TableDefForTableName; type Row = RowType; diff --git a/crates/bindings-typescript/tests/table_cache.test.ts b/crates/bindings-typescript/tests/table_cache.test.ts index 939303e7287..7fa7595e887 100644 --- a/crates/bindings-typescript/tests/table_cache.test.ts +++ b/crates/bindings-typescript/tests/table_cache.test.ts @@ -2,7 +2,10 @@ import { type Operation, TableCacheImpl } from '../src/sdk/table_cache'; import { describe, expect, test } from 'vitest'; import Player from '../test-app/src/module_bindings/player_type.ts'; import { AlgebraicType, Identity, type Infer } from '../src'; -import { tables, UnindexedPlayer } from '../test-app/src/module_bindings/index.ts'; +import { + tables, + UnindexedPlayer, +} from '../test-app/src/module_bindings/index.ts'; interface ApplyOperations { ops: Operation[]; From 6d5e5754c4154a4feba79f8e366cba773478d837 Mon Sep 17 00:00:00 2001 From: Tyler Cloutier Date: Mon, 10 Nov 2025 22:44:22 -0500 Subject: [PATCH 28/49] cargo fmt --- crates/codegen/src/typescript.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/crates/codegen/src/typescript.rs b/crates/codegen/src/typescript.rs index 21a3887104a..a2f4f9c4f32 100644 --- a/crates/codegen/src/typescript.rs +++ b/crates/codegen/src/typescript.rs @@ -533,7 +533,7 @@ fn write_object_type_builder_fields( primary_key: Option, convert_case: bool, ) -> anyhow::Result<()> { - for (i, (ident, ty)) in elements.iter().enumerate() { + for (i, (ident, ty)) in elements.iter().enumerate() { let name = if convert_case { ident.deref().to_case(Case::Camel) } else { @@ -550,7 +550,13 @@ fn write_object_type_builder_fields( Ok(()) } -fn write_type_builder_field(module: &ModuleDef, out: &mut Indenter, name: &str, ty: &AlgebraicTypeUse, is_primary_key: bool) -> fmt::Result { +fn write_type_builder_field( + module: &ModuleDef, + out: &mut Indenter, + name: &str, + ty: &AlgebraicTypeUse, + is_primary_key: bool, +) -> fmt::Result { // Do we need a getter? (Option/Array only if their inner is a Ref) let needs_getter = match ty { AlgebraicTypeUse::Ref(_) => true, From 487d5a336c636e796c4a3e5f970ba9f80a9fefbd Mon Sep 17 00:00:00 2001 From: Tyler Cloutier Date: Mon, 10 Nov 2025 22:49:16 -0500 Subject: [PATCH 29/49] formatting --- crates/bindings-typescript/src/lib/util.ts | 4 +++- crates/bindings-typescript/src/sdk/reducers.ts | 6 ++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/crates/bindings-typescript/src/lib/util.ts b/crates/bindings-typescript/src/lib/util.ts index 025b9c70bf3..47974fff6d5 100644 --- a/crates/bindings-typescript/src/lib/util.ts +++ b/crates/bindings-typescript/src/lib/util.ts @@ -111,7 +111,9 @@ export function u256ToHexString(data: bigint): string { * @returns The converted string */ export function toCamelCase(str: T): CamelCase { - return str.replace(/[-_]+(\w)/g, (_, c) => c.toUpperCase()) as CamelCase; + return str + .replace(/[-_]+/g, '_') // collapse runs to a single separator (no backtracking issue) + .replace(/_([a-zA-Z0-9])/g, (_, c) => c.toUpperCase()) as CamelCase; } import type { AlgebraicType } from './algebraic_type'; diff --git a/crates/bindings-typescript/src/sdk/reducers.ts b/crates/bindings-typescript/src/sdk/reducers.ts index 602e426539f..03cce971d0e 100644 --- a/crates/bindings-typescript/src/sdk/reducers.ts +++ b/crates/bindings-typescript/src/sdk/reducers.ts @@ -46,14 +46,16 @@ export type ReducersView = IfAny< [K in RemoteModule['reducers'][number] as CamelCase< K['accessorName'] >]: (params: InferTypeOfRow) => void; - } & { // onX: `on${PascalCase(name)}` + } & { + // onX: `on${PascalCase(name)}` [K in RemoteModule['reducers'][number] as `on${PascalCase}`]: ( callback: ReducerEventCallback< RemoteModule, InferTypeOfRow > ) => void; - } & { // removeOnX: `removeOn${PascalCase(name)}` + } & { + // removeOnX: `removeOn${PascalCase(name)}` [K in RemoteModule['reducers'][number] as `removeOn${PascalCase}`]: ( callback: ReducerEventCallback< RemoteModule, From 256d04f255193da18c7788842c058784bfc21147 Mon Sep 17 00:00:00 2001 From: Tyler Cloutier Date: Mon, 10 Nov 2025 22:55:52 -0500 Subject: [PATCH 30/49] Builds, tests, works --- crates/bindings-typescript/src/lib/indexes.ts | 1 + crates/bindings-typescript/src/lib/schema.ts | 2 +- crates/bindings-typescript/src/lib/table.ts | 10 ++++++++++ crates/bindings-typescript/src/lib/table_schema.ts | 2 +- 4 files changed, 13 insertions(+), 2 deletions(-) diff --git a/crates/bindings-typescript/src/lib/indexes.ts b/crates/bindings-typescript/src/lib/indexes.ts index 993789e09a5..7cbef810435 100644 --- a/crates/bindings-typescript/src/lib/indexes.ts +++ b/crates/bindings-typescript/src/lib/indexes.ts @@ -20,6 +20,7 @@ export type IndexOpts = { */ export type UntypedIndex = { name: string; + unique?: boolean; algorithm: 'btree' | 'direct'; columns: readonly AllowedCol[]; }; diff --git a/crates/bindings-typescript/src/lib/schema.ts b/crates/bindings-typescript/src/lib/schema.ts index f01ad323aac..57c49d813ff 100644 --- a/crates/bindings-typescript/src/lib/schema.ts +++ b/crates/bindings-typescript/src/lib/schema.ts @@ -88,7 +88,7 @@ export function tablesToSchema< ...schema.tableDef.constraints.map(c => ({ name: c.name, constraint: 'unique' as const, - columns: c.data.value.columns.map(i => colNameList[i]), + columns: Array.from(c.data.value.columns.map(i => colNameList[i])), })), ], // UntypedTableDef expects mutable array; idxs are readonly, spread to copy. diff --git a/crates/bindings-typescript/src/lib/table.ts b/crates/bindings-typescript/src/lib/table.ts index 2da1fcb7cc8..e5cf5af416c 100644 --- a/crates/bindings-typescript/src/lib/table.ts +++ b/crates/bindings-typescript/src/lib/table.ts @@ -139,6 +139,15 @@ type OptsIndices> = Opts extends { ? Ixs : CoerceArray<[]>; +/** + * Extracts the constraints from TableOpts, defaulting to an empty array if none are provided. + */ +type OptsConstraints> = Opts extends { + constraints: infer Constraints extends NonNullable; +} + ? Constraints + : CoerceArray<[]>; + /** * Table * @@ -374,5 +383,6 @@ export function table>( rowSpacetimeType: productType, tableDef, idxs: indexes as OptsIndices, + constraints: constraints as OptsConstraints }; } diff --git a/crates/bindings-typescript/src/lib/table_schema.ts b/crates/bindings-typescript/src/lib/table_schema.ts index 8cb5e01444c..9b6a56269aa 100644 --- a/crates/bindings-typescript/src/lib/table_schema.ts +++ b/crates/bindings-typescript/src/lib/table_schema.ts @@ -42,6 +42,6 @@ export type TableSchema< readonly constraints: readonly { name: string | undefined; constraint: 'unique'; - columns: readonly string[]; + columns: [any]; }[]; }; From 181e50f4b77d8ea4b10d1b8ffbd4081d8a0f35e6 Mon Sep 17 00:00:00 2001 From: Tyler Cloutier Date: Mon, 10 Nov 2025 22:56:14 -0500 Subject: [PATCH 31/49] Formatting --- crates/bindings-typescript/src/lib/table.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/bindings-typescript/src/lib/table.ts b/crates/bindings-typescript/src/lib/table.ts index e5cf5af416c..20a37bf3988 100644 --- a/crates/bindings-typescript/src/lib/table.ts +++ b/crates/bindings-typescript/src/lib/table.ts @@ -145,7 +145,7 @@ type OptsIndices> = Opts extends { type OptsConstraints> = Opts extends { constraints: infer Constraints extends NonNullable; } - ? Constraints + ? Constraints : CoerceArray<[]>; /** @@ -383,6 +383,6 @@ export function table>( rowSpacetimeType: productType, tableDef, idxs: indexes as OptsIndices, - constraints: constraints as OptsConstraints + constraints: constraints as OptsConstraints, }; } From 6fbb8fc2b8f0c952ce9bcf0a407e2dfec6195f3d Mon Sep 17 00:00:00 2001 From: = Date: Thu, 30 Oct 2025 15:31:20 -0400 Subject: [PATCH 32/49] Now generating module_bindings for examples and also moved pnpm scripts into portable rust scripts --- Cargo.lock | 67 ++++ Cargo.toml | 3 + .../examples/basic-react/package.json | 8 +- .../examples/basic-react/src/main.tsx | 2 +- .../src/module_bindings/add_reducer.ts | 70 ++++ .../client_connected_reducer.ts | 68 ++++ .../client_disconnected_reducer.ts | 68 ++++ .../basic-react/src/module_bindings/index.ts | 303 ++++++++++++++++++ .../src/module_bindings/init_reducer.ts | 65 ++++ .../src/module_bindings/person_table.ts | 83 +++++ .../src/module_bindings/person_type.ts | 70 ++++ .../src/module_bindings/say_hello_reducer.ts | 67 ++++ .../examples/basic-react/tsconfig.json | 1 + .../examples/empty/package.json | 6 +- .../empty/src/module_bindings/add_reducer.ts | 70 ++++ .../client_connected_reducer.ts | 68 ++++ .../client_disconnected_reducer.ts | 68 ++++ .../empty/src/module_bindings/index.ts | 303 ++++++++++++++++++ .../empty/src/module_bindings/init_reducer.ts | 65 ++++ .../empty/src/module_bindings/person_table.ts | 83 +++++ .../empty/src/module_bindings/person_type.ts | 70 ++++ .../src/module_bindings/say_hello_reducer.ts | 67 ++++ .../examples/quickstart-chat/package.json | 8 +- .../src/module_bindings/index.ts | 2 +- .../quickstart-chat/src/vite-env.d.ts | 1 - .../quickstart-chat/tsconfig.app.json | 1 + crates/bindings-typescript/package.json | 7 +- .../src/sdk/client_api/index.ts | 4 + .../bindings-typescript/test-app/package.json | 2 +- .../test-app/replace-spacetimedb.js | 38 --- .../test-app/src/module_bindings/index.ts | 4 + .../test-react-router-app/package.json | 2 +- .../replace-spacetimedb.js | 38 --- pnpm-lock.yaml | 61 ++++ pnpm-workspace.yaml | 2 + tools/gen-bindings/Cargo.toml | 9 + tools/gen-bindings/src/main.rs | 96 ++++++ tools/generate-client-api/Cargo.toml | 9 + tools/generate-client-api/src/main.rs | 107 +++++++ tools/replace-spacetimedb/Cargo.toml | 18 ++ tools/replace-spacetimedb/src/lib.rs | 131 ++++++++ tools/replace-spacetimedb/src/main.rs | 64 ++++ 42 files changed, 2188 insertions(+), 91 deletions(-) create mode 100644 crates/bindings-typescript/examples/basic-react/src/module_bindings/add_reducer.ts create mode 100644 crates/bindings-typescript/examples/basic-react/src/module_bindings/client_connected_reducer.ts create mode 100644 crates/bindings-typescript/examples/basic-react/src/module_bindings/client_disconnected_reducer.ts create mode 100644 crates/bindings-typescript/examples/basic-react/src/module_bindings/index.ts create mode 100644 crates/bindings-typescript/examples/basic-react/src/module_bindings/init_reducer.ts create mode 100644 crates/bindings-typescript/examples/basic-react/src/module_bindings/person_table.ts create mode 100644 crates/bindings-typescript/examples/basic-react/src/module_bindings/person_type.ts create mode 100644 crates/bindings-typescript/examples/basic-react/src/module_bindings/say_hello_reducer.ts create mode 100644 crates/bindings-typescript/examples/empty/src/module_bindings/add_reducer.ts create mode 100644 crates/bindings-typescript/examples/empty/src/module_bindings/client_connected_reducer.ts create mode 100644 crates/bindings-typescript/examples/empty/src/module_bindings/client_disconnected_reducer.ts create mode 100644 crates/bindings-typescript/examples/empty/src/module_bindings/index.ts create mode 100644 crates/bindings-typescript/examples/empty/src/module_bindings/init_reducer.ts create mode 100644 crates/bindings-typescript/examples/empty/src/module_bindings/person_table.ts create mode 100644 crates/bindings-typescript/examples/empty/src/module_bindings/person_type.ts create mode 100644 crates/bindings-typescript/examples/empty/src/module_bindings/say_hello_reducer.ts delete mode 100644 crates/bindings-typescript/examples/quickstart-chat/src/vite-env.d.ts delete mode 100644 crates/bindings-typescript/test-app/replace-spacetimedb.js delete mode 100644 crates/bindings-typescript/test-react-router-app/replace-spacetimedb.js create mode 100644 tools/gen-bindings/Cargo.toml create mode 100644 tools/gen-bindings/src/main.rs create mode 100644 tools/generate-client-api/Cargo.toml create mode 100644 tools/generate-client-api/src/main.rs create mode 100644 tools/replace-spacetimedb/Cargo.toml create mode 100644 tools/replace-spacetimedb/src/lib.rs create mode 100644 tools/replace-spacetimedb/src/main.rs diff --git a/Cargo.lock b/Cargo.lock index 262094f4fce..36650a6ad0b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -616,6 +616,16 @@ dependencies = [ "alloc-stdlib", ] +[[package]] +name = "bstr" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63044e1ae8e69f3b5a92c736ca6269b8d12fa7efe39bf34ddb06d102cf0e2cab" +dependencies = [ + "memchr", + "serde", +] + [[package]] name = "bumpalo" version = "3.19.0" @@ -2350,6 +2360,24 @@ dependencies = [ "byteorder", ] +[[package]] +name = "gen-bindings" +version = "0.1.0" +dependencies = [ + "anyhow", + "clap 4.5.50", + "replace-spacetimedb", +] + +[[package]] +name = "generate-client-api" +version = "0.1.0" +dependencies = [ + "anyhow", + "replace-spacetimedb", + "tempfile", +] + [[package]] name = "generator" version = "0.8.7" @@ -2439,6 +2467,19 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" +[[package]] +name = "globset" +version = "0.4.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52dfc19153a48bde0cbd630453615c8151bce3a5adfac7a0aebfbf0a1e1f57e3" +dependencies = [ + "aho-corasick", + "bstr", + "log", + "regex-automata", + "regex-syntax", +] + [[package]] name = "gzip-header" version = "1.0.0" @@ -3061,6 +3102,22 @@ dependencies = [ "icu_properties", ] +[[package]] +name = "ignore" +version = "0.4.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3d782a365a015e0f5c04902246139249abf769125006fbe7649e2ee88169b4a" +dependencies = [ + "crossbeam-deque", + "globset", + "log", + "memchr", + "regex-automata", + "same-file", + "walkdir", + "winapi-util", +] + [[package]] name = "imara-diff" version = "0.1.8" @@ -5765,6 +5822,16 @@ version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cadadef317c2f20755a64d7fdc48f9e7178ee6b0e1f7fce33fa60f1d68a276e6" +[[package]] +name = "replace-spacetimedb" +version = "0.1.0" +dependencies = [ + "clap 4.5.50", + "ignore", + "memchr", + "regex", +] + [[package]] name = "reqwest" version = "0.11.27" diff --git a/Cargo.toml b/Cargo.toml index 0551f9f5edb..fa17a32e5e2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -50,6 +50,9 @@ members = [ "sdks/rust/tests/procedure-client", "tools/upgrade-version", "tools/license-check", + "tools/replace-spacetimedb", + "tools/generate-client-api", + "tools/gen-bindings", "crates/bindings-typescript/test-app/server", "crates/bindings-typescript/test-react-router-app/server", ] diff --git a/crates/bindings-typescript/examples/basic-react/package.json b/crates/bindings-typescript/examples/basic-react/package.json index cb30120ed8f..b9f51487874 100644 --- a/crates/bindings-typescript/examples/basic-react/package.json +++ b/crates/bindings-typescript/examples/basic-react/package.json @@ -7,13 +7,15 @@ "dev": "vite", "build": "tsc -b && vite build", "preview": "vite preview", - "local": "spacetime publish --project-path spacetimedb --server local && spacetime generate --lang typescript --out-dir src/module_bindings --project-path spacetimedb", - "deploy": "spacetime publish --project-path spacetimedb && spacetime generate --lang typescript --out-dir src/module_bindings --project-path spacetimedb" + "generate": "cargo run -p gen-bindings -- --out-dir src/module_bindings --project-path ../../../cli/templates/basic-typescript/server && prettier --write src/module_bindings", + "spacetime:generate": "spacetime generate --lang typescript --out-dir src/module_bindings --project-path spacetimedb", + "spacetime:publish:local": "spacetime publish --project-path server --server local", + "spacetime:publish": "spacetime publish --project-path server --server testnet" }, "dependencies": { "spacetimedb": "workspace:*", "react": "^18.3.1", - "react-dom": "^18.3.1" + "react-dom": "^18.3.1" }, "devDependencies": { "@types/react": "^18.3.18", diff --git a/crates/bindings-typescript/examples/basic-react/src/main.tsx b/crates/bindings-typescript/examples/basic-react/src/main.tsx index f176f6ef300..0cfb34e144b 100644 --- a/crates/bindings-typescript/examples/basic-react/src/main.tsx +++ b/crates/bindings-typescript/examples/basic-react/src/main.tsx @@ -8,7 +8,7 @@ import { DbConnection, ErrorContext } from './module_bindings/index.ts'; const HOST = import.meta.env.VITE_SPACETIMEDB_HOST ?? 'ws://localhost:3000'; const DB_NAME = import.meta.env.VITE_SPACETIMEDB_DB_NAME ?? 'my-db'; -const onConnect = (conn: DbConnection, identity: Identity, token: string) => { +const onConnect = (_conn: DbConnection, identity: Identity, token: string) => { localStorage.setItem('auth_token', token); console.log( 'Connected to SpacetimeDB with identity:', diff --git a/crates/bindings-typescript/examples/basic-react/src/module_bindings/add_reducer.ts b/crates/bindings-typescript/examples/basic-react/src/module_bindings/add_reducer.ts new file mode 100644 index 00000000000..bc8fe325253 --- /dev/null +++ b/crates/bindings-typescript/examples/basic-react/src/module_bindings/add_reducer.ts @@ -0,0 +1,70 @@ +// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE +// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. + +/* eslint-disable */ +/* tslint:disable */ +import { + AlgebraicType as __AlgebraicTypeValue, + BinaryReader as __BinaryReader, + BinaryWriter as __BinaryWriter, + ClientCache as __ClientCache, + ConnectionId as __ConnectionId, + DbConnectionBuilder as __DbConnectionBuilder, + DbConnectionImpl as __DbConnectionImpl, + Identity as __Identity, + SubscriptionBuilderImpl as __SubscriptionBuilderImpl, + TableCache as __TableCache, + TimeDuration as __TimeDuration, + Timestamp as __Timestamp, + deepEqual as __deepEqual, + type AlgebraicType as __AlgebraicTypeType, + type AlgebraicTypeVariants as __AlgebraicTypeVariants, + type CallReducerFlags as __CallReducerFlags, + type ErrorContextInterface as __ErrorContextInterface, + type Event as __Event, + type EventContextInterface as __EventContextInterface, + type ReducerEventContextInterface as __ReducerEventContextInterface, + type SubscriptionEventContextInterface as __SubscriptionEventContextInterface, + type TableHandle as __TableHandle, +} from 'spacetimedb'; + +export type Add = { + name: string; +}; +let _cached_Add_type_value: __AlgebraicTypeType | null = null; + +/** + * An object for generated helper functions. + */ +export const Add = { + /** + * A function which returns this type represented as an AlgebraicType. + * This function is derived from the AlgebraicType used to generate this type. + */ + getTypeScriptAlgebraicType(): __AlgebraicTypeType { + if (_cached_Add_type_value) return _cached_Add_type_value; + _cached_Add_type_value = __AlgebraicTypeValue.Product({ elements: [] }); + _cached_Add_type_value.value.elements.push({ + name: 'name', + algebraicType: __AlgebraicTypeValue.String, + }); + return _cached_Add_type_value; + }, + + serialize(writer: __BinaryWriter, value: Add): void { + __AlgebraicTypeValue.serializeValue( + writer, + Add.getTypeScriptAlgebraicType(), + value + ); + }, + + deserialize(reader: __BinaryReader): Add { + return __AlgebraicTypeValue.deserializeValue( + reader, + Add.getTypeScriptAlgebraicType() + ); + }, +}; + +export default Add; diff --git a/crates/bindings-typescript/examples/basic-react/src/module_bindings/client_connected_reducer.ts b/crates/bindings-typescript/examples/basic-react/src/module_bindings/client_connected_reducer.ts new file mode 100644 index 00000000000..a8b7233cef8 --- /dev/null +++ b/crates/bindings-typescript/examples/basic-react/src/module_bindings/client_connected_reducer.ts @@ -0,0 +1,68 @@ +// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE +// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. + +/* eslint-disable */ +/* tslint:disable */ +import { + AlgebraicType as __AlgebraicTypeValue, + BinaryReader as __BinaryReader, + BinaryWriter as __BinaryWriter, + ClientCache as __ClientCache, + ConnectionId as __ConnectionId, + DbConnectionBuilder as __DbConnectionBuilder, + DbConnectionImpl as __DbConnectionImpl, + Identity as __Identity, + SubscriptionBuilderImpl as __SubscriptionBuilderImpl, + TableCache as __TableCache, + TimeDuration as __TimeDuration, + Timestamp as __Timestamp, + deepEqual as __deepEqual, + type AlgebraicType as __AlgebraicTypeType, + type AlgebraicTypeVariants as __AlgebraicTypeVariants, + type CallReducerFlags as __CallReducerFlags, + type ErrorContextInterface as __ErrorContextInterface, + type Event as __Event, + type EventContextInterface as __EventContextInterface, + type ReducerEventContextInterface as __ReducerEventContextInterface, + type SubscriptionEventContextInterface as __SubscriptionEventContextInterface, + type TableHandle as __TableHandle, +} from 'spacetimedb'; + +export type ClientConnected = {}; +let _cached_ClientConnected_type_value: __AlgebraicTypeType | null = null; + +/** + * An object for generated helper functions. + */ +export const ClientConnected = { + /** + * A function which returns this type represented as an AlgebraicType. + * This function is derived from the AlgebraicType used to generate this type. + */ + getTypeScriptAlgebraicType(): __AlgebraicTypeType { + if (_cached_ClientConnected_type_value) + return _cached_ClientConnected_type_value; + _cached_ClientConnected_type_value = __AlgebraicTypeValue.Product({ + elements: [], + }); + _cached_ClientConnected_type_value.value.elements.push(); + return _cached_ClientConnected_type_value; + }, + + serialize(writer: __BinaryWriter, value: ClientConnected): void { + __AlgebraicTypeValue.serializeValue( + writer, + ClientConnected.getTypeScriptAlgebraicType(), + value + ); + }, + + deserialize(reader: __BinaryReader): ClientConnected { + return __AlgebraicTypeValue.deserializeValue( + reader, + ClientConnected.getTypeScriptAlgebraicType() + ); + }, +}; + +export default ClientConnected; diff --git a/crates/bindings-typescript/examples/basic-react/src/module_bindings/client_disconnected_reducer.ts b/crates/bindings-typescript/examples/basic-react/src/module_bindings/client_disconnected_reducer.ts new file mode 100644 index 00000000000..385acd9bd3c --- /dev/null +++ b/crates/bindings-typescript/examples/basic-react/src/module_bindings/client_disconnected_reducer.ts @@ -0,0 +1,68 @@ +// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE +// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. + +/* eslint-disable */ +/* tslint:disable */ +import { + AlgebraicType as __AlgebraicTypeValue, + BinaryReader as __BinaryReader, + BinaryWriter as __BinaryWriter, + ClientCache as __ClientCache, + ConnectionId as __ConnectionId, + DbConnectionBuilder as __DbConnectionBuilder, + DbConnectionImpl as __DbConnectionImpl, + Identity as __Identity, + SubscriptionBuilderImpl as __SubscriptionBuilderImpl, + TableCache as __TableCache, + TimeDuration as __TimeDuration, + Timestamp as __Timestamp, + deepEqual as __deepEqual, + type AlgebraicType as __AlgebraicTypeType, + type AlgebraicTypeVariants as __AlgebraicTypeVariants, + type CallReducerFlags as __CallReducerFlags, + type ErrorContextInterface as __ErrorContextInterface, + type Event as __Event, + type EventContextInterface as __EventContextInterface, + type ReducerEventContextInterface as __ReducerEventContextInterface, + type SubscriptionEventContextInterface as __SubscriptionEventContextInterface, + type TableHandle as __TableHandle, +} from 'spacetimedb'; + +export type ClientDisconnected = {}; +let _cached_ClientDisconnected_type_value: __AlgebraicTypeType | null = null; + +/** + * An object for generated helper functions. + */ +export const ClientDisconnected = { + /** + * A function which returns this type represented as an AlgebraicType. + * This function is derived from the AlgebraicType used to generate this type. + */ + getTypeScriptAlgebraicType(): __AlgebraicTypeType { + if (_cached_ClientDisconnected_type_value) + return _cached_ClientDisconnected_type_value; + _cached_ClientDisconnected_type_value = __AlgebraicTypeValue.Product({ + elements: [], + }); + _cached_ClientDisconnected_type_value.value.elements.push(); + return _cached_ClientDisconnected_type_value; + }, + + serialize(writer: __BinaryWriter, value: ClientDisconnected): void { + __AlgebraicTypeValue.serializeValue( + writer, + ClientDisconnected.getTypeScriptAlgebraicType(), + value + ); + }, + + deserialize(reader: __BinaryReader): ClientDisconnected { + return __AlgebraicTypeValue.deserializeValue( + reader, + ClientDisconnected.getTypeScriptAlgebraicType() + ); + }, +}; + +export default ClientDisconnected; diff --git a/crates/bindings-typescript/examples/basic-react/src/module_bindings/index.ts b/crates/bindings-typescript/examples/basic-react/src/module_bindings/index.ts new file mode 100644 index 00000000000..08fef081923 --- /dev/null +++ b/crates/bindings-typescript/examples/basic-react/src/module_bindings/index.ts @@ -0,0 +1,303 @@ +// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE +// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. + +// This was generated using spacetimedb cli version 1.6.0 (commit 64812908d1dd2fb0ac1a44ae8c669306ce3f001e). + +/* eslint-disable */ +/* tslint:disable */ +import { + AlgebraicType as __AlgebraicTypeValue, + BinaryReader as __BinaryReader, + BinaryWriter as __BinaryWriter, + ClientCache as __ClientCache, + ConnectionId as __ConnectionId, + DbConnectionBuilder as __DbConnectionBuilder, + DbConnectionImpl as __DbConnectionImpl, + Identity as __Identity, + SubscriptionBuilderImpl as __SubscriptionBuilderImpl, + TableCache as __TableCache, + TimeDuration as __TimeDuration, + Timestamp as __Timestamp, + deepEqual as __deepEqual, + type AlgebraicType as __AlgebraicTypeType, + type AlgebraicTypeVariants as __AlgebraicTypeVariants, + type CallReducerFlags as __CallReducerFlags, + type ErrorContextInterface as __ErrorContextInterface, + type Event as __Event, + type EventContextInterface as __EventContextInterface, + type ReducerEventContextInterface as __ReducerEventContextInterface, + type SubscriptionEventContextInterface as __SubscriptionEventContextInterface, + type TableHandle as __TableHandle, +} from 'spacetimedb'; + +// Import and reexport all reducer arg types +import { Init } from './init_reducer.ts'; +export { Init }; +import { ClientConnected } from './client_connected_reducer.ts'; +export { ClientConnected }; +import { ClientDisconnected } from './client_disconnected_reducer.ts'; +export { ClientDisconnected }; +import { Add } from './add_reducer.ts'; +export { Add }; +import { SayHello } from './say_hello_reducer.ts'; +export { SayHello }; + +// Import and reexport all table handle types +import { PersonTableHandle } from './person_table.ts'; +export { PersonTableHandle }; + +// Import and reexport all types +import { Person } from './person_type.ts'; +export { Person }; + +const REMOTE_MODULE = { + tables: { + person: { + tableName: 'person' as const, + rowType: Person.getTypeScriptAlgebraicType(), + }, + }, + reducers: { + init: { + reducerName: 'init', + argsType: Init.getTypeScriptAlgebraicType(), + }, + client_connected: { + reducerName: 'client_connected', + argsType: ClientConnected.getTypeScriptAlgebraicType(), + }, + client_disconnected: { + reducerName: 'client_disconnected', + argsType: ClientDisconnected.getTypeScriptAlgebraicType(), + }, + add: { + reducerName: 'add', + argsType: Add.getTypeScriptAlgebraicType(), + }, + say_hello: { + reducerName: 'say_hello', + argsType: SayHello.getTypeScriptAlgebraicType(), + }, + }, + versionInfo: { + cliVersion: '1.6.0', + }, + // Constructors which are used by the DbConnectionImpl to + // extract type information from the generated RemoteModule. + // + // NOTE: This is not strictly necessary for `eventContextConstructor` because + // all we do is build a TypeScript object which we could have done inside the + // SDK, but if in the future we wanted to create a class this would be + // necessary because classes have methods, so we'll keep it. + eventContextConstructor: ( + imp: __DbConnectionImpl, + event: __Event + ) => { + return { + ...(imp as DbConnection), + event, + }; + }, + dbViewConstructor: (imp: __DbConnectionImpl) => { + return new RemoteTables(imp); + }, + reducersConstructor: ( + imp: __DbConnectionImpl, + setReducerFlags: SetReducerFlags + ) => { + return new RemoteReducers(imp, setReducerFlags); + }, + setReducerFlagsConstructor: () => { + return new SetReducerFlags(); + }, +}; + +// A type representing all the possible variants of a reducer. +export type Reducer = + | never + | { name: 'Init'; args: Init } + | { name: 'ClientConnected'; args: ClientConnected } + | { name: 'ClientDisconnected'; args: ClientDisconnected } + | { name: 'Add'; args: Add } + | { name: 'SayHello'; args: SayHello }; + +export class RemoteReducers { + constructor( + private connection: __DbConnectionImpl, + private setCallReducerFlags: SetReducerFlags + ) {} + + init() { + this.connection.callReducer( + 'init', + new Uint8Array(0), + this.setCallReducerFlags.initFlags + ); + } + + onInit(callback: (ctx: ReducerEventContext) => void) { + this.connection.onReducer('init', callback); + } + + removeOnInit(callback: (ctx: ReducerEventContext) => void) { + this.connection.offReducer('init', callback); + } + + clientConnected() { + this.connection.callReducer( + 'client_connected', + new Uint8Array(0), + this.setCallReducerFlags.clientConnectedFlags + ); + } + + onClientConnected(callback: (ctx: ReducerEventContext) => void) { + this.connection.onReducer('client_connected', callback); + } + + removeOnClientConnected(callback: (ctx: ReducerEventContext) => void) { + this.connection.offReducer('client_connected', callback); + } + + clientDisconnected() { + this.connection.callReducer( + 'client_disconnected', + new Uint8Array(0), + this.setCallReducerFlags.clientDisconnectedFlags + ); + } + + onClientDisconnected(callback: (ctx: ReducerEventContext) => void) { + this.connection.onReducer('client_disconnected', callback); + } + + removeOnClientDisconnected(callback: (ctx: ReducerEventContext) => void) { + this.connection.offReducer('client_disconnected', callback); + } + + add(name: string) { + const __args = { name }; + let __writer = new __BinaryWriter(1024); + Add.serialize(__writer, __args); + let __argsBuffer = __writer.getBuffer(); + this.connection.callReducer( + 'add', + __argsBuffer, + this.setCallReducerFlags.addFlags + ); + } + + onAdd(callback: (ctx: ReducerEventContext, name: string) => void) { + this.connection.onReducer('add', callback); + } + + removeOnAdd(callback: (ctx: ReducerEventContext, name: string) => void) { + this.connection.offReducer('add', callback); + } + + sayHello() { + this.connection.callReducer( + 'say_hello', + new Uint8Array(0), + this.setCallReducerFlags.sayHelloFlags + ); + } + + onSayHello(callback: (ctx: ReducerEventContext) => void) { + this.connection.onReducer('say_hello', callback); + } + + removeOnSayHello(callback: (ctx: ReducerEventContext) => void) { + this.connection.offReducer('say_hello', callback); + } +} + +export class SetReducerFlags { + initFlags: __CallReducerFlags = 'FullUpdate'; + init(flags: __CallReducerFlags) { + this.initFlags = flags; + } + + clientConnectedFlags: __CallReducerFlags = 'FullUpdate'; + clientConnected(flags: __CallReducerFlags) { + this.clientConnectedFlags = flags; + } + + clientDisconnectedFlags: __CallReducerFlags = 'FullUpdate'; + clientDisconnected(flags: __CallReducerFlags) { + this.clientDisconnectedFlags = flags; + } + + addFlags: __CallReducerFlags = 'FullUpdate'; + add(flags: __CallReducerFlags) { + this.addFlags = flags; + } + + sayHelloFlags: __CallReducerFlags = 'FullUpdate'; + sayHello(flags: __CallReducerFlags) { + this.sayHelloFlags = flags; + } +} + +export class RemoteTables { + constructor(private connection: __DbConnectionImpl) {} + + get person(): PersonTableHandle<'person'> { + // clientCache is a private property + return new PersonTableHandle( + ( + this.connection as unknown as { clientCache: __ClientCache } + ).clientCache.getOrCreateTable(REMOTE_MODULE.tables.person) + ); + } +} + +export class SubscriptionBuilder extends __SubscriptionBuilderImpl< + RemoteTables, + RemoteReducers, + SetReducerFlags +> {} + +export class DbConnection extends __DbConnectionImpl< + RemoteTables, + RemoteReducers, + SetReducerFlags +> { + static builder = (): __DbConnectionBuilder< + DbConnection, + ErrorContext, + SubscriptionEventContext + > => { + return new __DbConnectionBuilder< + DbConnection, + ErrorContext, + SubscriptionEventContext + >(REMOTE_MODULE, (imp: __DbConnectionImpl) => imp as DbConnection); + }; + subscriptionBuilder = (): SubscriptionBuilder => { + return new SubscriptionBuilder(this); + }; +} + +export type EventContext = __EventContextInterface< + RemoteTables, + RemoteReducers, + SetReducerFlags, + Reducer +>; +export type ReducerEventContext = __ReducerEventContextInterface< + RemoteTables, + RemoteReducers, + SetReducerFlags, + Reducer +>; +export type SubscriptionEventContext = __SubscriptionEventContextInterface< + RemoteTables, + RemoteReducers, + SetReducerFlags +>; +export type ErrorContext = __ErrorContextInterface< + RemoteTables, + RemoteReducers, + SetReducerFlags +>; diff --git a/crates/bindings-typescript/examples/basic-react/src/module_bindings/init_reducer.ts b/crates/bindings-typescript/examples/basic-react/src/module_bindings/init_reducer.ts new file mode 100644 index 00000000000..12e0782fc1a --- /dev/null +++ b/crates/bindings-typescript/examples/basic-react/src/module_bindings/init_reducer.ts @@ -0,0 +1,65 @@ +// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE +// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. + +/* eslint-disable */ +/* tslint:disable */ +import { + AlgebraicType as __AlgebraicTypeValue, + BinaryReader as __BinaryReader, + BinaryWriter as __BinaryWriter, + ClientCache as __ClientCache, + ConnectionId as __ConnectionId, + DbConnectionBuilder as __DbConnectionBuilder, + DbConnectionImpl as __DbConnectionImpl, + Identity as __Identity, + SubscriptionBuilderImpl as __SubscriptionBuilderImpl, + TableCache as __TableCache, + TimeDuration as __TimeDuration, + Timestamp as __Timestamp, + deepEqual as __deepEqual, + type AlgebraicType as __AlgebraicTypeType, + type AlgebraicTypeVariants as __AlgebraicTypeVariants, + type CallReducerFlags as __CallReducerFlags, + type ErrorContextInterface as __ErrorContextInterface, + type Event as __Event, + type EventContextInterface as __EventContextInterface, + type ReducerEventContextInterface as __ReducerEventContextInterface, + type SubscriptionEventContextInterface as __SubscriptionEventContextInterface, + type TableHandle as __TableHandle, +} from 'spacetimedb'; + +export type Init = {}; +let _cached_Init_type_value: __AlgebraicTypeType | null = null; + +/** + * An object for generated helper functions. + */ +export const Init = { + /** + * A function which returns this type represented as an AlgebraicType. + * This function is derived from the AlgebraicType used to generate this type. + */ + getTypeScriptAlgebraicType(): __AlgebraicTypeType { + if (_cached_Init_type_value) return _cached_Init_type_value; + _cached_Init_type_value = __AlgebraicTypeValue.Product({ elements: [] }); + _cached_Init_type_value.value.elements.push(); + return _cached_Init_type_value; + }, + + serialize(writer: __BinaryWriter, value: Init): void { + __AlgebraicTypeValue.serializeValue( + writer, + Init.getTypeScriptAlgebraicType(), + value + ); + }, + + deserialize(reader: __BinaryReader): Init { + return __AlgebraicTypeValue.deserializeValue( + reader, + Init.getTypeScriptAlgebraicType() + ); + }, +}; + +export default Init; diff --git a/crates/bindings-typescript/examples/basic-react/src/module_bindings/person_table.ts b/crates/bindings-typescript/examples/basic-react/src/module_bindings/person_table.ts new file mode 100644 index 00000000000..c50f51f9ff0 --- /dev/null +++ b/crates/bindings-typescript/examples/basic-react/src/module_bindings/person_table.ts @@ -0,0 +1,83 @@ +// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE +// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. + +/* eslint-disable */ +/* tslint:disable */ +import { + AlgebraicType as __AlgebraicTypeValue, + BinaryReader as __BinaryReader, + BinaryWriter as __BinaryWriter, + ClientCache as __ClientCache, + ConnectionId as __ConnectionId, + DbConnectionBuilder as __DbConnectionBuilder, + DbConnectionImpl as __DbConnectionImpl, + Identity as __Identity, + SubscriptionBuilderImpl as __SubscriptionBuilderImpl, + TableCache as __TableCache, + TimeDuration as __TimeDuration, + Timestamp as __Timestamp, + deepEqual as __deepEqual, + type AlgebraicType as __AlgebraicTypeType, + type AlgebraicTypeVariants as __AlgebraicTypeVariants, + type CallReducerFlags as __CallReducerFlags, + type ErrorContextInterface as __ErrorContextInterface, + type Event as __Event, + type EventContextInterface as __EventContextInterface, + type ReducerEventContextInterface as __ReducerEventContextInterface, + type SubscriptionEventContextInterface as __SubscriptionEventContextInterface, + type TableHandle as __TableHandle, +} from 'spacetimedb'; +import { Person } from './person_type'; +import { + type EventContext, + type Reducer, + RemoteReducers, + RemoteTables, +} from '.'; +declare type __keep = [EventContext, Reducer, RemoteReducers, RemoteTables]; + +/** + * Table handle for the table `person`. + * + * Obtain a handle from the [`person`] property on [`RemoteTables`], + * like `ctx.db.person`. + * + * Users are encouraged not to explicitly reference this type, + * but to directly chain method calls, + * like `ctx.db.person.on_insert(...)`. + */ +export class PersonTableHandle + implements __TableHandle +{ + // phantom type to track the table name + readonly tableName!: TableName; + tableCache: __TableCache; + + constructor(tableCache: __TableCache) { + this.tableCache = tableCache; + } + + count(): number { + return this.tableCache.count(); + } + + iter(): Iterable { + return this.tableCache.iter(); + } + + onInsert = (cb: (ctx: EventContext, row: Person) => void) => { + return this.tableCache.onInsert(cb); + }; + + removeOnInsert = (cb: (ctx: EventContext, row: Person) => void) => { + return this.tableCache.removeOnInsert(cb); + }; + + onDelete = (cb: (ctx: EventContext, row: Person) => void) => { + return this.tableCache.onDelete(cb); + }; + + removeOnDelete = (cb: (ctx: EventContext, row: Person) => void) => { + return this.tableCache.removeOnDelete(cb); + }; +} diff --git a/crates/bindings-typescript/examples/basic-react/src/module_bindings/person_type.ts b/crates/bindings-typescript/examples/basic-react/src/module_bindings/person_type.ts new file mode 100644 index 00000000000..c3085f4f3ba --- /dev/null +++ b/crates/bindings-typescript/examples/basic-react/src/module_bindings/person_type.ts @@ -0,0 +1,70 @@ +// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE +// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. + +/* eslint-disable */ +/* tslint:disable */ +import { + AlgebraicType as __AlgebraicTypeValue, + BinaryReader as __BinaryReader, + BinaryWriter as __BinaryWriter, + ClientCache as __ClientCache, + ConnectionId as __ConnectionId, + DbConnectionBuilder as __DbConnectionBuilder, + DbConnectionImpl as __DbConnectionImpl, + Identity as __Identity, + SubscriptionBuilderImpl as __SubscriptionBuilderImpl, + TableCache as __TableCache, + TimeDuration as __TimeDuration, + Timestamp as __Timestamp, + deepEqual as __deepEqual, + type AlgebraicType as __AlgebraicTypeType, + type AlgebraicTypeVariants as __AlgebraicTypeVariants, + type CallReducerFlags as __CallReducerFlags, + type ErrorContextInterface as __ErrorContextInterface, + type Event as __Event, + type EventContextInterface as __EventContextInterface, + type ReducerEventContextInterface as __ReducerEventContextInterface, + type SubscriptionEventContextInterface as __SubscriptionEventContextInterface, + type TableHandle as __TableHandle, +} from 'spacetimedb'; + +export type Person = { + name: string; +}; +let _cached_Person_type_value: __AlgebraicTypeType | null = null; + +/** + * An object for generated helper functions. + */ +export const Person = { + /** + * A function which returns this type represented as an AlgebraicType. + * This function is derived from the AlgebraicType used to generate this type. + */ + getTypeScriptAlgebraicType(): __AlgebraicTypeType { + if (_cached_Person_type_value) return _cached_Person_type_value; + _cached_Person_type_value = __AlgebraicTypeValue.Product({ elements: [] }); + _cached_Person_type_value.value.elements.push({ + name: 'name', + algebraicType: __AlgebraicTypeValue.String, + }); + return _cached_Person_type_value; + }, + + serialize(writer: __BinaryWriter, value: Person): void { + __AlgebraicTypeValue.serializeValue( + writer, + Person.getTypeScriptAlgebraicType(), + value + ); + }, + + deserialize(reader: __BinaryReader): Person { + return __AlgebraicTypeValue.deserializeValue( + reader, + Person.getTypeScriptAlgebraicType() + ); + }, +}; + +export default Person; diff --git a/crates/bindings-typescript/examples/basic-react/src/module_bindings/say_hello_reducer.ts b/crates/bindings-typescript/examples/basic-react/src/module_bindings/say_hello_reducer.ts new file mode 100644 index 00000000000..e0cdd2d5259 --- /dev/null +++ b/crates/bindings-typescript/examples/basic-react/src/module_bindings/say_hello_reducer.ts @@ -0,0 +1,67 @@ +// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE +// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. + +/* eslint-disable */ +/* tslint:disable */ +import { + AlgebraicType as __AlgebraicTypeValue, + BinaryReader as __BinaryReader, + BinaryWriter as __BinaryWriter, + ClientCache as __ClientCache, + ConnectionId as __ConnectionId, + DbConnectionBuilder as __DbConnectionBuilder, + DbConnectionImpl as __DbConnectionImpl, + Identity as __Identity, + SubscriptionBuilderImpl as __SubscriptionBuilderImpl, + TableCache as __TableCache, + TimeDuration as __TimeDuration, + Timestamp as __Timestamp, + deepEqual as __deepEqual, + type AlgebraicType as __AlgebraicTypeType, + type AlgebraicTypeVariants as __AlgebraicTypeVariants, + type CallReducerFlags as __CallReducerFlags, + type ErrorContextInterface as __ErrorContextInterface, + type Event as __Event, + type EventContextInterface as __EventContextInterface, + type ReducerEventContextInterface as __ReducerEventContextInterface, + type SubscriptionEventContextInterface as __SubscriptionEventContextInterface, + type TableHandle as __TableHandle, +} from 'spacetimedb'; + +export type SayHello = {}; +let _cached_SayHello_type_value: __AlgebraicTypeType | null = null; + +/** + * An object for generated helper functions. + */ +export const SayHello = { + /** + * A function which returns this type represented as an AlgebraicType. + * This function is derived from the AlgebraicType used to generate this type. + */ + getTypeScriptAlgebraicType(): __AlgebraicTypeType { + if (_cached_SayHello_type_value) return _cached_SayHello_type_value; + _cached_SayHello_type_value = __AlgebraicTypeValue.Product({ + elements: [], + }); + _cached_SayHello_type_value.value.elements.push(); + return _cached_SayHello_type_value; + }, + + serialize(writer: __BinaryWriter, value: SayHello): void { + __AlgebraicTypeValue.serializeValue( + writer, + SayHello.getTypeScriptAlgebraicType(), + value + ); + }, + + deserialize(reader: __BinaryReader): SayHello { + return __AlgebraicTypeValue.deserializeValue( + reader, + SayHello.getTypeScriptAlgebraicType() + ); + }, +}; + +export default SayHello; diff --git a/crates/bindings-typescript/examples/basic-react/tsconfig.json b/crates/bindings-typescript/examples/basic-react/tsconfig.json index c7224f57541..46f00dbd6d1 100644 --- a/crates/bindings-typescript/examples/basic-react/tsconfig.json +++ b/crates/bindings-typescript/examples/basic-react/tsconfig.json @@ -3,6 +3,7 @@ "target": "ES2020", "useDefineForClassFields": true, "lib": ["ES2020", "DOM", "DOM.Iterable"], + "types": ["vite/client"], "module": "ESNext", "skipLibCheck": true, diff --git a/crates/bindings-typescript/examples/empty/package.json b/crates/bindings-typescript/examples/empty/package.json index 78d933bf832..eab974922a6 100644 --- a/crates/bindings-typescript/examples/empty/package.json +++ b/crates/bindings-typescript/examples/empty/package.json @@ -6,7 +6,11 @@ "scripts": { "dev": "vite", "build": "tsc && vite build", - "preview": "vite preview" + "preview": "vite preview", + "generate": "cargo run -p gen-bindings -- --out-dir src/module_bindings --project-path ../../../cli/templates/basic-typescript/server && prettier --write src/module_bindings", + "spacetime:generate": "spacetime generate --lang typescript --out-dir src/module_bindings --project-path spacetimedb", + "spacetime:publish:local": "spacetime publish --project-path server --server local", + "spacetime:publish": "spacetime publish --project-path server --server testnet" }, "dependencies": { "spacetimedb": "^1.5.0" diff --git a/crates/bindings-typescript/examples/empty/src/module_bindings/add_reducer.ts b/crates/bindings-typescript/examples/empty/src/module_bindings/add_reducer.ts new file mode 100644 index 00000000000..bc8fe325253 --- /dev/null +++ b/crates/bindings-typescript/examples/empty/src/module_bindings/add_reducer.ts @@ -0,0 +1,70 @@ +// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE +// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. + +/* eslint-disable */ +/* tslint:disable */ +import { + AlgebraicType as __AlgebraicTypeValue, + BinaryReader as __BinaryReader, + BinaryWriter as __BinaryWriter, + ClientCache as __ClientCache, + ConnectionId as __ConnectionId, + DbConnectionBuilder as __DbConnectionBuilder, + DbConnectionImpl as __DbConnectionImpl, + Identity as __Identity, + SubscriptionBuilderImpl as __SubscriptionBuilderImpl, + TableCache as __TableCache, + TimeDuration as __TimeDuration, + Timestamp as __Timestamp, + deepEqual as __deepEqual, + type AlgebraicType as __AlgebraicTypeType, + type AlgebraicTypeVariants as __AlgebraicTypeVariants, + type CallReducerFlags as __CallReducerFlags, + type ErrorContextInterface as __ErrorContextInterface, + type Event as __Event, + type EventContextInterface as __EventContextInterface, + type ReducerEventContextInterface as __ReducerEventContextInterface, + type SubscriptionEventContextInterface as __SubscriptionEventContextInterface, + type TableHandle as __TableHandle, +} from 'spacetimedb'; + +export type Add = { + name: string; +}; +let _cached_Add_type_value: __AlgebraicTypeType | null = null; + +/** + * An object for generated helper functions. + */ +export const Add = { + /** + * A function which returns this type represented as an AlgebraicType. + * This function is derived from the AlgebraicType used to generate this type. + */ + getTypeScriptAlgebraicType(): __AlgebraicTypeType { + if (_cached_Add_type_value) return _cached_Add_type_value; + _cached_Add_type_value = __AlgebraicTypeValue.Product({ elements: [] }); + _cached_Add_type_value.value.elements.push({ + name: 'name', + algebraicType: __AlgebraicTypeValue.String, + }); + return _cached_Add_type_value; + }, + + serialize(writer: __BinaryWriter, value: Add): void { + __AlgebraicTypeValue.serializeValue( + writer, + Add.getTypeScriptAlgebraicType(), + value + ); + }, + + deserialize(reader: __BinaryReader): Add { + return __AlgebraicTypeValue.deserializeValue( + reader, + Add.getTypeScriptAlgebraicType() + ); + }, +}; + +export default Add; diff --git a/crates/bindings-typescript/examples/empty/src/module_bindings/client_connected_reducer.ts b/crates/bindings-typescript/examples/empty/src/module_bindings/client_connected_reducer.ts new file mode 100644 index 00000000000..a8b7233cef8 --- /dev/null +++ b/crates/bindings-typescript/examples/empty/src/module_bindings/client_connected_reducer.ts @@ -0,0 +1,68 @@ +// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE +// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. + +/* eslint-disable */ +/* tslint:disable */ +import { + AlgebraicType as __AlgebraicTypeValue, + BinaryReader as __BinaryReader, + BinaryWriter as __BinaryWriter, + ClientCache as __ClientCache, + ConnectionId as __ConnectionId, + DbConnectionBuilder as __DbConnectionBuilder, + DbConnectionImpl as __DbConnectionImpl, + Identity as __Identity, + SubscriptionBuilderImpl as __SubscriptionBuilderImpl, + TableCache as __TableCache, + TimeDuration as __TimeDuration, + Timestamp as __Timestamp, + deepEqual as __deepEqual, + type AlgebraicType as __AlgebraicTypeType, + type AlgebraicTypeVariants as __AlgebraicTypeVariants, + type CallReducerFlags as __CallReducerFlags, + type ErrorContextInterface as __ErrorContextInterface, + type Event as __Event, + type EventContextInterface as __EventContextInterface, + type ReducerEventContextInterface as __ReducerEventContextInterface, + type SubscriptionEventContextInterface as __SubscriptionEventContextInterface, + type TableHandle as __TableHandle, +} from 'spacetimedb'; + +export type ClientConnected = {}; +let _cached_ClientConnected_type_value: __AlgebraicTypeType | null = null; + +/** + * An object for generated helper functions. + */ +export const ClientConnected = { + /** + * A function which returns this type represented as an AlgebraicType. + * This function is derived from the AlgebraicType used to generate this type. + */ + getTypeScriptAlgebraicType(): __AlgebraicTypeType { + if (_cached_ClientConnected_type_value) + return _cached_ClientConnected_type_value; + _cached_ClientConnected_type_value = __AlgebraicTypeValue.Product({ + elements: [], + }); + _cached_ClientConnected_type_value.value.elements.push(); + return _cached_ClientConnected_type_value; + }, + + serialize(writer: __BinaryWriter, value: ClientConnected): void { + __AlgebraicTypeValue.serializeValue( + writer, + ClientConnected.getTypeScriptAlgebraicType(), + value + ); + }, + + deserialize(reader: __BinaryReader): ClientConnected { + return __AlgebraicTypeValue.deserializeValue( + reader, + ClientConnected.getTypeScriptAlgebraicType() + ); + }, +}; + +export default ClientConnected; diff --git a/crates/bindings-typescript/examples/empty/src/module_bindings/client_disconnected_reducer.ts b/crates/bindings-typescript/examples/empty/src/module_bindings/client_disconnected_reducer.ts new file mode 100644 index 00000000000..385acd9bd3c --- /dev/null +++ b/crates/bindings-typescript/examples/empty/src/module_bindings/client_disconnected_reducer.ts @@ -0,0 +1,68 @@ +// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE +// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. + +/* eslint-disable */ +/* tslint:disable */ +import { + AlgebraicType as __AlgebraicTypeValue, + BinaryReader as __BinaryReader, + BinaryWriter as __BinaryWriter, + ClientCache as __ClientCache, + ConnectionId as __ConnectionId, + DbConnectionBuilder as __DbConnectionBuilder, + DbConnectionImpl as __DbConnectionImpl, + Identity as __Identity, + SubscriptionBuilderImpl as __SubscriptionBuilderImpl, + TableCache as __TableCache, + TimeDuration as __TimeDuration, + Timestamp as __Timestamp, + deepEqual as __deepEqual, + type AlgebraicType as __AlgebraicTypeType, + type AlgebraicTypeVariants as __AlgebraicTypeVariants, + type CallReducerFlags as __CallReducerFlags, + type ErrorContextInterface as __ErrorContextInterface, + type Event as __Event, + type EventContextInterface as __EventContextInterface, + type ReducerEventContextInterface as __ReducerEventContextInterface, + type SubscriptionEventContextInterface as __SubscriptionEventContextInterface, + type TableHandle as __TableHandle, +} from 'spacetimedb'; + +export type ClientDisconnected = {}; +let _cached_ClientDisconnected_type_value: __AlgebraicTypeType | null = null; + +/** + * An object for generated helper functions. + */ +export const ClientDisconnected = { + /** + * A function which returns this type represented as an AlgebraicType. + * This function is derived from the AlgebraicType used to generate this type. + */ + getTypeScriptAlgebraicType(): __AlgebraicTypeType { + if (_cached_ClientDisconnected_type_value) + return _cached_ClientDisconnected_type_value; + _cached_ClientDisconnected_type_value = __AlgebraicTypeValue.Product({ + elements: [], + }); + _cached_ClientDisconnected_type_value.value.elements.push(); + return _cached_ClientDisconnected_type_value; + }, + + serialize(writer: __BinaryWriter, value: ClientDisconnected): void { + __AlgebraicTypeValue.serializeValue( + writer, + ClientDisconnected.getTypeScriptAlgebraicType(), + value + ); + }, + + deserialize(reader: __BinaryReader): ClientDisconnected { + return __AlgebraicTypeValue.deserializeValue( + reader, + ClientDisconnected.getTypeScriptAlgebraicType() + ); + }, +}; + +export default ClientDisconnected; diff --git a/crates/bindings-typescript/examples/empty/src/module_bindings/index.ts b/crates/bindings-typescript/examples/empty/src/module_bindings/index.ts new file mode 100644 index 00000000000..08fef081923 --- /dev/null +++ b/crates/bindings-typescript/examples/empty/src/module_bindings/index.ts @@ -0,0 +1,303 @@ +// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE +// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. + +// This was generated using spacetimedb cli version 1.6.0 (commit 64812908d1dd2fb0ac1a44ae8c669306ce3f001e). + +/* eslint-disable */ +/* tslint:disable */ +import { + AlgebraicType as __AlgebraicTypeValue, + BinaryReader as __BinaryReader, + BinaryWriter as __BinaryWriter, + ClientCache as __ClientCache, + ConnectionId as __ConnectionId, + DbConnectionBuilder as __DbConnectionBuilder, + DbConnectionImpl as __DbConnectionImpl, + Identity as __Identity, + SubscriptionBuilderImpl as __SubscriptionBuilderImpl, + TableCache as __TableCache, + TimeDuration as __TimeDuration, + Timestamp as __Timestamp, + deepEqual as __deepEqual, + type AlgebraicType as __AlgebraicTypeType, + type AlgebraicTypeVariants as __AlgebraicTypeVariants, + type CallReducerFlags as __CallReducerFlags, + type ErrorContextInterface as __ErrorContextInterface, + type Event as __Event, + type EventContextInterface as __EventContextInterface, + type ReducerEventContextInterface as __ReducerEventContextInterface, + type SubscriptionEventContextInterface as __SubscriptionEventContextInterface, + type TableHandle as __TableHandle, +} from 'spacetimedb'; + +// Import and reexport all reducer arg types +import { Init } from './init_reducer.ts'; +export { Init }; +import { ClientConnected } from './client_connected_reducer.ts'; +export { ClientConnected }; +import { ClientDisconnected } from './client_disconnected_reducer.ts'; +export { ClientDisconnected }; +import { Add } from './add_reducer.ts'; +export { Add }; +import { SayHello } from './say_hello_reducer.ts'; +export { SayHello }; + +// Import and reexport all table handle types +import { PersonTableHandle } from './person_table.ts'; +export { PersonTableHandle }; + +// Import and reexport all types +import { Person } from './person_type.ts'; +export { Person }; + +const REMOTE_MODULE = { + tables: { + person: { + tableName: 'person' as const, + rowType: Person.getTypeScriptAlgebraicType(), + }, + }, + reducers: { + init: { + reducerName: 'init', + argsType: Init.getTypeScriptAlgebraicType(), + }, + client_connected: { + reducerName: 'client_connected', + argsType: ClientConnected.getTypeScriptAlgebraicType(), + }, + client_disconnected: { + reducerName: 'client_disconnected', + argsType: ClientDisconnected.getTypeScriptAlgebraicType(), + }, + add: { + reducerName: 'add', + argsType: Add.getTypeScriptAlgebraicType(), + }, + say_hello: { + reducerName: 'say_hello', + argsType: SayHello.getTypeScriptAlgebraicType(), + }, + }, + versionInfo: { + cliVersion: '1.6.0', + }, + // Constructors which are used by the DbConnectionImpl to + // extract type information from the generated RemoteModule. + // + // NOTE: This is not strictly necessary for `eventContextConstructor` because + // all we do is build a TypeScript object which we could have done inside the + // SDK, but if in the future we wanted to create a class this would be + // necessary because classes have methods, so we'll keep it. + eventContextConstructor: ( + imp: __DbConnectionImpl, + event: __Event + ) => { + return { + ...(imp as DbConnection), + event, + }; + }, + dbViewConstructor: (imp: __DbConnectionImpl) => { + return new RemoteTables(imp); + }, + reducersConstructor: ( + imp: __DbConnectionImpl, + setReducerFlags: SetReducerFlags + ) => { + return new RemoteReducers(imp, setReducerFlags); + }, + setReducerFlagsConstructor: () => { + return new SetReducerFlags(); + }, +}; + +// A type representing all the possible variants of a reducer. +export type Reducer = + | never + | { name: 'Init'; args: Init } + | { name: 'ClientConnected'; args: ClientConnected } + | { name: 'ClientDisconnected'; args: ClientDisconnected } + | { name: 'Add'; args: Add } + | { name: 'SayHello'; args: SayHello }; + +export class RemoteReducers { + constructor( + private connection: __DbConnectionImpl, + private setCallReducerFlags: SetReducerFlags + ) {} + + init() { + this.connection.callReducer( + 'init', + new Uint8Array(0), + this.setCallReducerFlags.initFlags + ); + } + + onInit(callback: (ctx: ReducerEventContext) => void) { + this.connection.onReducer('init', callback); + } + + removeOnInit(callback: (ctx: ReducerEventContext) => void) { + this.connection.offReducer('init', callback); + } + + clientConnected() { + this.connection.callReducer( + 'client_connected', + new Uint8Array(0), + this.setCallReducerFlags.clientConnectedFlags + ); + } + + onClientConnected(callback: (ctx: ReducerEventContext) => void) { + this.connection.onReducer('client_connected', callback); + } + + removeOnClientConnected(callback: (ctx: ReducerEventContext) => void) { + this.connection.offReducer('client_connected', callback); + } + + clientDisconnected() { + this.connection.callReducer( + 'client_disconnected', + new Uint8Array(0), + this.setCallReducerFlags.clientDisconnectedFlags + ); + } + + onClientDisconnected(callback: (ctx: ReducerEventContext) => void) { + this.connection.onReducer('client_disconnected', callback); + } + + removeOnClientDisconnected(callback: (ctx: ReducerEventContext) => void) { + this.connection.offReducer('client_disconnected', callback); + } + + add(name: string) { + const __args = { name }; + let __writer = new __BinaryWriter(1024); + Add.serialize(__writer, __args); + let __argsBuffer = __writer.getBuffer(); + this.connection.callReducer( + 'add', + __argsBuffer, + this.setCallReducerFlags.addFlags + ); + } + + onAdd(callback: (ctx: ReducerEventContext, name: string) => void) { + this.connection.onReducer('add', callback); + } + + removeOnAdd(callback: (ctx: ReducerEventContext, name: string) => void) { + this.connection.offReducer('add', callback); + } + + sayHello() { + this.connection.callReducer( + 'say_hello', + new Uint8Array(0), + this.setCallReducerFlags.sayHelloFlags + ); + } + + onSayHello(callback: (ctx: ReducerEventContext) => void) { + this.connection.onReducer('say_hello', callback); + } + + removeOnSayHello(callback: (ctx: ReducerEventContext) => void) { + this.connection.offReducer('say_hello', callback); + } +} + +export class SetReducerFlags { + initFlags: __CallReducerFlags = 'FullUpdate'; + init(flags: __CallReducerFlags) { + this.initFlags = flags; + } + + clientConnectedFlags: __CallReducerFlags = 'FullUpdate'; + clientConnected(flags: __CallReducerFlags) { + this.clientConnectedFlags = flags; + } + + clientDisconnectedFlags: __CallReducerFlags = 'FullUpdate'; + clientDisconnected(flags: __CallReducerFlags) { + this.clientDisconnectedFlags = flags; + } + + addFlags: __CallReducerFlags = 'FullUpdate'; + add(flags: __CallReducerFlags) { + this.addFlags = flags; + } + + sayHelloFlags: __CallReducerFlags = 'FullUpdate'; + sayHello(flags: __CallReducerFlags) { + this.sayHelloFlags = flags; + } +} + +export class RemoteTables { + constructor(private connection: __DbConnectionImpl) {} + + get person(): PersonTableHandle<'person'> { + // clientCache is a private property + return new PersonTableHandle( + ( + this.connection as unknown as { clientCache: __ClientCache } + ).clientCache.getOrCreateTable(REMOTE_MODULE.tables.person) + ); + } +} + +export class SubscriptionBuilder extends __SubscriptionBuilderImpl< + RemoteTables, + RemoteReducers, + SetReducerFlags +> {} + +export class DbConnection extends __DbConnectionImpl< + RemoteTables, + RemoteReducers, + SetReducerFlags +> { + static builder = (): __DbConnectionBuilder< + DbConnection, + ErrorContext, + SubscriptionEventContext + > => { + return new __DbConnectionBuilder< + DbConnection, + ErrorContext, + SubscriptionEventContext + >(REMOTE_MODULE, (imp: __DbConnectionImpl) => imp as DbConnection); + }; + subscriptionBuilder = (): SubscriptionBuilder => { + return new SubscriptionBuilder(this); + }; +} + +export type EventContext = __EventContextInterface< + RemoteTables, + RemoteReducers, + SetReducerFlags, + Reducer +>; +export type ReducerEventContext = __ReducerEventContextInterface< + RemoteTables, + RemoteReducers, + SetReducerFlags, + Reducer +>; +export type SubscriptionEventContext = __SubscriptionEventContextInterface< + RemoteTables, + RemoteReducers, + SetReducerFlags +>; +export type ErrorContext = __ErrorContextInterface< + RemoteTables, + RemoteReducers, + SetReducerFlags +>; diff --git a/crates/bindings-typescript/examples/empty/src/module_bindings/init_reducer.ts b/crates/bindings-typescript/examples/empty/src/module_bindings/init_reducer.ts new file mode 100644 index 00000000000..12e0782fc1a --- /dev/null +++ b/crates/bindings-typescript/examples/empty/src/module_bindings/init_reducer.ts @@ -0,0 +1,65 @@ +// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE +// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. + +/* eslint-disable */ +/* tslint:disable */ +import { + AlgebraicType as __AlgebraicTypeValue, + BinaryReader as __BinaryReader, + BinaryWriter as __BinaryWriter, + ClientCache as __ClientCache, + ConnectionId as __ConnectionId, + DbConnectionBuilder as __DbConnectionBuilder, + DbConnectionImpl as __DbConnectionImpl, + Identity as __Identity, + SubscriptionBuilderImpl as __SubscriptionBuilderImpl, + TableCache as __TableCache, + TimeDuration as __TimeDuration, + Timestamp as __Timestamp, + deepEqual as __deepEqual, + type AlgebraicType as __AlgebraicTypeType, + type AlgebraicTypeVariants as __AlgebraicTypeVariants, + type CallReducerFlags as __CallReducerFlags, + type ErrorContextInterface as __ErrorContextInterface, + type Event as __Event, + type EventContextInterface as __EventContextInterface, + type ReducerEventContextInterface as __ReducerEventContextInterface, + type SubscriptionEventContextInterface as __SubscriptionEventContextInterface, + type TableHandle as __TableHandle, +} from 'spacetimedb'; + +export type Init = {}; +let _cached_Init_type_value: __AlgebraicTypeType | null = null; + +/** + * An object for generated helper functions. + */ +export const Init = { + /** + * A function which returns this type represented as an AlgebraicType. + * This function is derived from the AlgebraicType used to generate this type. + */ + getTypeScriptAlgebraicType(): __AlgebraicTypeType { + if (_cached_Init_type_value) return _cached_Init_type_value; + _cached_Init_type_value = __AlgebraicTypeValue.Product({ elements: [] }); + _cached_Init_type_value.value.elements.push(); + return _cached_Init_type_value; + }, + + serialize(writer: __BinaryWriter, value: Init): void { + __AlgebraicTypeValue.serializeValue( + writer, + Init.getTypeScriptAlgebraicType(), + value + ); + }, + + deserialize(reader: __BinaryReader): Init { + return __AlgebraicTypeValue.deserializeValue( + reader, + Init.getTypeScriptAlgebraicType() + ); + }, +}; + +export default Init; diff --git a/crates/bindings-typescript/examples/empty/src/module_bindings/person_table.ts b/crates/bindings-typescript/examples/empty/src/module_bindings/person_table.ts new file mode 100644 index 00000000000..c50f51f9ff0 --- /dev/null +++ b/crates/bindings-typescript/examples/empty/src/module_bindings/person_table.ts @@ -0,0 +1,83 @@ +// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE +// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. + +/* eslint-disable */ +/* tslint:disable */ +import { + AlgebraicType as __AlgebraicTypeValue, + BinaryReader as __BinaryReader, + BinaryWriter as __BinaryWriter, + ClientCache as __ClientCache, + ConnectionId as __ConnectionId, + DbConnectionBuilder as __DbConnectionBuilder, + DbConnectionImpl as __DbConnectionImpl, + Identity as __Identity, + SubscriptionBuilderImpl as __SubscriptionBuilderImpl, + TableCache as __TableCache, + TimeDuration as __TimeDuration, + Timestamp as __Timestamp, + deepEqual as __deepEqual, + type AlgebraicType as __AlgebraicTypeType, + type AlgebraicTypeVariants as __AlgebraicTypeVariants, + type CallReducerFlags as __CallReducerFlags, + type ErrorContextInterface as __ErrorContextInterface, + type Event as __Event, + type EventContextInterface as __EventContextInterface, + type ReducerEventContextInterface as __ReducerEventContextInterface, + type SubscriptionEventContextInterface as __SubscriptionEventContextInterface, + type TableHandle as __TableHandle, +} from 'spacetimedb'; +import { Person } from './person_type'; +import { + type EventContext, + type Reducer, + RemoteReducers, + RemoteTables, +} from '.'; +declare type __keep = [EventContext, Reducer, RemoteReducers, RemoteTables]; + +/** + * Table handle for the table `person`. + * + * Obtain a handle from the [`person`] property on [`RemoteTables`], + * like `ctx.db.person`. + * + * Users are encouraged not to explicitly reference this type, + * but to directly chain method calls, + * like `ctx.db.person.on_insert(...)`. + */ +export class PersonTableHandle + implements __TableHandle +{ + // phantom type to track the table name + readonly tableName!: TableName; + tableCache: __TableCache; + + constructor(tableCache: __TableCache) { + this.tableCache = tableCache; + } + + count(): number { + return this.tableCache.count(); + } + + iter(): Iterable { + return this.tableCache.iter(); + } + + onInsert = (cb: (ctx: EventContext, row: Person) => void) => { + return this.tableCache.onInsert(cb); + }; + + removeOnInsert = (cb: (ctx: EventContext, row: Person) => void) => { + return this.tableCache.removeOnInsert(cb); + }; + + onDelete = (cb: (ctx: EventContext, row: Person) => void) => { + return this.tableCache.onDelete(cb); + }; + + removeOnDelete = (cb: (ctx: EventContext, row: Person) => void) => { + return this.tableCache.removeOnDelete(cb); + }; +} diff --git a/crates/bindings-typescript/examples/empty/src/module_bindings/person_type.ts b/crates/bindings-typescript/examples/empty/src/module_bindings/person_type.ts new file mode 100644 index 00000000000..c3085f4f3ba --- /dev/null +++ b/crates/bindings-typescript/examples/empty/src/module_bindings/person_type.ts @@ -0,0 +1,70 @@ +// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE +// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. + +/* eslint-disable */ +/* tslint:disable */ +import { + AlgebraicType as __AlgebraicTypeValue, + BinaryReader as __BinaryReader, + BinaryWriter as __BinaryWriter, + ClientCache as __ClientCache, + ConnectionId as __ConnectionId, + DbConnectionBuilder as __DbConnectionBuilder, + DbConnectionImpl as __DbConnectionImpl, + Identity as __Identity, + SubscriptionBuilderImpl as __SubscriptionBuilderImpl, + TableCache as __TableCache, + TimeDuration as __TimeDuration, + Timestamp as __Timestamp, + deepEqual as __deepEqual, + type AlgebraicType as __AlgebraicTypeType, + type AlgebraicTypeVariants as __AlgebraicTypeVariants, + type CallReducerFlags as __CallReducerFlags, + type ErrorContextInterface as __ErrorContextInterface, + type Event as __Event, + type EventContextInterface as __EventContextInterface, + type ReducerEventContextInterface as __ReducerEventContextInterface, + type SubscriptionEventContextInterface as __SubscriptionEventContextInterface, + type TableHandle as __TableHandle, +} from 'spacetimedb'; + +export type Person = { + name: string; +}; +let _cached_Person_type_value: __AlgebraicTypeType | null = null; + +/** + * An object for generated helper functions. + */ +export const Person = { + /** + * A function which returns this type represented as an AlgebraicType. + * This function is derived from the AlgebraicType used to generate this type. + */ + getTypeScriptAlgebraicType(): __AlgebraicTypeType { + if (_cached_Person_type_value) return _cached_Person_type_value; + _cached_Person_type_value = __AlgebraicTypeValue.Product({ elements: [] }); + _cached_Person_type_value.value.elements.push({ + name: 'name', + algebraicType: __AlgebraicTypeValue.String, + }); + return _cached_Person_type_value; + }, + + serialize(writer: __BinaryWriter, value: Person): void { + __AlgebraicTypeValue.serializeValue( + writer, + Person.getTypeScriptAlgebraicType(), + value + ); + }, + + deserialize(reader: __BinaryReader): Person { + return __AlgebraicTypeValue.deserializeValue( + reader, + Person.getTypeScriptAlgebraicType() + ); + }, +}; + +export default Person; diff --git a/crates/bindings-typescript/examples/empty/src/module_bindings/say_hello_reducer.ts b/crates/bindings-typescript/examples/empty/src/module_bindings/say_hello_reducer.ts new file mode 100644 index 00000000000..e0cdd2d5259 --- /dev/null +++ b/crates/bindings-typescript/examples/empty/src/module_bindings/say_hello_reducer.ts @@ -0,0 +1,67 @@ +// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE +// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. + +/* eslint-disable */ +/* tslint:disable */ +import { + AlgebraicType as __AlgebraicTypeValue, + BinaryReader as __BinaryReader, + BinaryWriter as __BinaryWriter, + ClientCache as __ClientCache, + ConnectionId as __ConnectionId, + DbConnectionBuilder as __DbConnectionBuilder, + DbConnectionImpl as __DbConnectionImpl, + Identity as __Identity, + SubscriptionBuilderImpl as __SubscriptionBuilderImpl, + TableCache as __TableCache, + TimeDuration as __TimeDuration, + Timestamp as __Timestamp, + deepEqual as __deepEqual, + type AlgebraicType as __AlgebraicTypeType, + type AlgebraicTypeVariants as __AlgebraicTypeVariants, + type CallReducerFlags as __CallReducerFlags, + type ErrorContextInterface as __ErrorContextInterface, + type Event as __Event, + type EventContextInterface as __EventContextInterface, + type ReducerEventContextInterface as __ReducerEventContextInterface, + type SubscriptionEventContextInterface as __SubscriptionEventContextInterface, + type TableHandle as __TableHandle, +} from 'spacetimedb'; + +export type SayHello = {}; +let _cached_SayHello_type_value: __AlgebraicTypeType | null = null; + +/** + * An object for generated helper functions. + */ +export const SayHello = { + /** + * A function which returns this type represented as an AlgebraicType. + * This function is derived from the AlgebraicType used to generate this type. + */ + getTypeScriptAlgebraicType(): __AlgebraicTypeType { + if (_cached_SayHello_type_value) return _cached_SayHello_type_value; + _cached_SayHello_type_value = __AlgebraicTypeValue.Product({ + elements: [], + }); + _cached_SayHello_type_value.value.elements.push(); + return _cached_SayHello_type_value; + }, + + serialize(writer: __BinaryWriter, value: SayHello): void { + __AlgebraicTypeValue.serializeValue( + writer, + SayHello.getTypeScriptAlgebraicType(), + value + ); + }, + + deserialize(reader: __BinaryReader): SayHello { + return __AlgebraicTypeValue.deserializeValue( + reader, + SayHello.getTypeScriptAlgebraicType() + ); + }, +}; + +export default SayHello; diff --git a/crates/bindings-typescript/examples/quickstart-chat/package.json b/crates/bindings-typescript/examples/quickstart-chat/package.json index 3de530f9985..26f0de419cf 100644 --- a/crates/bindings-typescript/examples/quickstart-chat/package.json +++ b/crates/bindings-typescript/examples/quickstart-chat/package.json @@ -10,10 +10,10 @@ "lint": "eslint . && prettier . --check --ignore-path ../../../../.prettierignore", "preview": "vite preview", "test": "vitest run", - "generate": "cargo build -p spacetimedb-standalone && cargo run -p spacetimedb-cli generate --lang typescript --out-dir src/module_bindings --project-path ../../../../modules/quickstart-chat && prettier --write src/module_bindings", - "spacetime:generate": "spacetime generate --lang typescript --out-dir src/module_bindings --project-path server", - "spacetime:publish:local": "spacetime publish chat --project-path server --server local", - "spacetime:publish": "spacetime publish chat --project-path server --server testnet" + "generate": "cargo run -p gen-bindings -- --out-dir src/module_bindings --project-path ../../../../modules/quickstart-chat && prettier --write src/module_bindings", + "spacetime:generate": "spacetime generate --lang typescript --out-dir src/module_bindings --project-path spacetimedb", + "spacetime:publish:local": "spacetime publish --project-path server --server local", + "spacetime:publish": "spacetime publish --project-path server --server testnet" }, "dependencies": { "spacetimedb": "workspace:*", diff --git a/crates/bindings-typescript/examples/quickstart-chat/src/module_bindings/index.ts b/crates/bindings-typescript/examples/quickstart-chat/src/module_bindings/index.ts index f74aad067dc..a7794856485 100644 --- a/crates/bindings-typescript/examples/quickstart-chat/src/module_bindings/index.ts +++ b/crates/bindings-typescript/examples/quickstart-chat/src/module_bindings/index.ts @@ -1,7 +1,7 @@ // THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE // WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. -// This was generated using spacetimedb cli version 1.5.0 (commit 5bfc84351742a6a8dc717b6c0011946f2d1b632d). +// This was generated using spacetimedb cli version 1.6.0 (commit 64812908d1dd2fb0ac1a44ae8c669306ce3f001e). /* eslint-disable */ /* tslint:disable */ diff --git a/crates/bindings-typescript/examples/quickstart-chat/src/vite-env.d.ts b/crates/bindings-typescript/examples/quickstart-chat/src/vite-env.d.ts deleted file mode 100644 index 11f02fe2a00..00000000000 --- a/crates/bindings-typescript/examples/quickstart-chat/src/vite-env.d.ts +++ /dev/null @@ -1 +0,0 @@ -/// diff --git a/crates/bindings-typescript/examples/quickstart-chat/tsconfig.app.json b/crates/bindings-typescript/examples/quickstart-chat/tsconfig.app.json index 2934471320f..11b9d355b80 100644 --- a/crates/bindings-typescript/examples/quickstart-chat/tsconfig.app.json +++ b/crates/bindings-typescript/examples/quickstart-chat/tsconfig.app.json @@ -4,6 +4,7 @@ "target": "ES2020", "useDefineForClassFields": true, "lib": ["ES2020", "DOM", "DOM.Iterable"], + "types": ["vite/client"], "module": "ESNext", "skipLibCheck": true, diff --git a/crates/bindings-typescript/package.json b/crates/bindings-typescript/package.json index 74217fac8e8..aae8b211f6d 100644 --- a/crates/bindings-typescript/package.json +++ b/crates/bindings-typescript/package.json @@ -34,9 +34,12 @@ "brotli-size": "brotli-size dist/index.js", "size": "pnpm -s build && size-limit", "generate:moduledef": "cargo run -p spacetimedb-codegen --example regen-typescript-moduledef && prettier --write src/lib/autogen", - "generate:client-api": "cargo build -p spacetimedb-standalone && cargo run -p spacetimedb-client-api-messages --example get_ws_schema > ws_schema.json && cargo run -p spacetimedb-cli generate --lang typescript --out-dir src/sdk/client_api --module-def ws_schema.json && rm ws_schema.json && find src/sdk/client_api -type f -exec perl -pi -e 's#spacetimedb#../../index#g' {} + && prettier --write src/sdk/client_api", + "generate:client-api": "cargo run -p generate-client-api && prettier --write src/sdk/client_api", "generate:test-app": "pnpm --filter @clockworklabs/test-app generate", - "generate": "pnpm generate:moduledef && pnpm generate:client-api && pnpm generate:test-app", + "generate:examples:quickstart-chat": "pnpm --filter @clockworklabs/quickstart-chat generate", + "generate:examples:basic-react": "pnpm --filter @clockworklabs/basic-react generate", + "generate:examples:empty": "pnpm --filter @clockworklabs/empty-client generate", + "generate": "pnpm generate:moduledef && pnpm generate:client-api && pnpm generate:test-app && pnpm generate:examples:quickstart-chat && pnpm generate:examples:basic-react && pnpm generate:examples:empty", "prepublishOnly": "pnpm run build && pnpm run test && pnpm run size" }, "main": "dist/index.cjs", diff --git a/crates/bindings-typescript/src/sdk/client_api/index.ts b/crates/bindings-typescript/src/sdk/client_api/index.ts index 8548380f1dd..97687590999 100644 --- a/crates/bindings-typescript/src/sdk/client_api/index.ts +++ b/crates/bindings-typescript/src/sdk/client_api/index.ts @@ -107,7 +107,11 @@ const reducersSchema = __reducers(); const REMOTE_MODULE = { versionInfo: { +<<<<<<< HEAD cliVersion: '1.7.0' as const, +======= + cliVersion: '1.6.0', +>>>>>>> 6d91ae0f5 (Now generating module_bindings for examples and also moved pnpm scripts into portable rust scripts) }, tables: tablesSchema.schemaType.tables, reducers: reducersSchema.reducersType.reducers, diff --git a/crates/bindings-typescript/test-app/package.json b/crates/bindings-typescript/test-app/package.json index ea7805f3deb..28c8f27673e 100644 --- a/crates/bindings-typescript/test-app/package.json +++ b/crates/bindings-typescript/test-app/package.json @@ -12,7 +12,7 @@ "format": "prettier . --write --ignore-path ../../../.prettierignore", "lint": "eslint . && prettier . --check --ignore-path ../../../.prettierignore", "preview": "vite preview", - "generate": "cargo build -p spacetimedb-standalone && cargo run -p spacetimedb-cli generate --lang typescript --out-dir src/module_bindings --project-path server && prettier --write src/module_bindings && node ./replace-spacetimedb.js && prettier --write src/module_bindings", + "generate": "cargo run -p gen-bindings -- --replacement ../../../src/index && prettier --write src/module_bindings", "spacetime:generate": "spacetime generate --lang typescript --out-dir src/module_bindings --project-path server", "spacetime:start": "spacetime start server", "spacetime:publish:local": "spacetime publish game --project-path server --server local", diff --git a/crates/bindings-typescript/test-app/replace-spacetimedb.js b/crates/bindings-typescript/test-app/replace-spacetimedb.js deleted file mode 100644 index e5e6329ccad..00000000000 --- a/crates/bindings-typescript/test-app/replace-spacetimedb.js +++ /dev/null @@ -1,38 +0,0 @@ -#!/usr/bin/env node - -/** - * Cross-platform replacement script - * Equivalent to: - * find src/module_bindings -type f -exec perl -pi -e 's#spacetimedb#../../../src/index#g' {} - */ - -import fs from 'fs'; -import path from 'path'; - -const ROOT = path.resolve('src/module_bindings'); -const SEARCH = /spacetimedb/g; -const REPLACEMENT = '../../../src/index'; - -function replaceInFile(filePath) { - try { - let content = fs.readFileSync(filePath, 'utf8'); - if (SEARCH.test(content)) { - const updated = content.replace(SEARCH, REPLACEMENT); - fs.writeFileSync(filePath, updated, 'utf8'); - console.log(`✔ Updated: ${filePath}`); - } - } catch (err) { - console.error(`✖ Error processing ${filePath}:`, err); - } -} - -function walkDir(dir) { - for (const entry of fs.readdirSync(dir, { withFileTypes: true })) { - const fullPath = path.join(dir, entry.name); - if (entry.isDirectory()) walkDir(fullPath); - else if (entry.isFile()) replaceInFile(fullPath); - } -} - -walkDir(ROOT); -console.log('✅ Replacement complete.'); diff --git a/crates/bindings-typescript/test-app/src/module_bindings/index.ts b/crates/bindings-typescript/test-app/src/module_bindings/index.ts index 2f42fe19a15..bf9be8260c8 100644 --- a/crates/bindings-typescript/test-app/src/module_bindings/index.ts +++ b/crates/bindings-typescript/test-app/src/module_bindings/index.ts @@ -1,7 +1,11 @@ // THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE // WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. +<<<<<<< HEAD // This was generated using ../../../src/index cli version 1.7.0 (commit 57bd49bec937a3ae060c1c9af85979525fdb839d). +======= +// This was generated using spacetimedb cli version 1.6.0 (commit 64812908d1dd2fb0ac1a44ae8c669306ce3f001e). +>>>>>>> 6d91ae0f5 (Now generating module_bindings for examples and also moved pnpm scripts into portable rust scripts) /* eslint-disable */ /* tslint:disable */ diff --git a/crates/bindings-typescript/test-react-router-app/package.json b/crates/bindings-typescript/test-react-router-app/package.json index 235f719db0e..5372e67cbfe 100644 --- a/crates/bindings-typescript/test-react-router-app/package.json +++ b/crates/bindings-typescript/test-react-router-app/package.json @@ -12,7 +12,7 @@ "format": "prettier . --write --ignore-path ../../../.prettierignore", "lint": "eslint . && prettier . --check --ignore-path ../../../.prettierignore", "preview": "vite preview", - "generate": "cargo build -p spacetimedb-standalone && cargo run -p spacetimedb-cli generate --lang typescript --out-dir src/module_bindings --project-path server && prettier --write src/module_bindings && node ./replace-spacetimedb.js && prettier --write src/module_bindings", + "generate": "cargo run -p gen-bindings -- --replacement ../../../src/index && prettier --write src/module_bindings", "spacetime:generate": "spacetime generate --lang typescript --out-dir src/module_bindings --project-path server", "spacetime:start": "spacetime start server", "spacetime:publish:local": "spacetime publish game --project-path server --server local", diff --git a/crates/bindings-typescript/test-react-router-app/replace-spacetimedb.js b/crates/bindings-typescript/test-react-router-app/replace-spacetimedb.js deleted file mode 100644 index e5e6329ccad..00000000000 --- a/crates/bindings-typescript/test-react-router-app/replace-spacetimedb.js +++ /dev/null @@ -1,38 +0,0 @@ -#!/usr/bin/env node - -/** - * Cross-platform replacement script - * Equivalent to: - * find src/module_bindings -type f -exec perl -pi -e 's#spacetimedb#../../../src/index#g' {} - */ - -import fs from 'fs'; -import path from 'path'; - -const ROOT = path.resolve('src/module_bindings'); -const SEARCH = /spacetimedb/g; -const REPLACEMENT = '../../../src/index'; - -function replaceInFile(filePath) { - try { - let content = fs.readFileSync(filePath, 'utf8'); - if (SEARCH.test(content)) { - const updated = content.replace(SEARCH, REPLACEMENT); - fs.writeFileSync(filePath, updated, 'utf8'); - console.log(`✔ Updated: ${filePath}`); - } - } catch (err) { - console.error(`✖ Error processing ${filePath}:`, err); - } -} - -function walkDir(dir) { - for (const entry of fs.readdirSync(dir, { withFileTypes: true })) { - const fullPath = path.join(dir, entry.name); - if (entry.isDirectory()) walkDir(fullPath); - else if (entry.isFile()) replaceInFile(fullPath); - } -} - -walkDir(ROOT); -console.log('✅ Replacement complete.'); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 97fbd3cc06f..f153d17db74 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -115,6 +115,47 @@ importers: specifier: ^3.2.4 version: 3.2.4(@types/debug@4.1.12)(@types/node@24.3.0)(jiti@2.5.1)(jsdom@26.1.0)(terser@5.43.1)(tsx@4.20.4) + crates/bindings-typescript/examples/basic-react: + dependencies: + react: + specifier: ^18.3.1 + version: 18.3.1 + react-dom: + specifier: ^18.3.1 + version: 18.3.1(react@18.3.1) + spacetimedb: + specifier: workspace:* + version: link:../.. + devDependencies: + '@types/react': + specifier: ^18.3.18 + version: 18.3.23 + '@types/react-dom': + specifier: ^18.3.5 + version: 18.3.7(@types/react@18.3.23) + '@vitejs/plugin-react': + specifier: ^5.0.2 + version: 5.0.2(vite@7.1.5(@types/node@24.3.0)(jiti@2.5.1)(terser@5.43.1)(tsx@4.20.4)) + typescript: + specifier: ~5.6.2 + version: 5.6.3 + vite: + specifier: ^7.1.5 + version: 7.1.5(@types/node@24.3.0)(jiti@2.5.1)(terser@5.43.1)(tsx@4.20.4) + + crates/bindings-typescript/examples/empty: + dependencies: + spacetimedb: + specifier: ^1.5.0 + version: 1.6.2(react@19.2.0)(undici@6.21.3) + devDependencies: + typescript: + specifier: ~5.6.2 + version: 5.6.3 + vite: + specifier: ^7.1.5 + version: 7.1.5(@types/node@24.3.0)(jiti@2.5.1)(terser@5.43.1)(tsx@4.20.4) + crates/bindings-typescript/examples/quickstart-chat: dependencies: react: @@ -7947,6 +7988,17 @@ packages: space-separated-tokens@2.0.2: resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==} + spacetimedb@1.6.2: + resolution: {integrity: sha512-XOdIgnTT1j2wZNiPdEIiv9uzhpnbqO0Rk/kOxVA9XhMMmrbtS3bXduBf1MzcaS/gJzXFK+Tf27j1HVa5SNbhLQ==} + peerDependencies: + react: ^18.0.0 || ^19.0.0-0 || ^19.0.0 + undici: ^6.19.2 + peerDependenciesMeta: + react: + optional: true + undici: + optional: true + spdy-transport@3.0.0: resolution: {integrity: sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==} @@ -19397,6 +19449,15 @@ snapshots: space-separated-tokens@2.0.2: {} + spacetimedb@1.6.2(react@19.2.0)(undici@6.21.3): + dependencies: + base64-js: 1.5.1 + fast-text-encoding: 1.0.6 + prettier: 3.6.2 + optionalDependencies: + react: 19.2.0 + undici: 6.21.3 + spdy-transport@3.0.0: dependencies: debug: 4.4.3 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index cc374f6f306..44dd8100610 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -2,6 +2,8 @@ packages: - 'crates/bindings-typescript' - 'crates/bindings-typescript/test-app' - 'crates/bindings-typescript/examples/quickstart-chat' + - 'crates/bindings-typescript/examples/basic-react' + - 'crates/bindings-typescript/examples/empty' - 'modules/benchmarks-ts' - 'modules/module-test-ts' - 'modules/quickstart-chat-ts' diff --git a/tools/gen-bindings/Cargo.toml b/tools/gen-bindings/Cargo.toml new file mode 100644 index 00000000000..343564fba45 --- /dev/null +++ b/tools/gen-bindings/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "gen-bindings" +version = "0.1.0" +edition = "2021" + +[dependencies] +anyhow = "1" +clap.workspace = true +replace-spacetimedb = { path = "../replace-spacetimedb" } \ No newline at end of file diff --git a/tools/gen-bindings/src/main.rs b/tools/gen-bindings/src/main.rs new file mode 100644 index 00000000000..d48f3cdeea8 --- /dev/null +++ b/tools/gen-bindings/src/main.rs @@ -0,0 +1,96 @@ +#![allow(clippy::disallowed_macros)] +use anyhow::{anyhow, Context, Result}; +use clap::Parser; +use replace_spacetimedb::{replace_in_tree, ReplaceOptions}; +use std::fs; +use std::path::Path; +use std::process::{Command, Stdio}; + +#[derive(Parser, Debug)] +#[command(version, about = "Build + generate TS bindings + replace + prettier")] +struct Cli { + /// Output directory for generated code + #[arg(long, default_value = "src/module_bindings")] + out_dir: String, + + /// Project path passed to spacetimedb-cli + #[arg(long, default_value = "server")] + project_path: String, + + /// Replacement for 'spacetimedb' (relative string used in imports) + #[arg(long)] + replacement: Option, +} + +fn run_inherit(cmd: &str, args: &[&str]) -> Result<()> { + let status = Command::new(cmd) + .args(args) + .stdin(Stdio::null()) + .status() + .with_context(|| format!("Failed to start {cmd}"))?; + if !status.success() { + return Err(anyhow!("Command failed: {cmd} {args:?} (exit {status})")); + } + Ok(()) +} + +fn main() -> Result<()> { + let args = Cli::parse(); + + // 1) Build prerequisite + run_inherit("cargo", &["build", "-p", "spacetimedb-standalone"])?; + + // 2) Ensure output directory exists + if !Path::new(&args.out_dir).exists() { + fs::create_dir_all(&args.out_dir).context("create output directory")?; + } + + // 3) Generate TS client from project + run_inherit( + "cargo", + &[ + "run", + "-p", + "spacetimedb-cli", + "generate", + "--lang", + "typescript", + "--out-dir", + &args.out_dir, + "--project-path", + &args.project_path, + ], + )?; + + if let Some(replacement) = &args.replacement { + + // 5) Replace "spacetimedb" references + let opts = ReplaceOptions { + dry_run: false, + only_exts: Some(vec![ + "ts".into(), + "tsx".into(), + "js".into(), + "jsx".into(), + "mts".into(), + "cts".into(), + "json".into(), + "d.ts".into(), + ]), + follow_symlinks: false, + include_hidden: false, + ignore_globs: vec![ + "**/node_modules/**".into(), + "**/dist/**".into(), + "**/target/**".into(), + ], + }; + + let stats = replace_in_tree(&args.out_dir, replacement, &opts)?; + println!( + "Replaced 'spacetimedb' → '{}' in {} files ({} occurrences).", + replacement, stats.files_changed, stats.occurrences + ); + } + Ok(()) +} diff --git a/tools/generate-client-api/Cargo.toml b/tools/generate-client-api/Cargo.toml new file mode 100644 index 00000000000..e6645aa15b0 --- /dev/null +++ b/tools/generate-client-api/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "generate-client-api" +version = "0.1.0" +edition = "2021" + +[dependencies] +tempfile = "3" +anyhow = "1" +replace-spacetimedb = { path = "../replace-spacetimedb" } # use the library directly diff --git a/tools/generate-client-api/src/main.rs b/tools/generate-client-api/src/main.rs new file mode 100644 index 00000000000..0fb05f0c1b8 --- /dev/null +++ b/tools/generate-client-api/src/main.rs @@ -0,0 +1,107 @@ +#![allow(clippy::disallowed_macros)] +use anyhow::{anyhow, Context, Result}; +use replace_spacetimedb::{replace_in_tree, ReplaceOptions}; +use std::fs; +use std::path::Path; +use std::process::{Command, Stdio}; +use tempfile::NamedTempFile; + +/// Run a command inheriting stdio; error if it fails. +fn run_inherit(cmd: &str, args: &[&str]) -> Result<()> { + let status = Command::new(cmd) + .args(args) + .stdin(Stdio::null()) + .status() + .with_context(|| format!("Failed to start {cmd}"))?; + if !status.success() { + return Err(anyhow!("Command failed: {cmd} {args:?} (exit {status})")); + } + Ok(()) +} + +/// Run a command and return captured stdout as UTF-8 string. +fn run_capture(cmd: &str, args: &[&str]) -> Result { + let out = Command::new(cmd) + .args(args) + .stdin(Stdio::null()) + .output() + .with_context(|| format!("Failed to start {cmd}"))?; + if !out.status.success() { + return Err(anyhow!( + "Command failed: {cmd} {args:?} (exit {})", + out.status + )); + } + Ok(String::from_utf8(out.stdout)?) +} + +fn main() -> Result<()> { + let out_dir = "src/sdk/client_api"; + let replacement = "../../index"; + + // 1) Build prerequisite + run_inherit("cargo", &["build", "-p", "spacetimedb-standalone"])?; + + // 2) Get schema to a temp file (auto-cleaned) + let mut tmp_schema = NamedTempFile::new().context("create temp schema file")?; + let schema_json = run_capture( + "cargo", + &[ + "run", + "-p", + "spacetimedb-client-api-messages", + "--example", + "get_ws_schema", + ], + )?; + use std::io::Write; + tmp_schema.write_all(schema_json.as_bytes())?; + let schema_path = tmp_schema.path(); + + // 3) Ensure output directory exists + if !Path::new(out_dir).exists() { + fs::create_dir_all(out_dir).context("create output directory")?; + } + + // 4) Generate TS client + run_inherit( + "cargo", + &[ + "run", + "-p", + "spacetimedb-cli", + "generate", + "--lang", + "typescript", + "--out-dir", + out_dir, + "--module-def", + schema_path.to_str().unwrap(), + ], + )?; + + // 5) Replace "spacetimedb" references under out_dir + let opts = ReplaceOptions { + dry_run: false, + only_exts: Some(vec![ + "ts".into(), + "tsx".into(), + "js".into(), + "jsx".into(), + "mts".into(), + "cts".into(), + "json".into(), + "d.ts".into(), + ]), + follow_symlinks: false, + include_hidden: false, + ignore_globs: vec!["**/node_modules/**".into(), "**/dist/**".into()], + }; + let stats = replace_in_tree(out_dir, replacement, &opts)?; + println!( + "Replaced {} occurrences across {} files.", + stats.occurrences, stats.files_changed + ); + + Ok(()) +} diff --git a/tools/replace-spacetimedb/Cargo.toml b/tools/replace-spacetimedb/Cargo.toml new file mode 100644 index 00000000000..9cb80ef0282 --- /dev/null +++ b/tools/replace-spacetimedb/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "replace-spacetimedb" +version = "0.1.0" +edition = "2021" + +[lib] +name = "replace_spacetimedb" +path = "src/lib.rs" + +[[bin]] +name = "replace-spacetimedb" +path = "src/main.rs" + +[dependencies] +clap.workspace = true +regex.workspace = true +ignore = "0.4" +memchr = "2" \ No newline at end of file diff --git a/tools/replace-spacetimedb/src/lib.rs b/tools/replace-spacetimedb/src/lib.rs new file mode 100644 index 00000000000..d4e4b10ff22 --- /dev/null +++ b/tools/replace-spacetimedb/src/lib.rs @@ -0,0 +1,131 @@ +#![allow(clippy::disallowed_macros)] +use ignore::{DirEntry, WalkBuilder}; +use regex::Regex; +use std::fs; +use std::io; +use std::path::{Path}; + +#[derive(Clone, Debug)] +pub struct ReplaceOptions { + pub dry_run: bool, + pub only_exts: Option>, + pub follow_symlinks: bool, + pub include_hidden: bool, + pub ignore_globs: Vec, +} + +fn is_probably_text(bytes: &[u8]) -> bool { + !bytes.contains(&0) +} + +fn should_process_file(path: &Path, only_exts: &Option>) -> bool { + if let Some(exts) = only_exts { + if let Some(ext) = path.extension().and_then(|s| s.to_str()) { + return exts.iter().any(|e| e.eq_ignore_ascii_case(ext)); + } + return false; + } + true +} + +pub struct ReplaceStats { + pub files_changed: usize, + pub occurrences: usize, +} + +/// Replace only occurrences inside `} from 'spacetimedb'` or `} from "spacetimedb"` +/// (works for both `import { ... } from ...` and `export { ... } from ...`). +pub fn replace_in_tree( + root: impl AsRef, + replacement: &str, + options: &ReplaceOptions, +) -> io::Result { + let root = root.as_ref().to_path_buf(); + if !root.is_dir() { + return Err(io::Error::new( + io::ErrorKind::InvalidInput, + format!("Not a directory: {}", root.display()), + )); + } + + // Match exactly the two forms you want. No backreferences needed. + // We intentionally DO NOT include a trailing semicolon so we preserve it (or its absence). + let re_single = Regex::new(r#"}\s*from\s*'spacetimedb'"#).unwrap(); + let re_double = Regex::new(r#"}\s*from\s*"spacetimedb""#).unwrap(); + + let mut builder = WalkBuilder::new(&root); + builder + .follow_links(options.follow_symlinks) + .hidden(!options.include_hidden) + .git_exclude(true) + .git_ignore(true) + .git_global(true); + builder.add_ignore("node_modules"); + builder.add_ignore("target"); + builder.add_ignore(".git"); + for g in &options.ignore_globs { + builder.add_ignore(g); + } + + let mut files_changed = 0usize; + let mut total_matches = 0usize; + + for result in builder.build() { + let entry: DirEntry = match result { + Ok(e) => e, + Err(err) => { + eprintln!("walk error: {err}"); + continue; + } + }; + + let path = entry.path(); + if !entry.file_type().map(|t| t.is_file()).unwrap_or(false) { + continue; + } + if !should_process_file(path, &options.only_exts) { + continue; + } + + let bytes = match fs::read(path) { + Ok(b) => b, + Err(err) => { + eprintln!("read error {}: {err}", path.display()); + continue; + } + }; + if !is_probably_text(&bytes) { + continue; + } + + let content = match String::from_utf8(bytes) { + Ok(s) => s, + Err(_) => continue, + }; + + // Count before replacing + let matches = re_single.find_iter(&content).count() + + re_double.find_iter(&content).count(); + if matches == 0 { + continue; + } + + // Do the replacements, preserving quote style + let updated1 = re_single.replace_all(&content, format!("}} from '{}'", replacement)); + let updated = re_double.replace_all(&updated1, format!("}} from \"{}\"", replacement)); + + if options.dry_run { + println!("[dry-run] {} ({} matches)", path.display(), matches); + } else if let Err(err) = fs::write(path, updated.as_ref()) { + eprintln!("write error {}: {err}", path.display()); + continue; + } else { + println!("✔ {} ({} matches)", path.display(), matches); + } + + files_changed += 1; + total_matches += matches; + } + + Ok(ReplaceStats { files_changed, occurrences: total_matches }) +} \ No newline at end of file diff --git a/tools/replace-spacetimedb/src/main.rs b/tools/replace-spacetimedb/src/main.rs new file mode 100644 index 00000000000..1fea98e23a4 --- /dev/null +++ b/tools/replace-spacetimedb/src/main.rs @@ -0,0 +1,64 @@ +#![allow(clippy::disallowed_macros)] +use clap::Parser; +use replace_spacetimedb::{replace_in_tree, ReplaceOptions}; + +/// Replace all occurrences of "spacetimedb" under with . +#[derive(Parser, Debug)] +#[command(version, about)] +struct Args { + /// Directory to process (recursively). + target_dir: String, + /// Replacement string for 'spacetimedb'. + replacement: String, + + /// Only process given file extensions (comma-separated, e.g. "ts,tsx,js,json"). + #[arg(long)] + only_exts: Option, + + /// Follow symlinks. + #[arg(long)] + follow_symlinks: bool, + + /// Include hidden files/dirs. + #[arg(long)] + include_hidden: bool, + + /// Ignore globs to skip (can be used multiple times). + #[arg(long)] + ignore: Vec, + + /// Dry run: show changes without writing. + #[arg(long)] + dry_run: bool, +} + +fn main() { + let args = Args::parse(); + let only_exts = args.only_exts.map(|s| { + s.split(',') + .map(|e| e.trim().trim_start_matches('.').to_string()) + .filter(|e| !e.is_empty()) + .collect::>() + }); + + let opts = ReplaceOptions { + dry_run: args.dry_run, + only_exts, + follow_symlinks: args.follow_symlinks, + include_hidden: args.include_hidden, + ignore_globs: args.ignore, + }; + + match replace_in_tree(&args.target_dir, &args.replacement, &opts) { + Ok(stats) => { + println!( + "✅ Replacement complete. Files changed: {} | Occurrences: {}", + stats.files_changed, stats.occurrences + ); + } + Err(e) => { + eprintln!("error: {e}"); + std::process::exit(1); + } + } +} From ef52bb67bfd79ad1001e8e307fbcaa2b55bd9375 Mon Sep 17 00:00:00 2001 From: = Date: Tue, 11 Nov 2025 10:54:16 -0500 Subject: [PATCH 33/49] Fixed the testnet thing --- crates/bindings-typescript/examples/basic-react/package.json | 2 +- crates/bindings-typescript/examples/empty/package.json | 2 +- .../bindings-typescript/examples/quickstart-chat/package.json | 2 +- crates/bindings-typescript/test-app/package.json | 2 +- crates/bindings-typescript/test-react-router-app/package.json | 2 +- sdks/csharp/src/SpacetimeDBClient.cs | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/crates/bindings-typescript/examples/basic-react/package.json b/crates/bindings-typescript/examples/basic-react/package.json index b9f51487874..7ca43645e65 100644 --- a/crates/bindings-typescript/examples/basic-react/package.json +++ b/crates/bindings-typescript/examples/basic-react/package.json @@ -10,7 +10,7 @@ "generate": "cargo run -p gen-bindings -- --out-dir src/module_bindings --project-path ../../../cli/templates/basic-typescript/server && prettier --write src/module_bindings", "spacetime:generate": "spacetime generate --lang typescript --out-dir src/module_bindings --project-path spacetimedb", "spacetime:publish:local": "spacetime publish --project-path server --server local", - "spacetime:publish": "spacetime publish --project-path server --server testnet" + "spacetime:publish": "spacetime publish --project-path server --server maincloud" }, "dependencies": { "spacetimedb": "workspace:*", diff --git a/crates/bindings-typescript/examples/empty/package.json b/crates/bindings-typescript/examples/empty/package.json index eab974922a6..daa3b650234 100644 --- a/crates/bindings-typescript/examples/empty/package.json +++ b/crates/bindings-typescript/examples/empty/package.json @@ -10,7 +10,7 @@ "generate": "cargo run -p gen-bindings -- --out-dir src/module_bindings --project-path ../../../cli/templates/basic-typescript/server && prettier --write src/module_bindings", "spacetime:generate": "spacetime generate --lang typescript --out-dir src/module_bindings --project-path spacetimedb", "spacetime:publish:local": "spacetime publish --project-path server --server local", - "spacetime:publish": "spacetime publish --project-path server --server testnet" + "spacetime:publish": "spacetime publish --project-path server --server maincloud" }, "dependencies": { "spacetimedb": "^1.5.0" diff --git a/crates/bindings-typescript/examples/quickstart-chat/package.json b/crates/bindings-typescript/examples/quickstart-chat/package.json index 26f0de419cf..777d14106ec 100644 --- a/crates/bindings-typescript/examples/quickstart-chat/package.json +++ b/crates/bindings-typescript/examples/quickstart-chat/package.json @@ -13,7 +13,7 @@ "generate": "cargo run -p gen-bindings -- --out-dir src/module_bindings --project-path ../../../../modules/quickstart-chat && prettier --write src/module_bindings", "spacetime:generate": "spacetime generate --lang typescript --out-dir src/module_bindings --project-path spacetimedb", "spacetime:publish:local": "spacetime publish --project-path server --server local", - "spacetime:publish": "spacetime publish --project-path server --server testnet" + "spacetime:publish": "spacetime publish --project-path server --server maincloud" }, "dependencies": { "spacetimedb": "workspace:*", diff --git a/crates/bindings-typescript/test-app/package.json b/crates/bindings-typescript/test-app/package.json index 28c8f27673e..79efec60038 100644 --- a/crates/bindings-typescript/test-app/package.json +++ b/crates/bindings-typescript/test-app/package.json @@ -16,7 +16,7 @@ "spacetime:generate": "spacetime generate --lang typescript --out-dir src/module_bindings --project-path server", "spacetime:start": "spacetime start server", "spacetime:publish:local": "spacetime publish game --project-path server --server local", - "spacetime:publish": "spacetime publish game --project-path server --server testnet" + "spacetime:publish": "spacetime publish game --project-path server --server maincloud" }, "dependencies": { "react": "^18.3.1", diff --git a/crates/bindings-typescript/test-react-router-app/package.json b/crates/bindings-typescript/test-react-router-app/package.json index 5372e67cbfe..8cde69ad138 100644 --- a/crates/bindings-typescript/test-react-router-app/package.json +++ b/crates/bindings-typescript/test-react-router-app/package.json @@ -16,7 +16,7 @@ "spacetime:generate": "spacetime generate --lang typescript --out-dir src/module_bindings --project-path server", "spacetime:start": "spacetime start server", "spacetime:publish:local": "spacetime publish game --project-path server --server local", - "spacetime:publish": "spacetime publish game --project-path server --server testnet" + "spacetime:publish": "spacetime publish game --project-path server --server maincloud" }, "dependencies": { "react": "^18.3.1", diff --git a/sdks/csharp/src/SpacetimeDBClient.cs b/sdks/csharp/src/SpacetimeDBClient.cs index 1dac02ccf60..238437c0d23 100644 --- a/sdks/csharp/src/SpacetimeDBClient.cs +++ b/sdks/csharp/src/SpacetimeDBClient.cs @@ -482,7 +482,7 @@ public void Disconnect() /// /// Connect to a remote spacetime instance. /// - /// URI of the SpacetimeDB server (ex: https://testnet.spacetimedb.com) + /// URI of the SpacetimeDB server (ex: https://maincloud.spacetimedb.com) /// The name or address of the database to connect to void IDbConnection.Connect(string? token, string uri, string addressOrName, Compression compression, bool light) { From ed7a21079a6514e5b5221fb0299f663b6b739c5f Mon Sep 17 00:00:00 2001 From: = Date: Tue, 11 Nov 2025 14:41:05 -0500 Subject: [PATCH 34/49] Fix quickstart docs to use the new APIs --- .../src/module_bindings/add_reducer.ts | 67 +--- .../client_connected_reducer.ts | 65 +--- .../client_disconnected_reducer.ts | 65 +--- .../basic-react/src/module_bindings/index.ts | 328 ++++-------------- .../src/module_bindings/init_reducer.ts | 62 +--- .../src/module_bindings/person_table.ts | 82 +---- .../src/module_bindings/person_type.ts | 69 +--- .../src/module_bindings/say_hello_reducer.ts | 64 +--- .../empty/src/module_bindings/add_reducer.ts | 67 +--- .../client_connected_reducer.ts | 65 +--- .../client_disconnected_reducer.ts | 65 +--- .../empty/src/module_bindings/index.ts | 328 ++++-------------- .../empty/src/module_bindings/init_reducer.ts | 62 +--- .../empty/src/module_bindings/person_table.ts | 82 +---- .../empty/src/module_bindings/person_type.ts | 69 +--- .../src/module_bindings/say_hello_reducer.ts | 64 +--- .../examples/quickstart-chat/src/App.tsx | 30 +- .../identity_connected_reducer.ts | 65 +--- .../identity_disconnected_reducer.ts | 65 +--- .../src/module_bindings/index.ts | 317 +++++------------ .../src/module_bindings/message_table.ts | 84 +---- .../src/module_bindings/message_type.ts | 80 +---- .../module_bindings/send_message_reducer.ts | 69 +--- .../src/module_bindings/set_name_reducer.ts | 67 +--- .../src/module_bindings/user_table.ts | 117 +------ .../src/module_bindings/user_type.ts | 82 +---- .../src/sdk/client_api/index.ts | 6 +- .../test-app/src/module_bindings/index.ts | 6 +- .../06-typescript-quickstart.md | 27 +- tools/gen-bindings/src/main.rs | 14 +- tools/generate-client-api/src/main.rs | 5 +- tools/replace-spacetimedb/src/lib.rs | 29 +- tools/replace-spacetimedb/src/main.rs | 8 +- 33 files changed, 429 insertions(+), 2246 deletions(-) diff --git a/crates/bindings-typescript/examples/basic-react/src/module_bindings/add_reducer.ts b/crates/bindings-typescript/examples/basic-react/src/module_bindings/add_reducer.ts index bc8fe325253..85081559c7d 100644 --- a/crates/bindings-typescript/examples/basic-react/src/module_bindings/add_reducer.ts +++ b/crates/bindings-typescript/examples/basic-react/src/module_bindings/add_reducer.ts @@ -4,67 +4,12 @@ /* eslint-disable */ /* tslint:disable */ import { - AlgebraicType as __AlgebraicTypeValue, - BinaryReader as __BinaryReader, - BinaryWriter as __BinaryWriter, - ClientCache as __ClientCache, - ConnectionId as __ConnectionId, - DbConnectionBuilder as __DbConnectionBuilder, - DbConnectionImpl as __DbConnectionImpl, - Identity as __Identity, - SubscriptionBuilderImpl as __SubscriptionBuilderImpl, - TableCache as __TableCache, - TimeDuration as __TimeDuration, - Timestamp as __Timestamp, - deepEqual as __deepEqual, - type AlgebraicType as __AlgebraicTypeType, - type AlgebraicTypeVariants as __AlgebraicTypeVariants, - type CallReducerFlags as __CallReducerFlags, - type ErrorContextInterface as __ErrorContextInterface, - type Event as __Event, - type EventContextInterface as __EventContextInterface, - type ReducerEventContextInterface as __ReducerEventContextInterface, - type SubscriptionEventContextInterface as __SubscriptionEventContextInterface, - type TableHandle as __TableHandle, + TypeBuilder as __TypeBuilder, + t as __t, + type AlgebraicTypeType as __AlgebraicTypeType, + type Infer as __Infer, } from 'spacetimedb'; -export type Add = { - name: string; +export default { + name: __t.string(), }; -let _cached_Add_type_value: __AlgebraicTypeType | null = null; - -/** - * An object for generated helper functions. - */ -export const Add = { - /** - * A function which returns this type represented as an AlgebraicType. - * This function is derived from the AlgebraicType used to generate this type. - */ - getTypeScriptAlgebraicType(): __AlgebraicTypeType { - if (_cached_Add_type_value) return _cached_Add_type_value; - _cached_Add_type_value = __AlgebraicTypeValue.Product({ elements: [] }); - _cached_Add_type_value.value.elements.push({ - name: 'name', - algebraicType: __AlgebraicTypeValue.String, - }); - return _cached_Add_type_value; - }, - - serialize(writer: __BinaryWriter, value: Add): void { - __AlgebraicTypeValue.serializeValue( - writer, - Add.getTypeScriptAlgebraicType(), - value - ); - }, - - deserialize(reader: __BinaryReader): Add { - return __AlgebraicTypeValue.deserializeValue( - reader, - Add.getTypeScriptAlgebraicType() - ); - }, -}; - -export default Add; diff --git a/crates/bindings-typescript/examples/basic-react/src/module_bindings/client_connected_reducer.ts b/crates/bindings-typescript/examples/basic-react/src/module_bindings/client_connected_reducer.ts index a8b7233cef8..2ca99c88fea 100644 --- a/crates/bindings-typescript/examples/basic-react/src/module_bindings/client_connected_reducer.ts +++ b/crates/bindings-typescript/examples/basic-react/src/module_bindings/client_connected_reducer.ts @@ -4,65 +4,10 @@ /* eslint-disable */ /* tslint:disable */ import { - AlgebraicType as __AlgebraicTypeValue, - BinaryReader as __BinaryReader, - BinaryWriter as __BinaryWriter, - ClientCache as __ClientCache, - ConnectionId as __ConnectionId, - DbConnectionBuilder as __DbConnectionBuilder, - DbConnectionImpl as __DbConnectionImpl, - Identity as __Identity, - SubscriptionBuilderImpl as __SubscriptionBuilderImpl, - TableCache as __TableCache, - TimeDuration as __TimeDuration, - Timestamp as __Timestamp, - deepEqual as __deepEqual, - type AlgebraicType as __AlgebraicTypeType, - type AlgebraicTypeVariants as __AlgebraicTypeVariants, - type CallReducerFlags as __CallReducerFlags, - type ErrorContextInterface as __ErrorContextInterface, - type Event as __Event, - type EventContextInterface as __EventContextInterface, - type ReducerEventContextInterface as __ReducerEventContextInterface, - type SubscriptionEventContextInterface as __SubscriptionEventContextInterface, - type TableHandle as __TableHandle, + TypeBuilder as __TypeBuilder, + t as __t, + type AlgebraicTypeType as __AlgebraicTypeType, + type Infer as __Infer, } from 'spacetimedb'; -export type ClientConnected = {}; -let _cached_ClientConnected_type_value: __AlgebraicTypeType | null = null; - -/** - * An object for generated helper functions. - */ -export const ClientConnected = { - /** - * A function which returns this type represented as an AlgebraicType. - * This function is derived from the AlgebraicType used to generate this type. - */ - getTypeScriptAlgebraicType(): __AlgebraicTypeType { - if (_cached_ClientConnected_type_value) - return _cached_ClientConnected_type_value; - _cached_ClientConnected_type_value = __AlgebraicTypeValue.Product({ - elements: [], - }); - _cached_ClientConnected_type_value.value.elements.push(); - return _cached_ClientConnected_type_value; - }, - - serialize(writer: __BinaryWriter, value: ClientConnected): void { - __AlgebraicTypeValue.serializeValue( - writer, - ClientConnected.getTypeScriptAlgebraicType(), - value - ); - }, - - deserialize(reader: __BinaryReader): ClientConnected { - return __AlgebraicTypeValue.deserializeValue( - reader, - ClientConnected.getTypeScriptAlgebraicType() - ); - }, -}; - -export default ClientConnected; +export default {}; diff --git a/crates/bindings-typescript/examples/basic-react/src/module_bindings/client_disconnected_reducer.ts b/crates/bindings-typescript/examples/basic-react/src/module_bindings/client_disconnected_reducer.ts index 385acd9bd3c..2ca99c88fea 100644 --- a/crates/bindings-typescript/examples/basic-react/src/module_bindings/client_disconnected_reducer.ts +++ b/crates/bindings-typescript/examples/basic-react/src/module_bindings/client_disconnected_reducer.ts @@ -4,65 +4,10 @@ /* eslint-disable */ /* tslint:disable */ import { - AlgebraicType as __AlgebraicTypeValue, - BinaryReader as __BinaryReader, - BinaryWriter as __BinaryWriter, - ClientCache as __ClientCache, - ConnectionId as __ConnectionId, - DbConnectionBuilder as __DbConnectionBuilder, - DbConnectionImpl as __DbConnectionImpl, - Identity as __Identity, - SubscriptionBuilderImpl as __SubscriptionBuilderImpl, - TableCache as __TableCache, - TimeDuration as __TimeDuration, - Timestamp as __Timestamp, - deepEqual as __deepEqual, - type AlgebraicType as __AlgebraicTypeType, - type AlgebraicTypeVariants as __AlgebraicTypeVariants, - type CallReducerFlags as __CallReducerFlags, - type ErrorContextInterface as __ErrorContextInterface, - type Event as __Event, - type EventContextInterface as __EventContextInterface, - type ReducerEventContextInterface as __ReducerEventContextInterface, - type SubscriptionEventContextInterface as __SubscriptionEventContextInterface, - type TableHandle as __TableHandle, + TypeBuilder as __TypeBuilder, + t as __t, + type AlgebraicTypeType as __AlgebraicTypeType, + type Infer as __Infer, } from 'spacetimedb'; -export type ClientDisconnected = {}; -let _cached_ClientDisconnected_type_value: __AlgebraicTypeType | null = null; - -/** - * An object for generated helper functions. - */ -export const ClientDisconnected = { - /** - * A function which returns this type represented as an AlgebraicType. - * This function is derived from the AlgebraicType used to generate this type. - */ - getTypeScriptAlgebraicType(): __AlgebraicTypeType { - if (_cached_ClientDisconnected_type_value) - return _cached_ClientDisconnected_type_value; - _cached_ClientDisconnected_type_value = __AlgebraicTypeValue.Product({ - elements: [], - }); - _cached_ClientDisconnected_type_value.value.elements.push(); - return _cached_ClientDisconnected_type_value; - }, - - serialize(writer: __BinaryWriter, value: ClientDisconnected): void { - __AlgebraicTypeValue.serializeValue( - writer, - ClientDisconnected.getTypeScriptAlgebraicType(), - value - ); - }, - - deserialize(reader: __BinaryReader): ClientDisconnected { - return __AlgebraicTypeValue.deserializeValue( - reader, - ClientDisconnected.getTypeScriptAlgebraicType() - ); - }, -}; - -export default ClientDisconnected; +export default {}; diff --git a/crates/bindings-typescript/examples/basic-react/src/module_bindings/index.ts b/crates/bindings-typescript/examples/basic-react/src/module_bindings/index.ts index 08fef081923..8dccaeb0421 100644 --- a/crates/bindings-typescript/examples/basic-react/src/module_bindings/index.ts +++ b/crates/bindings-typescript/examples/basic-react/src/module_bindings/index.ts @@ -1,303 +1,111 @@ // THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE // WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. -// This was generated using spacetimedb cli version 1.6.0 (commit 64812908d1dd2fb0ac1a44ae8c669306ce3f001e). +// This was generated using spacetimedb cli version 1.7.0 (commit fe91e78ecbfb9714b563a08a5290db6a780f1bc3). /* eslint-disable */ /* tslint:disable */ import { - AlgebraicType as __AlgebraicTypeValue, - BinaryReader as __BinaryReader, - BinaryWriter as __BinaryWriter, - ClientCache as __ClientCache, - ConnectionId as __ConnectionId, DbConnectionBuilder as __DbConnectionBuilder, DbConnectionImpl as __DbConnectionImpl, - Identity as __Identity, SubscriptionBuilderImpl as __SubscriptionBuilderImpl, - TableCache as __TableCache, - TimeDuration as __TimeDuration, - Timestamp as __Timestamp, - deepEqual as __deepEqual, - type AlgebraicType as __AlgebraicTypeType, - type AlgebraicTypeVariants as __AlgebraicTypeVariants, - type CallReducerFlags as __CallReducerFlags, + TypeBuilder as __TypeBuilder, + convertToAccessorMap as __convertToAccessorMap, + reducerSchema as __reducerSchema, + reducers as __reducers, + schema as __schema, + t as __t, + table as __table, + type AlgebraicTypeType as __AlgebraicTypeType, + type DbConnectionConfig as __DbConnectionConfig, type ErrorContextInterface as __ErrorContextInterface, type Event as __Event, type EventContextInterface as __EventContextInterface, + type Infer as __Infer, type ReducerEventContextInterface as __ReducerEventContextInterface, + type RemoteModule as __RemoteModule, type SubscriptionEventContextInterface as __SubscriptionEventContextInterface, - type TableHandle as __TableHandle, } from 'spacetimedb'; // Import and reexport all reducer arg types -import { Init } from './init_reducer.ts'; +import Init from './init_reducer'; export { Init }; -import { ClientConnected } from './client_connected_reducer.ts'; +import ClientConnected from './client_connected_reducer'; export { ClientConnected }; -import { ClientDisconnected } from './client_disconnected_reducer.ts'; +import ClientDisconnected from './client_disconnected_reducer'; export { ClientDisconnected }; -import { Add } from './add_reducer.ts'; +import Add from './add_reducer'; export { Add }; -import { SayHello } from './say_hello_reducer.ts'; +import SayHello from './say_hello_reducer'; export { SayHello }; // Import and reexport all table handle types -import { PersonTableHandle } from './person_table.ts'; -export { PersonTableHandle }; +import PersonRow from './person_table'; +export { PersonRow }; // Import and reexport all types -import { Person } from './person_type.ts'; +import Person from './person_type'; export { Person }; -const REMOTE_MODULE = { - tables: { - person: { - tableName: 'person' as const, - rowType: Person.getTypeScriptAlgebraicType(), - }, - }, - reducers: { - init: { - reducerName: 'init', - argsType: Init.getTypeScriptAlgebraicType(), - }, - client_connected: { - reducerName: 'client_connected', - argsType: ClientConnected.getTypeScriptAlgebraicType(), +const tablesSchema = __schema( + __table( + { + name: 'person', + indexes: [], + constraints: [], }, - client_disconnected: { - reducerName: 'client_disconnected', - argsType: ClientDisconnected.getTypeScriptAlgebraicType(), - }, - add: { - reducerName: 'add', - argsType: Add.getTypeScriptAlgebraicType(), - }, - say_hello: { - reducerName: 'say_hello', - argsType: SayHello.getTypeScriptAlgebraicType(), - }, - }, + PersonRow + ) +); + +const reducersSchema = __reducers( + __reducerSchema('init', Init), + __reducerSchema('client_connected', ClientConnected), + __reducerSchema('client_disconnected', ClientDisconnected), + __reducerSchema('add', Add), + __reducerSchema('say_hello', SayHello) +); + +const REMOTE_MODULE = { versionInfo: { - cliVersion: '1.6.0', - }, - // Constructors which are used by the DbConnectionImpl to - // extract type information from the generated RemoteModule. - // - // NOTE: This is not strictly necessary for `eventContextConstructor` because - // all we do is build a TypeScript object which we could have done inside the - // SDK, but if in the future we wanted to create a class this would be - // necessary because classes have methods, so we'll keep it. - eventContextConstructor: ( - imp: __DbConnectionImpl, - event: __Event - ) => { - return { - ...(imp as DbConnection), - event, - }; - }, - dbViewConstructor: (imp: __DbConnectionImpl) => { - return new RemoteTables(imp); + cliVersion: '1.7.0' as const, }, - reducersConstructor: ( - imp: __DbConnectionImpl, - setReducerFlags: SetReducerFlags - ) => { - return new RemoteReducers(imp, setReducerFlags); - }, - setReducerFlagsConstructor: () => { - return new SetReducerFlags(); - }, -}; - -// A type representing all the possible variants of a reducer. -export type Reducer = - | never - | { name: 'Init'; args: Init } - | { name: 'ClientConnected'; args: ClientConnected } - | { name: 'ClientDisconnected'; args: ClientDisconnected } - | { name: 'Add'; args: Add } - | { name: 'SayHello'; args: SayHello }; - -export class RemoteReducers { - constructor( - private connection: __DbConnectionImpl, - private setCallReducerFlags: SetReducerFlags - ) {} - - init() { - this.connection.callReducer( - 'init', - new Uint8Array(0), - this.setCallReducerFlags.initFlags - ); - } - - onInit(callback: (ctx: ReducerEventContext) => void) { - this.connection.onReducer('init', callback); - } - - removeOnInit(callback: (ctx: ReducerEventContext) => void) { - this.connection.offReducer('init', callback); - } - - clientConnected() { - this.connection.callReducer( - 'client_connected', - new Uint8Array(0), - this.setCallReducerFlags.clientConnectedFlags - ); - } - - onClientConnected(callback: (ctx: ReducerEventContext) => void) { - this.connection.onReducer('client_connected', callback); - } - - removeOnClientConnected(callback: (ctx: ReducerEventContext) => void) { - this.connection.offReducer('client_connected', callback); - } - - clientDisconnected() { - this.connection.callReducer( - 'client_disconnected', - new Uint8Array(0), - this.setCallReducerFlags.clientDisconnectedFlags - ); - } - - onClientDisconnected(callback: (ctx: ReducerEventContext) => void) { - this.connection.onReducer('client_disconnected', callback); - } - - removeOnClientDisconnected(callback: (ctx: ReducerEventContext) => void) { - this.connection.offReducer('client_disconnected', callback); - } - - add(name: string) { - const __args = { name }; - let __writer = new __BinaryWriter(1024); - Add.serialize(__writer, __args); - let __argsBuffer = __writer.getBuffer(); - this.connection.callReducer( - 'add', - __argsBuffer, - this.setCallReducerFlags.addFlags - ); - } - - onAdd(callback: (ctx: ReducerEventContext, name: string) => void) { - this.connection.onReducer('add', callback); - } - - removeOnAdd(callback: (ctx: ReducerEventContext, name: string) => void) { - this.connection.offReducer('add', callback); - } - - sayHello() { - this.connection.callReducer( - 'say_hello', - new Uint8Array(0), - this.setCallReducerFlags.sayHelloFlags - ); - } - - onSayHello(callback: (ctx: ReducerEventContext) => void) { - this.connection.onReducer('say_hello', callback); - } - - removeOnSayHello(callback: (ctx: ReducerEventContext) => void) { - this.connection.offReducer('say_hello', callback); - } -} - -export class SetReducerFlags { - initFlags: __CallReducerFlags = 'FullUpdate'; - init(flags: __CallReducerFlags) { - this.initFlags = flags; - } - - clientConnectedFlags: __CallReducerFlags = 'FullUpdate'; - clientConnected(flags: __CallReducerFlags) { - this.clientConnectedFlags = flags; - } - - clientDisconnectedFlags: __CallReducerFlags = 'FullUpdate'; - clientDisconnected(flags: __CallReducerFlags) { - this.clientDisconnectedFlags = flags; - } - - addFlags: __CallReducerFlags = 'FullUpdate'; - add(flags: __CallReducerFlags) { - this.addFlags = flags; - } - - sayHelloFlags: __CallReducerFlags = 'FullUpdate'; - sayHello(flags: __CallReducerFlags) { - this.sayHelloFlags = flags; - } -} + tables: tablesSchema.schemaType.tables, + reducers: reducersSchema.reducersType.reducers, +} satisfies __RemoteModule< + typeof tablesSchema.schemaType, + typeof reducersSchema.reducersType +>; -export class RemoteTables { - constructor(private connection: __DbConnectionImpl) {} +export const tables = __convertToAccessorMap(tablesSchema.schemaType.tables); +export const reducers = __convertToAccessorMap( + reducersSchema.reducersType.reducers +); - get person(): PersonTableHandle<'person'> { - // clientCache is a private property - return new PersonTableHandle( - ( - this.connection as unknown as { clientCache: __ClientCache } - ).clientCache.getOrCreateTable(REMOTE_MODULE.tables.person) - ); - } -} +export type EventContext = __EventContextInterface; +export type ReducerEventContext = __ReducerEventContextInterface< + typeof REMOTE_MODULE +>; +export type SubscriptionEventContext = __SubscriptionEventContextInterface< + typeof REMOTE_MODULE +>; +export type ErrorContext = __ErrorContextInterface; export class SubscriptionBuilder extends __SubscriptionBuilderImpl< - RemoteTables, - RemoteReducers, - SetReducerFlags + typeof REMOTE_MODULE > {} -export class DbConnection extends __DbConnectionImpl< - RemoteTables, - RemoteReducers, - SetReducerFlags -> { - static builder = (): __DbConnectionBuilder< - DbConnection, - ErrorContext, - SubscriptionEventContext - > => { - return new __DbConnectionBuilder< - DbConnection, - ErrorContext, - SubscriptionEventContext - >(REMOTE_MODULE, (imp: __DbConnectionImpl) => imp as DbConnection); +export class DbConnectionBuilder extends __DbConnectionBuilder {} + +export class DbConnection extends __DbConnectionImpl { + static builder = (): DbConnectionBuilder => { + return new DbConnectionBuilder( + REMOTE_MODULE, + (config: __DbConnectionConfig) => + new DbConnection(config) + ); }; subscriptionBuilder = (): SubscriptionBuilder => { return new SubscriptionBuilder(this); }; } - -export type EventContext = __EventContextInterface< - RemoteTables, - RemoteReducers, - SetReducerFlags, - Reducer ->; -export type ReducerEventContext = __ReducerEventContextInterface< - RemoteTables, - RemoteReducers, - SetReducerFlags, - Reducer ->; -export type SubscriptionEventContext = __SubscriptionEventContextInterface< - RemoteTables, - RemoteReducers, - SetReducerFlags ->; -export type ErrorContext = __ErrorContextInterface< - RemoteTables, - RemoteReducers, - SetReducerFlags ->; diff --git a/crates/bindings-typescript/examples/basic-react/src/module_bindings/init_reducer.ts b/crates/bindings-typescript/examples/basic-react/src/module_bindings/init_reducer.ts index 12e0782fc1a..2ca99c88fea 100644 --- a/crates/bindings-typescript/examples/basic-react/src/module_bindings/init_reducer.ts +++ b/crates/bindings-typescript/examples/basic-react/src/module_bindings/init_reducer.ts @@ -4,62 +4,10 @@ /* eslint-disable */ /* tslint:disable */ import { - AlgebraicType as __AlgebraicTypeValue, - BinaryReader as __BinaryReader, - BinaryWriter as __BinaryWriter, - ClientCache as __ClientCache, - ConnectionId as __ConnectionId, - DbConnectionBuilder as __DbConnectionBuilder, - DbConnectionImpl as __DbConnectionImpl, - Identity as __Identity, - SubscriptionBuilderImpl as __SubscriptionBuilderImpl, - TableCache as __TableCache, - TimeDuration as __TimeDuration, - Timestamp as __Timestamp, - deepEqual as __deepEqual, - type AlgebraicType as __AlgebraicTypeType, - type AlgebraicTypeVariants as __AlgebraicTypeVariants, - type CallReducerFlags as __CallReducerFlags, - type ErrorContextInterface as __ErrorContextInterface, - type Event as __Event, - type EventContextInterface as __EventContextInterface, - type ReducerEventContextInterface as __ReducerEventContextInterface, - type SubscriptionEventContextInterface as __SubscriptionEventContextInterface, - type TableHandle as __TableHandle, + TypeBuilder as __TypeBuilder, + t as __t, + type AlgebraicTypeType as __AlgebraicTypeType, + type Infer as __Infer, } from 'spacetimedb'; -export type Init = {}; -let _cached_Init_type_value: __AlgebraicTypeType | null = null; - -/** - * An object for generated helper functions. - */ -export const Init = { - /** - * A function which returns this type represented as an AlgebraicType. - * This function is derived from the AlgebraicType used to generate this type. - */ - getTypeScriptAlgebraicType(): __AlgebraicTypeType { - if (_cached_Init_type_value) return _cached_Init_type_value; - _cached_Init_type_value = __AlgebraicTypeValue.Product({ elements: [] }); - _cached_Init_type_value.value.elements.push(); - return _cached_Init_type_value; - }, - - serialize(writer: __BinaryWriter, value: Init): void { - __AlgebraicTypeValue.serializeValue( - writer, - Init.getTypeScriptAlgebraicType(), - value - ); - }, - - deserialize(reader: __BinaryReader): Init { - return __AlgebraicTypeValue.deserializeValue( - reader, - Init.getTypeScriptAlgebraicType() - ); - }, -}; - -export default Init; +export default {}; diff --git a/crates/bindings-typescript/examples/basic-react/src/module_bindings/person_table.ts b/crates/bindings-typescript/examples/basic-react/src/module_bindings/person_table.ts index c50f51f9ff0..0f70f74f617 100644 --- a/crates/bindings-typescript/examples/basic-react/src/module_bindings/person_table.ts +++ b/crates/bindings-typescript/examples/basic-react/src/module_bindings/person_table.ts @@ -4,80 +4,12 @@ /* eslint-disable */ /* tslint:disable */ import { - AlgebraicType as __AlgebraicTypeValue, - BinaryReader as __BinaryReader, - BinaryWriter as __BinaryWriter, - ClientCache as __ClientCache, - ConnectionId as __ConnectionId, - DbConnectionBuilder as __DbConnectionBuilder, - DbConnectionImpl as __DbConnectionImpl, - Identity as __Identity, - SubscriptionBuilderImpl as __SubscriptionBuilderImpl, - TableCache as __TableCache, - TimeDuration as __TimeDuration, - Timestamp as __Timestamp, - deepEqual as __deepEqual, - type AlgebraicType as __AlgebraicTypeType, - type AlgebraicTypeVariants as __AlgebraicTypeVariants, - type CallReducerFlags as __CallReducerFlags, - type ErrorContextInterface as __ErrorContextInterface, - type Event as __Event, - type EventContextInterface as __EventContextInterface, - type ReducerEventContextInterface as __ReducerEventContextInterface, - type SubscriptionEventContextInterface as __SubscriptionEventContextInterface, - type TableHandle as __TableHandle, + TypeBuilder as __TypeBuilder, + t as __t, + type AlgebraicTypeType as __AlgebraicTypeType, + type Infer as __Infer, } from 'spacetimedb'; -import { Person } from './person_type'; -import { - type EventContext, - type Reducer, - RemoteReducers, - RemoteTables, -} from '.'; -declare type __keep = [EventContext, Reducer, RemoteReducers, RemoteTables]; - -/** - * Table handle for the table `person`. - * - * Obtain a handle from the [`person`] property on [`RemoteTables`], - * like `ctx.db.person`. - * - * Users are encouraged not to explicitly reference this type, - * but to directly chain method calls, - * like `ctx.db.person.on_insert(...)`. - */ -export class PersonTableHandle - implements __TableHandle -{ - // phantom type to track the table name - readonly tableName!: TableName; - tableCache: __TableCache; - - constructor(tableCache: __TableCache) { - this.tableCache = tableCache; - } - - count(): number { - return this.tableCache.count(); - } - - iter(): Iterable { - return this.tableCache.iter(); - } - - onInsert = (cb: (ctx: EventContext, row: Person) => void) => { - return this.tableCache.onInsert(cb); - }; - - removeOnInsert = (cb: (ctx: EventContext, row: Person) => void) => { - return this.tableCache.removeOnInsert(cb); - }; - - onDelete = (cb: (ctx: EventContext, row: Person) => void) => { - return this.tableCache.onDelete(cb); - }; - removeOnDelete = (cb: (ctx: EventContext, row: Person) => void) => { - return this.tableCache.removeOnDelete(cb); - }; -} +export default __t.row({ + name: __t.string(), +}); diff --git a/crates/bindings-typescript/examples/basic-react/src/module_bindings/person_type.ts b/crates/bindings-typescript/examples/basic-react/src/module_bindings/person_type.ts index c3085f4f3ba..1156775a3cf 100644 --- a/crates/bindings-typescript/examples/basic-react/src/module_bindings/person_type.ts +++ b/crates/bindings-typescript/examples/basic-react/src/module_bindings/person_type.ts @@ -4,67 +4,12 @@ /* eslint-disable */ /* tslint:disable */ import { - AlgebraicType as __AlgebraicTypeValue, - BinaryReader as __BinaryReader, - BinaryWriter as __BinaryWriter, - ClientCache as __ClientCache, - ConnectionId as __ConnectionId, - DbConnectionBuilder as __DbConnectionBuilder, - DbConnectionImpl as __DbConnectionImpl, - Identity as __Identity, - SubscriptionBuilderImpl as __SubscriptionBuilderImpl, - TableCache as __TableCache, - TimeDuration as __TimeDuration, - Timestamp as __Timestamp, - deepEqual as __deepEqual, - type AlgebraicType as __AlgebraicTypeType, - type AlgebraicTypeVariants as __AlgebraicTypeVariants, - type CallReducerFlags as __CallReducerFlags, - type ErrorContextInterface as __ErrorContextInterface, - type Event as __Event, - type EventContextInterface as __EventContextInterface, - type ReducerEventContextInterface as __ReducerEventContextInterface, - type SubscriptionEventContextInterface as __SubscriptionEventContextInterface, - type TableHandle as __TableHandle, + TypeBuilder as __TypeBuilder, + t as __t, + type AlgebraicTypeType as __AlgebraicTypeType, + type Infer as __Infer, } from 'spacetimedb'; -export type Person = { - name: string; -}; -let _cached_Person_type_value: __AlgebraicTypeType | null = null; - -/** - * An object for generated helper functions. - */ -export const Person = { - /** - * A function which returns this type represented as an AlgebraicType. - * This function is derived from the AlgebraicType used to generate this type. - */ - getTypeScriptAlgebraicType(): __AlgebraicTypeType { - if (_cached_Person_type_value) return _cached_Person_type_value; - _cached_Person_type_value = __AlgebraicTypeValue.Product({ elements: [] }); - _cached_Person_type_value.value.elements.push({ - name: 'name', - algebraicType: __AlgebraicTypeValue.String, - }); - return _cached_Person_type_value; - }, - - serialize(writer: __BinaryWriter, value: Person): void { - __AlgebraicTypeValue.serializeValue( - writer, - Person.getTypeScriptAlgebraicType(), - value - ); - }, - - deserialize(reader: __BinaryReader): Person { - return __AlgebraicTypeValue.deserializeValue( - reader, - Person.getTypeScriptAlgebraicType() - ); - }, -}; - -export default Person; +export default __t.object('Person', { + name: __t.string(), +}); diff --git a/crates/bindings-typescript/examples/basic-react/src/module_bindings/say_hello_reducer.ts b/crates/bindings-typescript/examples/basic-react/src/module_bindings/say_hello_reducer.ts index e0cdd2d5259..2ca99c88fea 100644 --- a/crates/bindings-typescript/examples/basic-react/src/module_bindings/say_hello_reducer.ts +++ b/crates/bindings-typescript/examples/basic-react/src/module_bindings/say_hello_reducer.ts @@ -4,64 +4,10 @@ /* eslint-disable */ /* tslint:disable */ import { - AlgebraicType as __AlgebraicTypeValue, - BinaryReader as __BinaryReader, - BinaryWriter as __BinaryWriter, - ClientCache as __ClientCache, - ConnectionId as __ConnectionId, - DbConnectionBuilder as __DbConnectionBuilder, - DbConnectionImpl as __DbConnectionImpl, - Identity as __Identity, - SubscriptionBuilderImpl as __SubscriptionBuilderImpl, - TableCache as __TableCache, - TimeDuration as __TimeDuration, - Timestamp as __Timestamp, - deepEqual as __deepEqual, - type AlgebraicType as __AlgebraicTypeType, - type AlgebraicTypeVariants as __AlgebraicTypeVariants, - type CallReducerFlags as __CallReducerFlags, - type ErrorContextInterface as __ErrorContextInterface, - type Event as __Event, - type EventContextInterface as __EventContextInterface, - type ReducerEventContextInterface as __ReducerEventContextInterface, - type SubscriptionEventContextInterface as __SubscriptionEventContextInterface, - type TableHandle as __TableHandle, + TypeBuilder as __TypeBuilder, + t as __t, + type AlgebraicTypeType as __AlgebraicTypeType, + type Infer as __Infer, } from 'spacetimedb'; -export type SayHello = {}; -let _cached_SayHello_type_value: __AlgebraicTypeType | null = null; - -/** - * An object for generated helper functions. - */ -export const SayHello = { - /** - * A function which returns this type represented as an AlgebraicType. - * This function is derived from the AlgebraicType used to generate this type. - */ - getTypeScriptAlgebraicType(): __AlgebraicTypeType { - if (_cached_SayHello_type_value) return _cached_SayHello_type_value; - _cached_SayHello_type_value = __AlgebraicTypeValue.Product({ - elements: [], - }); - _cached_SayHello_type_value.value.elements.push(); - return _cached_SayHello_type_value; - }, - - serialize(writer: __BinaryWriter, value: SayHello): void { - __AlgebraicTypeValue.serializeValue( - writer, - SayHello.getTypeScriptAlgebraicType(), - value - ); - }, - - deserialize(reader: __BinaryReader): SayHello { - return __AlgebraicTypeValue.deserializeValue( - reader, - SayHello.getTypeScriptAlgebraicType() - ); - }, -}; - -export default SayHello; +export default {}; diff --git a/crates/bindings-typescript/examples/empty/src/module_bindings/add_reducer.ts b/crates/bindings-typescript/examples/empty/src/module_bindings/add_reducer.ts index bc8fe325253..85081559c7d 100644 --- a/crates/bindings-typescript/examples/empty/src/module_bindings/add_reducer.ts +++ b/crates/bindings-typescript/examples/empty/src/module_bindings/add_reducer.ts @@ -4,67 +4,12 @@ /* eslint-disable */ /* tslint:disable */ import { - AlgebraicType as __AlgebraicTypeValue, - BinaryReader as __BinaryReader, - BinaryWriter as __BinaryWriter, - ClientCache as __ClientCache, - ConnectionId as __ConnectionId, - DbConnectionBuilder as __DbConnectionBuilder, - DbConnectionImpl as __DbConnectionImpl, - Identity as __Identity, - SubscriptionBuilderImpl as __SubscriptionBuilderImpl, - TableCache as __TableCache, - TimeDuration as __TimeDuration, - Timestamp as __Timestamp, - deepEqual as __deepEqual, - type AlgebraicType as __AlgebraicTypeType, - type AlgebraicTypeVariants as __AlgebraicTypeVariants, - type CallReducerFlags as __CallReducerFlags, - type ErrorContextInterface as __ErrorContextInterface, - type Event as __Event, - type EventContextInterface as __EventContextInterface, - type ReducerEventContextInterface as __ReducerEventContextInterface, - type SubscriptionEventContextInterface as __SubscriptionEventContextInterface, - type TableHandle as __TableHandle, + TypeBuilder as __TypeBuilder, + t as __t, + type AlgebraicTypeType as __AlgebraicTypeType, + type Infer as __Infer, } from 'spacetimedb'; -export type Add = { - name: string; +export default { + name: __t.string(), }; -let _cached_Add_type_value: __AlgebraicTypeType | null = null; - -/** - * An object for generated helper functions. - */ -export const Add = { - /** - * A function which returns this type represented as an AlgebraicType. - * This function is derived from the AlgebraicType used to generate this type. - */ - getTypeScriptAlgebraicType(): __AlgebraicTypeType { - if (_cached_Add_type_value) return _cached_Add_type_value; - _cached_Add_type_value = __AlgebraicTypeValue.Product({ elements: [] }); - _cached_Add_type_value.value.elements.push({ - name: 'name', - algebraicType: __AlgebraicTypeValue.String, - }); - return _cached_Add_type_value; - }, - - serialize(writer: __BinaryWriter, value: Add): void { - __AlgebraicTypeValue.serializeValue( - writer, - Add.getTypeScriptAlgebraicType(), - value - ); - }, - - deserialize(reader: __BinaryReader): Add { - return __AlgebraicTypeValue.deserializeValue( - reader, - Add.getTypeScriptAlgebraicType() - ); - }, -}; - -export default Add; diff --git a/crates/bindings-typescript/examples/empty/src/module_bindings/client_connected_reducer.ts b/crates/bindings-typescript/examples/empty/src/module_bindings/client_connected_reducer.ts index a8b7233cef8..2ca99c88fea 100644 --- a/crates/bindings-typescript/examples/empty/src/module_bindings/client_connected_reducer.ts +++ b/crates/bindings-typescript/examples/empty/src/module_bindings/client_connected_reducer.ts @@ -4,65 +4,10 @@ /* eslint-disable */ /* tslint:disable */ import { - AlgebraicType as __AlgebraicTypeValue, - BinaryReader as __BinaryReader, - BinaryWriter as __BinaryWriter, - ClientCache as __ClientCache, - ConnectionId as __ConnectionId, - DbConnectionBuilder as __DbConnectionBuilder, - DbConnectionImpl as __DbConnectionImpl, - Identity as __Identity, - SubscriptionBuilderImpl as __SubscriptionBuilderImpl, - TableCache as __TableCache, - TimeDuration as __TimeDuration, - Timestamp as __Timestamp, - deepEqual as __deepEqual, - type AlgebraicType as __AlgebraicTypeType, - type AlgebraicTypeVariants as __AlgebraicTypeVariants, - type CallReducerFlags as __CallReducerFlags, - type ErrorContextInterface as __ErrorContextInterface, - type Event as __Event, - type EventContextInterface as __EventContextInterface, - type ReducerEventContextInterface as __ReducerEventContextInterface, - type SubscriptionEventContextInterface as __SubscriptionEventContextInterface, - type TableHandle as __TableHandle, + TypeBuilder as __TypeBuilder, + t as __t, + type AlgebraicTypeType as __AlgebraicTypeType, + type Infer as __Infer, } from 'spacetimedb'; -export type ClientConnected = {}; -let _cached_ClientConnected_type_value: __AlgebraicTypeType | null = null; - -/** - * An object for generated helper functions. - */ -export const ClientConnected = { - /** - * A function which returns this type represented as an AlgebraicType. - * This function is derived from the AlgebraicType used to generate this type. - */ - getTypeScriptAlgebraicType(): __AlgebraicTypeType { - if (_cached_ClientConnected_type_value) - return _cached_ClientConnected_type_value; - _cached_ClientConnected_type_value = __AlgebraicTypeValue.Product({ - elements: [], - }); - _cached_ClientConnected_type_value.value.elements.push(); - return _cached_ClientConnected_type_value; - }, - - serialize(writer: __BinaryWriter, value: ClientConnected): void { - __AlgebraicTypeValue.serializeValue( - writer, - ClientConnected.getTypeScriptAlgebraicType(), - value - ); - }, - - deserialize(reader: __BinaryReader): ClientConnected { - return __AlgebraicTypeValue.deserializeValue( - reader, - ClientConnected.getTypeScriptAlgebraicType() - ); - }, -}; - -export default ClientConnected; +export default {}; diff --git a/crates/bindings-typescript/examples/empty/src/module_bindings/client_disconnected_reducer.ts b/crates/bindings-typescript/examples/empty/src/module_bindings/client_disconnected_reducer.ts index 385acd9bd3c..2ca99c88fea 100644 --- a/crates/bindings-typescript/examples/empty/src/module_bindings/client_disconnected_reducer.ts +++ b/crates/bindings-typescript/examples/empty/src/module_bindings/client_disconnected_reducer.ts @@ -4,65 +4,10 @@ /* eslint-disable */ /* tslint:disable */ import { - AlgebraicType as __AlgebraicTypeValue, - BinaryReader as __BinaryReader, - BinaryWriter as __BinaryWriter, - ClientCache as __ClientCache, - ConnectionId as __ConnectionId, - DbConnectionBuilder as __DbConnectionBuilder, - DbConnectionImpl as __DbConnectionImpl, - Identity as __Identity, - SubscriptionBuilderImpl as __SubscriptionBuilderImpl, - TableCache as __TableCache, - TimeDuration as __TimeDuration, - Timestamp as __Timestamp, - deepEqual as __deepEqual, - type AlgebraicType as __AlgebraicTypeType, - type AlgebraicTypeVariants as __AlgebraicTypeVariants, - type CallReducerFlags as __CallReducerFlags, - type ErrorContextInterface as __ErrorContextInterface, - type Event as __Event, - type EventContextInterface as __EventContextInterface, - type ReducerEventContextInterface as __ReducerEventContextInterface, - type SubscriptionEventContextInterface as __SubscriptionEventContextInterface, - type TableHandle as __TableHandle, + TypeBuilder as __TypeBuilder, + t as __t, + type AlgebraicTypeType as __AlgebraicTypeType, + type Infer as __Infer, } from 'spacetimedb'; -export type ClientDisconnected = {}; -let _cached_ClientDisconnected_type_value: __AlgebraicTypeType | null = null; - -/** - * An object for generated helper functions. - */ -export const ClientDisconnected = { - /** - * A function which returns this type represented as an AlgebraicType. - * This function is derived from the AlgebraicType used to generate this type. - */ - getTypeScriptAlgebraicType(): __AlgebraicTypeType { - if (_cached_ClientDisconnected_type_value) - return _cached_ClientDisconnected_type_value; - _cached_ClientDisconnected_type_value = __AlgebraicTypeValue.Product({ - elements: [], - }); - _cached_ClientDisconnected_type_value.value.elements.push(); - return _cached_ClientDisconnected_type_value; - }, - - serialize(writer: __BinaryWriter, value: ClientDisconnected): void { - __AlgebraicTypeValue.serializeValue( - writer, - ClientDisconnected.getTypeScriptAlgebraicType(), - value - ); - }, - - deserialize(reader: __BinaryReader): ClientDisconnected { - return __AlgebraicTypeValue.deserializeValue( - reader, - ClientDisconnected.getTypeScriptAlgebraicType() - ); - }, -}; - -export default ClientDisconnected; +export default {}; diff --git a/crates/bindings-typescript/examples/empty/src/module_bindings/index.ts b/crates/bindings-typescript/examples/empty/src/module_bindings/index.ts index 08fef081923..8dccaeb0421 100644 --- a/crates/bindings-typescript/examples/empty/src/module_bindings/index.ts +++ b/crates/bindings-typescript/examples/empty/src/module_bindings/index.ts @@ -1,303 +1,111 @@ // THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE // WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. -// This was generated using spacetimedb cli version 1.6.0 (commit 64812908d1dd2fb0ac1a44ae8c669306ce3f001e). +// This was generated using spacetimedb cli version 1.7.0 (commit fe91e78ecbfb9714b563a08a5290db6a780f1bc3). /* eslint-disable */ /* tslint:disable */ import { - AlgebraicType as __AlgebraicTypeValue, - BinaryReader as __BinaryReader, - BinaryWriter as __BinaryWriter, - ClientCache as __ClientCache, - ConnectionId as __ConnectionId, DbConnectionBuilder as __DbConnectionBuilder, DbConnectionImpl as __DbConnectionImpl, - Identity as __Identity, SubscriptionBuilderImpl as __SubscriptionBuilderImpl, - TableCache as __TableCache, - TimeDuration as __TimeDuration, - Timestamp as __Timestamp, - deepEqual as __deepEqual, - type AlgebraicType as __AlgebraicTypeType, - type AlgebraicTypeVariants as __AlgebraicTypeVariants, - type CallReducerFlags as __CallReducerFlags, + TypeBuilder as __TypeBuilder, + convertToAccessorMap as __convertToAccessorMap, + reducerSchema as __reducerSchema, + reducers as __reducers, + schema as __schema, + t as __t, + table as __table, + type AlgebraicTypeType as __AlgebraicTypeType, + type DbConnectionConfig as __DbConnectionConfig, type ErrorContextInterface as __ErrorContextInterface, type Event as __Event, type EventContextInterface as __EventContextInterface, + type Infer as __Infer, type ReducerEventContextInterface as __ReducerEventContextInterface, + type RemoteModule as __RemoteModule, type SubscriptionEventContextInterface as __SubscriptionEventContextInterface, - type TableHandle as __TableHandle, } from 'spacetimedb'; // Import and reexport all reducer arg types -import { Init } from './init_reducer.ts'; +import Init from './init_reducer'; export { Init }; -import { ClientConnected } from './client_connected_reducer.ts'; +import ClientConnected from './client_connected_reducer'; export { ClientConnected }; -import { ClientDisconnected } from './client_disconnected_reducer.ts'; +import ClientDisconnected from './client_disconnected_reducer'; export { ClientDisconnected }; -import { Add } from './add_reducer.ts'; +import Add from './add_reducer'; export { Add }; -import { SayHello } from './say_hello_reducer.ts'; +import SayHello from './say_hello_reducer'; export { SayHello }; // Import and reexport all table handle types -import { PersonTableHandle } from './person_table.ts'; -export { PersonTableHandle }; +import PersonRow from './person_table'; +export { PersonRow }; // Import and reexport all types -import { Person } from './person_type.ts'; +import Person from './person_type'; export { Person }; -const REMOTE_MODULE = { - tables: { - person: { - tableName: 'person' as const, - rowType: Person.getTypeScriptAlgebraicType(), - }, - }, - reducers: { - init: { - reducerName: 'init', - argsType: Init.getTypeScriptAlgebraicType(), - }, - client_connected: { - reducerName: 'client_connected', - argsType: ClientConnected.getTypeScriptAlgebraicType(), +const tablesSchema = __schema( + __table( + { + name: 'person', + indexes: [], + constraints: [], }, - client_disconnected: { - reducerName: 'client_disconnected', - argsType: ClientDisconnected.getTypeScriptAlgebraicType(), - }, - add: { - reducerName: 'add', - argsType: Add.getTypeScriptAlgebraicType(), - }, - say_hello: { - reducerName: 'say_hello', - argsType: SayHello.getTypeScriptAlgebraicType(), - }, - }, + PersonRow + ) +); + +const reducersSchema = __reducers( + __reducerSchema('init', Init), + __reducerSchema('client_connected', ClientConnected), + __reducerSchema('client_disconnected', ClientDisconnected), + __reducerSchema('add', Add), + __reducerSchema('say_hello', SayHello) +); + +const REMOTE_MODULE = { versionInfo: { - cliVersion: '1.6.0', - }, - // Constructors which are used by the DbConnectionImpl to - // extract type information from the generated RemoteModule. - // - // NOTE: This is not strictly necessary for `eventContextConstructor` because - // all we do is build a TypeScript object which we could have done inside the - // SDK, but if in the future we wanted to create a class this would be - // necessary because classes have methods, so we'll keep it. - eventContextConstructor: ( - imp: __DbConnectionImpl, - event: __Event - ) => { - return { - ...(imp as DbConnection), - event, - }; - }, - dbViewConstructor: (imp: __DbConnectionImpl) => { - return new RemoteTables(imp); + cliVersion: '1.7.0' as const, }, - reducersConstructor: ( - imp: __DbConnectionImpl, - setReducerFlags: SetReducerFlags - ) => { - return new RemoteReducers(imp, setReducerFlags); - }, - setReducerFlagsConstructor: () => { - return new SetReducerFlags(); - }, -}; - -// A type representing all the possible variants of a reducer. -export type Reducer = - | never - | { name: 'Init'; args: Init } - | { name: 'ClientConnected'; args: ClientConnected } - | { name: 'ClientDisconnected'; args: ClientDisconnected } - | { name: 'Add'; args: Add } - | { name: 'SayHello'; args: SayHello }; - -export class RemoteReducers { - constructor( - private connection: __DbConnectionImpl, - private setCallReducerFlags: SetReducerFlags - ) {} - - init() { - this.connection.callReducer( - 'init', - new Uint8Array(0), - this.setCallReducerFlags.initFlags - ); - } - - onInit(callback: (ctx: ReducerEventContext) => void) { - this.connection.onReducer('init', callback); - } - - removeOnInit(callback: (ctx: ReducerEventContext) => void) { - this.connection.offReducer('init', callback); - } - - clientConnected() { - this.connection.callReducer( - 'client_connected', - new Uint8Array(0), - this.setCallReducerFlags.clientConnectedFlags - ); - } - - onClientConnected(callback: (ctx: ReducerEventContext) => void) { - this.connection.onReducer('client_connected', callback); - } - - removeOnClientConnected(callback: (ctx: ReducerEventContext) => void) { - this.connection.offReducer('client_connected', callback); - } - - clientDisconnected() { - this.connection.callReducer( - 'client_disconnected', - new Uint8Array(0), - this.setCallReducerFlags.clientDisconnectedFlags - ); - } - - onClientDisconnected(callback: (ctx: ReducerEventContext) => void) { - this.connection.onReducer('client_disconnected', callback); - } - - removeOnClientDisconnected(callback: (ctx: ReducerEventContext) => void) { - this.connection.offReducer('client_disconnected', callback); - } - - add(name: string) { - const __args = { name }; - let __writer = new __BinaryWriter(1024); - Add.serialize(__writer, __args); - let __argsBuffer = __writer.getBuffer(); - this.connection.callReducer( - 'add', - __argsBuffer, - this.setCallReducerFlags.addFlags - ); - } - - onAdd(callback: (ctx: ReducerEventContext, name: string) => void) { - this.connection.onReducer('add', callback); - } - - removeOnAdd(callback: (ctx: ReducerEventContext, name: string) => void) { - this.connection.offReducer('add', callback); - } - - sayHello() { - this.connection.callReducer( - 'say_hello', - new Uint8Array(0), - this.setCallReducerFlags.sayHelloFlags - ); - } - - onSayHello(callback: (ctx: ReducerEventContext) => void) { - this.connection.onReducer('say_hello', callback); - } - - removeOnSayHello(callback: (ctx: ReducerEventContext) => void) { - this.connection.offReducer('say_hello', callback); - } -} - -export class SetReducerFlags { - initFlags: __CallReducerFlags = 'FullUpdate'; - init(flags: __CallReducerFlags) { - this.initFlags = flags; - } - - clientConnectedFlags: __CallReducerFlags = 'FullUpdate'; - clientConnected(flags: __CallReducerFlags) { - this.clientConnectedFlags = flags; - } - - clientDisconnectedFlags: __CallReducerFlags = 'FullUpdate'; - clientDisconnected(flags: __CallReducerFlags) { - this.clientDisconnectedFlags = flags; - } - - addFlags: __CallReducerFlags = 'FullUpdate'; - add(flags: __CallReducerFlags) { - this.addFlags = flags; - } - - sayHelloFlags: __CallReducerFlags = 'FullUpdate'; - sayHello(flags: __CallReducerFlags) { - this.sayHelloFlags = flags; - } -} + tables: tablesSchema.schemaType.tables, + reducers: reducersSchema.reducersType.reducers, +} satisfies __RemoteModule< + typeof tablesSchema.schemaType, + typeof reducersSchema.reducersType +>; -export class RemoteTables { - constructor(private connection: __DbConnectionImpl) {} +export const tables = __convertToAccessorMap(tablesSchema.schemaType.tables); +export const reducers = __convertToAccessorMap( + reducersSchema.reducersType.reducers +); - get person(): PersonTableHandle<'person'> { - // clientCache is a private property - return new PersonTableHandle( - ( - this.connection as unknown as { clientCache: __ClientCache } - ).clientCache.getOrCreateTable(REMOTE_MODULE.tables.person) - ); - } -} +export type EventContext = __EventContextInterface; +export type ReducerEventContext = __ReducerEventContextInterface< + typeof REMOTE_MODULE +>; +export type SubscriptionEventContext = __SubscriptionEventContextInterface< + typeof REMOTE_MODULE +>; +export type ErrorContext = __ErrorContextInterface; export class SubscriptionBuilder extends __SubscriptionBuilderImpl< - RemoteTables, - RemoteReducers, - SetReducerFlags + typeof REMOTE_MODULE > {} -export class DbConnection extends __DbConnectionImpl< - RemoteTables, - RemoteReducers, - SetReducerFlags -> { - static builder = (): __DbConnectionBuilder< - DbConnection, - ErrorContext, - SubscriptionEventContext - > => { - return new __DbConnectionBuilder< - DbConnection, - ErrorContext, - SubscriptionEventContext - >(REMOTE_MODULE, (imp: __DbConnectionImpl) => imp as DbConnection); +export class DbConnectionBuilder extends __DbConnectionBuilder {} + +export class DbConnection extends __DbConnectionImpl { + static builder = (): DbConnectionBuilder => { + return new DbConnectionBuilder( + REMOTE_MODULE, + (config: __DbConnectionConfig) => + new DbConnection(config) + ); }; subscriptionBuilder = (): SubscriptionBuilder => { return new SubscriptionBuilder(this); }; } - -export type EventContext = __EventContextInterface< - RemoteTables, - RemoteReducers, - SetReducerFlags, - Reducer ->; -export type ReducerEventContext = __ReducerEventContextInterface< - RemoteTables, - RemoteReducers, - SetReducerFlags, - Reducer ->; -export type SubscriptionEventContext = __SubscriptionEventContextInterface< - RemoteTables, - RemoteReducers, - SetReducerFlags ->; -export type ErrorContext = __ErrorContextInterface< - RemoteTables, - RemoteReducers, - SetReducerFlags ->; diff --git a/crates/bindings-typescript/examples/empty/src/module_bindings/init_reducer.ts b/crates/bindings-typescript/examples/empty/src/module_bindings/init_reducer.ts index 12e0782fc1a..2ca99c88fea 100644 --- a/crates/bindings-typescript/examples/empty/src/module_bindings/init_reducer.ts +++ b/crates/bindings-typescript/examples/empty/src/module_bindings/init_reducer.ts @@ -4,62 +4,10 @@ /* eslint-disable */ /* tslint:disable */ import { - AlgebraicType as __AlgebraicTypeValue, - BinaryReader as __BinaryReader, - BinaryWriter as __BinaryWriter, - ClientCache as __ClientCache, - ConnectionId as __ConnectionId, - DbConnectionBuilder as __DbConnectionBuilder, - DbConnectionImpl as __DbConnectionImpl, - Identity as __Identity, - SubscriptionBuilderImpl as __SubscriptionBuilderImpl, - TableCache as __TableCache, - TimeDuration as __TimeDuration, - Timestamp as __Timestamp, - deepEqual as __deepEqual, - type AlgebraicType as __AlgebraicTypeType, - type AlgebraicTypeVariants as __AlgebraicTypeVariants, - type CallReducerFlags as __CallReducerFlags, - type ErrorContextInterface as __ErrorContextInterface, - type Event as __Event, - type EventContextInterface as __EventContextInterface, - type ReducerEventContextInterface as __ReducerEventContextInterface, - type SubscriptionEventContextInterface as __SubscriptionEventContextInterface, - type TableHandle as __TableHandle, + TypeBuilder as __TypeBuilder, + t as __t, + type AlgebraicTypeType as __AlgebraicTypeType, + type Infer as __Infer, } from 'spacetimedb'; -export type Init = {}; -let _cached_Init_type_value: __AlgebraicTypeType | null = null; - -/** - * An object for generated helper functions. - */ -export const Init = { - /** - * A function which returns this type represented as an AlgebraicType. - * This function is derived from the AlgebraicType used to generate this type. - */ - getTypeScriptAlgebraicType(): __AlgebraicTypeType { - if (_cached_Init_type_value) return _cached_Init_type_value; - _cached_Init_type_value = __AlgebraicTypeValue.Product({ elements: [] }); - _cached_Init_type_value.value.elements.push(); - return _cached_Init_type_value; - }, - - serialize(writer: __BinaryWriter, value: Init): void { - __AlgebraicTypeValue.serializeValue( - writer, - Init.getTypeScriptAlgebraicType(), - value - ); - }, - - deserialize(reader: __BinaryReader): Init { - return __AlgebraicTypeValue.deserializeValue( - reader, - Init.getTypeScriptAlgebraicType() - ); - }, -}; - -export default Init; +export default {}; diff --git a/crates/bindings-typescript/examples/empty/src/module_bindings/person_table.ts b/crates/bindings-typescript/examples/empty/src/module_bindings/person_table.ts index c50f51f9ff0..0f70f74f617 100644 --- a/crates/bindings-typescript/examples/empty/src/module_bindings/person_table.ts +++ b/crates/bindings-typescript/examples/empty/src/module_bindings/person_table.ts @@ -4,80 +4,12 @@ /* eslint-disable */ /* tslint:disable */ import { - AlgebraicType as __AlgebraicTypeValue, - BinaryReader as __BinaryReader, - BinaryWriter as __BinaryWriter, - ClientCache as __ClientCache, - ConnectionId as __ConnectionId, - DbConnectionBuilder as __DbConnectionBuilder, - DbConnectionImpl as __DbConnectionImpl, - Identity as __Identity, - SubscriptionBuilderImpl as __SubscriptionBuilderImpl, - TableCache as __TableCache, - TimeDuration as __TimeDuration, - Timestamp as __Timestamp, - deepEqual as __deepEqual, - type AlgebraicType as __AlgebraicTypeType, - type AlgebraicTypeVariants as __AlgebraicTypeVariants, - type CallReducerFlags as __CallReducerFlags, - type ErrorContextInterface as __ErrorContextInterface, - type Event as __Event, - type EventContextInterface as __EventContextInterface, - type ReducerEventContextInterface as __ReducerEventContextInterface, - type SubscriptionEventContextInterface as __SubscriptionEventContextInterface, - type TableHandle as __TableHandle, + TypeBuilder as __TypeBuilder, + t as __t, + type AlgebraicTypeType as __AlgebraicTypeType, + type Infer as __Infer, } from 'spacetimedb'; -import { Person } from './person_type'; -import { - type EventContext, - type Reducer, - RemoteReducers, - RemoteTables, -} from '.'; -declare type __keep = [EventContext, Reducer, RemoteReducers, RemoteTables]; - -/** - * Table handle for the table `person`. - * - * Obtain a handle from the [`person`] property on [`RemoteTables`], - * like `ctx.db.person`. - * - * Users are encouraged not to explicitly reference this type, - * but to directly chain method calls, - * like `ctx.db.person.on_insert(...)`. - */ -export class PersonTableHandle - implements __TableHandle -{ - // phantom type to track the table name - readonly tableName!: TableName; - tableCache: __TableCache; - - constructor(tableCache: __TableCache) { - this.tableCache = tableCache; - } - - count(): number { - return this.tableCache.count(); - } - - iter(): Iterable { - return this.tableCache.iter(); - } - - onInsert = (cb: (ctx: EventContext, row: Person) => void) => { - return this.tableCache.onInsert(cb); - }; - - removeOnInsert = (cb: (ctx: EventContext, row: Person) => void) => { - return this.tableCache.removeOnInsert(cb); - }; - - onDelete = (cb: (ctx: EventContext, row: Person) => void) => { - return this.tableCache.onDelete(cb); - }; - removeOnDelete = (cb: (ctx: EventContext, row: Person) => void) => { - return this.tableCache.removeOnDelete(cb); - }; -} +export default __t.row({ + name: __t.string(), +}); diff --git a/crates/bindings-typescript/examples/empty/src/module_bindings/person_type.ts b/crates/bindings-typescript/examples/empty/src/module_bindings/person_type.ts index c3085f4f3ba..1156775a3cf 100644 --- a/crates/bindings-typescript/examples/empty/src/module_bindings/person_type.ts +++ b/crates/bindings-typescript/examples/empty/src/module_bindings/person_type.ts @@ -4,67 +4,12 @@ /* eslint-disable */ /* tslint:disable */ import { - AlgebraicType as __AlgebraicTypeValue, - BinaryReader as __BinaryReader, - BinaryWriter as __BinaryWriter, - ClientCache as __ClientCache, - ConnectionId as __ConnectionId, - DbConnectionBuilder as __DbConnectionBuilder, - DbConnectionImpl as __DbConnectionImpl, - Identity as __Identity, - SubscriptionBuilderImpl as __SubscriptionBuilderImpl, - TableCache as __TableCache, - TimeDuration as __TimeDuration, - Timestamp as __Timestamp, - deepEqual as __deepEqual, - type AlgebraicType as __AlgebraicTypeType, - type AlgebraicTypeVariants as __AlgebraicTypeVariants, - type CallReducerFlags as __CallReducerFlags, - type ErrorContextInterface as __ErrorContextInterface, - type Event as __Event, - type EventContextInterface as __EventContextInterface, - type ReducerEventContextInterface as __ReducerEventContextInterface, - type SubscriptionEventContextInterface as __SubscriptionEventContextInterface, - type TableHandle as __TableHandle, + TypeBuilder as __TypeBuilder, + t as __t, + type AlgebraicTypeType as __AlgebraicTypeType, + type Infer as __Infer, } from 'spacetimedb'; -export type Person = { - name: string; -}; -let _cached_Person_type_value: __AlgebraicTypeType | null = null; - -/** - * An object for generated helper functions. - */ -export const Person = { - /** - * A function which returns this type represented as an AlgebraicType. - * This function is derived from the AlgebraicType used to generate this type. - */ - getTypeScriptAlgebraicType(): __AlgebraicTypeType { - if (_cached_Person_type_value) return _cached_Person_type_value; - _cached_Person_type_value = __AlgebraicTypeValue.Product({ elements: [] }); - _cached_Person_type_value.value.elements.push({ - name: 'name', - algebraicType: __AlgebraicTypeValue.String, - }); - return _cached_Person_type_value; - }, - - serialize(writer: __BinaryWriter, value: Person): void { - __AlgebraicTypeValue.serializeValue( - writer, - Person.getTypeScriptAlgebraicType(), - value - ); - }, - - deserialize(reader: __BinaryReader): Person { - return __AlgebraicTypeValue.deserializeValue( - reader, - Person.getTypeScriptAlgebraicType() - ); - }, -}; - -export default Person; +export default __t.object('Person', { + name: __t.string(), +}); diff --git a/crates/bindings-typescript/examples/empty/src/module_bindings/say_hello_reducer.ts b/crates/bindings-typescript/examples/empty/src/module_bindings/say_hello_reducer.ts index e0cdd2d5259..2ca99c88fea 100644 --- a/crates/bindings-typescript/examples/empty/src/module_bindings/say_hello_reducer.ts +++ b/crates/bindings-typescript/examples/empty/src/module_bindings/say_hello_reducer.ts @@ -4,64 +4,10 @@ /* eslint-disable */ /* tslint:disable */ import { - AlgebraicType as __AlgebraicTypeValue, - BinaryReader as __BinaryReader, - BinaryWriter as __BinaryWriter, - ClientCache as __ClientCache, - ConnectionId as __ConnectionId, - DbConnectionBuilder as __DbConnectionBuilder, - DbConnectionImpl as __DbConnectionImpl, - Identity as __Identity, - SubscriptionBuilderImpl as __SubscriptionBuilderImpl, - TableCache as __TableCache, - TimeDuration as __TimeDuration, - Timestamp as __Timestamp, - deepEqual as __deepEqual, - type AlgebraicType as __AlgebraicTypeType, - type AlgebraicTypeVariants as __AlgebraicTypeVariants, - type CallReducerFlags as __CallReducerFlags, - type ErrorContextInterface as __ErrorContextInterface, - type Event as __Event, - type EventContextInterface as __EventContextInterface, - type ReducerEventContextInterface as __ReducerEventContextInterface, - type SubscriptionEventContextInterface as __SubscriptionEventContextInterface, - type TableHandle as __TableHandle, + TypeBuilder as __TypeBuilder, + t as __t, + type AlgebraicTypeType as __AlgebraicTypeType, + type Infer as __Infer, } from 'spacetimedb'; -export type SayHello = {}; -let _cached_SayHello_type_value: __AlgebraicTypeType | null = null; - -/** - * An object for generated helper functions. - */ -export const SayHello = { - /** - * A function which returns this type represented as an AlgebraicType. - * This function is derived from the AlgebraicType used to generate this type. - */ - getTypeScriptAlgebraicType(): __AlgebraicTypeType { - if (_cached_SayHello_type_value) return _cached_SayHello_type_value; - _cached_SayHello_type_value = __AlgebraicTypeValue.Product({ - elements: [], - }); - _cached_SayHello_type_value.value.elements.push(); - return _cached_SayHello_type_value; - }, - - serialize(writer: __BinaryWriter, value: SayHello): void { - __AlgebraicTypeValue.serializeValue( - writer, - SayHello.getTypeScriptAlgebraicType(), - value - ); - }, - - deserialize(reader: __BinaryReader): SayHello { - return __AlgebraicTypeValue.deserializeValue( - reader, - SayHello.getTypeScriptAlgebraicType() - ); - }, -}; - -export default SayHello; +export default {}; diff --git a/crates/bindings-typescript/examples/quickstart-chat/src/App.tsx b/crates/bindings-typescript/examples/quickstart-chat/src/App.tsx index a6cf1f2751c..bee83b9e697 100644 --- a/crates/bindings-typescript/examples/quickstart-chat/src/App.tsx +++ b/crates/bindings-typescript/examples/quickstart-chat/src/App.tsx @@ -1,8 +1,8 @@ import React, { useState } from 'react'; import './App.css'; -import { DbConnection, Message, User } from './module_bindings'; -import { useSpacetimeDB, useTable, where, eq } from 'spacetimedb/react'; -import { Identity, Timestamp } from 'spacetimedb'; +import { tables, reducers, Message } from './module_bindings'; +import { useSpacetimeDB, useTable, where, eq, useReducer } from 'spacetimedb/react'; +import { Identity, Infer, Timestamp } from 'spacetimedb'; export type PrettyMessage = { senderName: string; @@ -14,21 +14,21 @@ export type PrettyMessage = { function App() { const [newName, setNewName] = useState(''); const [settingName, setSettingName] = useState(false); - const [systemMessages, setSystemMessages] = useState([] as Message[]); + const [systemMessages, setSystemMessages] = useState([] as Infer[]); const [newMessage, setNewMessage] = useState(''); - const conn = useSpacetimeDB(); - conn.setReducerFlags(); - const { identity, isActive: connected } = conn; + const { identity, isActive: connected } = useSpacetimeDB(); + const setName = useReducer(reducers.setName); + const sendMessage = useReducer(reducers.sendMessage); // Subscribe to all messages in the chat - const { rows: messages } = useTable('message'); + const messages = useTable(tables.message); // Subscribe to all online users in the chat // so we can show who's online and demonstrate // the `where` and `eq` query expressions - const { rows: onlineUsers } = useTable( - 'user', + const onlineUsers = useTable( + tables.user, where(eq('online', true)), { onInsert: user => { @@ -58,13 +58,13 @@ function App() { } ); - const { rows: offlineUsers } = useTable( - 'user', + const offlineUsers = useTable( + tables.user, where(eq('online', false)) ); const users = [...onlineUsers, ...offlineUsers]; - const prettyMessages: PrettyMessage[] = Array.from(messages) + const prettyMessages: PrettyMessage[] = messages .concat(systemMessages) .sort((a, b) => (a.sent.toDate() > b.sent.toDate() ? 1 : -1)) .map(message => { @@ -97,13 +97,13 @@ function App() { const onSubmitNewName = (e: React.FormEvent) => { e.preventDefault(); setSettingName(false); - conn.reducers.setName(newName); + setName({ name: newName }); }; const onSubmitMessage = (e: React.FormEvent) => { e.preventDefault(); setNewMessage(''); - conn.reducers.sendMessage(newMessage); + sendMessage({ text: newMessage }); }; return ( diff --git a/crates/bindings-typescript/examples/quickstart-chat/src/module_bindings/identity_connected_reducer.ts b/crates/bindings-typescript/examples/quickstart-chat/src/module_bindings/identity_connected_reducer.ts index c5f335a93ad..2ca99c88fea 100644 --- a/crates/bindings-typescript/examples/quickstart-chat/src/module_bindings/identity_connected_reducer.ts +++ b/crates/bindings-typescript/examples/quickstart-chat/src/module_bindings/identity_connected_reducer.ts @@ -4,65 +4,10 @@ /* eslint-disable */ /* tslint:disable */ import { - AlgebraicType as __AlgebraicTypeValue, - BinaryReader as __BinaryReader, - BinaryWriter as __BinaryWriter, - ClientCache as __ClientCache, - ConnectionId as __ConnectionId, - DbConnectionBuilder as __DbConnectionBuilder, - DbConnectionImpl as __DbConnectionImpl, - Identity as __Identity, - SubscriptionBuilderImpl as __SubscriptionBuilderImpl, - TableCache as __TableCache, - TimeDuration as __TimeDuration, - Timestamp as __Timestamp, - deepEqual as __deepEqual, - type AlgebraicType as __AlgebraicTypeType, - type AlgebraicTypeVariants as __AlgebraicTypeVariants, - type CallReducerFlags as __CallReducerFlags, - type ErrorContextInterface as __ErrorContextInterface, - type Event as __Event, - type EventContextInterface as __EventContextInterface, - type ReducerEventContextInterface as __ReducerEventContextInterface, - type SubscriptionEventContextInterface as __SubscriptionEventContextInterface, - type TableHandle as __TableHandle, + TypeBuilder as __TypeBuilder, + t as __t, + type AlgebraicTypeType as __AlgebraicTypeType, + type Infer as __Infer, } from 'spacetimedb'; -export type IdentityConnected = {}; -let _cached_IdentityConnected_type_value: __AlgebraicTypeType | null = null; - -/** - * An object for generated helper functions. - */ -export const IdentityConnected = { - /** - * A function which returns this type represented as an AlgebraicType. - * This function is derived from the AlgebraicType used to generate this type. - */ - getTypeScriptAlgebraicType(): __AlgebraicTypeType { - if (_cached_IdentityConnected_type_value) - return _cached_IdentityConnected_type_value; - _cached_IdentityConnected_type_value = __AlgebraicTypeValue.Product({ - elements: [], - }); - _cached_IdentityConnected_type_value.value.elements.push(); - return _cached_IdentityConnected_type_value; - }, - - serialize(writer: __BinaryWriter, value: IdentityConnected): void { - __AlgebraicTypeValue.serializeValue( - writer, - IdentityConnected.getTypeScriptAlgebraicType(), - value - ); - }, - - deserialize(reader: __BinaryReader): IdentityConnected { - return __AlgebraicTypeValue.deserializeValue( - reader, - IdentityConnected.getTypeScriptAlgebraicType() - ); - }, -}; - -export default IdentityConnected; +export default {}; diff --git a/crates/bindings-typescript/examples/quickstart-chat/src/module_bindings/identity_disconnected_reducer.ts b/crates/bindings-typescript/examples/quickstart-chat/src/module_bindings/identity_disconnected_reducer.ts index 1d2c3901076..2ca99c88fea 100644 --- a/crates/bindings-typescript/examples/quickstart-chat/src/module_bindings/identity_disconnected_reducer.ts +++ b/crates/bindings-typescript/examples/quickstart-chat/src/module_bindings/identity_disconnected_reducer.ts @@ -4,65 +4,10 @@ /* eslint-disable */ /* tslint:disable */ import { - AlgebraicType as __AlgebraicTypeValue, - BinaryReader as __BinaryReader, - BinaryWriter as __BinaryWriter, - ClientCache as __ClientCache, - ConnectionId as __ConnectionId, - DbConnectionBuilder as __DbConnectionBuilder, - DbConnectionImpl as __DbConnectionImpl, - Identity as __Identity, - SubscriptionBuilderImpl as __SubscriptionBuilderImpl, - TableCache as __TableCache, - TimeDuration as __TimeDuration, - Timestamp as __Timestamp, - deepEqual as __deepEqual, - type AlgebraicType as __AlgebraicTypeType, - type AlgebraicTypeVariants as __AlgebraicTypeVariants, - type CallReducerFlags as __CallReducerFlags, - type ErrorContextInterface as __ErrorContextInterface, - type Event as __Event, - type EventContextInterface as __EventContextInterface, - type ReducerEventContextInterface as __ReducerEventContextInterface, - type SubscriptionEventContextInterface as __SubscriptionEventContextInterface, - type TableHandle as __TableHandle, + TypeBuilder as __TypeBuilder, + t as __t, + type AlgebraicTypeType as __AlgebraicTypeType, + type Infer as __Infer, } from 'spacetimedb'; -export type IdentityDisconnected = {}; -let _cached_IdentityDisconnected_type_value: __AlgebraicTypeType | null = null; - -/** - * An object for generated helper functions. - */ -export const IdentityDisconnected = { - /** - * A function which returns this type represented as an AlgebraicType. - * This function is derived from the AlgebraicType used to generate this type. - */ - getTypeScriptAlgebraicType(): __AlgebraicTypeType { - if (_cached_IdentityDisconnected_type_value) - return _cached_IdentityDisconnected_type_value; - _cached_IdentityDisconnected_type_value = __AlgebraicTypeValue.Product({ - elements: [], - }); - _cached_IdentityDisconnected_type_value.value.elements.push(); - return _cached_IdentityDisconnected_type_value; - }, - - serialize(writer: __BinaryWriter, value: IdentityDisconnected): void { - __AlgebraicTypeValue.serializeValue( - writer, - IdentityDisconnected.getTypeScriptAlgebraicType(), - value - ); - }, - - deserialize(reader: __BinaryReader): IdentityDisconnected { - return __AlgebraicTypeValue.deserializeValue( - reader, - IdentityDisconnected.getTypeScriptAlgebraicType() - ); - }, -}; - -export default IdentityDisconnected; +export default {}; diff --git a/crates/bindings-typescript/examples/quickstart-chat/src/module_bindings/index.ts b/crates/bindings-typescript/examples/quickstart-chat/src/module_bindings/index.ts index a7794856485..c7e54e38d83 100644 --- a/crates/bindings-typescript/examples/quickstart-chat/src/module_bindings/index.ts +++ b/crates/bindings-typescript/examples/quickstart-chat/src/module_bindings/index.ts @@ -1,279 +1,126 @@ // THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE // WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. -// This was generated using spacetimedb cli version 1.6.0 (commit 64812908d1dd2fb0ac1a44ae8c669306ce3f001e). +// This was generated using spacetimedb cli version 1.7.0 (commit fe91e78ecbfb9714b563a08a5290db6a780f1bc3). /* eslint-disable */ /* tslint:disable */ import { - AlgebraicType as __AlgebraicTypeValue, - BinaryReader as __BinaryReader, - BinaryWriter as __BinaryWriter, - ClientCache as __ClientCache, - ConnectionId as __ConnectionId, DbConnectionBuilder as __DbConnectionBuilder, DbConnectionImpl as __DbConnectionImpl, - Identity as __Identity, SubscriptionBuilderImpl as __SubscriptionBuilderImpl, - TableCache as __TableCache, - TimeDuration as __TimeDuration, - Timestamp as __Timestamp, - deepEqual as __deepEqual, - type AlgebraicType as __AlgebraicTypeType, - type AlgebraicTypeVariants as __AlgebraicTypeVariants, - type CallReducerFlags as __CallReducerFlags, + TypeBuilder as __TypeBuilder, + convertToAccessorMap as __convertToAccessorMap, + reducerSchema as __reducerSchema, + reducers as __reducers, + schema as __schema, + t as __t, + table as __table, + type AlgebraicTypeType as __AlgebraicTypeType, + type DbConnectionConfig as __DbConnectionConfig, type ErrorContextInterface as __ErrorContextInterface, type Event as __Event, type EventContextInterface as __EventContextInterface, + type Infer as __Infer, type ReducerEventContextInterface as __ReducerEventContextInterface, + type RemoteModule as __RemoteModule, type SubscriptionEventContextInterface as __SubscriptionEventContextInterface, - type TableHandle as __TableHandle, } from 'spacetimedb'; // Import and reexport all reducer arg types -import { IdentityConnected } from './identity_connected_reducer.ts'; +import IdentityConnected from './identity_connected_reducer'; export { IdentityConnected }; -import { IdentityDisconnected } from './identity_disconnected_reducer.ts'; +import IdentityDisconnected from './identity_disconnected_reducer'; export { IdentityDisconnected }; -import { SendMessage } from './send_message_reducer.ts'; +import SendMessage from './send_message_reducer'; export { SendMessage }; -import { SetName } from './set_name_reducer.ts'; +import SetName from './set_name_reducer'; export { SetName }; // Import and reexport all table handle types -import { MessageTableHandle } from './message_table.ts'; -export { MessageTableHandle }; -import { UserTableHandle } from './user_table.ts'; -export { UserTableHandle }; +import MessageRow from './message_table'; +export { MessageRow }; +import UserRow from './user_table'; +export { UserRow }; // Import and reexport all types -import { Message } from './message_type.ts'; +import Message from './message_type'; export { Message }; -import { User } from './user_type.ts'; +import User from './user_type'; export { User }; -const REMOTE_MODULE = { - tables: { - message: { - tableName: 'message' as const, - rowType: Message.getTypeScriptAlgebraicType(), - }, - user: { - tableName: 'user' as const, - rowType: User.getTypeScriptAlgebraicType(), - primaryKey: 'identity' as const, - primaryKeyInfo: { - colName: 'identity' as const, - colType: ( - User.getTypeScriptAlgebraicType() as __AlgebraicTypeVariants.Product - ).value.elements[0].algebraicType, - }, - }, - }, - reducers: { - identity_connected: { - reducerName: 'identity_connected', - argsType: IdentityConnected.getTypeScriptAlgebraicType(), +const tablesSchema = __schema( + __table( + { + name: 'message', + indexes: [], + constraints: [], }, - identity_disconnected: { - reducerName: 'identity_disconnected', - argsType: IdentityDisconnected.getTypeScriptAlgebraicType(), + MessageRow + ), + __table( + { + name: 'user', + indexes: [ + { name: 'identity', algorithm: 'btree', columns: ['identity'] }, + ], + constraints: [ + { + name: 'user_identity_key', + constraint: 'unique', + columns: ['identity'], + }, + ], }, - send_message: { - reducerName: 'send_message', - argsType: SendMessage.getTypeScriptAlgebraicType(), - }, - set_name: { - reducerName: 'set_name', - argsType: SetName.getTypeScriptAlgebraicType(), - }, - }, - versionInfo: { - cliVersion: '1.7.0', - }, - // Constructors which are used by the DbConnectionImpl to - // extract type information from the generated RemoteModule. - // - // NOTE: This is not strictly necessary for `eventContextConstructor` because - // all we do is build a TypeScript object which we could have done inside the - // SDK, but if in the future we wanted to create a class this would be - // necessary because classes have methods, so we'll keep it. - eventContextConstructor: ( - imp: __DbConnectionImpl, - event: __Event - ) => { - return { - ...(imp as DbConnection), - event, - }; - }, - dbViewConstructor: (imp: __DbConnectionImpl) => { - return new RemoteTables(imp); - }, - reducersConstructor: ( - imp: __DbConnectionImpl, - setReducerFlags: SetReducerFlags - ) => { - return new RemoteReducers(imp, setReducerFlags); - }, - setReducerFlagsConstructor: () => { - return new SetReducerFlags(); - }, -} satisfies RemoteModule; - -// A type representing all the possible variants of a reducer. -export type Reducer = - | never - | { name: 'IdentityConnected'; args: IdentityConnected } - | { name: 'IdentityDisconnected'; args: IdentityDisconnected } - | { name: 'SendMessage'; args: SendMessage } - | { name: 'SetName'; args: SetName }; - -export class RemoteReducers { - constructor( - private connection: __DbConnectionImpl, - private setCallReducerFlags: SetReducerFlags - ) {} - - onIdentityConnected(callback: (ctx: ReducerEventContext) => void) { - this.connection.onReducer('identity_connected', callback); - } - - removeOnIdentityConnected(callback: (ctx: ReducerEventContext) => void) { - this.connection.offReducer('identity_connected', callback); - } - - onIdentityDisconnected(callback: (ctx: ReducerEventContext) => void) { - this.connection.onReducer('identity_disconnected', callback); - } - - removeOnIdentityDisconnected(callback: (ctx: ReducerEventContext) => void) { - this.connection.offReducer('identity_disconnected', callback); - } - - sendMessage(text: string) { - const __args = { text }; - let __writer = new __BinaryWriter(1024); - SendMessage.serialize(__writer, __args); - let __argsBuffer = __writer.getBuffer(); - this.connection.callReducer( - 'send_message', - __argsBuffer, - this.setCallReducerFlags.sendMessageFlags - ); - } - - onSendMessage(callback: (ctx: ReducerEventContext, text: string) => void) { - this.connection.onReducer('send_message', callback); - } - - removeOnSendMessage( - callback: (ctx: ReducerEventContext, text: string) => void - ) { - this.connection.offReducer('send_message', callback); - } - - setName(name: string) { - const __args = { name }; - let __writer = new __BinaryWriter(1024); - SetName.serialize(__writer, __args); - let __argsBuffer = __writer.getBuffer(); - this.connection.callReducer( - 'set_name', - __argsBuffer, - this.setCallReducerFlags.setNameFlags - ); - } + UserRow + ) +); - onSetName(callback: (ctx: ReducerEventContext, name: string) => void) { - this.connection.onReducer('set_name', callback); - } +const reducersSchema = __reducers( + __reducerSchema('send_message', SendMessage), + __reducerSchema('set_name', SetName) +); - removeOnSetName(callback: (ctx: ReducerEventContext, name: string) => void) { - this.connection.offReducer('set_name', callback); - } -} - -export class SetReducerFlags { - sendMessageFlags: __CallReducerFlags = 'FullUpdate'; - sendMessage(flags: __CallReducerFlags) { - this.sendMessageFlags = flags; - } - - setNameFlags: __CallReducerFlags = 'FullUpdate'; - setName(flags: __CallReducerFlags) { - this.setNameFlags = flags; - } -} - -export class RemoteTables { - constructor(private connection: __DbConnectionImpl) {} +const REMOTE_MODULE = { + versionInfo: { + cliVersion: '1.7.0' as const, + }, + tables: tablesSchema.schemaType.tables, + reducers: reducersSchema.reducersType.reducers, +} satisfies __RemoteModule< + typeof tablesSchema.schemaType, + typeof reducersSchema.reducersType +>; - get message(): MessageTableHandle<'message'> { - // clientCache is a private property - return new MessageTableHandle( - ( - this.connection as unknown as { clientCache: __ClientCache } - ).clientCache.getOrCreateTable(REMOTE_MODULE.tables.message) - ); - } +export const tables = __convertToAccessorMap(tablesSchema.schemaType.tables); +export const reducers = __convertToAccessorMap( + reducersSchema.reducersType.reducers +); - get user(): UserTableHandle<'user'> { - // clientCache is a private property - return new UserTableHandle( - ( - this.connection as unknown as { clientCache: __ClientCache } - ).clientCache.getOrCreateTable(REMOTE_MODULE.tables.user) - ); - } -} +export type EventContext = __EventContextInterface; +export type ReducerEventContext = __ReducerEventContextInterface< + typeof REMOTE_MODULE +>; +export type SubscriptionEventContext = __SubscriptionEventContextInterface< + typeof REMOTE_MODULE +>; +export type ErrorContext = __ErrorContextInterface; export class SubscriptionBuilder extends __SubscriptionBuilderImpl< - RemoteTables, - RemoteReducers, - SetReducerFlags + typeof REMOTE_MODULE > {} -export class DbConnection extends __DbConnectionImpl< - RemoteTables, - RemoteReducers, - SetReducerFlags -> { - static builder = (): __DbConnectionBuilder< - DbConnection, - ErrorContext, - SubscriptionEventContext - > => { - return new __DbConnectionBuilder< - DbConnection, - ErrorContext, - SubscriptionEventContext - >(REMOTE_MODULE, (imp: __DbConnectionImpl) => imp as DbConnection); +export class DbConnectionBuilder extends __DbConnectionBuilder {} + +export class DbConnection extends __DbConnectionImpl { + static builder = (): DbConnectionBuilder => { + return new DbConnectionBuilder( + REMOTE_MODULE, + (config: __DbConnectionConfig) => + new DbConnection(config) + ); }; subscriptionBuilder = (): SubscriptionBuilder => { return new SubscriptionBuilder(this); }; } - -export type EventContext = __EventContextInterface< - RemoteTables, - RemoteReducers, - SetReducerFlags, - Reducer ->; -export type ReducerEventContext = __ReducerEventContextInterface< - RemoteTables, - RemoteReducers, - SetReducerFlags, - Reducer ->; -export type SubscriptionEventContext = __SubscriptionEventContextInterface< - RemoteTables, - RemoteReducers, - SetReducerFlags ->; -export type ErrorContext = __ErrorContextInterface< - RemoteTables, - RemoteReducers, - SetReducerFlags ->; diff --git a/crates/bindings-typescript/examples/quickstart-chat/src/module_bindings/message_table.ts b/crates/bindings-typescript/examples/quickstart-chat/src/module_bindings/message_table.ts index 26b0bc1e34a..87044c64df4 100644 --- a/crates/bindings-typescript/examples/quickstart-chat/src/module_bindings/message_table.ts +++ b/crates/bindings-typescript/examples/quickstart-chat/src/module_bindings/message_table.ts @@ -4,80 +4,14 @@ /* eslint-disable */ /* tslint:disable */ import { - AlgebraicType as __AlgebraicTypeValue, - BinaryReader as __BinaryReader, - BinaryWriter as __BinaryWriter, - ClientCache as __ClientCache, - ConnectionId as __ConnectionId, - DbConnectionBuilder as __DbConnectionBuilder, - DbConnectionImpl as __DbConnectionImpl, - Identity as __Identity, - SubscriptionBuilderImpl as __SubscriptionBuilderImpl, - TableCache as __TableCache, - TimeDuration as __TimeDuration, - Timestamp as __Timestamp, - deepEqual as __deepEqual, - type AlgebraicType as __AlgebraicTypeType, - type AlgebraicTypeVariants as __AlgebraicTypeVariants, - type CallReducerFlags as __CallReducerFlags, - type ErrorContextInterface as __ErrorContextInterface, - type Event as __Event, - type EventContextInterface as __EventContextInterface, - type ReducerEventContextInterface as __ReducerEventContextInterface, - type SubscriptionEventContextInterface as __SubscriptionEventContextInterface, - type TableHandle as __TableHandle, + TypeBuilder as __TypeBuilder, + t as __t, + type AlgebraicTypeType as __AlgebraicTypeType, + type Infer as __Infer, } from 'spacetimedb'; -import { Message } from './message_type'; -import { - type EventContext, - type Reducer, - RemoteReducers, - RemoteTables, -} from '.'; -declare type __keep = [EventContext, Reducer, RemoteReducers, RemoteTables]; - -/** - * Table handle for the table `message`. - * - * Obtain a handle from the [`message`] property on [`RemoteTables`], - * like `ctx.db.message`. - * - * Users are encouraged not to explicitly reference this type, - * but to directly chain method calls, - * like `ctx.db.message.on_insert(...)`. - */ -export class MessageTableHandle - implements __TableHandle -{ - // phantom type to track the table name - readonly tableName!: TableName; - tableCache: __TableCache; - - constructor(tableCache: __TableCache) { - this.tableCache = tableCache; - } - - count(): number { - return this.tableCache.count(); - } - - iter(): Iterable { - return this.tableCache.iter(); - } - - onInsert = (cb: (ctx: EventContext, row: Message) => void) => { - return this.tableCache.onInsert(cb); - }; - - removeOnInsert = (cb: (ctx: EventContext, row: Message) => void) => { - return this.tableCache.removeOnInsert(cb); - }; - - onDelete = (cb: (ctx: EventContext, row: Message) => void) => { - return this.tableCache.onDelete(cb); - }; - removeOnDelete = (cb: (ctx: EventContext, row: Message) => void) => { - return this.tableCache.removeOnDelete(cb); - }; -} +export default __t.row({ + sender: __t.identity(), + sent: __t.timestamp(), + text: __t.string(), +}); diff --git a/crates/bindings-typescript/examples/quickstart-chat/src/module_bindings/message_type.ts b/crates/bindings-typescript/examples/quickstart-chat/src/module_bindings/message_type.ts index e4080eced64..c15fedf0f6a 100644 --- a/crates/bindings-typescript/examples/quickstart-chat/src/module_bindings/message_type.ts +++ b/crates/bindings-typescript/examples/quickstart-chat/src/module_bindings/message_type.ts @@ -4,76 +4,14 @@ /* eslint-disable */ /* tslint:disable */ import { - AlgebraicType as __AlgebraicTypeValue, - BinaryReader as __BinaryReader, - BinaryWriter as __BinaryWriter, - ClientCache as __ClientCache, - ConnectionId as __ConnectionId, - DbConnectionBuilder as __DbConnectionBuilder, - DbConnectionImpl as __DbConnectionImpl, - Identity as __Identity, - SubscriptionBuilderImpl as __SubscriptionBuilderImpl, - TableCache as __TableCache, - TimeDuration as __TimeDuration, - Timestamp as __Timestamp, - deepEqual as __deepEqual, - type AlgebraicType as __AlgebraicTypeType, - type AlgebraicTypeVariants as __AlgebraicTypeVariants, - type CallReducerFlags as __CallReducerFlags, - type ErrorContextInterface as __ErrorContextInterface, - type Event as __Event, - type EventContextInterface as __EventContextInterface, - type ReducerEventContextInterface as __ReducerEventContextInterface, - type SubscriptionEventContextInterface as __SubscriptionEventContextInterface, - type TableHandle as __TableHandle, + TypeBuilder as __TypeBuilder, + t as __t, + type AlgebraicTypeType as __AlgebraicTypeType, + type Infer as __Infer, } from 'spacetimedb'; -export type Message = { - sender: __Identity; - sent: __Timestamp; - text: string; -}; -let _cached_Message_type_value: __AlgebraicTypeType | null = null; - -/** - * An object for generated helper functions. - */ -export const Message = { - /** - * A function which returns this type represented as an AlgebraicType. - * This function is derived from the AlgebraicType used to generate this type. - */ - getTypeScriptAlgebraicType(): __AlgebraicTypeType { - if (_cached_Message_type_value) return _cached_Message_type_value; - _cached_Message_type_value = __AlgebraicTypeValue.Product({ elements: [] }); - _cached_Message_type_value.value.elements.push( - { - name: 'sender', - algebraicType: __AlgebraicTypeValue.createIdentityType(), - }, - { - name: 'sent', - algebraicType: __AlgebraicTypeValue.createTimestampType(), - }, - { name: 'text', algebraicType: __AlgebraicTypeValue.String } - ); - return _cached_Message_type_value; - }, - - serialize(writer: __BinaryWriter, value: Message): void { - __AlgebraicTypeValue.serializeValue( - writer, - Message.getTypeScriptAlgebraicType(), - value - ); - }, - - deserialize(reader: __BinaryReader): Message { - return __AlgebraicTypeValue.deserializeValue( - reader, - Message.getTypeScriptAlgebraicType() - ); - }, -}; - -export default Message; +export default __t.object('Message', { + sender: __t.identity(), + sent: __t.timestamp(), + text: __t.string(), +}); diff --git a/crates/bindings-typescript/examples/quickstart-chat/src/module_bindings/send_message_reducer.ts b/crates/bindings-typescript/examples/quickstart-chat/src/module_bindings/send_message_reducer.ts index e30d08b732e..4aeb65a0ae9 100644 --- a/crates/bindings-typescript/examples/quickstart-chat/src/module_bindings/send_message_reducer.ts +++ b/crates/bindings-typescript/examples/quickstart-chat/src/module_bindings/send_message_reducer.ts @@ -4,69 +4,12 @@ /* eslint-disable */ /* tslint:disable */ import { - AlgebraicType as __AlgebraicTypeValue, - BinaryReader as __BinaryReader, - BinaryWriter as __BinaryWriter, - ClientCache as __ClientCache, - ConnectionId as __ConnectionId, - DbConnectionBuilder as __DbConnectionBuilder, - DbConnectionImpl as __DbConnectionImpl, - Identity as __Identity, - SubscriptionBuilderImpl as __SubscriptionBuilderImpl, - TableCache as __TableCache, - TimeDuration as __TimeDuration, - Timestamp as __Timestamp, - deepEqual as __deepEqual, - type AlgebraicType as __AlgebraicTypeType, - type AlgebraicTypeVariants as __AlgebraicTypeVariants, - type CallReducerFlags as __CallReducerFlags, - type ErrorContextInterface as __ErrorContextInterface, - type Event as __Event, - type EventContextInterface as __EventContextInterface, - type ReducerEventContextInterface as __ReducerEventContextInterface, - type SubscriptionEventContextInterface as __SubscriptionEventContextInterface, - type TableHandle as __TableHandle, + TypeBuilder as __TypeBuilder, + t as __t, + type AlgebraicTypeType as __AlgebraicTypeType, + type Infer as __Infer, } from 'spacetimedb'; -export type SendMessage = { - text: string; +export default { + text: __t.string(), }; -let _cached_SendMessage_type_value: __AlgebraicTypeType | null = null; - -/** - * An object for generated helper functions. - */ -export const SendMessage = { - /** - * A function which returns this type represented as an AlgebraicType. - * This function is derived from the AlgebraicType used to generate this type. - */ - getTypeScriptAlgebraicType(): __AlgebraicTypeType { - if (_cached_SendMessage_type_value) return _cached_SendMessage_type_value; - _cached_SendMessage_type_value = __AlgebraicTypeValue.Product({ - elements: [], - }); - _cached_SendMessage_type_value.value.elements.push({ - name: 'text', - algebraicType: __AlgebraicTypeValue.String, - }); - return _cached_SendMessage_type_value; - }, - - serialize(writer: __BinaryWriter, value: SendMessage): void { - __AlgebraicTypeValue.serializeValue( - writer, - SendMessage.getTypeScriptAlgebraicType(), - value - ); - }, - - deserialize(reader: __BinaryReader): SendMessage { - return __AlgebraicTypeValue.deserializeValue( - reader, - SendMessage.getTypeScriptAlgebraicType() - ); - }, -}; - -export default SendMessage; diff --git a/crates/bindings-typescript/examples/quickstart-chat/src/module_bindings/set_name_reducer.ts b/crates/bindings-typescript/examples/quickstart-chat/src/module_bindings/set_name_reducer.ts index e571226e6be..85081559c7d 100644 --- a/crates/bindings-typescript/examples/quickstart-chat/src/module_bindings/set_name_reducer.ts +++ b/crates/bindings-typescript/examples/quickstart-chat/src/module_bindings/set_name_reducer.ts @@ -4,67 +4,12 @@ /* eslint-disable */ /* tslint:disable */ import { - AlgebraicType as __AlgebraicTypeValue, - BinaryReader as __BinaryReader, - BinaryWriter as __BinaryWriter, - ClientCache as __ClientCache, - ConnectionId as __ConnectionId, - DbConnectionBuilder as __DbConnectionBuilder, - DbConnectionImpl as __DbConnectionImpl, - Identity as __Identity, - SubscriptionBuilderImpl as __SubscriptionBuilderImpl, - TableCache as __TableCache, - TimeDuration as __TimeDuration, - Timestamp as __Timestamp, - deepEqual as __deepEqual, - type AlgebraicType as __AlgebraicTypeType, - type AlgebraicTypeVariants as __AlgebraicTypeVariants, - type CallReducerFlags as __CallReducerFlags, - type ErrorContextInterface as __ErrorContextInterface, - type Event as __Event, - type EventContextInterface as __EventContextInterface, - type ReducerEventContextInterface as __ReducerEventContextInterface, - type SubscriptionEventContextInterface as __SubscriptionEventContextInterface, - type TableHandle as __TableHandle, + TypeBuilder as __TypeBuilder, + t as __t, + type AlgebraicTypeType as __AlgebraicTypeType, + type Infer as __Infer, } from 'spacetimedb'; -export type SetName = { - name: string; +export default { + name: __t.string(), }; -let _cached_SetName_type_value: __AlgebraicTypeType | null = null; - -/** - * An object for generated helper functions. - */ -export const SetName = { - /** - * A function which returns this type represented as an AlgebraicType. - * This function is derived from the AlgebraicType used to generate this type. - */ - getTypeScriptAlgebraicType(): __AlgebraicTypeType { - if (_cached_SetName_type_value) return _cached_SetName_type_value; - _cached_SetName_type_value = __AlgebraicTypeValue.Product({ elements: [] }); - _cached_SetName_type_value.value.elements.push({ - name: 'name', - algebraicType: __AlgebraicTypeValue.String, - }); - return _cached_SetName_type_value; - }, - - serialize(writer: __BinaryWriter, value: SetName): void { - __AlgebraicTypeValue.serializeValue( - writer, - SetName.getTypeScriptAlgebraicType(), - value - ); - }, - - deserialize(reader: __BinaryReader): SetName { - return __AlgebraicTypeValue.deserializeValue( - reader, - SetName.getTypeScriptAlgebraicType() - ); - }, -}; - -export default SetName; diff --git a/crates/bindings-typescript/examples/quickstart-chat/src/module_bindings/user_table.ts b/crates/bindings-typescript/examples/quickstart-chat/src/module_bindings/user_table.ts index 61c82b8de12..93e32698c03 100644 --- a/crates/bindings-typescript/examples/quickstart-chat/src/module_bindings/user_table.ts +++ b/crates/bindings-typescript/examples/quickstart-chat/src/module_bindings/user_table.ts @@ -4,113 +4,14 @@ /* eslint-disable */ /* tslint:disable */ import { - AlgebraicType as __AlgebraicTypeValue, - BinaryReader as __BinaryReader, - BinaryWriter as __BinaryWriter, - ClientCache as __ClientCache, - ConnectionId as __ConnectionId, - DbConnectionBuilder as __DbConnectionBuilder, - DbConnectionImpl as __DbConnectionImpl, - Identity as __Identity, - SubscriptionBuilderImpl as __SubscriptionBuilderImpl, - TableCache as __TableCache, - TimeDuration as __TimeDuration, - Timestamp as __Timestamp, - deepEqual as __deepEqual, - type AlgebraicType as __AlgebraicTypeType, - type AlgebraicTypeVariants as __AlgebraicTypeVariants, - type CallReducerFlags as __CallReducerFlags, - type ErrorContextInterface as __ErrorContextInterface, - type Event as __Event, - type EventContextInterface as __EventContextInterface, - type ReducerEventContextInterface as __ReducerEventContextInterface, - type SubscriptionEventContextInterface as __SubscriptionEventContextInterface, - type TableHandle as __TableHandle, + TypeBuilder as __TypeBuilder, + t as __t, + type AlgebraicTypeType as __AlgebraicTypeType, + type Infer as __Infer, } from 'spacetimedb'; -import { User } from './user_type'; -import { - type EventContext, - type Reducer, - RemoteReducers, - RemoteTables, -} from '.'; -declare type __keep = [EventContext, Reducer, RemoteReducers, RemoteTables]; - -/** - * Table handle for the table `user`. - * - * Obtain a handle from the [`user`] property on [`RemoteTables`], - * like `ctx.db.user`. - * - * Users are encouraged not to explicitly reference this type, - * but to directly chain method calls, - * like `ctx.db.user.on_insert(...)`. - */ -export class UserTableHandle< - TableName extends string, -> extends ClientTable { - // phantom type to track the table name - readonly tableName!: TableName; - tableCache: __TableCache; - - constructor(tableCache: __TableCache) { - this.tableCache = tableCache; - } - - count(): number { - return this.tableCache.count(); - } - - iter(): Iterable { - return this.tableCache.iter(); - } - /** - * Access to the `identity` unique index on the table `user`, - * which allows point queries on the field of the same name - * via the [`UserIdentityUnique.find`] method. - * - * Users are encouraged not to explicitly reference this type, - * but to directly chain method calls, - * like `ctx.db.user.identity().find(...)`. - * - * Get a handle on the `identity` unique index on the table `user`. - */ - identity = { - // Find the subscribed row whose `identity` column value is equal to `colVal`, - // if such a row is present in the client cache. - find: (colVal: __Identity): User | undefined => { - for (let row of this.tableCache.iter()) { - if (__deepEqual(row.identity, colVal)) { - return row; - } - } - }, - }; - - onInsert = (cb: (ctx: EventContext, row: User) => void) => { - return this.tableCache.onInsert(cb); - }; - - removeOnInsert = (cb: (ctx: EventContext, row: User) => void) => { - return this.tableCache.removeOnInsert(cb); - }; - - onDelete = (cb: (ctx: EventContext, row: User) => void) => { - return this.tableCache.onDelete(cb); - }; - - removeOnDelete = (cb: (ctx: EventContext, row: User) => void) => { - return this.tableCache.removeOnDelete(cb); - }; - - // Updates are only defined for tables with primary keys. - onUpdate = (cb: (ctx: EventContext, oldRow: User, newRow: User) => void) => { - return this.tableCache.onUpdate(cb); - }; - removeOnUpdate = ( - cb: (ctx: EventContext, onRow: User, newRow: User) => void - ) => { - return this.tableCache.removeOnUpdate(cb); - }; -} +export default __t.row({ + identity: __t.identity().primaryKey(), + name: __t.option(__t.string()), + online: __t.bool(), +}); diff --git a/crates/bindings-typescript/examples/quickstart-chat/src/module_bindings/user_type.ts b/crates/bindings-typescript/examples/quickstart-chat/src/module_bindings/user_type.ts index 974cc8d48e6..89123cb9ad8 100644 --- a/crates/bindings-typescript/examples/quickstart-chat/src/module_bindings/user_type.ts +++ b/crates/bindings-typescript/examples/quickstart-chat/src/module_bindings/user_type.ts @@ -4,78 +4,14 @@ /* eslint-disable */ /* tslint:disable */ import { - AlgebraicType as __AlgebraicTypeValue, - BinaryReader as __BinaryReader, - BinaryWriter as __BinaryWriter, - ClientCache as __ClientCache, - ConnectionId as __ConnectionId, - DbConnectionBuilder as __DbConnectionBuilder, - DbConnectionImpl as __DbConnectionImpl, - Identity as __Identity, - SubscriptionBuilderImpl as __SubscriptionBuilderImpl, - TableCache as __TableCache, - TimeDuration as __TimeDuration, - Timestamp as __Timestamp, - deepEqual as __deepEqual, - type AlgebraicType as __AlgebraicTypeType, - type AlgebraicTypeVariants as __AlgebraicTypeVariants, - type CallReducerFlags as __CallReducerFlags, - type ErrorContextInterface as __ErrorContextInterface, - type Event as __Event, - type EventContextInterface as __EventContextInterface, - type ReducerEventContextInterface as __ReducerEventContextInterface, - type SubscriptionEventContextInterface as __SubscriptionEventContextInterface, - type TableHandle as __TableHandle, + TypeBuilder as __TypeBuilder, + t as __t, + type AlgebraicTypeType as __AlgebraicTypeType, + type Infer as __Infer, } from 'spacetimedb'; -export type User = { - identity: __Identity; - name: string | undefined; - online: boolean; -}; -let _cached_User_type_value: __AlgebraicTypeType | null = null; - -/** - * An object for generated helper functions. - */ -export const User = { - /** - * A function which returns this type represented as an AlgebraicType. - * This function is derived from the AlgebraicType used to generate this type. - */ - getTypeScriptAlgebraicType(): __AlgebraicTypeType { - if (_cached_User_type_value) return _cached_User_type_value; - _cached_User_type_value = __AlgebraicTypeValue.Product({ elements: [] }); - _cached_User_type_value.value.elements.push( - { - name: 'identity', - algebraicType: __AlgebraicTypeValue.createIdentityType(), - }, - { - name: 'name', - algebraicType: __AlgebraicTypeValue.createOptionType( - __AlgebraicTypeValue.String - ), - }, - { name: 'online', algebraicType: __AlgebraicTypeValue.Bool } - ); - return _cached_User_type_value; - }, - - serialize(writer: __BinaryWriter, value: User): void { - __AlgebraicTypeValue.serializeValue( - writer, - User.getTypeScriptAlgebraicType(), - value - ); - }, - - deserialize(reader: __BinaryReader): User { - return __AlgebraicTypeValue.deserializeValue( - reader, - User.getTypeScriptAlgebraicType() - ); - }, -}; - -export default User; +export default __t.object('User', { + identity: __t.identity(), + name: __t.option(__t.string()), + online: __t.bool(), +}); diff --git a/crates/bindings-typescript/src/sdk/client_api/index.ts b/crates/bindings-typescript/src/sdk/client_api/index.ts index 97687590999..54996337bfe 100644 --- a/crates/bindings-typescript/src/sdk/client_api/index.ts +++ b/crates/bindings-typescript/src/sdk/client_api/index.ts @@ -1,7 +1,7 @@ // THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE // WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. -// This was generated using spacetimedb cli version 1.7.0 (commit cb16789be729954a7c47b87fb40b35baa0bd1029). +// This was generated using spacetimedb cli version 1.7.0 (commit fe91e78ecbfb9714b563a08a5290db6a780f1bc3). /* eslint-disable */ /* tslint:disable */ @@ -107,11 +107,7 @@ const reducersSchema = __reducers(); const REMOTE_MODULE = { versionInfo: { -<<<<<<< HEAD cliVersion: '1.7.0' as const, -======= - cliVersion: '1.6.0', ->>>>>>> 6d91ae0f5 (Now generating module_bindings for examples and also moved pnpm scripts into portable rust scripts) }, tables: tablesSchema.schemaType.tables, reducers: reducersSchema.reducersType.reducers, diff --git a/crates/bindings-typescript/test-app/src/module_bindings/index.ts b/crates/bindings-typescript/test-app/src/module_bindings/index.ts index bf9be8260c8..fd80b80658c 100644 --- a/crates/bindings-typescript/test-app/src/module_bindings/index.ts +++ b/crates/bindings-typescript/test-app/src/module_bindings/index.ts @@ -1,11 +1,7 @@ // THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE // WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. -<<<<<<< HEAD -// This was generated using ../../../src/index cli version 1.7.0 (commit 57bd49bec937a3ae060c1c9af85979525fdb839d). -======= -// This was generated using spacetimedb cli version 1.6.0 (commit 64812908d1dd2fb0ac1a44ae8c669306ce3f001e). ->>>>>>> 6d91ae0f5 (Now generating module_bindings for examples and also moved pnpm scripts into portable rust scripts) +// This was generated using spacetimedb cli version 1.7.0 (commit fe91e78ecbfb9714b563a08a5290db6a780f1bc3). /* eslint-disable */ /* tslint:disable */ diff --git a/docs/docs/07-Client SDK Languages/06-typescript-quickstart.md b/docs/docs/07-Client SDK Languages/06-typescript-quickstart.md index 558dd02b429..38086d94373 100644 --- a/docs/docs/07-Client SDK Languages/06-typescript-quickstart.md +++ b/docs/docs/07-Client SDK Languages/06-typescript-quickstart.md @@ -63,7 +63,7 @@ Replace the entire contents of `client/src/App.tsx` with the following: ```tsx import React, { useEffect, useState } from 'react'; -import { DbConnection, Message, User } from './module_bindings'; +import { Message, tables, reducers } from './module_bindings'; import { useSpacetimeDB, useTable, where, eq } from 'spacetimedb/react'; import { Identity, Timestamp } from 'spacetimedb'; import './App.css'; @@ -78,7 +78,7 @@ export type PrettyMessage = { function App() { const [newName, setNewName] = useState(''); const [settingName, setSettingName] = useState(false); - const [systemMessages, setSystemMessages] = useState([] as Message[]); + const [systemMessages, setSystemMessages] = useState([] as Infer[]); const [newMessage, setNewMessage] = useState(''); const prettyMessages: PrettyMessage[] = []; @@ -570,11 +570,12 @@ Once SpacetimeDB is connected, we can easily access the data in the client cache Add the following `useSpacetimeDB` hook to the top of your render function, just below your `useState` declarations. ```tsx -const conn = useSpacetimeDB(); -const { identity, isActive: connected } = conn; +const { identity, isActive: connected } = useSpacetimeDB(); +const setName = useReducer(reducers.setName); +const sendMessage = useReducer(reducers.sendMessage); // Subscribe to all messages in the chat -const { rows: messages } = useTable('message'); +const messages = useTable(tables.message); ``` Next replace `const onlineUsers: User[] = [];` with the following: @@ -583,8 +584,8 @@ Next replace `const onlineUsers: User[] = [];` with the following: // Subscribe to all online users in the chat // so we can show who's online and demonstrate // the `where` and `eq` query expressions -const { rows: onlineUsers } = useTable( - 'user', +const onlineUsers = useTable( + tables.user, where(eq('online', true)) ); ``` @@ -594,11 +595,11 @@ Notice that we can filter users in the `user` table based on their online status Let's now prettify our messages in our render function by sorting them by their `sent` timestamp, and joining the username of the sender to the message by looking up the user by their `Identity` in the `user` table. Replace `const prettyMessages: PrettyMessage[] = [];` with the following: ```tsx -const prettyMessages: PrettyMessage[] = Array.from(messages) +const prettyMessages: PrettyMessage[] = messages .sort((a, b) => (a.sent.toDate() > b.sent.toDate() ? 1 : -1)) .map(message => { const user = users.find( - u => u.identity.toHexString() === message.sender.toHexString() + u => u.identity.message.sender.toHexString() ); return { senderName: user?.name || message.sender.toHexString().substring(0, 8), @@ -642,7 +643,7 @@ Modify the `onSubmitNewName` callback by adding a call to the `setName` reducer: const onSubmitNewName = (e: React.FormEvent) => { e.preventDefault(); setSettingName(false); - conn.reducers.setName(newName); + setName({ name: newName }); }; ``` @@ -652,7 +653,7 @@ Next, modify the `onSubmitMessage` callback by adding a call to the `sendMessage const onSubmitMessage = (e: React.FormEvent) => { e.preventDefault(); setNewMessage(''); - conn.reducers.sendMessage(newMessage); + sendMessage({ text: newMessage }); }; ``` @@ -750,8 +751,8 @@ const prettyMessages: PrettyMessage[] = Array.from(messages) Finally, let's also subscribe to offline users so we can show them in the sidebar as well. Replace `const offlineUsers: User[] = [];` with: ```tsx -const { rows: offlineUsers } = useTable( - 'user', +const offlineUsers = useTable( + tables.user, where(eq('online', false)) ); ``` diff --git a/tools/gen-bindings/src/main.rs b/tools/gen-bindings/src/main.rs index d48f3cdeea8..2a9aec9c157 100644 --- a/tools/gen-bindings/src/main.rs +++ b/tools/gen-bindings/src/main.rs @@ -20,6 +20,9 @@ struct Cli { /// Replacement for 'spacetimedb' (relative string used in imports) #[arg(long)] replacement: Option, + + #[arg(long)] + index_replacement: Option, } fn run_inherit(cmd: &str, args: &[&str]) -> Result<()> { @@ -62,7 +65,12 @@ fn main() -> Result<()> { ], )?; - if let Some(replacement) = &args.replacement { + if let Some(other_replacement) = &args.replacement { + let index_replacement = if let Some(index_replacement) = &args.index_replacement { + index_replacement + } else { + other_replacement + }; // 5) Replace "spacetimedb" references let opts = ReplaceOptions { @@ -86,10 +94,10 @@ fn main() -> Result<()> { ], }; - let stats = replace_in_tree(&args.out_dir, replacement, &opts)?; + let stats = replace_in_tree(&args.out_dir, index_replacement, other_replacement, &opts)?; println!( "Replaced 'spacetimedb' → '{}' in {} files ({} occurrences).", - replacement, stats.files_changed, stats.occurrences + other_replacement, stats.files_changed, stats.occurrences ); } Ok(()) diff --git a/tools/generate-client-api/src/main.rs b/tools/generate-client-api/src/main.rs index 0fb05f0c1b8..0f6d35a1015 100644 --- a/tools/generate-client-api/src/main.rs +++ b/tools/generate-client-api/src/main.rs @@ -37,7 +37,8 @@ fn run_capture(cmd: &str, args: &[&str]) -> Result { fn main() -> Result<()> { let out_dir = "src/sdk/client_api"; - let replacement = "../../index"; + let index_replacement = "../../index"; + let other_replacement = "../../lib/type_builders"; // 1) Build prerequisite run_inherit("cargo", &["build", "-p", "spacetimedb-standalone"])?; @@ -97,7 +98,7 @@ fn main() -> Result<()> { include_hidden: false, ignore_globs: vec!["**/node_modules/**".into(), "**/dist/**".into()], }; - let stats = replace_in_tree(out_dir, replacement, &opts)?; + let stats = replace_in_tree(out_dir, index_replacement, other_replacement, &opts)?; println!( "Replaced {} occurrences across {} files.", stats.occurrences, stats.files_changed diff --git a/tools/replace-spacetimedb/src/lib.rs b/tools/replace-spacetimedb/src/lib.rs index d4e4b10ff22..af28c392cae 100644 --- a/tools/replace-spacetimedb/src/lib.rs +++ b/tools/replace-spacetimedb/src/lib.rs @@ -37,7 +37,8 @@ pub struct ReplaceStats { /// (works for both `import { ... } from ...` and `export { ... } from ...`). pub fn replace_in_tree( root: impl AsRef, - replacement: &str, + replacement_index_ts: &str, + replacement_other_ts: &str, options: &ReplaceOptions, ) -> io::Result { let root = root.as_ref().to_path_buf(); @@ -48,7 +49,6 @@ pub fn replace_in_tree( )); } - // Match exactly the two forms you want. No backreferences needed. // We intentionally DO NOT include a trailing semicolon so we preserve it (or its absence). let re_single = Regex::new(r#"}\s*from\s*'spacetimedb'"#).unwrap(); let re_double = Regex::new(r#"}\s*from\s*"spacetimedb""#).unwrap(); @@ -87,6 +87,21 @@ pub fn replace_in_tree( continue; } + // Only operate on .ts files. + // If you want .tsx too, add it here. + let is_ts = path.extension().and_then(|e| e.to_str()) == Some("ts"); + if !is_ts { + continue; + } + + // Decide which replacement to use for this file + let is_index_ts = path.file_name().and_then(|n| n.to_str()) == Some("index.ts"); + let repl = if is_index_ts { + replacement_index_ts + } else { + replacement_other_ts + }; + let bytes = match fs::read(path) { Ok(b) => b, Err(err) => { @@ -111,16 +126,18 @@ pub fn replace_in_tree( } // Do the replacements, preserving quote style - let updated1 = re_single.replace_all(&content, format!("}} from '{}'", replacement)); - let updated = re_double.replace_all(&updated1, format!("}} from \"{}\"", replacement)); + let updated1 = re_single.replace_all(&content, format!("}} from '{}'", repl)); + let updated = re_double.replace_all(&updated1, format!("}} from \"{}\"", repl)); if options.dry_run { - println!("[dry-run] {} ({} matches)", path.display(), matches); + let which = if is_index_ts { "index.ts" } else { "*.ts" }; + println!("[dry-run] {} ({} matches, rule: {})", path.display(), matches, which); } else if let Err(err) = fs::write(path, updated.as_ref()) { eprintln!("write error {}: {err}", path.display()); continue; } else { - println!("✔ {} ({} matches)", path.display(), matches); + let which = if is_index_ts { "index.ts" } else { "*.ts" }; + println!("✔ {} ({} matches, rule: {})", path.display(), matches, which); } files_changed += 1; diff --git a/tools/replace-spacetimedb/src/main.rs b/tools/replace-spacetimedb/src/main.rs index 1fea98e23a4..3f64d2b7f23 100644 --- a/tools/replace-spacetimedb/src/main.rs +++ b/tools/replace-spacetimedb/src/main.rs @@ -8,8 +8,10 @@ use replace_spacetimedb::{replace_in_tree, ReplaceOptions}; struct Args { /// Directory to process (recursively). target_dir: String, - /// Replacement string for 'spacetimedb'. - replacement: String, + /// Replacement string for 'spacetimedb' in index files. + index_replacement: String, + /// Replacement string for 'spacetimedb' in other files. + other_replacement: String, /// Only process given file extensions (comma-separated, e.g. "ts,tsx,js,json"). #[arg(long)] @@ -49,7 +51,7 @@ fn main() { ignore_globs: args.ignore, }; - match replace_in_tree(&args.target_dir, &args.replacement, &opts) { + match replace_in_tree(&args.target_dir, &args.index_replacement, &args.other_replacement, &opts) { Ok(stats) => { println!( "✅ Replacement complete. Files changed: {} | Occurrences: {}", From 29913d462eaf47960d407dbe104b90700872cfc7 Mon Sep 17 00:00:00 2001 From: = Date: Tue, 11 Nov 2025 17:07:54 -0500 Subject: [PATCH 35/49] Snap and format --- .../codegen__codegen_typescript.snap | 4192 +++-------------- tools/gen-bindings/src/main.rs | 8 +- tools/generate-client-api/src/main.rs | 5 +- tools/replace-spacetimedb/src/lib.rs | 14 +- tools/replace-spacetimedb/src/main.rs | 7 +- 5 files changed, 617 insertions(+), 3609 deletions(-) diff --git a/crates/codegen/tests/snapshots/codegen__codegen_typescript.snap b/crates/codegen/tests/snapshots/codegen__codegen_typescript.snap index 799e85147f9..94fc2c0b3fc 100644 --- a/crates/codegen/tests/snapshots/codegen__codegen_typescript.snap +++ b/crates/codegen/tests/snapshots/codegen__codegen_typescript.snap @@ -9,64 +9,15 @@ expression: outfiles /* eslint-disable */ /* tslint:disable */ import { - AlgebraicType as __AlgebraicTypeValue, - BinaryReader as __BinaryReader, - BinaryWriter as __BinaryWriter, - ClientCache as __ClientCache, - ConnectionId as __ConnectionId, - DbConnectionBuilder as __DbConnectionBuilder, - DbConnectionImpl as __DbConnectionImpl, - Identity as __Identity, - SubscriptionBuilderImpl as __SubscriptionBuilderImpl, - TableCache as __TableCache, - TimeDuration as __TimeDuration, - Timestamp as __Timestamp, - deepEqual as __deepEqual, - type AlgebraicType as __AlgebraicTypeType, - type AlgebraicTypeVariants as __AlgebraicTypeVariants, - type CallReducerFlags as __CallReducerFlags, - type ErrorContextInterface as __ErrorContextInterface, - type Event as __Event, - type EventContextInterface as __EventContextInterface, - type ReducerEventContextInterface as __ReducerEventContextInterface, - type SubscriptionEventContextInterface as __SubscriptionEventContextInterface, - type TableHandle as __TableHandle, + TypeBuilder as __TypeBuilder, + t as __t, + type AlgebraicTypeType as __AlgebraicTypeType, + type Infer as __Infer, } from "spacetimedb"; -export type AddPlayer = { - name: string, +export default { + name: __t.string(), }; -let _cached_AddPlayer_type_value: __AlgebraicTypeType | null = null; - -/** - * An object for generated helper functions. - */ -export const AddPlayer = { - /** - * A function which returns this type represented as an AlgebraicType. - * This function is derived from the AlgebraicType used to generate this type. - */ - getTypeScriptAlgebraicType(): __AlgebraicTypeType { - if (_cached_AddPlayer_type_value) return _cached_AddPlayer_type_value; - _cached_AddPlayer_type_value = __AlgebraicTypeValue.Product({ elements: [] }); - _cached_AddPlayer_type_value.value.elements.push( - { name: "name", algebraicType: __AlgebraicTypeValue.String }, - ); - return _cached_AddPlayer_type_value; - }, - - serialize(writer: __BinaryWriter, value: AddPlayer): void { - __AlgebraicTypeValue.serializeValue(writer, AddPlayer.getTypeScriptAlgebraicType(), value); - }, - - deserialize(reader: __BinaryReader): AddPlayer { - return __AlgebraicTypeValue.deserializeValue(reader, AddPlayer.getTypeScriptAlgebraicType()); - }, - -} - -export default AddPlayer; - ''' "add_private_reducer.ts" = ''' // THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE @@ -75,64 +26,15 @@ export default AddPlayer; /* eslint-disable */ /* tslint:disable */ import { - AlgebraicType as __AlgebraicTypeValue, - BinaryReader as __BinaryReader, - BinaryWriter as __BinaryWriter, - ClientCache as __ClientCache, - ConnectionId as __ConnectionId, - DbConnectionBuilder as __DbConnectionBuilder, - DbConnectionImpl as __DbConnectionImpl, - Identity as __Identity, - SubscriptionBuilderImpl as __SubscriptionBuilderImpl, - TableCache as __TableCache, - TimeDuration as __TimeDuration, - Timestamp as __Timestamp, - deepEqual as __deepEqual, - type AlgebraicType as __AlgebraicTypeType, - type AlgebraicTypeVariants as __AlgebraicTypeVariants, - type CallReducerFlags as __CallReducerFlags, - type ErrorContextInterface as __ErrorContextInterface, - type Event as __Event, - type EventContextInterface as __EventContextInterface, - type ReducerEventContextInterface as __ReducerEventContextInterface, - type SubscriptionEventContextInterface as __SubscriptionEventContextInterface, - type TableHandle as __TableHandle, + TypeBuilder as __TypeBuilder, + t as __t, + type AlgebraicTypeType as __AlgebraicTypeType, + type Infer as __Infer, } from "spacetimedb"; -export type AddPrivate = { - name: string, +export default { + name: __t.string(), }; -let _cached_AddPrivate_type_value: __AlgebraicTypeType | null = null; - -/** - * An object for generated helper functions. - */ -export const AddPrivate = { - /** - * A function which returns this type represented as an AlgebraicType. - * This function is derived from the AlgebraicType used to generate this type. - */ - getTypeScriptAlgebraicType(): __AlgebraicTypeType { - if (_cached_AddPrivate_type_value) return _cached_AddPrivate_type_value; - _cached_AddPrivate_type_value = __AlgebraicTypeValue.Product({ elements: [] }); - _cached_AddPrivate_type_value.value.elements.push( - { name: "name", algebraicType: __AlgebraicTypeValue.String }, - ); - return _cached_AddPrivate_type_value; - }, - - serialize(writer: __BinaryWriter, value: AddPrivate): void { - __AlgebraicTypeValue.serializeValue(writer, AddPrivate.getTypeScriptAlgebraicType(), value); - }, - - deserialize(reader: __BinaryReader): AddPrivate { - return __AlgebraicTypeValue.deserializeValue(reader, AddPrivate.getTypeScriptAlgebraicType()); - }, - -} - -export default AddPrivate; - ''' "add_reducer.ts" = ''' // THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE @@ -141,66 +43,16 @@ export default AddPrivate; /* eslint-disable */ /* tslint:disable */ import { - AlgebraicType as __AlgebraicTypeValue, - BinaryReader as __BinaryReader, - BinaryWriter as __BinaryWriter, - ClientCache as __ClientCache, - ConnectionId as __ConnectionId, - DbConnectionBuilder as __DbConnectionBuilder, - DbConnectionImpl as __DbConnectionImpl, - Identity as __Identity, - SubscriptionBuilderImpl as __SubscriptionBuilderImpl, - TableCache as __TableCache, - TimeDuration as __TimeDuration, - Timestamp as __Timestamp, - deepEqual as __deepEqual, - type AlgebraicType as __AlgebraicTypeType, - type AlgebraicTypeVariants as __AlgebraicTypeVariants, - type CallReducerFlags as __CallReducerFlags, - type ErrorContextInterface as __ErrorContextInterface, - type Event as __Event, - type EventContextInterface as __EventContextInterface, - type ReducerEventContextInterface as __ReducerEventContextInterface, - type SubscriptionEventContextInterface as __SubscriptionEventContextInterface, - type TableHandle as __TableHandle, + TypeBuilder as __TypeBuilder, + t as __t, + type AlgebraicTypeType as __AlgebraicTypeType, + type Infer as __Infer, } from "spacetimedb"; -export type Add = { - name: string, - age: number, +export default { + name: __t.string(), + age: __t.u8(), }; -let _cached_Add_type_value: __AlgebraicTypeType | null = null; - -/** - * An object for generated helper functions. - */ -export const Add = { - /** - * A function which returns this type represented as an AlgebraicType. - * This function is derived from the AlgebraicType used to generate this type. - */ - getTypeScriptAlgebraicType(): __AlgebraicTypeType { - if (_cached_Add_type_value) return _cached_Add_type_value; - _cached_Add_type_value = __AlgebraicTypeValue.Product({ elements: [] }); - _cached_Add_type_value.value.elements.push( - { name: "name", algebraicType: __AlgebraicTypeValue.String }, - { name: "age", algebraicType: __AlgebraicTypeValue.U8 }, - ); - return _cached_Add_type_value; - }, - - serialize(writer: __BinaryWriter, value: Add): void { - __AlgebraicTypeValue.serializeValue(writer, Add.getTypeScriptAlgebraicType(), value); - }, - - deserialize(reader: __BinaryReader): Add { - return __AlgebraicTypeValue.deserializeValue(reader, Add.getTypeScriptAlgebraicType()); - }, - -} - -export default Add; - ''' "assert_caller_identity_is_module_identity_reducer.ts" = ''' // THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE @@ -209,61 +61,13 @@ export default Add; /* eslint-disable */ /* tslint:disable */ import { - AlgebraicType as __AlgebraicTypeValue, - BinaryReader as __BinaryReader, - BinaryWriter as __BinaryWriter, - ClientCache as __ClientCache, - ConnectionId as __ConnectionId, - DbConnectionBuilder as __DbConnectionBuilder, - DbConnectionImpl as __DbConnectionImpl, - Identity as __Identity, - SubscriptionBuilderImpl as __SubscriptionBuilderImpl, - TableCache as __TableCache, - TimeDuration as __TimeDuration, - Timestamp as __Timestamp, - deepEqual as __deepEqual, - type AlgebraicType as __AlgebraicTypeType, - type AlgebraicTypeVariants as __AlgebraicTypeVariants, - type CallReducerFlags as __CallReducerFlags, - type ErrorContextInterface as __ErrorContextInterface, - type Event as __Event, - type EventContextInterface as __EventContextInterface, - type ReducerEventContextInterface as __ReducerEventContextInterface, - type SubscriptionEventContextInterface as __SubscriptionEventContextInterface, - type TableHandle as __TableHandle, + TypeBuilder as __TypeBuilder, + t as __t, + type AlgebraicTypeType as __AlgebraicTypeType, + type Infer as __Infer, } from "spacetimedb"; -export type AssertCallerIdentityIsModuleIdentity = {}; -let _cached_AssertCallerIdentityIsModuleIdentity_type_value: __AlgebraicTypeType | null = null; - -/** - * An object for generated helper functions. - */ -export const AssertCallerIdentityIsModuleIdentity = { - /** - * A function which returns this type represented as an AlgebraicType. - * This function is derived from the AlgebraicType used to generate this type. - */ - getTypeScriptAlgebraicType(): __AlgebraicTypeType { - if (_cached_AssertCallerIdentityIsModuleIdentity_type_value) return _cached_AssertCallerIdentityIsModuleIdentity_type_value; - _cached_AssertCallerIdentityIsModuleIdentity_type_value = __AlgebraicTypeValue.Product({ elements: [] }); - _cached_AssertCallerIdentityIsModuleIdentity_type_value.value.elements.push( - ); - return _cached_AssertCallerIdentityIsModuleIdentity_type_value; - }, - - serialize(writer: __BinaryWriter, value: AssertCallerIdentityIsModuleIdentity): void { - __AlgebraicTypeValue.serializeValue(writer, AssertCallerIdentityIsModuleIdentity.getTypeScriptAlgebraicType(), value); - }, - - deserialize(reader: __BinaryReader): AssertCallerIdentityIsModuleIdentity { - return __AlgebraicTypeValue.deserializeValue(reader, AssertCallerIdentityIsModuleIdentity.getTypeScriptAlgebraicType()); - }, - -} - -export default AssertCallerIdentityIsModuleIdentity; - +export default {}; ''' "baz_type.ts" = ''' // THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE @@ -272,63 +76,15 @@ export default AssertCallerIdentityIsModuleIdentity; /* eslint-disable */ /* tslint:disable */ import { - AlgebraicType as __AlgebraicTypeValue, - BinaryReader as __BinaryReader, - BinaryWriter as __BinaryWriter, - ClientCache as __ClientCache, - ConnectionId as __ConnectionId, - DbConnectionBuilder as __DbConnectionBuilder, - DbConnectionImpl as __DbConnectionImpl, - Identity as __Identity, - SubscriptionBuilderImpl as __SubscriptionBuilderImpl, - TableCache as __TableCache, - TimeDuration as __TimeDuration, - Timestamp as __Timestamp, - deepEqual as __deepEqual, - type AlgebraicType as __AlgebraicTypeType, - type AlgebraicTypeVariants as __AlgebraicTypeVariants, - type CallReducerFlags as __CallReducerFlags, - type ErrorContextInterface as __ErrorContextInterface, - type Event as __Event, - type EventContextInterface as __EventContextInterface, - type ReducerEventContextInterface as __ReducerEventContextInterface, - type SubscriptionEventContextInterface as __SubscriptionEventContextInterface, - type TableHandle as __TableHandle, + TypeBuilder as __TypeBuilder, + t as __t, + type AlgebraicTypeType as __AlgebraicTypeType, + type Infer as __Infer, } from "spacetimedb"; -export type Baz = { - field: string, -}; -let _cached_Baz_type_value: __AlgebraicTypeType | null = null; - -/** - * An object for generated helper functions. - */ -export const Baz = { - /** - * A function which returns this type represented as an AlgebraicType. - * This function is derived from the AlgebraicType used to generate this type. - */ - getTypeScriptAlgebraicType(): __AlgebraicTypeType { - if (_cached_Baz_type_value) return _cached_Baz_type_value; - _cached_Baz_type_value = __AlgebraicTypeValue.Product({ elements: [] }); - _cached_Baz_type_value.value.elements.push( - { name: "field", algebraicType: __AlgebraicTypeValue.String }, - ); - return _cached_Baz_type_value; - }, - - serialize(writer: __BinaryWriter, value: Baz): void { - __AlgebraicTypeValue.serializeValue(writer, Baz.getTypeScriptAlgebraicType(), value); - }, - - deserialize(reader: __BinaryReader): Baz { - return __AlgebraicTypeValue.deserializeValue(reader, Baz.getTypeScriptAlgebraicType()); - }, - -} - -export default Baz; +export default __t.object("Baz", { + field: __t.string(), +}); ''' @@ -339,61 +95,13 @@ export default Baz; /* eslint-disable */ /* tslint:disable */ import { - AlgebraicType as __AlgebraicTypeValue, - BinaryReader as __BinaryReader, - BinaryWriter as __BinaryWriter, - ClientCache as __ClientCache, - ConnectionId as __ConnectionId, - DbConnectionBuilder as __DbConnectionBuilder, - DbConnectionImpl as __DbConnectionImpl, - Identity as __Identity, - SubscriptionBuilderImpl as __SubscriptionBuilderImpl, - TableCache as __TableCache, - TimeDuration as __TimeDuration, - Timestamp as __Timestamp, - deepEqual as __deepEqual, - type AlgebraicType as __AlgebraicTypeType, - type AlgebraicTypeVariants as __AlgebraicTypeVariants, - type CallReducerFlags as __CallReducerFlags, - type ErrorContextInterface as __ErrorContextInterface, - type Event as __Event, - type EventContextInterface as __EventContextInterface, - type ReducerEventContextInterface as __ReducerEventContextInterface, - type SubscriptionEventContextInterface as __SubscriptionEventContextInterface, - type TableHandle as __TableHandle, + TypeBuilder as __TypeBuilder, + t as __t, + type AlgebraicTypeType as __AlgebraicTypeType, + type Infer as __Infer, } from "spacetimedb"; -export type ClientConnected = {}; -let _cached_ClientConnected_type_value: __AlgebraicTypeType | null = null; - -/** - * An object for generated helper functions. - */ -export const ClientConnected = { - /** - * A function which returns this type represented as an AlgebraicType. - * This function is derived from the AlgebraicType used to generate this type. - */ - getTypeScriptAlgebraicType(): __AlgebraicTypeType { - if (_cached_ClientConnected_type_value) return _cached_ClientConnected_type_value; - _cached_ClientConnected_type_value = __AlgebraicTypeValue.Product({ elements: [] }); - _cached_ClientConnected_type_value.value.elements.push( - ); - return _cached_ClientConnected_type_value; - }, - - serialize(writer: __BinaryWriter, value: ClientConnected): void { - __AlgebraicTypeValue.serializeValue(writer, ClientConnected.getTypeScriptAlgebraicType(), value); - }, - - deserialize(reader: __BinaryReader): ClientConnected { - return __AlgebraicTypeValue.deserializeValue(reader, ClientConnected.getTypeScriptAlgebraicType()); - }, - -} - -export default ClientConnected; - +export default {}; ''' "delete_player_reducer.ts" = ''' // THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE @@ -402,64 +110,15 @@ export default ClientConnected; /* eslint-disable */ /* tslint:disable */ import { - AlgebraicType as __AlgebraicTypeValue, - BinaryReader as __BinaryReader, - BinaryWriter as __BinaryWriter, - ClientCache as __ClientCache, - ConnectionId as __ConnectionId, - DbConnectionBuilder as __DbConnectionBuilder, - DbConnectionImpl as __DbConnectionImpl, - Identity as __Identity, - SubscriptionBuilderImpl as __SubscriptionBuilderImpl, - TableCache as __TableCache, - TimeDuration as __TimeDuration, - Timestamp as __Timestamp, - deepEqual as __deepEqual, - type AlgebraicType as __AlgebraicTypeType, - type AlgebraicTypeVariants as __AlgebraicTypeVariants, - type CallReducerFlags as __CallReducerFlags, - type ErrorContextInterface as __ErrorContextInterface, - type Event as __Event, - type EventContextInterface as __EventContextInterface, - type ReducerEventContextInterface as __ReducerEventContextInterface, - type SubscriptionEventContextInterface as __SubscriptionEventContextInterface, - type TableHandle as __TableHandle, + TypeBuilder as __TypeBuilder, + t as __t, + type AlgebraicTypeType as __AlgebraicTypeType, + type Infer as __Infer, } from "spacetimedb"; -export type DeletePlayer = { - id: bigint, +export default { + id: __t.u64(), }; -let _cached_DeletePlayer_type_value: __AlgebraicTypeType | null = null; - -/** - * An object for generated helper functions. - */ -export const DeletePlayer = { - /** - * A function which returns this type represented as an AlgebraicType. - * This function is derived from the AlgebraicType used to generate this type. - */ - getTypeScriptAlgebraicType(): __AlgebraicTypeType { - if (_cached_DeletePlayer_type_value) return _cached_DeletePlayer_type_value; - _cached_DeletePlayer_type_value = __AlgebraicTypeValue.Product({ elements: [] }); - _cached_DeletePlayer_type_value.value.elements.push( - { name: "id", algebraicType: __AlgebraicTypeValue.U64 }, - ); - return _cached_DeletePlayer_type_value; - }, - - serialize(writer: __BinaryWriter, value: DeletePlayer): void { - __AlgebraicTypeValue.serializeValue(writer, DeletePlayer.getTypeScriptAlgebraicType(), value); - }, - - deserialize(reader: __BinaryReader): DeletePlayer { - return __AlgebraicTypeValue.deserializeValue(reader, DeletePlayer.getTypeScriptAlgebraicType()); - }, - -} - -export default DeletePlayer; - ''' "delete_players_by_name_reducer.ts" = ''' // THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE @@ -468,64 +127,15 @@ export default DeletePlayer; /* eslint-disable */ /* tslint:disable */ import { - AlgebraicType as __AlgebraicTypeValue, - BinaryReader as __BinaryReader, - BinaryWriter as __BinaryWriter, - ClientCache as __ClientCache, - ConnectionId as __ConnectionId, - DbConnectionBuilder as __DbConnectionBuilder, - DbConnectionImpl as __DbConnectionImpl, - Identity as __Identity, - SubscriptionBuilderImpl as __SubscriptionBuilderImpl, - TableCache as __TableCache, - TimeDuration as __TimeDuration, - Timestamp as __Timestamp, - deepEqual as __deepEqual, - type AlgebraicType as __AlgebraicTypeType, - type AlgebraicTypeVariants as __AlgebraicTypeVariants, - type CallReducerFlags as __CallReducerFlags, - type ErrorContextInterface as __ErrorContextInterface, - type Event as __Event, - type EventContextInterface as __EventContextInterface, - type ReducerEventContextInterface as __ReducerEventContextInterface, - type SubscriptionEventContextInterface as __SubscriptionEventContextInterface, - type TableHandle as __TableHandle, + TypeBuilder as __TypeBuilder, + t as __t, + type AlgebraicTypeType as __AlgebraicTypeType, + type Infer as __Infer, } from "spacetimedb"; -export type DeletePlayersByName = { - name: string, +export default { + name: __t.string(), }; -let _cached_DeletePlayersByName_type_value: __AlgebraicTypeType | null = null; - -/** - * An object for generated helper functions. - */ -export const DeletePlayersByName = { - /** - * A function which returns this type represented as an AlgebraicType. - * This function is derived from the AlgebraicType used to generate this type. - */ - getTypeScriptAlgebraicType(): __AlgebraicTypeType { - if (_cached_DeletePlayersByName_type_value) return _cached_DeletePlayersByName_type_value; - _cached_DeletePlayersByName_type_value = __AlgebraicTypeValue.Product({ elements: [] }); - _cached_DeletePlayersByName_type_value.value.elements.push( - { name: "name", algebraicType: __AlgebraicTypeValue.String }, - ); - return _cached_DeletePlayersByName_type_value; - }, - - serialize(writer: __BinaryWriter, value: DeletePlayersByName): void { - __AlgebraicTypeValue.serializeValue(writer, DeletePlayersByName.getTypeScriptAlgebraicType(), value); - }, - - deserialize(reader: __BinaryReader): DeletePlayersByName { - return __AlgebraicTypeValue.deserializeValue(reader, DeletePlayersByName.getTypeScriptAlgebraicType()); - }, - -} - -export default DeletePlayersByName; - ''' "foobar_type.ts" = ''' // THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE @@ -534,118 +144,25 @@ export default DeletePlayersByName; /* eslint-disable */ /* tslint:disable */ import { - AlgebraicType as __AlgebraicTypeValue, - BinaryReader as __BinaryReader, - BinaryWriter as __BinaryWriter, - ClientCache as __ClientCache, - ConnectionId as __ConnectionId, - DbConnectionBuilder as __DbConnectionBuilder, - DbConnectionImpl as __DbConnectionImpl, - Identity as __Identity, - SubscriptionBuilderImpl as __SubscriptionBuilderImpl, - TableCache as __TableCache, - TimeDuration as __TimeDuration, - Timestamp as __Timestamp, - deepEqual as __deepEqual, - type AlgebraicType as __AlgebraicTypeType, - type AlgebraicTypeVariants as __AlgebraicTypeVariants, - type CallReducerFlags as __CallReducerFlags, - type ErrorContextInterface as __ErrorContextInterface, - type Event as __Event, - type EventContextInterface as __EventContextInterface, - type ReducerEventContextInterface as __ReducerEventContextInterface, - type SubscriptionEventContextInterface as __SubscriptionEventContextInterface, - type TableHandle as __TableHandle, + TypeBuilder as __TypeBuilder, + t as __t, + type AlgebraicTypeType as __AlgebraicTypeType, + type Infer as __Infer, } from "spacetimedb"; -import { Baz } from "./baz_type"; -// Mark import as potentially unused -declare type __keep_Baz = Baz; +import Baz from "./baz_type"; -import * as FoobarVariants from './foobar_variants' // The tagged union or sum type for the algebraic type `Foobar`. -export type Foobar = FoobarVariants.Baz | - FoobarVariants.Bar | - FoobarVariants.Har; - -let _cached_Foobar_type_value: __AlgebraicTypeType | null = null; - -// A value with helper functions to construct the type. -export const Foobar = { - // Helper functions for constructing each variant of the tagged union. - // ``` - // const foo = Foo.A(42); - // assert!(foo.tag === "A"); - // assert!(foo.value === 42); - // ``` - Baz: (value: Baz): FoobarVariants.Baz => ({ tag: "Baz", value }), - Bar: { tag: "Bar" } as const, - Har: (value: number): FoobarVariants.Har => ({ tag: "Har", value }), - - getTypeScriptAlgebraicType(): __AlgebraicTypeType { - if (_cached_Foobar_type_value) return _cached_Foobar_type_value; - _cached_Foobar_type_value = __AlgebraicTypeValue.Sum({ variants: [] }); - _cached_Foobar_type_value.value.variants.push( - { name: "Baz", algebraicType: Baz.getTypeScriptAlgebraicType() }, - { name: "Bar", algebraicType: __AlgebraicTypeValue.Product({ elements: [] }) }, - { name: "Har", algebraicType: __AlgebraicTypeValue.U32 }, - ); - return _cached_Foobar_type_value; +const Foobar = __t.enum("Foobar", {get Baz() { + return Baz; }, - - serialize(writer: __BinaryWriter, value: Foobar): void { - __AlgebraicTypeValue.serializeValue(writer, Foobar.getTypeScriptAlgebraicType(), value); - }, - - deserialize(reader: __BinaryReader): Foobar { - return __AlgebraicTypeValue.deserializeValue(reader, Foobar.getTypeScriptAlgebraicType()); - }, - -} + Bar: __t.unit(), + Har: __t.u32(), +}); export default Foobar; -''' -"foobar_variants.ts" = ''' -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -/* eslint-disable */ -/* tslint:disable */ -import { - AlgebraicType as __AlgebraicTypeValue, - BinaryReader as __BinaryReader, - BinaryWriter as __BinaryWriter, - ClientCache as __ClientCache, - ConnectionId as __ConnectionId, - DbConnectionBuilder as __DbConnectionBuilder, - DbConnectionImpl as __DbConnectionImpl, - Identity as __Identity, - SubscriptionBuilderImpl as __SubscriptionBuilderImpl, - TableCache as __TableCache, - TimeDuration as __TimeDuration, - Timestamp as __Timestamp, - deepEqual as __deepEqual, - type AlgebraicType as __AlgebraicTypeType, - type AlgebraicTypeVariants as __AlgebraicTypeVariants, - type CallReducerFlags as __CallReducerFlags, - type ErrorContextInterface as __ErrorContextInterface, - type Event as __Event, - type EventContextInterface as __EventContextInterface, - type ReducerEventContextInterface as __ReducerEventContextInterface, - type SubscriptionEventContextInterface as __SubscriptionEventContextInterface, - type TableHandle as __TableHandle, -} from "spacetimedb"; -import { Baz as BazType } from "./baz_type"; -// Mark import as potentially unused -declare type __keep_BazType = BazType; - - -export type Baz = { tag: "Baz", value: BazType }; -export type Bar = { tag: "Bar" }; -export type Har = { tag: "Har", value: number }; - ''' "has_special_stuff_table.ts" = ''' // THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE @@ -654,76 +171,16 @@ export type Har = { tag: "Har", value: number }; /* eslint-disable */ /* tslint:disable */ import { - AlgebraicType as __AlgebraicTypeValue, - BinaryReader as __BinaryReader, - BinaryWriter as __BinaryWriter, - ClientCache as __ClientCache, - ConnectionId as __ConnectionId, - DbConnectionBuilder as __DbConnectionBuilder, - DbConnectionImpl as __DbConnectionImpl, - Identity as __Identity, - SubscriptionBuilderImpl as __SubscriptionBuilderImpl, - TableCache as __TableCache, - TimeDuration as __TimeDuration, - Timestamp as __Timestamp, - deepEqual as __deepEqual, - type AlgebraicType as __AlgebraicTypeType, - type AlgebraicTypeVariants as __AlgebraicTypeVariants, - type CallReducerFlags as __CallReducerFlags, - type ErrorContextInterface as __ErrorContextInterface, - type Event as __Event, - type EventContextInterface as __EventContextInterface, - type ReducerEventContextInterface as __ReducerEventContextInterface, - type SubscriptionEventContextInterface as __SubscriptionEventContextInterface, - type TableHandle as __TableHandle, + TypeBuilder as __TypeBuilder, + t as __t, + type AlgebraicTypeType as __AlgebraicTypeType, + type Infer as __Infer, } from "spacetimedb"; -import { HasSpecialStuff } from "./has_special_stuff_type"; -import { type EventContext, type Reducer, RemoteReducers, RemoteTables } from "."; -declare type __keep = [EventContext, Reducer, RemoteReducers, RemoteTables]; - -/** - * Table handle for the table `has_special_stuff`. - * - * Obtain a handle from the [`hasSpecialStuff`] property on [`RemoteTables`], - * like `ctx.db.hasSpecialStuff`. - * - * Users are encouraged not to explicitly reference this type, - * but to directly chain method calls, - * like `ctx.db.hasSpecialStuff.on_insert(...)`. - */ -export class HasSpecialStuffTableHandle implements __TableHandle { - // phantom type to track the table name - readonly tableName!: TableName; - tableCache: __TableCache; - - constructor(tableCache: __TableCache) { - this.tableCache = tableCache; - } - - count(): number { - return this.tableCache.count(); - } - - iter(): Iterable { - return this.tableCache.iter(); - } - - onInsert = (cb: (ctx: EventContext, row: HasSpecialStuff) => void) => { - return this.tableCache.onInsert(cb); - } - - removeOnInsert = (cb: (ctx: EventContext, row: HasSpecialStuff) => void) => { - return this.tableCache.removeOnInsert(cb); - } - - onDelete = (cb: (ctx: EventContext, row: HasSpecialStuff) => void) => { - return this.tableCache.onDelete(cb); - } - - removeOnDelete = (cb: (ctx: EventContext, row: HasSpecialStuff) => void) => { - return this.tableCache.removeOnDelete(cb); - } -} + +export default __t.row({ + identity: __t.identity(), + connectionId: __t.connectionId(), +}); ''' "has_special_stuff_type.ts" = ''' // THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE @@ -732,65 +189,16 @@ export class HasSpecialStuffTableHandle implements __T /* eslint-disable */ /* tslint:disable */ import { - AlgebraicType as __AlgebraicTypeValue, - BinaryReader as __BinaryReader, - BinaryWriter as __BinaryWriter, - ClientCache as __ClientCache, - ConnectionId as __ConnectionId, - DbConnectionBuilder as __DbConnectionBuilder, - DbConnectionImpl as __DbConnectionImpl, - Identity as __Identity, - SubscriptionBuilderImpl as __SubscriptionBuilderImpl, - TableCache as __TableCache, - TimeDuration as __TimeDuration, - Timestamp as __Timestamp, - deepEqual as __deepEqual, - type AlgebraicType as __AlgebraicTypeType, - type AlgebraicTypeVariants as __AlgebraicTypeVariants, - type CallReducerFlags as __CallReducerFlags, - type ErrorContextInterface as __ErrorContextInterface, - type Event as __Event, - type EventContextInterface as __EventContextInterface, - type ReducerEventContextInterface as __ReducerEventContextInterface, - type SubscriptionEventContextInterface as __SubscriptionEventContextInterface, - type TableHandle as __TableHandle, + TypeBuilder as __TypeBuilder, + t as __t, + type AlgebraicTypeType as __AlgebraicTypeType, + type Infer as __Infer, } from "spacetimedb"; -export type HasSpecialStuff = { - identity: __Identity, - connectionId: __ConnectionId, -}; -let _cached_HasSpecialStuff_type_value: __AlgebraicTypeType | null = null; - -/** - * An object for generated helper functions. - */ -export const HasSpecialStuff = { - /** - * A function which returns this type represented as an AlgebraicType. - * This function is derived from the AlgebraicType used to generate this type. - */ - getTypeScriptAlgebraicType(): __AlgebraicTypeType { - if (_cached_HasSpecialStuff_type_value) return _cached_HasSpecialStuff_type_value; - _cached_HasSpecialStuff_type_value = __AlgebraicTypeValue.Product({ elements: [] }); - _cached_HasSpecialStuff_type_value.value.elements.push( - { name: "identity", algebraicType: __AlgebraicTypeValue.createIdentityType() }, - { name: "connectionId", algebraicType: __AlgebraicTypeValue.createConnectionIdType() }, - ); - return _cached_HasSpecialStuff_type_value; - }, - - serialize(writer: __BinaryWriter, value: HasSpecialStuff): void { - __AlgebraicTypeValue.serializeValue(writer, HasSpecialStuff.getTypeScriptAlgebraicType(), value); - }, - - deserialize(reader: __BinaryReader): HasSpecialStuff { - return __AlgebraicTypeValue.deserializeValue(reader, HasSpecialStuff.getTypeScriptAlgebraicType()); - }, - -} - -export default HasSpecialStuff; +export default __t.object("HasSpecialStuff", { + identity: __t.identity(), + connectionId: __t.connectionId(), +}); ''' @@ -803,652 +211,315 @@ VERSION_COMMENT /* eslint-disable */ /* tslint:disable */ import { - AlgebraicType as __AlgebraicTypeValue, - BinaryReader as __BinaryReader, - BinaryWriter as __BinaryWriter, - ClientCache as __ClientCache, - ConnectionId as __ConnectionId, DbConnectionBuilder as __DbConnectionBuilder, DbConnectionImpl as __DbConnectionImpl, - Identity as __Identity, SubscriptionBuilderImpl as __SubscriptionBuilderImpl, - TableCache as __TableCache, - TimeDuration as __TimeDuration, - Timestamp as __Timestamp, - deepEqual as __deepEqual, - type AlgebraicType as __AlgebraicTypeType, - type AlgebraicTypeVariants as __AlgebraicTypeVariants, - type CallReducerFlags as __CallReducerFlags, + TypeBuilder as __TypeBuilder, + convertToAccessorMap as __convertToAccessorMap, + reducerSchema as __reducerSchema, + reducers as __reducers, + schema as __schema, + t as __t, + table as __table, + type AlgebraicTypeType as __AlgebraicTypeType, + type DbConnectionConfig as __DbConnectionConfig, type ErrorContextInterface as __ErrorContextInterface, type Event as __Event, type EventContextInterface as __EventContextInterface, + type Infer as __Infer, type ReducerEventContextInterface as __ReducerEventContextInterface, + type RemoteModule as __RemoteModule, type SubscriptionEventContextInterface as __SubscriptionEventContextInterface, - type TableHandle as __TableHandle, } from "spacetimedb"; // Import and reexport all reducer arg types -import { Add } from "./add_reducer.ts"; +import Add from "./add_reducer"; export { Add }; -import { AddPlayer } from "./add_player_reducer.ts"; +import AddPlayer from "./add_player_reducer"; export { AddPlayer }; -import { AddPrivate } from "./add_private_reducer.ts"; +import AddPrivate from "./add_private_reducer"; export { AddPrivate }; -import { AssertCallerIdentityIsModuleIdentity } from "./assert_caller_identity_is_module_identity_reducer.ts"; +import AssertCallerIdentityIsModuleIdentity from "./assert_caller_identity_is_module_identity_reducer"; export { AssertCallerIdentityIsModuleIdentity }; -import { ClientConnected } from "./client_connected_reducer.ts"; +import ClientConnected from "./client_connected_reducer"; export { ClientConnected }; -import { DeletePlayer } from "./delete_player_reducer.ts"; +import DeletePlayer from "./delete_player_reducer"; export { DeletePlayer }; -import { DeletePlayersByName } from "./delete_players_by_name_reducer.ts"; +import DeletePlayersByName from "./delete_players_by_name_reducer"; export { DeletePlayersByName }; -import { ListOverAge } from "./list_over_age_reducer.ts"; +import ListOverAge from "./list_over_age_reducer"; export { ListOverAge }; -import { LogModuleIdentity } from "./log_module_identity_reducer.ts"; +import LogModuleIdentity from "./log_module_identity_reducer"; export { LogModuleIdentity }; -import { QueryPrivate } from "./query_private_reducer.ts"; +import QueryPrivate from "./query_private_reducer"; export { QueryPrivate }; -import { RepeatingTest } from "./repeating_test_reducer.ts"; +import RepeatingTest from "./repeating_test_reducer"; export { RepeatingTest }; -import { SayHello } from "./say_hello_reducer.ts"; +import SayHello from "./say_hello_reducer"; export { SayHello }; -import { Test } from "./test_reducer.ts"; +import Test from "./test_reducer"; export { Test }; -import { TestBtreeIndexArgs } from "./test_btree_index_args_reducer.ts"; +import TestBtreeIndexArgs from "./test_btree_index_args_reducer"; export { TestBtreeIndexArgs }; // Import and reexport all table handle types -import { HasSpecialStuffTableHandle } from "./has_special_stuff_table.ts"; -export { HasSpecialStuffTableHandle }; -import { LoggedOutPlayerTableHandle } from "./logged_out_player_table.ts"; -export { LoggedOutPlayerTableHandle }; -import { PersonTableHandle } from "./person_table.ts"; -export { PersonTableHandle }; -import { PkMultiIdentityTableHandle } from "./pk_multi_identity_table.ts"; -export { PkMultiIdentityTableHandle }; -import { PlayerTableHandle } from "./player_table.ts"; -export { PlayerTableHandle }; -import { PointsTableHandle } from "./points_table.ts"; -export { PointsTableHandle }; -import { PrivateTableTableHandle } from "./private_table_table.ts"; -export { PrivateTableTableHandle }; -import { RepeatingTestArgTableHandle } from "./repeating_test_arg_table.ts"; -export { RepeatingTestArgTableHandle }; -import { TestATableHandle } from "./test_a_table.ts"; -export { TestATableHandle }; -import { TestDTableHandle } from "./test_d_table.ts"; -export { TestDTableHandle }; -import { TestETableHandle } from "./test_e_table.ts"; -export { TestETableHandle }; -import { TestFTableHandle } from "./test_f_table.ts"; -export { TestFTableHandle }; +import HasSpecialStuffRow from "./has_special_stuff_table"; +export { HasSpecialStuffRow }; +import LoggedOutPlayerRow from "./logged_out_player_table"; +export { LoggedOutPlayerRow }; +import PersonRow from "./person_table"; +export { PersonRow }; +import PkMultiIdentityRow from "./pk_multi_identity_table"; +export { PkMultiIdentityRow }; +import PlayerRow from "./player_table"; +export { PlayerRow }; +import PointsRow from "./points_table"; +export { PointsRow }; +import PrivateTableRow from "./private_table_table"; +export { PrivateTableRow }; +import RepeatingTestArgRow from "./repeating_test_arg_table"; +export { RepeatingTestArgRow }; +import TestARow from "./test_a_table"; +export { TestARow }; +import TestDRow from "./test_d_table"; +export { TestDRow }; +import TestERow from "./test_e_table"; +export { TestERow }; +import TestFRow from "./test_f_table"; +export { TestFRow }; // Import and reexport all types -import { Baz } from "./baz_type.ts"; +import Baz from "./baz_type"; export { Baz }; -import { Foobar } from "./foobar_type.ts"; +import Foobar from "./foobar_type"; export { Foobar }; -import { HasSpecialStuff } from "./has_special_stuff_type.ts"; +import HasSpecialStuff from "./has_special_stuff_type"; export { HasSpecialStuff }; -import { Person } from "./person_type.ts"; +import Person from "./person_type"; export { Person }; -import { PkMultiIdentity } from "./pk_multi_identity_type.ts"; +import PkMultiIdentity from "./pk_multi_identity_type"; export { PkMultiIdentity }; -import { Player } from "./player_type.ts"; +import Player from "./player_type"; export { Player }; -import { Point } from "./point_type.ts"; +import Point from "./point_type"; export { Point }; -import { PrivateTable } from "./private_table_type.ts"; +import PrivateTable from "./private_table_type"; export { PrivateTable }; -import { RepeatingTestArg } from "./repeating_test_arg_type.ts"; +import RepeatingTestArg from "./repeating_test_arg_type"; export { RepeatingTestArg }; -import { TestA } from "./test_a_type.ts"; +import TestA from "./test_a_type"; export { TestA }; -import { TestB } from "./test_b_type.ts"; +import TestB from "./test_b_type"; export { TestB }; -import { TestD } from "./test_d_type.ts"; +import TestD from "./test_d_type"; export { TestD }; -import { TestE } from "./test_e_type.ts"; +import TestE from "./test_e_type"; export { TestE }; -import { TestFoobar } from "./test_foobar_type.ts"; +import TestFoobar from "./test_foobar_type"; export { TestFoobar }; -import { NamespaceTestC } from "./namespace_test_c_type.ts"; +import NamespaceTestC from "./namespace_test_c_type"; export { NamespaceTestC }; -import { NamespaceTestF } from "./namespace_test_f_type.ts"; +import NamespaceTestF from "./namespace_test_f_type"; export { NamespaceTestF }; + +const tablesSchema = __schema( + __table({ + name: 'has_special_stuff', + indexes: [ + ], + constraints: [ + ], + }, HasSpecialStuffRow), + __table({ + name: 'logged_out_player', + indexes: [ + { name: 'identity', algorithm: 'btree', columns: [ + 'identity', + ] }, + { name: 'name', algorithm: 'btree', columns: [ + 'name', + ] }, + { name: 'player_id', algorithm: 'btree', columns: [ + 'playerId', + ] }, + ], + constraints: [ + { name: 'logged_out_player_player_id_key', constraint: 'unique', columns: ['player_id'] }, + { name: 'logged_out_player_name_key', constraint: 'unique', columns: ['name'] }, + { name: 'logged_out_player_identity_key', constraint: 'unique', columns: ['identity'] }, + ], + }, PlayerRow), + __table({ + name: 'person', + indexes: [ + { name: 'age', algorithm: 'btree', columns: [ + 'age', + ] }, + { name: 'id', algorithm: 'btree', columns: [ + 'id', + ] }, + ], + constraints: [ + { name: 'person_id_key', constraint: 'unique', columns: ['id'] }, + ], + }, PersonRow), + __table({ + name: 'pk_multi_identity', + indexes: [ + { name: 'id', algorithm: 'btree', columns: [ + 'id', + ] }, + { name: 'other', algorithm: 'btree', columns: [ + 'other', + ] }, + ], + constraints: [ + { name: 'pk_multi_identity_id_key', constraint: 'unique', columns: ['id'] }, + { name: 'pk_multi_identity_other_key', constraint: 'unique', columns: ['other'] }, + ], + }, PkMultiIdentityRow), + __table({ + name: 'player', + indexes: [ + { name: 'identity', algorithm: 'btree', columns: [ + 'identity', + ] }, + { name: 'name', algorithm: 'btree', columns: [ + 'name', + ] }, + { name: 'player_id', algorithm: 'btree', columns: [ + 'playerId', + ] }, + ], + constraints: [ + { name: 'player_player_id_key', constraint: 'unique', columns: ['player_id'] }, + { name: 'player_name_key', constraint: 'unique', columns: ['name'] }, + { name: 'player_identity_key', constraint: 'unique', columns: ['identity'] }, + ], + }, PlayerRow), + __table({ + name: 'points', + indexes: [ + { name: 'multi_column_index', algorithm: 'btree', columns: [ + 'x', + 'y', + ] }, + ], + constraints: [ + ], + }, PointRow), + __table({ + name: 'private_table', + indexes: [ + ], + constraints: [ + ], + }, PrivateTableRow), + __table({ + name: 'repeating_test_arg', + indexes: [ + { name: 'scheduled_id', algorithm: 'btree', columns: [ + 'scheduledId', + ] }, + ], + constraints: [ + { name: 'repeating_test_arg_scheduled_id_key', constraint: 'unique', columns: ['scheduled_id'] }, + ], + }, RepeatingTestArgRow), + __table({ + name: 'test_a', + indexes: [ + { name: 'foo', algorithm: 'btree', columns: [ + 'x', + ] }, + ], + constraints: [ + ], + }, TestARow), + __table({ + name: 'test_d', + indexes: [ + ], + constraints: [ + ], + }, TestDRow), + __table({ + name: 'test_e', + indexes: [ + { name: 'id', algorithm: 'btree', columns: [ + 'id', + ] }, + { name: 'name', algorithm: 'btree', columns: [ + 'name', + ] }, + ], + constraints: [ + { name: 'test_e_id_key', constraint: 'unique', columns: ['id'] }, + ], + }, TestERow), + __table({ + name: 'test_f', + indexes: [ + ], + constraints: [ + ], + }, TestFoobarRow), +); + +const reducersSchema = __reducers( + __reducerSchema("add", Add), + __reducerSchema("add_player", AddPlayer), + __reducerSchema("add_private", AddPrivate), + __reducerSchema("assert_caller_identity_is_module_identity", AssertCallerIdentityIsModuleIdentity), + __reducerSchema("delete_player", DeletePlayer), + __reducerSchema("delete_players_by_name", DeletePlayersByName), + __reducerSchema("list_over_age", ListOverAge), + __reducerSchema("log_module_identity", LogModuleIdentity), + __reducerSchema("query_private", QueryPrivate), + __reducerSchema("repeating_test", RepeatingTest), + __reducerSchema("say_hello", SayHello), + __reducerSchema("test", Test), + __reducerSchema("test_btree_index_args", TestBtreeIndexArgs), +); + const REMOTE_MODULE = { - tables: { - has_special_stuff: { - tableName: "has_special_stuff" as const, - rowType: HasSpecialStuff.getTypeScriptAlgebraicType(), - }, - logged_out_player: { - tableName: "logged_out_player" as const, - rowType: Player.getTypeScriptAlgebraicType(), - primaryKey: "identity", - primaryKeyInfo: { - colName: "identity", - colType: (Player.getTypeScriptAlgebraicType() as __AlgebraicTypeVariants.Product).value.elements[0].algebraicType, - }, - }, - person: { - tableName: "person" as const, - rowType: Person.getTypeScriptAlgebraicType(), - primaryKey: "id", - primaryKeyInfo: { - colName: "id", - colType: (Person.getTypeScriptAlgebraicType() as __AlgebraicTypeVariants.Product).value.elements[0].algebraicType, - }, - }, - pk_multi_identity: { - tableName: "pk_multi_identity" as const, - rowType: PkMultiIdentity.getTypeScriptAlgebraicType(), - primaryKey: "id", - primaryKeyInfo: { - colName: "id", - colType: (PkMultiIdentity.getTypeScriptAlgebraicType() as __AlgebraicTypeVariants.Product).value.elements[0].algebraicType, - }, - }, - player: { - tableName: "player" as const, - rowType: Player.getTypeScriptAlgebraicType(), - primaryKey: "identity", - primaryKeyInfo: { - colName: "identity", - colType: (Player.getTypeScriptAlgebraicType() as __AlgebraicTypeVariants.Product).value.elements[0].algebraicType, - }, - }, - points: { - tableName: "points" as const, - rowType: Point.getTypeScriptAlgebraicType(), - }, - private_table: { - tableName: "private_table" as const, - rowType: PrivateTable.getTypeScriptAlgebraicType(), - }, - repeating_test_arg: { - tableName: "repeating_test_arg" as const, - rowType: RepeatingTestArg.getTypeScriptAlgebraicType(), - primaryKey: "scheduledId", - primaryKeyInfo: { - colName: "scheduledId", - colType: (RepeatingTestArg.getTypeScriptAlgebraicType() as __AlgebraicTypeVariants.Product).value.elements[0].algebraicType, - }, - }, - test_a: { - tableName: "test_a" as const, - rowType: TestA.getTypeScriptAlgebraicType(), - }, - test_d: { - tableName: "test_d" as const, - rowType: TestD.getTypeScriptAlgebraicType(), - }, - test_e: { - tableName: "test_e" as const, - rowType: TestE.getTypeScriptAlgebraicType(), - primaryKey: "id", - primaryKeyInfo: { - colName: "id", - colType: (TestE.getTypeScriptAlgebraicType() as __AlgebraicTypeVariants.Product).value.elements[0].algebraicType, - }, - }, - test_f: { - tableName: "test_f" as const, - rowType: TestFoobar.getTypeScriptAlgebraicType(), - }, - }, - reducers: { - add: { - reducerName: "add", - argsType: Add.getTypeScriptAlgebraicType(), - }, - add_player: { - reducerName: "add_player", - argsType: AddPlayer.getTypeScriptAlgebraicType(), - }, - add_private: { - reducerName: "add_private", - argsType: AddPrivate.getTypeScriptAlgebraicType(), - }, - assert_caller_identity_is_module_identity: { - reducerName: "assert_caller_identity_is_module_identity", - argsType: AssertCallerIdentityIsModuleIdentity.getTypeScriptAlgebraicType(), - }, - client_connected: { - reducerName: "client_connected", - argsType: ClientConnected.getTypeScriptAlgebraicType(), - }, - delete_player: { - reducerName: "delete_player", - argsType: DeletePlayer.getTypeScriptAlgebraicType(), - }, - delete_players_by_name: { - reducerName: "delete_players_by_name", - argsType: DeletePlayersByName.getTypeScriptAlgebraicType(), - }, - list_over_age: { - reducerName: "list_over_age", - argsType: ListOverAge.getTypeScriptAlgebraicType(), - }, - log_module_identity: { - reducerName: "log_module_identity", - argsType: LogModuleIdentity.getTypeScriptAlgebraicType(), - }, - query_private: { - reducerName: "query_private", - argsType: QueryPrivate.getTypeScriptAlgebraicType(), - }, - repeating_test: { - reducerName: "repeating_test", - argsType: RepeatingTest.getTypeScriptAlgebraicType(), - }, - say_hello: { - reducerName: "say_hello", - argsType: SayHello.getTypeScriptAlgebraicType(), - }, - test: { - reducerName: "test", - argsType: Test.getTypeScriptAlgebraicType(), - }, - test_btree_index_args: { - reducerName: "test_btree_index_args", - argsType: TestBtreeIndexArgs.getTypeScriptAlgebraicType(), - }, - }, versionInfo: { - cliVersion: "X.Y.Z", + cliVersion: "1.7.0" as const, }, - // Constructors which are used by the DbConnectionImpl to - // extract type information from the generated RemoteModule. - // - // NOTE: This is not strictly necessary for `eventContextConstructor` because - // all we do is build a TypeScript object which we could have done inside the - // SDK, but if in the future we wanted to create a class this would be - // necessary because classes have methods, so we'll keep it. - eventContextConstructor: (imp: __DbConnectionImpl, event: __Event) => { - return { - ...(imp as DbConnection), - event - } - }, - dbViewConstructor: (imp: __DbConnectionImpl) => { - return new RemoteTables(imp); - }, - reducersConstructor: (imp: __DbConnectionImpl, setReducerFlags: SetReducerFlags) => { - return new RemoteReducers(imp, setReducerFlags); - }, - setReducerFlagsConstructor: () => { - return new SetReducerFlags(); - } -} + tables: tablesSchema.schemaType.tables, + reducers: reducersSchema.reducersType.reducers, +} satisfies __RemoteModule< + typeof tablesSchema.schemaType, + typeof reducersSchema.reducersType +>; -// A type representing all the possible variants of a reducer. -export type Reducer = never -| { name: "Add", args: Add } -| { name: "AddPlayer", args: AddPlayer } -| { name: "AddPrivate", args: AddPrivate } -| { name: "AssertCallerIdentityIsModuleIdentity", args: AssertCallerIdentityIsModuleIdentity } -| { name: "ClientConnected", args: ClientConnected } -| { name: "DeletePlayer", args: DeletePlayer } -| { name: "DeletePlayersByName", args: DeletePlayersByName } -| { name: "ListOverAge", args: ListOverAge } -| { name: "LogModuleIdentity", args: LogModuleIdentity } -| { name: "QueryPrivate", args: QueryPrivate } -| { name: "RepeatingTest", args: RepeatingTest } -| { name: "SayHello", args: SayHello } -| { name: "Test", args: Test } -| { name: "TestBtreeIndexArgs", args: TestBtreeIndexArgs } -; - -export class RemoteReducers { - constructor(private connection: __DbConnectionImpl, private setCallReducerFlags: SetReducerFlags) {} - - add(name: string, age: number) { - const __args = { name, age }; - let __writer = new __BinaryWriter(1024); - Add.serialize(__writer, __args); - let __argsBuffer = __writer.getBuffer(); - this.connection.callReducer("add", __argsBuffer, this.setCallReducerFlags.addFlags); - } - - onAdd(callback: (ctx: ReducerEventContext, name: string, age: number) => void) { - this.connection.onReducer("add", callback); - } - - removeOnAdd(callback: (ctx: ReducerEventContext, name: string, age: number) => void) { - this.connection.offReducer("add", callback); - } - - addPlayer(name: string) { - const __args = { name }; - let __writer = new __BinaryWriter(1024); - AddPlayer.serialize(__writer, __args); - let __argsBuffer = __writer.getBuffer(); - this.connection.callReducer("add_player", __argsBuffer, this.setCallReducerFlags.addPlayerFlags); - } - - onAddPlayer(callback: (ctx: ReducerEventContext, name: string) => void) { - this.connection.onReducer("add_player", callback); - } - - removeOnAddPlayer(callback: (ctx: ReducerEventContext, name: string) => void) { - this.connection.offReducer("add_player", callback); - } - - addPrivate(name: string) { - const __args = { name }; - let __writer = new __BinaryWriter(1024); - AddPrivate.serialize(__writer, __args); - let __argsBuffer = __writer.getBuffer(); - this.connection.callReducer("add_private", __argsBuffer, this.setCallReducerFlags.addPrivateFlags); - } - - onAddPrivate(callback: (ctx: ReducerEventContext, name: string) => void) { - this.connection.onReducer("add_private", callback); - } - - removeOnAddPrivate(callback: (ctx: ReducerEventContext, name: string) => void) { - this.connection.offReducer("add_private", callback); - } - - assertCallerIdentityIsModuleIdentity() { - this.connection.callReducer("assert_caller_identity_is_module_identity", new Uint8Array(0), this.setCallReducerFlags.assertCallerIdentityIsModuleIdentityFlags); - } - - onAssertCallerIdentityIsModuleIdentity(callback: (ctx: ReducerEventContext) => void) { - this.connection.onReducer("assert_caller_identity_is_module_identity", callback); - } - - removeOnAssertCallerIdentityIsModuleIdentity(callback: (ctx: ReducerEventContext) => void) { - this.connection.offReducer("assert_caller_identity_is_module_identity", callback); - } - - onClientConnected(callback: (ctx: ReducerEventContext) => void) { - this.connection.onReducer("client_connected", callback); - } - - removeOnClientConnected(callback: (ctx: ReducerEventContext) => void) { - this.connection.offReducer("client_connected", callback); - } - - deletePlayer(id: bigint) { - const __args = { id }; - let __writer = new __BinaryWriter(1024); - DeletePlayer.serialize(__writer, __args); - let __argsBuffer = __writer.getBuffer(); - this.connection.callReducer("delete_player", __argsBuffer, this.setCallReducerFlags.deletePlayerFlags); - } - - onDeletePlayer(callback: (ctx: ReducerEventContext, id: bigint) => void) { - this.connection.onReducer("delete_player", callback); - } - - removeOnDeletePlayer(callback: (ctx: ReducerEventContext, id: bigint) => void) { - this.connection.offReducer("delete_player", callback); - } - - deletePlayersByName(name: string) { - const __args = { name }; - let __writer = new __BinaryWriter(1024); - DeletePlayersByName.serialize(__writer, __args); - let __argsBuffer = __writer.getBuffer(); - this.connection.callReducer("delete_players_by_name", __argsBuffer, this.setCallReducerFlags.deletePlayersByNameFlags); - } - - onDeletePlayersByName(callback: (ctx: ReducerEventContext, name: string) => void) { - this.connection.onReducer("delete_players_by_name", callback); - } - - removeOnDeletePlayersByName(callback: (ctx: ReducerEventContext, name: string) => void) { - this.connection.offReducer("delete_players_by_name", callback); - } - - listOverAge(age: number) { - const __args = { age }; - let __writer = new __BinaryWriter(1024); - ListOverAge.serialize(__writer, __args); - let __argsBuffer = __writer.getBuffer(); - this.connection.callReducer("list_over_age", __argsBuffer, this.setCallReducerFlags.listOverAgeFlags); - } - - onListOverAge(callback: (ctx: ReducerEventContext, age: number) => void) { - this.connection.onReducer("list_over_age", callback); - } - - removeOnListOverAge(callback: (ctx: ReducerEventContext, age: number) => void) { - this.connection.offReducer("list_over_age", callback); - } - - logModuleIdentity() { - this.connection.callReducer("log_module_identity", new Uint8Array(0), this.setCallReducerFlags.logModuleIdentityFlags); - } - - onLogModuleIdentity(callback: (ctx: ReducerEventContext) => void) { - this.connection.onReducer("log_module_identity", callback); - } - - removeOnLogModuleIdentity(callback: (ctx: ReducerEventContext) => void) { - this.connection.offReducer("log_module_identity", callback); - } - - queryPrivate() { - this.connection.callReducer("query_private", new Uint8Array(0), this.setCallReducerFlags.queryPrivateFlags); - } - - onQueryPrivate(callback: (ctx: ReducerEventContext) => void) { - this.connection.onReducer("query_private", callback); - } - - removeOnQueryPrivate(callback: (ctx: ReducerEventContext) => void) { - this.connection.offReducer("query_private", callback); - } - - repeatingTest(arg: RepeatingTestArg) { - const __args = { arg }; - let __writer = new __BinaryWriter(1024); - RepeatingTest.serialize(__writer, __args); - let __argsBuffer = __writer.getBuffer(); - this.connection.callReducer("repeating_test", __argsBuffer, this.setCallReducerFlags.repeatingTestFlags); - } - - onRepeatingTest(callback: (ctx: ReducerEventContext, arg: RepeatingTestArg) => void) { - this.connection.onReducer("repeating_test", callback); - } - - removeOnRepeatingTest(callback: (ctx: ReducerEventContext, arg: RepeatingTestArg) => void) { - this.connection.offReducer("repeating_test", callback); - } - - sayHello() { - this.connection.callReducer("say_hello", new Uint8Array(0), this.setCallReducerFlags.sayHelloFlags); - } - - onSayHello(callback: (ctx: ReducerEventContext) => void) { - this.connection.onReducer("say_hello", callback); - } - - removeOnSayHello(callback: (ctx: ReducerEventContext) => void) { - this.connection.offReducer("say_hello", callback); - } - - test(arg: TestA, arg2: TestB, arg3: NamespaceTestC, arg4: NamespaceTestF) { - const __args = { arg, arg2, arg3, arg4 }; - let __writer = new __BinaryWriter(1024); - Test.serialize(__writer, __args); - let __argsBuffer = __writer.getBuffer(); - this.connection.callReducer("test", __argsBuffer, this.setCallReducerFlags.testFlags); - } - - onTest(callback: (ctx: ReducerEventContext, arg: TestA, arg2: TestB, arg3: NamespaceTestC, arg4: NamespaceTestF) => void) { - this.connection.onReducer("test", callback); - } - - removeOnTest(callback: (ctx: ReducerEventContext, arg: TestA, arg2: TestB, arg3: NamespaceTestC, arg4: NamespaceTestF) => void) { - this.connection.offReducer("test", callback); - } - - testBtreeIndexArgs() { - this.connection.callReducer("test_btree_index_args", new Uint8Array(0), this.setCallReducerFlags.testBtreeIndexArgsFlags); - } - - onTestBtreeIndexArgs(callback: (ctx: ReducerEventContext) => void) { - this.connection.onReducer("test_btree_index_args", callback); - } - - removeOnTestBtreeIndexArgs(callback: (ctx: ReducerEventContext) => void) { - this.connection.offReducer("test_btree_index_args", callback); - } +export const tables = __convertToAccessorMap(tablesSchema.schemaType.tables); +export const reducers = __convertToAccessorMap(reducersSchema.reducersType.reducers); -} - -export class SetReducerFlags { - addFlags: __CallReducerFlags = 'FullUpdate'; - add(flags: __CallReducerFlags) { - this.addFlags = flags; - } - - addPlayerFlags: __CallReducerFlags = 'FullUpdate'; - addPlayer(flags: __CallReducerFlags) { - this.addPlayerFlags = flags; - } - - addPrivateFlags: __CallReducerFlags = 'FullUpdate'; - addPrivate(flags: __CallReducerFlags) { - this.addPrivateFlags = flags; - } - - assertCallerIdentityIsModuleIdentityFlags: __CallReducerFlags = 'FullUpdate'; - assertCallerIdentityIsModuleIdentity(flags: __CallReducerFlags) { - this.assertCallerIdentityIsModuleIdentityFlags = flags; - } - - deletePlayerFlags: __CallReducerFlags = 'FullUpdate'; - deletePlayer(flags: __CallReducerFlags) { - this.deletePlayerFlags = flags; - } - - deletePlayersByNameFlags: __CallReducerFlags = 'FullUpdate'; - deletePlayersByName(flags: __CallReducerFlags) { - this.deletePlayersByNameFlags = flags; - } - - listOverAgeFlags: __CallReducerFlags = 'FullUpdate'; - listOverAge(flags: __CallReducerFlags) { - this.listOverAgeFlags = flags; - } - - logModuleIdentityFlags: __CallReducerFlags = 'FullUpdate'; - logModuleIdentity(flags: __CallReducerFlags) { - this.logModuleIdentityFlags = flags; - } - - queryPrivateFlags: __CallReducerFlags = 'FullUpdate'; - queryPrivate(flags: __CallReducerFlags) { - this.queryPrivateFlags = flags; - } - - repeatingTestFlags: __CallReducerFlags = 'FullUpdate'; - repeatingTest(flags: __CallReducerFlags) { - this.repeatingTestFlags = flags; - } - - sayHelloFlags: __CallReducerFlags = 'FullUpdate'; - sayHello(flags: __CallReducerFlags) { - this.sayHelloFlags = flags; - } - - testFlags: __CallReducerFlags = 'FullUpdate'; - test(flags: __CallReducerFlags) { - this.testFlags = flags; - } - - testBtreeIndexArgsFlags: __CallReducerFlags = 'FullUpdate'; - testBtreeIndexArgs(flags: __CallReducerFlags) { - this.testBtreeIndexArgsFlags = flags; - } -} +export type EventContext = __EventContextInterface; +export type ReducerEventContext = __ReducerEventContextInterface; +export type SubscriptionEventContext = __SubscriptionEventContextInterface; +export type ErrorContext = __ErrorContextInterface; -export class RemoteTables { - constructor(private connection: __DbConnectionImpl) {} - - get hasSpecialStuff(): HasSpecialStuffTableHandle<'has_special_stuff'> { - // clientCache is a private property - return new HasSpecialStuffTableHandle((this.connection as unknown as { clientCache: __ClientCache }).clientCache.getOrCreateTable(REMOTE_MODULE.tables.has_special_stuff)); - } - - get loggedOutPlayer(): LoggedOutPlayerTableHandle<'logged_out_player'> { - // clientCache is a private property - return new LoggedOutPlayerTableHandle((this.connection as unknown as { clientCache: __ClientCache }).clientCache.getOrCreateTable(REMOTE_MODULE.tables.logged_out_player)); - } - - get person(): PersonTableHandle<'person'> { - // clientCache is a private property - return new PersonTableHandle((this.connection as unknown as { clientCache: __ClientCache }).clientCache.getOrCreateTable(REMOTE_MODULE.tables.person)); - } - - get pkMultiIdentity(): PkMultiIdentityTableHandle<'pk_multi_identity'> { - // clientCache is a private property - return new PkMultiIdentityTableHandle((this.connection as unknown as { clientCache: __ClientCache }).clientCache.getOrCreateTable(REMOTE_MODULE.tables.pk_multi_identity)); - } - - get player(): PlayerTableHandle<'player'> { - // clientCache is a private property - return new PlayerTableHandle((this.connection as unknown as { clientCache: __ClientCache }).clientCache.getOrCreateTable(REMOTE_MODULE.tables.player)); - } - - get points(): PointsTableHandle<'points'> { - // clientCache is a private property - return new PointsTableHandle((this.connection as unknown as { clientCache: __ClientCache }).clientCache.getOrCreateTable(REMOTE_MODULE.tables.points)); - } - - get privateTable(): PrivateTableTableHandle<'private_table'> { - // clientCache is a private property - return new PrivateTableTableHandle((this.connection as unknown as { clientCache: __ClientCache }).clientCache.getOrCreateTable(REMOTE_MODULE.tables.private_table)); - } - - get repeatingTestArg(): RepeatingTestArgTableHandle<'repeating_test_arg'> { - // clientCache is a private property - return new RepeatingTestArgTableHandle((this.connection as unknown as { clientCache: __ClientCache }).clientCache.getOrCreateTable(REMOTE_MODULE.tables.repeating_test_arg)); - } - - get testA(): TestATableHandle<'test_a'> { - // clientCache is a private property - return new TestATableHandle((this.connection as unknown as { clientCache: __ClientCache }).clientCache.getOrCreateTable(REMOTE_MODULE.tables.test_a)); - } - - get testD(): TestDTableHandle<'test_d'> { - // clientCache is a private property - return new TestDTableHandle((this.connection as unknown as { clientCache: __ClientCache }).clientCache.getOrCreateTable(REMOTE_MODULE.tables.test_d)); - } - - get testE(): TestETableHandle<'test_e'> { - // clientCache is a private property - return new TestETableHandle((this.connection as unknown as { clientCache: __ClientCache }).clientCache.getOrCreateTable(REMOTE_MODULE.tables.test_e)); - } - - get testF(): TestFTableHandle<'test_f'> { - // clientCache is a private property - return new TestFTableHandle((this.connection as unknown as { clientCache: __ClientCache }).clientCache.getOrCreateTable(REMOTE_MODULE.tables.test_f)); - } -} +export class SubscriptionBuilder extends __SubscriptionBuilderImpl< + typeof REMOTE_MODULE +> {} -export class SubscriptionBuilder extends __SubscriptionBuilderImpl { } +export class DbConnectionBuilder extends __DbConnectionBuilder< + DbConnection +> {} -export class DbConnection extends __DbConnectionImpl { - static builder = (): __DbConnectionBuilder => { - return new __DbConnectionBuilder(REMOTE_MODULE, (imp: __DbConnectionImpl) => imp as DbConnection); - } +export class DbConnection extends __DbConnectionImpl { + static builder = (): DbConnectionBuilder => { + return new DbConnectionBuilder(REMOTE_MODULE, (config: __DbConnectionConfig) => new DbConnection(config)); + }; subscriptionBuilder = (): SubscriptionBuilder => { return new SubscriptionBuilder(this); - } + }; } -export type EventContext = __EventContextInterface; -export type ReducerEventContext = __ReducerEventContextInterface; -export type SubscriptionEventContext = __SubscriptionEventContextInterface; -export type ErrorContext = __ErrorContextInterface; ''' "list_over_age_reducer.ts" = ''' // THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE @@ -1457,64 +528,15 @@ export type ErrorContext = __ErrorContextInterface implements __TableHandle { - // phantom type to track the table name - readonly tableName!: TableName; - tableCache: __TableCache; - - constructor(tableCache: __TableCache) { - this.tableCache = tableCache; - } - - count(): number { - return this.tableCache.count(); - } - - iter(): Iterable { - return this.tableCache.iter(); - } - /** - * Access to the `identity` unique index on the table `logged_out_player`, - * which allows point queries on the field of the same name - * via the [`LoggedOutPlayerIdentityUnique.find`] method. - * - * Users are encouraged not to explicitly reference this type, - * but to directly chain method calls, - * like `ctx.db.loggedOutPlayer.identity().find(...)`. - * - * Get a handle on the `identity` unique index on the table `logged_out_player`. - */ - identity = { - // Find the subscribed row whose `identity` column value is equal to `col_val`, - // if such a row is present in the client cache. - find: (col_val: __Identity): Player | undefined => { - for (let row of this.tableCache.iter()) { - if (__deepEqual(row.identity, col_val)) { - return row; - } - } - }, - }; - /** - * Access to the `playerId` unique index on the table `logged_out_player`, - * which allows point queries on the field of the same name - * via the [`LoggedOutPlayerPlayerIdUnique.find`] method. - * - * Users are encouraged not to explicitly reference this type, - * but to directly chain method calls, - * like `ctx.db.loggedOutPlayer.playerId().find(...)`. - * - * Get a handle on the `playerId` unique index on the table `logged_out_player`. - */ - playerId = { - // Find the subscribed row whose `playerId` column value is equal to `col_val`, - // if such a row is present in the client cache. - find: (col_val: bigint): Player | undefined => { - for (let row of this.tableCache.iter()) { - if (__deepEqual(row.playerId, col_val)) { - return row; - } - } - }, - }; - /** - * Access to the `name` unique index on the table `logged_out_player`, - * which allows point queries on the field of the same name - * via the [`LoggedOutPlayerNameUnique.find`] method. - * - * Users are encouraged not to explicitly reference this type, - * but to directly chain method calls, - * like `ctx.db.loggedOutPlayer.name().find(...)`. - * - * Get a handle on the `name` unique index on the table `logged_out_player`. - */ - name = { - // Find the subscribed row whose `name` column value is equal to `col_val`, - // if such a row is present in the client cache. - find: (col_val: string): Player | undefined => { - for (let row of this.tableCache.iter()) { - if (__deepEqual(row.name, col_val)) { - return row; - } - } - }, - }; - - onInsert = (cb: (ctx: EventContext, row: Player) => void) => { - return this.tableCache.onInsert(cb); - } - removeOnInsert = (cb: (ctx: EventContext, row: Player) => void) => { - return this.tableCache.removeOnInsert(cb); - } - - onDelete = (cb: (ctx: EventContext, row: Player) => void) => { - return this.tableCache.onDelete(cb); - } - - removeOnDelete = (cb: (ctx: EventContext, row: Player) => void) => { - return this.tableCache.removeOnDelete(cb); - } - - // Updates are only defined for tables with primary keys. - onUpdate = (cb: (ctx: EventContext, oldRow: Player, newRow: Player) => void) => { - return this.tableCache.onUpdate(cb); - } - - removeOnUpdate = (cb: (ctx: EventContext, onRow: Player, newRow: Player) => void) => { - return this.tableCache.removeOnUpdate(cb); - }} +export default __t.row({ + identity: __t.identity().primaryKey(), + playerId: __t.u64(), + name: __t.string(), +}); ''' "my_player_table.ts" = ''' // THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE @@ -1738,76 +579,17 @@ export class LoggedOutPlayerTableHandle implements __T /* eslint-disable */ /* tslint:disable */ import { - AlgebraicType as __AlgebraicTypeValue, - BinaryReader as __BinaryReader, - BinaryWriter as __BinaryWriter, - ClientCache as __ClientCache, - ConnectionId as __ConnectionId, - DbConnectionBuilder as __DbConnectionBuilder, - DbConnectionImpl as __DbConnectionImpl, - Identity as __Identity, - SubscriptionBuilderImpl as __SubscriptionBuilderImpl, - TableCache as __TableCache, - TimeDuration as __TimeDuration, - Timestamp as __Timestamp, - deepEqual as __deepEqual, - type AlgebraicType as __AlgebraicTypeType, - type AlgebraicTypeVariants as __AlgebraicTypeVariants, - type CallReducerFlags as __CallReducerFlags, - type ErrorContextInterface as __ErrorContextInterface, - type Event as __Event, - type EventContextInterface as __EventContextInterface, - type ReducerEventContextInterface as __ReducerEventContextInterface, - type SubscriptionEventContextInterface as __SubscriptionEventContextInterface, - type TableHandle as __TableHandle, + TypeBuilder as __TypeBuilder, + t as __t, + type AlgebraicTypeType as __AlgebraicTypeType, + type Infer as __Infer, } from "spacetimedb"; -import { Player } from "./player_type"; -import { type EventContext, type Reducer, RemoteReducers, RemoteTables } from "."; -declare type __keep = [EventContext, Reducer, RemoteReducers, RemoteTables]; - -/** - * Table handle for the table `my_player`. - * - * Obtain a handle from the [`myPlayer`] property on [`RemoteTables`], - * like `ctx.db.myPlayer`. - * - * Users are encouraged not to explicitly reference this type, - * but to directly chain method calls, - * like `ctx.db.myPlayer.on_insert(...)`. - */ -export class MyPlayerTableHandle implements __TableHandle { - // phantom type to track the table name - readonly tableName!: TableName; - tableCache: __TableCache; - - constructor(tableCache: __TableCache) { - this.tableCache = tableCache; - } - - count(): number { - return this.tableCache.count(); - } - - iter(): Iterable { - return this.tableCache.iter(); - } - - onInsert = (cb: (ctx: EventContext, row: Player) => void) => { - return this.tableCache.onInsert(cb); - } - - removeOnInsert = (cb: (ctx: EventContext, row: Player) => void) => { - return this.tableCache.removeOnInsert(cb); - } - - onDelete = (cb: (ctx: EventContext, row: Player) => void) => { - return this.tableCache.onDelete(cb); - } - - removeOnDelete = (cb: (ctx: EventContext, row: Player) => void) => { - return this.tableCache.removeOnDelete(cb); - } -} + +export default __t.row({ + identity: __t.identity(), + playerId: __t.u64(), + name: __t.string(), +}); ''' "namespace_test_c_type.ts" = ''' // THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE @@ -1816,106 +598,20 @@ export class MyPlayerTableHandle implements __TableHan /* eslint-disable */ /* tslint:disable */ import { - AlgebraicType as __AlgebraicTypeValue, - BinaryReader as __BinaryReader, - BinaryWriter as __BinaryWriter, - ClientCache as __ClientCache, - ConnectionId as __ConnectionId, - DbConnectionBuilder as __DbConnectionBuilder, - DbConnectionImpl as __DbConnectionImpl, - Identity as __Identity, - SubscriptionBuilderImpl as __SubscriptionBuilderImpl, - TableCache as __TableCache, - TimeDuration as __TimeDuration, - Timestamp as __Timestamp, - deepEqual as __deepEqual, - type AlgebraicType as __AlgebraicTypeType, - type AlgebraicTypeVariants as __AlgebraicTypeVariants, - type CallReducerFlags as __CallReducerFlags, - type ErrorContextInterface as __ErrorContextInterface, - type Event as __Event, - type EventContextInterface as __EventContextInterface, - type ReducerEventContextInterface as __ReducerEventContextInterface, - type SubscriptionEventContextInterface as __SubscriptionEventContextInterface, - type TableHandle as __TableHandle, + TypeBuilder as __TypeBuilder, + t as __t, + type AlgebraicTypeType as __AlgebraicTypeType, + type Infer as __Infer, } from "spacetimedb"; -import * as NamespaceTestCVariants from './namespace_test_c_variants' // The tagged union or sum type for the algebraic type `NamespaceTestC`. -export type NamespaceTestC = NamespaceTestCVariants.Foo | - NamespaceTestCVariants.Bar; - -let _cached_NamespaceTestC_type_value: __AlgebraicTypeType | null = null; - -// A value with helper functions to construct the type. -export const NamespaceTestC = { - // Helper functions for constructing each variant of the tagged union. - // ``` - // const foo = Foo.A(42); - // assert!(foo.tag === "A"); - // assert!(foo.value === 42); - // ``` - Foo: { tag: "Foo" } as const, - Bar: { tag: "Bar" } as const, - - getTypeScriptAlgebraicType(): __AlgebraicTypeType { - if (_cached_NamespaceTestC_type_value) return _cached_NamespaceTestC_type_value; - _cached_NamespaceTestC_type_value = __AlgebraicTypeValue.Sum({ variants: [] }); - _cached_NamespaceTestC_type_value.value.variants.push( - { name: "Foo", algebraicType: __AlgebraicTypeValue.Product({ elements: [] }) }, - { name: "Bar", algebraicType: __AlgebraicTypeValue.Product({ elements: [] }) }, - ); - return _cached_NamespaceTestC_type_value; - }, - - serialize(writer: __BinaryWriter, value: NamespaceTestC): void { - __AlgebraicTypeValue.serializeValue(writer, NamespaceTestC.getTypeScriptAlgebraicType(), value); - }, - - deserialize(reader: __BinaryReader): NamespaceTestC { - return __AlgebraicTypeValue.deserializeValue(reader, NamespaceTestC.getTypeScriptAlgebraicType()); - }, - -} +const NamespaceTestC = __t.enum("NamespaceTestC", {Foo: __t.unit(), + Bar: __t.unit(), +}); export default NamespaceTestC; -''' -"namespace_test_c_variants.ts" = ''' -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -/* eslint-disable */ -/* tslint:disable */ -import { - AlgebraicType as __AlgebraicTypeValue, - BinaryReader as __BinaryReader, - BinaryWriter as __BinaryWriter, - ClientCache as __ClientCache, - ConnectionId as __ConnectionId, - DbConnectionBuilder as __DbConnectionBuilder, - DbConnectionImpl as __DbConnectionImpl, - Identity as __Identity, - SubscriptionBuilderImpl as __SubscriptionBuilderImpl, - TableCache as __TableCache, - TimeDuration as __TimeDuration, - Timestamp as __Timestamp, - deepEqual as __deepEqual, - type AlgebraicType as __AlgebraicTypeType, - type AlgebraicTypeVariants as __AlgebraicTypeVariants, - type CallReducerFlags as __CallReducerFlags, - type ErrorContextInterface as __ErrorContextInterface, - type Event as __Event, - type EventContextInterface as __EventContextInterface, - type ReducerEventContextInterface as __ReducerEventContextInterface, - type SubscriptionEventContextInterface as __SubscriptionEventContextInterface, - type TableHandle as __TableHandle, -} from "spacetimedb"; - -export type Foo = { tag: "Foo" }; -export type Bar = { tag: "Bar" }; - ''' "namespace_test_f_type.ts" = ''' // THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE @@ -1924,110 +620,21 @@ export type Bar = { tag: "Bar" }; /* eslint-disable */ /* tslint:disable */ import { - AlgebraicType as __AlgebraicTypeValue, - BinaryReader as __BinaryReader, - BinaryWriter as __BinaryWriter, - ClientCache as __ClientCache, - ConnectionId as __ConnectionId, - DbConnectionBuilder as __DbConnectionBuilder, - DbConnectionImpl as __DbConnectionImpl, - Identity as __Identity, - SubscriptionBuilderImpl as __SubscriptionBuilderImpl, - TableCache as __TableCache, - TimeDuration as __TimeDuration, - Timestamp as __Timestamp, - deepEqual as __deepEqual, - type AlgebraicType as __AlgebraicTypeType, - type AlgebraicTypeVariants as __AlgebraicTypeVariants, - type CallReducerFlags as __CallReducerFlags, - type ErrorContextInterface as __ErrorContextInterface, - type Event as __Event, - type EventContextInterface as __EventContextInterface, - type ReducerEventContextInterface as __ReducerEventContextInterface, - type SubscriptionEventContextInterface as __SubscriptionEventContextInterface, - type TableHandle as __TableHandle, + TypeBuilder as __TypeBuilder, + t as __t, + type AlgebraicTypeType as __AlgebraicTypeType, + type Infer as __Infer, } from "spacetimedb"; -import * as NamespaceTestFVariants from './namespace_test_f_variants' // The tagged union or sum type for the algebraic type `NamespaceTestF`. -export type NamespaceTestF = NamespaceTestFVariants.Foo | - NamespaceTestFVariants.Bar | - NamespaceTestFVariants.Baz; - -let _cached_NamespaceTestF_type_value: __AlgebraicTypeType | null = null; - -// A value with helper functions to construct the type. -export const NamespaceTestF = { - // Helper functions for constructing each variant of the tagged union. - // ``` - // const foo = Foo.A(42); - // assert!(foo.tag === "A"); - // assert!(foo.value === 42); - // ``` - Foo: { tag: "Foo" } as const, - Bar: { tag: "Bar" } as const, - Baz: (value: string): NamespaceTestFVariants.Baz => ({ tag: "Baz", value }), - - getTypeScriptAlgebraicType(): __AlgebraicTypeType { - if (_cached_NamespaceTestF_type_value) return _cached_NamespaceTestF_type_value; - _cached_NamespaceTestF_type_value = __AlgebraicTypeValue.Sum({ variants: [] }); - _cached_NamespaceTestF_type_value.value.variants.push( - { name: "Foo", algebraicType: __AlgebraicTypeValue.Product({ elements: [] }) }, - { name: "Bar", algebraicType: __AlgebraicTypeValue.Product({ elements: [] }) }, - { name: "Baz", algebraicType: __AlgebraicTypeValue.String }, - ); - return _cached_NamespaceTestF_type_value; - }, - - serialize(writer: __BinaryWriter, value: NamespaceTestF): void { - __AlgebraicTypeValue.serializeValue(writer, NamespaceTestF.getTypeScriptAlgebraicType(), value); - }, - - deserialize(reader: __BinaryReader): NamespaceTestF { - return __AlgebraicTypeValue.deserializeValue(reader, NamespaceTestF.getTypeScriptAlgebraicType()); - }, - -} +const NamespaceTestF = __t.enum("NamespaceTestF", {Foo: __t.unit(), + Bar: __t.unit(), + Baz: __t.string(), +}); export default NamespaceTestF; -''' -"namespace_test_f_variants.ts" = ''' -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -/* eslint-disable */ -/* tslint:disable */ -import { - AlgebraicType as __AlgebraicTypeValue, - BinaryReader as __BinaryReader, - BinaryWriter as __BinaryWriter, - ClientCache as __ClientCache, - ConnectionId as __ConnectionId, - DbConnectionBuilder as __DbConnectionBuilder, - DbConnectionImpl as __DbConnectionImpl, - Identity as __Identity, - SubscriptionBuilderImpl as __SubscriptionBuilderImpl, - TableCache as __TableCache, - TimeDuration as __TimeDuration, - Timestamp as __Timestamp, - deepEqual as __deepEqual, - type AlgebraicType as __AlgebraicTypeType, - type AlgebraicTypeVariants as __AlgebraicTypeVariants, - type CallReducerFlags as __CallReducerFlags, - type ErrorContextInterface as __ErrorContextInterface, - type Event as __Event, - type EventContextInterface as __EventContextInterface, - type ReducerEventContextInterface as __ReducerEventContextInterface, - type SubscriptionEventContextInterface as __SubscriptionEventContextInterface, - type TableHandle as __TableHandle, -} from "spacetimedb"; - -export type Foo = { tag: "Foo" }; -export type Bar = { tag: "Bar" }; -export type Baz = { tag: "Baz", value: string }; - ''' "person_table.ts" = ''' // THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE @@ -2036,106 +643,17 @@ export type Baz = { tag: "Baz", value: string }; /* eslint-disable */ /* tslint:disable */ import { - AlgebraicType as __AlgebraicTypeValue, - BinaryReader as __BinaryReader, - BinaryWriter as __BinaryWriter, - ClientCache as __ClientCache, - ConnectionId as __ConnectionId, - DbConnectionBuilder as __DbConnectionBuilder, - DbConnectionImpl as __DbConnectionImpl, - Identity as __Identity, - SubscriptionBuilderImpl as __SubscriptionBuilderImpl, - TableCache as __TableCache, - TimeDuration as __TimeDuration, - Timestamp as __Timestamp, - deepEqual as __deepEqual, - type AlgebraicType as __AlgebraicTypeType, - type AlgebraicTypeVariants as __AlgebraicTypeVariants, - type CallReducerFlags as __CallReducerFlags, - type ErrorContextInterface as __ErrorContextInterface, - type Event as __Event, - type EventContextInterface as __EventContextInterface, - type ReducerEventContextInterface as __ReducerEventContextInterface, - type SubscriptionEventContextInterface as __SubscriptionEventContextInterface, - type TableHandle as __TableHandle, + TypeBuilder as __TypeBuilder, + t as __t, + type AlgebraicTypeType as __AlgebraicTypeType, + type Infer as __Infer, } from "spacetimedb"; -import { Person } from "./person_type"; -import { type EventContext, type Reducer, RemoteReducers, RemoteTables } from "."; -declare type __keep = [EventContext, Reducer, RemoteReducers, RemoteTables]; - -/** - * Table handle for the table `person`. - * - * Obtain a handle from the [`person`] property on [`RemoteTables`], - * like `ctx.db.person`. - * - * Users are encouraged not to explicitly reference this type, - * but to directly chain method calls, - * like `ctx.db.person.on_insert(...)`. - */ -export class PersonTableHandle implements __TableHandle { - // phantom type to track the table name - readonly tableName!: TableName; - tableCache: __TableCache; - - constructor(tableCache: __TableCache) { - this.tableCache = tableCache; - } - - count(): number { - return this.tableCache.count(); - } - - iter(): Iterable { - return this.tableCache.iter(); - } - /** - * Access to the `id` unique index on the table `person`, - * which allows point queries on the field of the same name - * via the [`PersonIdUnique.find`] method. - * - * Users are encouraged not to explicitly reference this type, - * but to directly chain method calls, - * like `ctx.db.person.id().find(...)`. - * - * Get a handle on the `id` unique index on the table `person`. - */ - id = { - // Find the subscribed row whose `id` column value is equal to `col_val`, - // if such a row is present in the client cache. - find: (col_val: number): Person | undefined => { - for (let row of this.tableCache.iter()) { - if (__deepEqual(row.id, col_val)) { - return row; - } - } - }, - }; - - onInsert = (cb: (ctx: EventContext, row: Person) => void) => { - return this.tableCache.onInsert(cb); - } - removeOnInsert = (cb: (ctx: EventContext, row: Person) => void) => { - return this.tableCache.removeOnInsert(cb); - } - - onDelete = (cb: (ctx: EventContext, row: Person) => void) => { - return this.tableCache.onDelete(cb); - } - - removeOnDelete = (cb: (ctx: EventContext, row: Person) => void) => { - return this.tableCache.removeOnDelete(cb); - } - - // Updates are only defined for tables with primary keys. - onUpdate = (cb: (ctx: EventContext, oldRow: Person, newRow: Person) => void) => { - return this.tableCache.onUpdate(cb); - } - - removeOnUpdate = (cb: (ctx: EventContext, onRow: Person, newRow: Person) => void) => { - return this.tableCache.removeOnUpdate(cb); - }} +export default __t.row({ + id: __t.u32().primaryKey(), + name: __t.string(), + age: __t.u8(), +}); ''' "person_type.ts" = ''' // THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE @@ -2144,67 +662,17 @@ export class PersonTableHandle implements __TableHandl /* eslint-disable */ /* tslint:disable */ import { - AlgebraicType as __AlgebraicTypeValue, - BinaryReader as __BinaryReader, - BinaryWriter as __BinaryWriter, - ClientCache as __ClientCache, - ConnectionId as __ConnectionId, - DbConnectionBuilder as __DbConnectionBuilder, - DbConnectionImpl as __DbConnectionImpl, - Identity as __Identity, - SubscriptionBuilderImpl as __SubscriptionBuilderImpl, - TableCache as __TableCache, - TimeDuration as __TimeDuration, - Timestamp as __Timestamp, - deepEqual as __deepEqual, - type AlgebraicType as __AlgebraicTypeType, - type AlgebraicTypeVariants as __AlgebraicTypeVariants, - type CallReducerFlags as __CallReducerFlags, - type ErrorContextInterface as __ErrorContextInterface, - type Event as __Event, - type EventContextInterface as __EventContextInterface, - type ReducerEventContextInterface as __ReducerEventContextInterface, - type SubscriptionEventContextInterface as __SubscriptionEventContextInterface, - type TableHandle as __TableHandle, + TypeBuilder as __TypeBuilder, + t as __t, + type AlgebraicTypeType as __AlgebraicTypeType, + type Infer as __Infer, } from "spacetimedb"; -export type Person = { - id: number, - name: string, - age: number, -}; -let _cached_Person_type_value: __AlgebraicTypeType | null = null; - -/** - * An object for generated helper functions. - */ -export const Person = { - /** - * A function which returns this type represented as an AlgebraicType. - * This function is derived from the AlgebraicType used to generate this type. - */ - getTypeScriptAlgebraicType(): __AlgebraicTypeType { - if (_cached_Person_type_value) return _cached_Person_type_value; - _cached_Person_type_value = __AlgebraicTypeValue.Product({ elements: [] }); - _cached_Person_type_value.value.elements.push( - { name: "id", algebraicType: __AlgebraicTypeValue.U32 }, - { name: "name", algebraicType: __AlgebraicTypeValue.String }, - { name: "age", algebraicType: __AlgebraicTypeValue.U8 }, - ); - return _cached_Person_type_value; - }, - - serialize(writer: __BinaryWriter, value: Person): void { - __AlgebraicTypeValue.serializeValue(writer, Person.getTypeScriptAlgebraicType(), value); - }, - - deserialize(reader: __BinaryReader): Person { - return __AlgebraicTypeValue.deserializeValue(reader, Person.getTypeScriptAlgebraicType()); - }, - -} - -export default Person; +export default __t.object("Person", { + id: __t.u32(), + name: __t.string(), + age: __t.u8(), +}); ''' @@ -2215,128 +683,16 @@ export default Person; /* eslint-disable */ /* tslint:disable */ import { - AlgebraicType as __AlgebraicTypeValue, - BinaryReader as __BinaryReader, - BinaryWriter as __BinaryWriter, - ClientCache as __ClientCache, - ConnectionId as __ConnectionId, - DbConnectionBuilder as __DbConnectionBuilder, - DbConnectionImpl as __DbConnectionImpl, - Identity as __Identity, - SubscriptionBuilderImpl as __SubscriptionBuilderImpl, - TableCache as __TableCache, - TimeDuration as __TimeDuration, - Timestamp as __Timestamp, - deepEqual as __deepEqual, - type AlgebraicType as __AlgebraicTypeType, - type AlgebraicTypeVariants as __AlgebraicTypeVariants, - type CallReducerFlags as __CallReducerFlags, - type ErrorContextInterface as __ErrorContextInterface, - type Event as __Event, - type EventContextInterface as __EventContextInterface, - type ReducerEventContextInterface as __ReducerEventContextInterface, - type SubscriptionEventContextInterface as __SubscriptionEventContextInterface, - type TableHandle as __TableHandle, + TypeBuilder as __TypeBuilder, + t as __t, + type AlgebraicTypeType as __AlgebraicTypeType, + type Infer as __Infer, } from "spacetimedb"; -import { PkMultiIdentity } from "./pk_multi_identity_type"; -import { type EventContext, type Reducer, RemoteReducers, RemoteTables } from "."; -declare type __keep = [EventContext, Reducer, RemoteReducers, RemoteTables]; - -/** - * Table handle for the table `pk_multi_identity`. - * - * Obtain a handle from the [`pkMultiIdentity`] property on [`RemoteTables`], - * like `ctx.db.pkMultiIdentity`. - * - * Users are encouraged not to explicitly reference this type, - * but to directly chain method calls, - * like `ctx.db.pkMultiIdentity.on_insert(...)`. - */ -export class PkMultiIdentityTableHandle implements __TableHandle { - // phantom type to track the table name - readonly tableName!: TableName; - tableCache: __TableCache; - - constructor(tableCache: __TableCache) { - this.tableCache = tableCache; - } - - count(): number { - return this.tableCache.count(); - } - - iter(): Iterable { - return this.tableCache.iter(); - } - /** - * Access to the `id` unique index on the table `pk_multi_identity`, - * which allows point queries on the field of the same name - * via the [`PkMultiIdentityIdUnique.find`] method. - * - * Users are encouraged not to explicitly reference this type, - * but to directly chain method calls, - * like `ctx.db.pkMultiIdentity.id().find(...)`. - * - * Get a handle on the `id` unique index on the table `pk_multi_identity`. - */ - id = { - // Find the subscribed row whose `id` column value is equal to `col_val`, - // if such a row is present in the client cache. - find: (col_val: number): PkMultiIdentity | undefined => { - for (let row of this.tableCache.iter()) { - if (__deepEqual(row.id, col_val)) { - return row; - } - } - }, - }; - /** - * Access to the `other` unique index on the table `pk_multi_identity`, - * which allows point queries on the field of the same name - * via the [`PkMultiIdentityOtherUnique.find`] method. - * - * Users are encouraged not to explicitly reference this type, - * but to directly chain method calls, - * like `ctx.db.pkMultiIdentity.other().find(...)`. - * - * Get a handle on the `other` unique index on the table `pk_multi_identity`. - */ - other = { - // Find the subscribed row whose `other` column value is equal to `col_val`, - // if such a row is present in the client cache. - find: (col_val: number): PkMultiIdentity | undefined => { - for (let row of this.tableCache.iter()) { - if (__deepEqual(row.other, col_val)) { - return row; - } - } - }, - }; - - onInsert = (cb: (ctx: EventContext, row: PkMultiIdentity) => void) => { - return this.tableCache.onInsert(cb); - } - - removeOnInsert = (cb: (ctx: EventContext, row: PkMultiIdentity) => void) => { - return this.tableCache.removeOnInsert(cb); - } - - onDelete = (cb: (ctx: EventContext, row: PkMultiIdentity) => void) => { - return this.tableCache.onDelete(cb); - } - removeOnDelete = (cb: (ctx: EventContext, row: PkMultiIdentity) => void) => { - return this.tableCache.removeOnDelete(cb); - } - - // Updates are only defined for tables with primary keys. - onUpdate = (cb: (ctx: EventContext, oldRow: PkMultiIdentity, newRow: PkMultiIdentity) => void) => { - return this.tableCache.onUpdate(cb); - } - - removeOnUpdate = (cb: (ctx: EventContext, onRow: PkMultiIdentity, newRow: PkMultiIdentity) => void) => { - return this.tableCache.removeOnUpdate(cb); - }} +export default __t.row({ + id: __t.u32().primaryKey(), + other: __t.u32(), +}); ''' "pk_multi_identity_type.ts" = ''' // THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE @@ -2345,65 +701,16 @@ export class PkMultiIdentityTableHandle implements __T /* eslint-disable */ /* tslint:disable */ import { - AlgebraicType as __AlgebraicTypeValue, - BinaryReader as __BinaryReader, - BinaryWriter as __BinaryWriter, - ClientCache as __ClientCache, - ConnectionId as __ConnectionId, - DbConnectionBuilder as __DbConnectionBuilder, - DbConnectionImpl as __DbConnectionImpl, - Identity as __Identity, - SubscriptionBuilderImpl as __SubscriptionBuilderImpl, - TableCache as __TableCache, - TimeDuration as __TimeDuration, - Timestamp as __Timestamp, - deepEqual as __deepEqual, - type AlgebraicType as __AlgebraicTypeType, - type AlgebraicTypeVariants as __AlgebraicTypeVariants, - type CallReducerFlags as __CallReducerFlags, - type ErrorContextInterface as __ErrorContextInterface, - type Event as __Event, - type EventContextInterface as __EventContextInterface, - type ReducerEventContextInterface as __ReducerEventContextInterface, - type SubscriptionEventContextInterface as __SubscriptionEventContextInterface, - type TableHandle as __TableHandle, + TypeBuilder as __TypeBuilder, + t as __t, + type AlgebraicTypeType as __AlgebraicTypeType, + type Infer as __Infer, } from "spacetimedb"; -export type PkMultiIdentity = { - id: number, - other: number, -}; -let _cached_PkMultiIdentity_type_value: __AlgebraicTypeType | null = null; - -/** - * An object for generated helper functions. - */ -export const PkMultiIdentity = { - /** - * A function which returns this type represented as an AlgebraicType. - * This function is derived from the AlgebraicType used to generate this type. - */ - getTypeScriptAlgebraicType(): __AlgebraicTypeType { - if (_cached_PkMultiIdentity_type_value) return _cached_PkMultiIdentity_type_value; - _cached_PkMultiIdentity_type_value = __AlgebraicTypeValue.Product({ elements: [] }); - _cached_PkMultiIdentity_type_value.value.elements.push( - { name: "id", algebraicType: __AlgebraicTypeValue.U32 }, - { name: "other", algebraicType: __AlgebraicTypeValue.U32 }, - ); - return _cached_PkMultiIdentity_type_value; - }, - - serialize(writer: __BinaryWriter, value: PkMultiIdentity): void { - __AlgebraicTypeValue.serializeValue(writer, PkMultiIdentity.getTypeScriptAlgebraicType(), value); - }, - - deserialize(reader: __BinaryReader): PkMultiIdentity { - return __AlgebraicTypeValue.deserializeValue(reader, PkMultiIdentity.getTypeScriptAlgebraicType()); - }, - -} - -export default PkMultiIdentity; +export default __t.object("PkMultiIdentity", { + id: __t.u32(), + other: __t.u32(), +}); ''' @@ -2414,150 +721,17 @@ export default PkMultiIdentity; /* eslint-disable */ /* tslint:disable */ import { - AlgebraicType as __AlgebraicTypeValue, - BinaryReader as __BinaryReader, - BinaryWriter as __BinaryWriter, - ClientCache as __ClientCache, - ConnectionId as __ConnectionId, - DbConnectionBuilder as __DbConnectionBuilder, - DbConnectionImpl as __DbConnectionImpl, - Identity as __Identity, - SubscriptionBuilderImpl as __SubscriptionBuilderImpl, - TableCache as __TableCache, - TimeDuration as __TimeDuration, - Timestamp as __Timestamp, - deepEqual as __deepEqual, - type AlgebraicType as __AlgebraicTypeType, - type AlgebraicTypeVariants as __AlgebraicTypeVariants, - type CallReducerFlags as __CallReducerFlags, - type ErrorContextInterface as __ErrorContextInterface, - type Event as __Event, - type EventContextInterface as __EventContextInterface, - type ReducerEventContextInterface as __ReducerEventContextInterface, - type SubscriptionEventContextInterface as __SubscriptionEventContextInterface, - type TableHandle as __TableHandle, + TypeBuilder as __TypeBuilder, + t as __t, + type AlgebraicTypeType as __AlgebraicTypeType, + type Infer as __Infer, } from "spacetimedb"; -import { Player } from "./player_type"; -import { type EventContext, type Reducer, RemoteReducers, RemoteTables } from "."; -declare type __keep = [EventContext, Reducer, RemoteReducers, RemoteTables]; - -/** - * Table handle for the table `player`. - * - * Obtain a handle from the [`player`] property on [`RemoteTables`], - * like `ctx.db.player`. - * - * Users are encouraged not to explicitly reference this type, - * but to directly chain method calls, - * like `ctx.db.player.on_insert(...)`. - */ -export class PlayerTableHandle implements __TableHandle { - // phantom type to track the table name - readonly tableName!: TableName; - tableCache: __TableCache; - - constructor(tableCache: __TableCache) { - this.tableCache = tableCache; - } - - count(): number { - return this.tableCache.count(); - } - - iter(): Iterable { - return this.tableCache.iter(); - } - /** - * Access to the `identity` unique index on the table `player`, - * which allows point queries on the field of the same name - * via the [`PlayerIdentityUnique.find`] method. - * - * Users are encouraged not to explicitly reference this type, - * but to directly chain method calls, - * like `ctx.db.player.identity().find(...)`. - * - * Get a handle on the `identity` unique index on the table `player`. - */ - identity = { - // Find the subscribed row whose `identity` column value is equal to `col_val`, - // if such a row is present in the client cache. - find: (col_val: __Identity): Player | undefined => { - for (let row of this.tableCache.iter()) { - if (__deepEqual(row.identity, col_val)) { - return row; - } - } - }, - }; - /** - * Access to the `playerId` unique index on the table `player`, - * which allows point queries on the field of the same name - * via the [`PlayerPlayerIdUnique.find`] method. - * - * Users are encouraged not to explicitly reference this type, - * but to directly chain method calls, - * like `ctx.db.player.playerId().find(...)`. - * - * Get a handle on the `playerId` unique index on the table `player`. - */ - playerId = { - // Find the subscribed row whose `playerId` column value is equal to `col_val`, - // if such a row is present in the client cache. - find: (col_val: bigint): Player | undefined => { - for (let row of this.tableCache.iter()) { - if (__deepEqual(row.playerId, col_val)) { - return row; - } - } - }, - }; - /** - * Access to the `name` unique index on the table `player`, - * which allows point queries on the field of the same name - * via the [`PlayerNameUnique.find`] method. - * - * Users are encouraged not to explicitly reference this type, - * but to directly chain method calls, - * like `ctx.db.player.name().find(...)`. - * - * Get a handle on the `name` unique index on the table `player`. - */ - name = { - // Find the subscribed row whose `name` column value is equal to `col_val`, - // if such a row is present in the client cache. - find: (col_val: string): Player | undefined => { - for (let row of this.tableCache.iter()) { - if (__deepEqual(row.name, col_val)) { - return row; - } - } - }, - }; - - onInsert = (cb: (ctx: EventContext, row: Player) => void) => { - return this.tableCache.onInsert(cb); - } - - removeOnInsert = (cb: (ctx: EventContext, row: Player) => void) => { - return this.tableCache.removeOnInsert(cb); - } - - onDelete = (cb: (ctx: EventContext, row: Player) => void) => { - return this.tableCache.onDelete(cb); - } - - removeOnDelete = (cb: (ctx: EventContext, row: Player) => void) => { - return this.tableCache.removeOnDelete(cb); - } - // Updates are only defined for tables with primary keys. - onUpdate = (cb: (ctx: EventContext, oldRow: Player, newRow: Player) => void) => { - return this.tableCache.onUpdate(cb); - } - - removeOnUpdate = (cb: (ctx: EventContext, onRow: Player, newRow: Player) => void) => { - return this.tableCache.removeOnUpdate(cb); - }} +export default __t.row({ + identity: __t.identity().primaryKey(), + playerId: __t.u64(), + name: __t.string(), +}); ''' "player_type.ts" = ''' // THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE @@ -2566,67 +740,17 @@ export class PlayerTableHandle implements __TableHandl /* eslint-disable */ /* tslint:disable */ import { - AlgebraicType as __AlgebraicTypeValue, - BinaryReader as __BinaryReader, - BinaryWriter as __BinaryWriter, - ClientCache as __ClientCache, - ConnectionId as __ConnectionId, - DbConnectionBuilder as __DbConnectionBuilder, - DbConnectionImpl as __DbConnectionImpl, - Identity as __Identity, - SubscriptionBuilderImpl as __SubscriptionBuilderImpl, - TableCache as __TableCache, - TimeDuration as __TimeDuration, - Timestamp as __Timestamp, - deepEqual as __deepEqual, - type AlgebraicType as __AlgebraicTypeType, - type AlgebraicTypeVariants as __AlgebraicTypeVariants, - type CallReducerFlags as __CallReducerFlags, - type ErrorContextInterface as __ErrorContextInterface, - type Event as __Event, - type EventContextInterface as __EventContextInterface, - type ReducerEventContextInterface as __ReducerEventContextInterface, - type SubscriptionEventContextInterface as __SubscriptionEventContextInterface, - type TableHandle as __TableHandle, + TypeBuilder as __TypeBuilder, + t as __t, + type AlgebraicTypeType as __AlgebraicTypeType, + type Infer as __Infer, } from "spacetimedb"; -export type Player = { - identity: __Identity, - playerId: bigint, - name: string, -}; -let _cached_Player_type_value: __AlgebraicTypeType | null = null; - -/** - * An object for generated helper functions. - */ -export const Player = { - /** - * A function which returns this type represented as an AlgebraicType. - * This function is derived from the AlgebraicType used to generate this type. - */ - getTypeScriptAlgebraicType(): __AlgebraicTypeType { - if (_cached_Player_type_value) return _cached_Player_type_value; - _cached_Player_type_value = __AlgebraicTypeValue.Product({ elements: [] }); - _cached_Player_type_value.value.elements.push( - { name: "identity", algebraicType: __AlgebraicTypeValue.createIdentityType() }, - { name: "playerId", algebraicType: __AlgebraicTypeValue.U64 }, - { name: "name", algebraicType: __AlgebraicTypeValue.String }, - ); - return _cached_Player_type_value; - }, - - serialize(writer: __BinaryWriter, value: Player): void { - __AlgebraicTypeValue.serializeValue(writer, Player.getTypeScriptAlgebraicType(), value); - }, - - deserialize(reader: __BinaryReader): Player { - return __AlgebraicTypeValue.deserializeValue(reader, Player.getTypeScriptAlgebraicType()); - }, - -} - -export default Player; +export default __t.object("Player", { + identity: __t.identity(), + playerId: __t.u64(), + name: __t.string(), +}); ''' @@ -2637,65 +761,16 @@ export default Player; /* eslint-disable */ /* tslint:disable */ import { - AlgebraicType as __AlgebraicTypeValue, - BinaryReader as __BinaryReader, - BinaryWriter as __BinaryWriter, - ClientCache as __ClientCache, - ConnectionId as __ConnectionId, - DbConnectionBuilder as __DbConnectionBuilder, - DbConnectionImpl as __DbConnectionImpl, - Identity as __Identity, - SubscriptionBuilderImpl as __SubscriptionBuilderImpl, - TableCache as __TableCache, - TimeDuration as __TimeDuration, - Timestamp as __Timestamp, - deepEqual as __deepEqual, - type AlgebraicType as __AlgebraicTypeType, - type AlgebraicTypeVariants as __AlgebraicTypeVariants, - type CallReducerFlags as __CallReducerFlags, - type ErrorContextInterface as __ErrorContextInterface, - type Event as __Event, - type EventContextInterface as __EventContextInterface, - type ReducerEventContextInterface as __ReducerEventContextInterface, - type SubscriptionEventContextInterface as __SubscriptionEventContextInterface, - type TableHandle as __TableHandle, + TypeBuilder as __TypeBuilder, + t as __t, + type AlgebraicTypeType as __AlgebraicTypeType, + type Infer as __Infer, } from "spacetimedb"; -export type Point = { - x: bigint, - y: bigint, -}; -let _cached_Point_type_value: __AlgebraicTypeType | null = null; - -/** - * An object for generated helper functions. - */ -export const Point = { - /** - * A function which returns this type represented as an AlgebraicType. - * This function is derived from the AlgebraicType used to generate this type. - */ - getTypeScriptAlgebraicType(): __AlgebraicTypeType { - if (_cached_Point_type_value) return _cached_Point_type_value; - _cached_Point_type_value = __AlgebraicTypeValue.Product({ elements: [] }); - _cached_Point_type_value.value.elements.push( - { name: "x", algebraicType: __AlgebraicTypeValue.I64 }, - { name: "y", algebraicType: __AlgebraicTypeValue.I64 }, - ); - return _cached_Point_type_value; - }, - - serialize(writer: __BinaryWriter, value: Point): void { - __AlgebraicTypeValue.serializeValue(writer, Point.getTypeScriptAlgebraicType(), value); - }, - - deserialize(reader: __BinaryReader): Point { - return __AlgebraicTypeValue.deserializeValue(reader, Point.getTypeScriptAlgebraicType()); - }, - -} - -export default Point; +export default __t.object("Point", { + x: __t.i64(), + y: __t.i64(), +}); ''' @@ -2706,76 +781,16 @@ export default Point; /* eslint-disable */ /* tslint:disable */ import { - AlgebraicType as __AlgebraicTypeValue, - BinaryReader as __BinaryReader, - BinaryWriter as __BinaryWriter, - ClientCache as __ClientCache, - ConnectionId as __ConnectionId, - DbConnectionBuilder as __DbConnectionBuilder, - DbConnectionImpl as __DbConnectionImpl, - Identity as __Identity, - SubscriptionBuilderImpl as __SubscriptionBuilderImpl, - TableCache as __TableCache, - TimeDuration as __TimeDuration, - Timestamp as __Timestamp, - deepEqual as __deepEqual, - type AlgebraicType as __AlgebraicTypeType, - type AlgebraicTypeVariants as __AlgebraicTypeVariants, - type CallReducerFlags as __CallReducerFlags, - type ErrorContextInterface as __ErrorContextInterface, - type Event as __Event, - type EventContextInterface as __EventContextInterface, - type ReducerEventContextInterface as __ReducerEventContextInterface, - type SubscriptionEventContextInterface as __SubscriptionEventContextInterface, - type TableHandle as __TableHandle, + TypeBuilder as __TypeBuilder, + t as __t, + type AlgebraicTypeType as __AlgebraicTypeType, + type Infer as __Infer, } from "spacetimedb"; -import { Point } from "./point_type"; -import { type EventContext, type Reducer, RemoteReducers, RemoteTables } from "."; -declare type __keep = [EventContext, Reducer, RemoteReducers, RemoteTables]; - -/** - * Table handle for the table `points`. - * - * Obtain a handle from the [`points`] property on [`RemoteTables`], - * like `ctx.db.points`. - * - * Users are encouraged not to explicitly reference this type, - * but to directly chain method calls, - * like `ctx.db.points.on_insert(...)`. - */ -export class PointsTableHandle implements __TableHandle { - // phantom type to track the table name - readonly tableName!: TableName; - tableCache: __TableCache; - - constructor(tableCache: __TableCache) { - this.tableCache = tableCache; - } - - count(): number { - return this.tableCache.count(); - } - - iter(): Iterable { - return this.tableCache.iter(); - } - - onInsert = (cb: (ctx: EventContext, row: Point) => void) => { - return this.tableCache.onInsert(cb); - } - - removeOnInsert = (cb: (ctx: EventContext, row: Point) => void) => { - return this.tableCache.removeOnInsert(cb); - } - - onDelete = (cb: (ctx: EventContext, row: Point) => void) => { - return this.tableCache.onDelete(cb); - } - - removeOnDelete = (cb: (ctx: EventContext, row: Point) => void) => { - return this.tableCache.removeOnDelete(cb); - } -} + +export default __t.row({ + x: __t.i64(), + y: __t.i64(), +}); ''' "private_table_table.ts" = ''' // THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE @@ -2784,76 +799,15 @@ export class PointsTableHandle implements __TableHandl /* eslint-disable */ /* tslint:disable */ import { - AlgebraicType as __AlgebraicTypeValue, - BinaryReader as __BinaryReader, - BinaryWriter as __BinaryWriter, - ClientCache as __ClientCache, - ConnectionId as __ConnectionId, - DbConnectionBuilder as __DbConnectionBuilder, - DbConnectionImpl as __DbConnectionImpl, - Identity as __Identity, - SubscriptionBuilderImpl as __SubscriptionBuilderImpl, - TableCache as __TableCache, - TimeDuration as __TimeDuration, - Timestamp as __Timestamp, - deepEqual as __deepEqual, - type AlgebraicType as __AlgebraicTypeType, - type AlgebraicTypeVariants as __AlgebraicTypeVariants, - type CallReducerFlags as __CallReducerFlags, - type ErrorContextInterface as __ErrorContextInterface, - type Event as __Event, - type EventContextInterface as __EventContextInterface, - type ReducerEventContextInterface as __ReducerEventContextInterface, - type SubscriptionEventContextInterface as __SubscriptionEventContextInterface, - type TableHandle as __TableHandle, + TypeBuilder as __TypeBuilder, + t as __t, + type AlgebraicTypeType as __AlgebraicTypeType, + type Infer as __Infer, } from "spacetimedb"; -import { PrivateTable } from "./private_table_type"; -import { type EventContext, type Reducer, RemoteReducers, RemoteTables } from "."; -declare type __keep = [EventContext, Reducer, RemoteReducers, RemoteTables]; - -/** - * Table handle for the table `private_table`. - * - * Obtain a handle from the [`privateTable`] property on [`RemoteTables`], - * like `ctx.db.privateTable`. - * - * Users are encouraged not to explicitly reference this type, - * but to directly chain method calls, - * like `ctx.db.privateTable.on_insert(...)`. - */ -export class PrivateTableTableHandle implements __TableHandle { - // phantom type to track the table name - readonly tableName!: TableName; - tableCache: __TableCache; - - constructor(tableCache: __TableCache) { - this.tableCache = tableCache; - } - - count(): number { - return this.tableCache.count(); - } - - iter(): Iterable { - return this.tableCache.iter(); - } - - onInsert = (cb: (ctx: EventContext, row: PrivateTable) => void) => { - return this.tableCache.onInsert(cb); - } - - removeOnInsert = (cb: (ctx: EventContext, row: PrivateTable) => void) => { - return this.tableCache.removeOnInsert(cb); - } - - onDelete = (cb: (ctx: EventContext, row: PrivateTable) => void) => { - return this.tableCache.onDelete(cb); - } - - removeOnDelete = (cb: (ctx: EventContext, row: PrivateTable) => void) => { - return this.tableCache.removeOnDelete(cb); - } -} + +export default __t.row({ + name: __t.string(), +}); ''' "private_table_type.ts" = ''' // THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE @@ -2862,63 +816,15 @@ export class PrivateTableTableHandle implements __Tabl /* eslint-disable */ /* tslint:disable */ import { - AlgebraicType as __AlgebraicTypeValue, - BinaryReader as __BinaryReader, - BinaryWriter as __BinaryWriter, - ClientCache as __ClientCache, - ConnectionId as __ConnectionId, - DbConnectionBuilder as __DbConnectionBuilder, - DbConnectionImpl as __DbConnectionImpl, - Identity as __Identity, - SubscriptionBuilderImpl as __SubscriptionBuilderImpl, - TableCache as __TableCache, - TimeDuration as __TimeDuration, - Timestamp as __Timestamp, - deepEqual as __deepEqual, - type AlgebraicType as __AlgebraicTypeType, - type AlgebraicTypeVariants as __AlgebraicTypeVariants, - type CallReducerFlags as __CallReducerFlags, - type ErrorContextInterface as __ErrorContextInterface, - type Event as __Event, - type EventContextInterface as __EventContextInterface, - type ReducerEventContextInterface as __ReducerEventContextInterface, - type SubscriptionEventContextInterface as __SubscriptionEventContextInterface, - type TableHandle as __TableHandle, + TypeBuilder as __TypeBuilder, + t as __t, + type AlgebraicTypeType as __AlgebraicTypeType, + type Infer as __Infer, } from "spacetimedb"; -export type PrivateTable = { - name: string, -}; -let _cached_PrivateTable_type_value: __AlgebraicTypeType | null = null; - -/** - * An object for generated helper functions. - */ -export const PrivateTable = { - /** - * A function which returns this type represented as an AlgebraicType. - * This function is derived from the AlgebraicType used to generate this type. - */ - getTypeScriptAlgebraicType(): __AlgebraicTypeType { - if (_cached_PrivateTable_type_value) return _cached_PrivateTable_type_value; - _cached_PrivateTable_type_value = __AlgebraicTypeValue.Product({ elements: [] }); - _cached_PrivateTable_type_value.value.elements.push( - { name: "name", algebraicType: __AlgebraicTypeValue.String }, - ); - return _cached_PrivateTable_type_value; - }, - - serialize(writer: __BinaryWriter, value: PrivateTable): void { - __AlgebraicTypeValue.serializeValue(writer, PrivateTable.getTypeScriptAlgebraicType(), value); - }, - - deserialize(reader: __BinaryReader): PrivateTable { - return __AlgebraicTypeValue.deserializeValue(reader, PrivateTable.getTypeScriptAlgebraicType()); - }, - -} - -export default PrivateTable; +export default __t.object("PrivateTable", { + name: __t.string(), +}); ''' @@ -2929,61 +835,13 @@ export default PrivateTable; /* eslint-disable */ /* tslint:disable */ import { - AlgebraicType as __AlgebraicTypeValue, - BinaryReader as __BinaryReader, - BinaryWriter as __BinaryWriter, - ClientCache as __ClientCache, - ConnectionId as __ConnectionId, - DbConnectionBuilder as __DbConnectionBuilder, - DbConnectionImpl as __DbConnectionImpl, - Identity as __Identity, - SubscriptionBuilderImpl as __SubscriptionBuilderImpl, - TableCache as __TableCache, - TimeDuration as __TimeDuration, - Timestamp as __Timestamp, - deepEqual as __deepEqual, - type AlgebraicType as __AlgebraicTypeType, - type AlgebraicTypeVariants as __AlgebraicTypeVariants, - type CallReducerFlags as __CallReducerFlags, - type ErrorContextInterface as __ErrorContextInterface, - type Event as __Event, - type EventContextInterface as __EventContextInterface, - type ReducerEventContextInterface as __ReducerEventContextInterface, - type SubscriptionEventContextInterface as __SubscriptionEventContextInterface, - type TableHandle as __TableHandle, + TypeBuilder as __TypeBuilder, + t as __t, + type AlgebraicTypeType as __AlgebraicTypeType, + type Infer as __Infer, } from "spacetimedb"; -export type QueryPrivate = {}; -let _cached_QueryPrivate_type_value: __AlgebraicTypeType | null = null; - -/** - * An object for generated helper functions. - */ -export const QueryPrivate = { - /** - * A function which returns this type represented as an AlgebraicType. - * This function is derived from the AlgebraicType used to generate this type. - */ - getTypeScriptAlgebraicType(): __AlgebraicTypeType { - if (_cached_QueryPrivate_type_value) return _cached_QueryPrivate_type_value; - _cached_QueryPrivate_type_value = __AlgebraicTypeValue.Product({ elements: [] }); - _cached_QueryPrivate_type_value.value.elements.push( - ); - return _cached_QueryPrivate_type_value; - }, - - serialize(writer: __BinaryWriter, value: QueryPrivate): void { - __AlgebraicTypeValue.serializeValue(writer, QueryPrivate.getTypeScriptAlgebraicType(), value); - }, - - deserialize(reader: __BinaryReader): QueryPrivate { - return __AlgebraicTypeValue.deserializeValue(reader, QueryPrivate.getTypeScriptAlgebraicType()); - }, - -} - -export default QueryPrivate; - +export default {}; ''' "repeating_test_arg_table.ts" = ''' // THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE @@ -2992,106 +850,17 @@ export default QueryPrivate; /* eslint-disable */ /* tslint:disable */ import { - AlgebraicType as __AlgebraicTypeValue, - BinaryReader as __BinaryReader, - BinaryWriter as __BinaryWriter, - ClientCache as __ClientCache, - ConnectionId as __ConnectionId, - DbConnectionBuilder as __DbConnectionBuilder, - DbConnectionImpl as __DbConnectionImpl, - Identity as __Identity, - SubscriptionBuilderImpl as __SubscriptionBuilderImpl, - TableCache as __TableCache, - TimeDuration as __TimeDuration, - Timestamp as __Timestamp, - deepEqual as __deepEqual, - type AlgebraicType as __AlgebraicTypeType, - type AlgebraicTypeVariants as __AlgebraicTypeVariants, - type CallReducerFlags as __CallReducerFlags, - type ErrorContextInterface as __ErrorContextInterface, - type Event as __Event, - type EventContextInterface as __EventContextInterface, - type ReducerEventContextInterface as __ReducerEventContextInterface, - type SubscriptionEventContextInterface as __SubscriptionEventContextInterface, - type TableHandle as __TableHandle, + TypeBuilder as __TypeBuilder, + t as __t, + type AlgebraicTypeType as __AlgebraicTypeType, + type Infer as __Infer, } from "spacetimedb"; -import { RepeatingTestArg } from "./repeating_test_arg_type"; -import { type EventContext, type Reducer, RemoteReducers, RemoteTables } from "."; -declare type __keep = [EventContext, Reducer, RemoteReducers, RemoteTables]; - -/** - * Table handle for the table `repeating_test_arg`. - * - * Obtain a handle from the [`repeatingTestArg`] property on [`RemoteTables`], - * like `ctx.db.repeatingTestArg`. - * - * Users are encouraged not to explicitly reference this type, - * but to directly chain method calls, - * like `ctx.db.repeatingTestArg.on_insert(...)`. - */ -export class RepeatingTestArgTableHandle implements __TableHandle { - // phantom type to track the table name - readonly tableName!: TableName; - tableCache: __TableCache; - - constructor(tableCache: __TableCache) { - this.tableCache = tableCache; - } - - count(): number { - return this.tableCache.count(); - } - - iter(): Iterable { - return this.tableCache.iter(); - } - /** - * Access to the `scheduledId` unique index on the table `repeating_test_arg`, - * which allows point queries on the field of the same name - * via the [`RepeatingTestArgScheduledIdUnique.find`] method. - * - * Users are encouraged not to explicitly reference this type, - * but to directly chain method calls, - * like `ctx.db.repeatingTestArg.scheduledId().find(...)`. - * - * Get a handle on the `scheduledId` unique index on the table `repeating_test_arg`. - */ - scheduledId = { - // Find the subscribed row whose `scheduledId` column value is equal to `col_val`, - // if such a row is present in the client cache. - find: (col_val: bigint): RepeatingTestArg | undefined => { - for (let row of this.tableCache.iter()) { - if (__deepEqual(row.scheduledId, col_val)) { - return row; - } - } - }, - }; - - onInsert = (cb: (ctx: EventContext, row: RepeatingTestArg) => void) => { - return this.tableCache.onInsert(cb); - } - - removeOnInsert = (cb: (ctx: EventContext, row: RepeatingTestArg) => void) => { - return this.tableCache.removeOnInsert(cb); - } - - onDelete = (cb: (ctx: EventContext, row: RepeatingTestArg) => void) => { - return this.tableCache.onDelete(cb); - } - removeOnDelete = (cb: (ctx: EventContext, row: RepeatingTestArg) => void) => { - return this.tableCache.removeOnDelete(cb); - } - - // Updates are only defined for tables with primary keys. - onUpdate = (cb: (ctx: EventContext, oldRow: RepeatingTestArg, newRow: RepeatingTestArg) => void) => { - return this.tableCache.onUpdate(cb); - } - - removeOnUpdate = (cb: (ctx: EventContext, onRow: RepeatingTestArg, newRow: RepeatingTestArg) => void) => { - return this.tableCache.removeOnUpdate(cb); - }} +export default __t.row({ + scheduledId: __t.u64().primaryKey(), + scheduledAt: __t.scheduleAt(), + prevTime: __t.timestamp(), +}); ''' "repeating_test_arg_type.ts" = ''' // THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE @@ -3100,67 +869,17 @@ export class RepeatingTestArgTableHandle implements __ /* eslint-disable */ /* tslint:disable */ import { - AlgebraicType as __AlgebraicTypeValue, - BinaryReader as __BinaryReader, - BinaryWriter as __BinaryWriter, - ClientCache as __ClientCache, - ConnectionId as __ConnectionId, - DbConnectionBuilder as __DbConnectionBuilder, - DbConnectionImpl as __DbConnectionImpl, - Identity as __Identity, - SubscriptionBuilderImpl as __SubscriptionBuilderImpl, - TableCache as __TableCache, - TimeDuration as __TimeDuration, - Timestamp as __Timestamp, - deepEqual as __deepEqual, - type AlgebraicType as __AlgebraicTypeType, - type AlgebraicTypeVariants as __AlgebraicTypeVariants, - type CallReducerFlags as __CallReducerFlags, - type ErrorContextInterface as __ErrorContextInterface, - type Event as __Event, - type EventContextInterface as __EventContextInterface, - type ReducerEventContextInterface as __ReducerEventContextInterface, - type SubscriptionEventContextInterface as __SubscriptionEventContextInterface, - type TableHandle as __TableHandle, + TypeBuilder as __TypeBuilder, + t as __t, + type AlgebraicTypeType as __AlgebraicTypeType, + type Infer as __Infer, } from "spacetimedb"; -export type RepeatingTestArg = { - scheduledId: bigint, - scheduledAt: { tag: "Interval", value: __TimeDuration } | { tag: "Time", value: __Timestamp }, - prevTime: __Timestamp, -}; -let _cached_RepeatingTestArg_type_value: __AlgebraicTypeType | null = null; - -/** - * An object for generated helper functions. - */ -export const RepeatingTestArg = { - /** - * A function which returns this type represented as an AlgebraicType. - * This function is derived from the AlgebraicType used to generate this type. - */ - getTypeScriptAlgebraicType(): __AlgebraicTypeType { - if (_cached_RepeatingTestArg_type_value) return _cached_RepeatingTestArg_type_value; - _cached_RepeatingTestArg_type_value = __AlgebraicTypeValue.Product({ elements: [] }); - _cached_RepeatingTestArg_type_value.value.elements.push( - { name: "scheduledId", algebraicType: __AlgebraicTypeValue.U64 }, - { name: "scheduledAt", algebraicType: __AlgebraicTypeValue.createScheduleAtType() }, - { name: "prevTime", algebraicType: __AlgebraicTypeValue.createTimestampType() }, - ); - return _cached_RepeatingTestArg_type_value; - }, - - serialize(writer: __BinaryWriter, value: RepeatingTestArg): void { - __AlgebraicTypeValue.serializeValue(writer, RepeatingTestArg.getTypeScriptAlgebraicType(), value); - }, - - deserialize(reader: __BinaryReader): RepeatingTestArg { - return __AlgebraicTypeValue.deserializeValue(reader, RepeatingTestArg.getTypeScriptAlgebraicType()); - }, - -} - -export default RepeatingTestArg; +export default __t.object("RepeatingTestArg", { + scheduledId: __t.u64(), + scheduledAt: __t.scheduleAt(), + prevTime: __t.timestamp(), +}); ''' @@ -3171,68 +890,19 @@ export default RepeatingTestArg; /* eslint-disable */ /* tslint:disable */ import { - AlgebraicType as __AlgebraicTypeValue, - BinaryReader as __BinaryReader, - BinaryWriter as __BinaryWriter, - ClientCache as __ClientCache, - ConnectionId as __ConnectionId, - DbConnectionBuilder as __DbConnectionBuilder, - DbConnectionImpl as __DbConnectionImpl, - Identity as __Identity, - SubscriptionBuilderImpl as __SubscriptionBuilderImpl, - TableCache as __TableCache, - TimeDuration as __TimeDuration, - Timestamp as __Timestamp, - deepEqual as __deepEqual, - type AlgebraicType as __AlgebraicTypeType, - type AlgebraicTypeVariants as __AlgebraicTypeVariants, - type CallReducerFlags as __CallReducerFlags, - type ErrorContextInterface as __ErrorContextInterface, - type Event as __Event, - type EventContextInterface as __EventContextInterface, - type ReducerEventContextInterface as __ReducerEventContextInterface, - type SubscriptionEventContextInterface as __SubscriptionEventContextInterface, - type TableHandle as __TableHandle, + TypeBuilder as __TypeBuilder, + t as __t, + type AlgebraicTypeType as __AlgebraicTypeType, + type Infer as __Infer, } from "spacetimedb"; -import { RepeatingTestArg } from "./repeating_test_arg_type"; -// Mark import as potentially unused -declare type __keep_RepeatingTestArg = RepeatingTestArg; - -export type RepeatingTest = { - arg: RepeatingTestArg, -}; -let _cached_RepeatingTest_type_value: __AlgebraicTypeType | null = null; - -/** - * An object for generated helper functions. - */ -export const RepeatingTest = { - /** - * A function which returns this type represented as an AlgebraicType. - * This function is derived from the AlgebraicType used to generate this type. - */ - getTypeScriptAlgebraicType(): __AlgebraicTypeType { - if (_cached_RepeatingTest_type_value) return _cached_RepeatingTest_type_value; - _cached_RepeatingTest_type_value = __AlgebraicTypeValue.Product({ elements: [] }); - _cached_RepeatingTest_type_value.value.elements.push( - { name: "arg", algebraicType: RepeatingTestArg.getTypeScriptAlgebraicType() }, - ); - return _cached_RepeatingTest_type_value; - }, - - serialize(writer: __BinaryWriter, value: RepeatingTest): void { - __AlgebraicTypeValue.serializeValue(writer, RepeatingTest.getTypeScriptAlgebraicType(), value); - }, +import RepeatingTestArg from "./repeating_test_arg_type"; - deserialize(reader: __BinaryReader): RepeatingTest { - return __AlgebraicTypeValue.deserializeValue(reader, RepeatingTest.getTypeScriptAlgebraicType()); +export default { + get arg() { + return RepeatingTestArg; }, - -} - -export default RepeatingTest; - +}; ''' "return_value_procedure.ts" = '' "say_hello_reducer.ts" = ''' @@ -3242,61 +912,13 @@ export default RepeatingTest; /* eslint-disable */ /* tslint:disable */ import { - AlgebraicType as __AlgebraicTypeValue, - BinaryReader as __BinaryReader, - BinaryWriter as __BinaryWriter, - ClientCache as __ClientCache, - ConnectionId as __ConnectionId, - DbConnectionBuilder as __DbConnectionBuilder, - DbConnectionImpl as __DbConnectionImpl, - Identity as __Identity, - SubscriptionBuilderImpl as __SubscriptionBuilderImpl, - TableCache as __TableCache, - TimeDuration as __TimeDuration, - Timestamp as __Timestamp, - deepEqual as __deepEqual, - type AlgebraicType as __AlgebraicTypeType, - type AlgebraicTypeVariants as __AlgebraicTypeVariants, - type CallReducerFlags as __CallReducerFlags, - type ErrorContextInterface as __ErrorContextInterface, - type Event as __Event, - type EventContextInterface as __EventContextInterface, - type ReducerEventContextInterface as __ReducerEventContextInterface, - type SubscriptionEventContextInterface as __SubscriptionEventContextInterface, - type TableHandle as __TableHandle, + TypeBuilder as __TypeBuilder, + t as __t, + type AlgebraicTypeType as __AlgebraicTypeType, + type Infer as __Infer, } from "spacetimedb"; -export type SayHello = {}; -let _cached_SayHello_type_value: __AlgebraicTypeType | null = null; - -/** - * An object for generated helper functions. - */ -export const SayHello = { - /** - * A function which returns this type represented as an AlgebraicType. - * This function is derived from the AlgebraicType used to generate this type. - */ - getTypeScriptAlgebraicType(): __AlgebraicTypeType { - if (_cached_SayHello_type_value) return _cached_SayHello_type_value; - _cached_SayHello_type_value = __AlgebraicTypeValue.Product({ elements: [] }); - _cached_SayHello_type_value.value.elements.push( - ); - return _cached_SayHello_type_value; - }, - - serialize(writer: __BinaryWriter, value: SayHello): void { - __AlgebraicTypeValue.serializeValue(writer, SayHello.getTypeScriptAlgebraicType(), value); - }, - - deserialize(reader: __BinaryReader): SayHello { - return __AlgebraicTypeValue.deserializeValue(reader, SayHello.getTypeScriptAlgebraicType()); - }, - -} - -export default SayHello; - +export default {}; ''' "sleep_one_second_procedure.ts" = '' "test_a_table.ts" = ''' @@ -3306,76 +928,17 @@ export default SayHello; /* eslint-disable */ /* tslint:disable */ import { - AlgebraicType as __AlgebraicTypeValue, - BinaryReader as __BinaryReader, - BinaryWriter as __BinaryWriter, - ClientCache as __ClientCache, - ConnectionId as __ConnectionId, - DbConnectionBuilder as __DbConnectionBuilder, - DbConnectionImpl as __DbConnectionImpl, - Identity as __Identity, - SubscriptionBuilderImpl as __SubscriptionBuilderImpl, - TableCache as __TableCache, - TimeDuration as __TimeDuration, - Timestamp as __Timestamp, - deepEqual as __deepEqual, - type AlgebraicType as __AlgebraicTypeType, - type AlgebraicTypeVariants as __AlgebraicTypeVariants, - type CallReducerFlags as __CallReducerFlags, - type ErrorContextInterface as __ErrorContextInterface, - type Event as __Event, - type EventContextInterface as __EventContextInterface, - type ReducerEventContextInterface as __ReducerEventContextInterface, - type SubscriptionEventContextInterface as __SubscriptionEventContextInterface, - type TableHandle as __TableHandle, + TypeBuilder as __TypeBuilder, + t as __t, + type AlgebraicTypeType as __AlgebraicTypeType, + type Infer as __Infer, } from "spacetimedb"; -import { TestA } from "./test_a_type"; -import { type EventContext, type Reducer, RemoteReducers, RemoteTables } from "."; -declare type __keep = [EventContext, Reducer, RemoteReducers, RemoteTables]; - -/** - * Table handle for the table `test_a`. - * - * Obtain a handle from the [`testA`] property on [`RemoteTables`], - * like `ctx.db.testA`. - * - * Users are encouraged not to explicitly reference this type, - * but to directly chain method calls, - * like `ctx.db.testA.on_insert(...)`. - */ -export class TestATableHandle implements __TableHandle { - // phantom type to track the table name - readonly tableName!: TableName; - tableCache: __TableCache; - - constructor(tableCache: __TableCache) { - this.tableCache = tableCache; - } - - count(): number { - return this.tableCache.count(); - } - - iter(): Iterable { - return this.tableCache.iter(); - } - - onInsert = (cb: (ctx: EventContext, row: TestA) => void) => { - return this.tableCache.onInsert(cb); - } - - removeOnInsert = (cb: (ctx: EventContext, row: TestA) => void) => { - return this.tableCache.removeOnInsert(cb); - } - - onDelete = (cb: (ctx: EventContext, row: TestA) => void) => { - return this.tableCache.onDelete(cb); - } - - removeOnDelete = (cb: (ctx: EventContext, row: TestA) => void) => { - return this.tableCache.removeOnDelete(cb); - } -} + +export default __t.row({ + x: __t.u32(), + y: __t.u32(), + z: __t.string(), +}); ''' "test_a_type.ts" = ''' // THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE @@ -3384,67 +947,17 @@ export class TestATableHandle implements __TableHandle /* eslint-disable */ /* tslint:disable */ import { - AlgebraicType as __AlgebraicTypeValue, - BinaryReader as __BinaryReader, - BinaryWriter as __BinaryWriter, - ClientCache as __ClientCache, - ConnectionId as __ConnectionId, - DbConnectionBuilder as __DbConnectionBuilder, - DbConnectionImpl as __DbConnectionImpl, - Identity as __Identity, - SubscriptionBuilderImpl as __SubscriptionBuilderImpl, - TableCache as __TableCache, - TimeDuration as __TimeDuration, - Timestamp as __Timestamp, - deepEqual as __deepEqual, - type AlgebraicType as __AlgebraicTypeType, - type AlgebraicTypeVariants as __AlgebraicTypeVariants, - type CallReducerFlags as __CallReducerFlags, - type ErrorContextInterface as __ErrorContextInterface, - type Event as __Event, - type EventContextInterface as __EventContextInterface, - type ReducerEventContextInterface as __ReducerEventContextInterface, - type SubscriptionEventContextInterface as __SubscriptionEventContextInterface, - type TableHandle as __TableHandle, + TypeBuilder as __TypeBuilder, + t as __t, + type AlgebraicTypeType as __AlgebraicTypeType, + type Infer as __Infer, } from "spacetimedb"; -export type TestA = { - x: number, - y: number, - z: string, -}; -let _cached_TestA_type_value: __AlgebraicTypeType | null = null; - -/** - * An object for generated helper functions. - */ -export const TestA = { - /** - * A function which returns this type represented as an AlgebraicType. - * This function is derived from the AlgebraicType used to generate this type. - */ - getTypeScriptAlgebraicType(): __AlgebraicTypeType { - if (_cached_TestA_type_value) return _cached_TestA_type_value; - _cached_TestA_type_value = __AlgebraicTypeValue.Product({ elements: [] }); - _cached_TestA_type_value.value.elements.push( - { name: "x", algebraicType: __AlgebraicTypeValue.U32 }, - { name: "y", algebraicType: __AlgebraicTypeValue.U32 }, - { name: "z", algebraicType: __AlgebraicTypeValue.String }, - ); - return _cached_TestA_type_value; - }, - - serialize(writer: __BinaryWriter, value: TestA): void { - __AlgebraicTypeValue.serializeValue(writer, TestA.getTypeScriptAlgebraicType(), value); - }, - - deserialize(reader: __BinaryReader): TestA { - return __AlgebraicTypeValue.deserializeValue(reader, TestA.getTypeScriptAlgebraicType()); - }, - -} - -export default TestA; +export default __t.object("TestA", { + x: __t.u32(), + y: __t.u32(), + z: __t.string(), +}); ''' @@ -3455,63 +968,15 @@ export default TestA; /* eslint-disable */ /* tslint:disable */ import { - AlgebraicType as __AlgebraicTypeValue, - BinaryReader as __BinaryReader, - BinaryWriter as __BinaryWriter, - ClientCache as __ClientCache, - ConnectionId as __ConnectionId, - DbConnectionBuilder as __DbConnectionBuilder, - DbConnectionImpl as __DbConnectionImpl, - Identity as __Identity, - SubscriptionBuilderImpl as __SubscriptionBuilderImpl, - TableCache as __TableCache, - TimeDuration as __TimeDuration, - Timestamp as __Timestamp, - deepEqual as __deepEqual, - type AlgebraicType as __AlgebraicTypeType, - type AlgebraicTypeVariants as __AlgebraicTypeVariants, - type CallReducerFlags as __CallReducerFlags, - type ErrorContextInterface as __ErrorContextInterface, - type Event as __Event, - type EventContextInterface as __EventContextInterface, - type ReducerEventContextInterface as __ReducerEventContextInterface, - type SubscriptionEventContextInterface as __SubscriptionEventContextInterface, - type TableHandle as __TableHandle, + TypeBuilder as __TypeBuilder, + t as __t, + type AlgebraicTypeType as __AlgebraicTypeType, + type Infer as __Infer, } from "spacetimedb"; -export type TestB = { - foo: string, -}; -let _cached_TestB_type_value: __AlgebraicTypeType | null = null; - -/** - * An object for generated helper functions. - */ -export const TestB = { - /** - * A function which returns this type represented as an AlgebraicType. - * This function is derived from the AlgebraicType used to generate this type. - */ - getTypeScriptAlgebraicType(): __AlgebraicTypeType { - if (_cached_TestB_type_value) return _cached_TestB_type_value; - _cached_TestB_type_value = __AlgebraicTypeValue.Product({ elements: [] }); - _cached_TestB_type_value.value.elements.push( - { name: "foo", algebraicType: __AlgebraicTypeValue.String }, - ); - return _cached_TestB_type_value; - }, - - serialize(writer: __BinaryWriter, value: TestB): void { - __AlgebraicTypeValue.serializeValue(writer, TestB.getTypeScriptAlgebraicType(), value); - }, - - deserialize(reader: __BinaryReader): TestB { - return __AlgebraicTypeValue.deserializeValue(reader, TestB.getTypeScriptAlgebraicType()); - }, - -} - -export default TestB; +export default __t.object("TestB", { + foo: __t.string(), +}); ''' @@ -3522,61 +987,13 @@ export default TestB; /* eslint-disable */ /* tslint:disable */ import { - AlgebraicType as __AlgebraicTypeValue, - BinaryReader as __BinaryReader, - BinaryWriter as __BinaryWriter, - ClientCache as __ClientCache, - ConnectionId as __ConnectionId, - DbConnectionBuilder as __DbConnectionBuilder, - DbConnectionImpl as __DbConnectionImpl, - Identity as __Identity, - SubscriptionBuilderImpl as __SubscriptionBuilderImpl, - TableCache as __TableCache, - TimeDuration as __TimeDuration, - Timestamp as __Timestamp, - deepEqual as __deepEqual, - type AlgebraicType as __AlgebraicTypeType, - type AlgebraicTypeVariants as __AlgebraicTypeVariants, - type CallReducerFlags as __CallReducerFlags, - type ErrorContextInterface as __ErrorContextInterface, - type Event as __Event, - type EventContextInterface as __EventContextInterface, - type ReducerEventContextInterface as __ReducerEventContextInterface, - type SubscriptionEventContextInterface as __SubscriptionEventContextInterface, - type TableHandle as __TableHandle, + TypeBuilder as __TypeBuilder, + t as __t, + type AlgebraicTypeType as __AlgebraicTypeType, + type Infer as __Infer, } from "spacetimedb"; -export type TestBtreeIndexArgs = {}; -let _cached_TestBtreeIndexArgs_type_value: __AlgebraicTypeType | null = null; - -/** - * An object for generated helper functions. - */ -export const TestBtreeIndexArgs = { - /** - * A function which returns this type represented as an AlgebraicType. - * This function is derived from the AlgebraicType used to generate this type. - */ - getTypeScriptAlgebraicType(): __AlgebraicTypeType { - if (_cached_TestBtreeIndexArgs_type_value) return _cached_TestBtreeIndexArgs_type_value; - _cached_TestBtreeIndexArgs_type_value = __AlgebraicTypeValue.Product({ elements: [] }); - _cached_TestBtreeIndexArgs_type_value.value.elements.push( - ); - return _cached_TestBtreeIndexArgs_type_value; - }, - - serialize(writer: __BinaryWriter, value: TestBtreeIndexArgs): void { - __AlgebraicTypeValue.serializeValue(writer, TestBtreeIndexArgs.getTypeScriptAlgebraicType(), value); - }, - - deserialize(reader: __BinaryReader): TestBtreeIndexArgs { - return __AlgebraicTypeValue.deserializeValue(reader, TestBtreeIndexArgs.getTypeScriptAlgebraicType()); - }, - -} - -export default TestBtreeIndexArgs; - +export default {}; ''' "test_d_table.ts" = ''' // THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE @@ -3585,80 +1002,19 @@ export default TestBtreeIndexArgs; /* eslint-disable */ /* tslint:disable */ import { - AlgebraicType as __AlgebraicTypeValue, - BinaryReader as __BinaryReader, - BinaryWriter as __BinaryWriter, - ClientCache as __ClientCache, - ConnectionId as __ConnectionId, - DbConnectionBuilder as __DbConnectionBuilder, - DbConnectionImpl as __DbConnectionImpl, - Identity as __Identity, - SubscriptionBuilderImpl as __SubscriptionBuilderImpl, - TableCache as __TableCache, - TimeDuration as __TimeDuration, - Timestamp as __Timestamp, - deepEqual as __deepEqual, - type AlgebraicType as __AlgebraicTypeType, - type AlgebraicTypeVariants as __AlgebraicTypeVariants, - type CallReducerFlags as __CallReducerFlags, - type ErrorContextInterface as __ErrorContextInterface, - type Event as __Event, - type EventContextInterface as __EventContextInterface, - type ReducerEventContextInterface as __ReducerEventContextInterface, - type SubscriptionEventContextInterface as __SubscriptionEventContextInterface, - type TableHandle as __TableHandle, + TypeBuilder as __TypeBuilder, + t as __t, + type AlgebraicTypeType as __AlgebraicTypeType, + type Infer as __Infer, } from "spacetimedb"; -import { TestD } from "./test_d_type"; -import { NamespaceTestC } from "./namespace_test_c_type"; -// Mark import as potentially unused -declare type __keep_NamespaceTestC = NamespaceTestC; - -import { type EventContext, type Reducer, RemoteReducers, RemoteTables } from "."; -declare type __keep = [EventContext, Reducer, RemoteReducers, RemoteTables]; - -/** - * Table handle for the table `test_d`. - * - * Obtain a handle from the [`testD`] property on [`RemoteTables`], - * like `ctx.db.testD`. - * - * Users are encouraged not to explicitly reference this type, - * but to directly chain method calls, - * like `ctx.db.testD.on_insert(...)`. - */ -export class TestDTableHandle implements __TableHandle { - // phantom type to track the table name - readonly tableName!: TableName; - tableCache: __TableCache; - - constructor(tableCache: __TableCache) { - this.tableCache = tableCache; - } - - count(): number { - return this.tableCache.count(); - } - - iter(): Iterable { - return this.tableCache.iter(); - } - - onInsert = (cb: (ctx: EventContext, row: TestD) => void) => { - return this.tableCache.onInsert(cb); - } - - removeOnInsert = (cb: (ctx: EventContext, row: TestD) => void) => { - return this.tableCache.removeOnInsert(cb); - } - - onDelete = (cb: (ctx: EventContext, row: TestD) => void) => { - return this.tableCache.onDelete(cb); - } - - removeOnDelete = (cb: (ctx: EventContext, row: TestD) => void) => { - return this.tableCache.removeOnDelete(cb); - } -} +import NamespaceTestC from "./namespace_test_c_type"; + + +export default __t.row({ + get testC() { + return __t.option(NamespaceTestC); + }, +}); ''' "test_d_type.ts" = ''' // THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE @@ -3667,67 +1023,19 @@ export class TestDTableHandle implements __TableHandle /* eslint-disable */ /* tslint:disable */ import { - AlgebraicType as __AlgebraicTypeValue, - BinaryReader as __BinaryReader, - BinaryWriter as __BinaryWriter, - ClientCache as __ClientCache, - ConnectionId as __ConnectionId, - DbConnectionBuilder as __DbConnectionBuilder, - DbConnectionImpl as __DbConnectionImpl, - Identity as __Identity, - SubscriptionBuilderImpl as __SubscriptionBuilderImpl, - TableCache as __TableCache, - TimeDuration as __TimeDuration, - Timestamp as __Timestamp, - deepEqual as __deepEqual, - type AlgebraicType as __AlgebraicTypeType, - type AlgebraicTypeVariants as __AlgebraicTypeVariants, - type CallReducerFlags as __CallReducerFlags, - type ErrorContextInterface as __ErrorContextInterface, - type Event as __Event, - type EventContextInterface as __EventContextInterface, - type ReducerEventContextInterface as __ReducerEventContextInterface, - type SubscriptionEventContextInterface as __SubscriptionEventContextInterface, - type TableHandle as __TableHandle, + TypeBuilder as __TypeBuilder, + t as __t, + type AlgebraicTypeType as __AlgebraicTypeType, + type Infer as __Infer, } from "spacetimedb"; -import { NamespaceTestC } from "./namespace_test_c_type"; -// Mark import as potentially unused -declare type __keep_NamespaceTestC = NamespaceTestC; +import NamespaceTestC from "./namespace_test_c_type"; -export type TestD = { - testC: NamespaceTestC | undefined, -}; -let _cached_TestD_type_value: __AlgebraicTypeType | null = null; - -/** - * An object for generated helper functions. - */ -export const TestD = { - /** - * A function which returns this type represented as an AlgebraicType. - * This function is derived from the AlgebraicType used to generate this type. - */ - getTypeScriptAlgebraicType(): __AlgebraicTypeType { - if (_cached_TestD_type_value) return _cached_TestD_type_value; - _cached_TestD_type_value = __AlgebraicTypeValue.Product({ elements: [] }); - _cached_TestD_type_value.value.elements.push( - { name: "testC", algebraicType: __AlgebraicTypeValue.createOptionType(NamespaceTestC.getTypeScriptAlgebraicType()) }, - ); - return _cached_TestD_type_value; - }, - - serialize(writer: __BinaryWriter, value: TestD): void { - __AlgebraicTypeValue.serializeValue(writer, TestD.getTypeScriptAlgebraicType(), value); +export default __t.object("TestD", { + get testC() { + return __t.option(NamespaceTestC); }, - - deserialize(reader: __BinaryReader): TestD { - return __AlgebraicTypeValue.deserializeValue(reader, TestD.getTypeScriptAlgebraicType()); - }, - -} - -export default TestD; +}); ''' @@ -3738,106 +1046,16 @@ export default TestD; /* eslint-disable */ /* tslint:disable */ import { - AlgebraicType as __AlgebraicTypeValue, - BinaryReader as __BinaryReader, - BinaryWriter as __BinaryWriter, - ClientCache as __ClientCache, - ConnectionId as __ConnectionId, - DbConnectionBuilder as __DbConnectionBuilder, - DbConnectionImpl as __DbConnectionImpl, - Identity as __Identity, - SubscriptionBuilderImpl as __SubscriptionBuilderImpl, - TableCache as __TableCache, - TimeDuration as __TimeDuration, - Timestamp as __Timestamp, - deepEqual as __deepEqual, - type AlgebraicType as __AlgebraicTypeType, - type AlgebraicTypeVariants as __AlgebraicTypeVariants, - type CallReducerFlags as __CallReducerFlags, - type ErrorContextInterface as __ErrorContextInterface, - type Event as __Event, - type EventContextInterface as __EventContextInterface, - type ReducerEventContextInterface as __ReducerEventContextInterface, - type SubscriptionEventContextInterface as __SubscriptionEventContextInterface, - type TableHandle as __TableHandle, + TypeBuilder as __TypeBuilder, + t as __t, + type AlgebraicTypeType as __AlgebraicTypeType, + type Infer as __Infer, } from "spacetimedb"; -import { TestE } from "./test_e_type"; -import { type EventContext, type Reducer, RemoteReducers, RemoteTables } from "."; -declare type __keep = [EventContext, Reducer, RemoteReducers, RemoteTables]; - -/** - * Table handle for the table `test_e`. - * - * Obtain a handle from the [`testE`] property on [`RemoteTables`], - * like `ctx.db.testE`. - * - * Users are encouraged not to explicitly reference this type, - * but to directly chain method calls, - * like `ctx.db.testE.on_insert(...)`. - */ -export class TestETableHandle implements __TableHandle { - // phantom type to track the table name - readonly tableName!: TableName; - tableCache: __TableCache; - - constructor(tableCache: __TableCache) { - this.tableCache = tableCache; - } - - count(): number { - return this.tableCache.count(); - } - - iter(): Iterable { - return this.tableCache.iter(); - } - /** - * Access to the `id` unique index on the table `test_e`, - * which allows point queries on the field of the same name - * via the [`TestEIdUnique.find`] method. - * - * Users are encouraged not to explicitly reference this type, - * but to directly chain method calls, - * like `ctx.db.testE.id().find(...)`. - * - * Get a handle on the `id` unique index on the table `test_e`. - */ - id = { - // Find the subscribed row whose `id` column value is equal to `col_val`, - // if such a row is present in the client cache. - find: (col_val: bigint): TestE | undefined => { - for (let row of this.tableCache.iter()) { - if (__deepEqual(row.id, col_val)) { - return row; - } - } - }, - }; - - onInsert = (cb: (ctx: EventContext, row: TestE) => void) => { - return this.tableCache.onInsert(cb); - } - - removeOnInsert = (cb: (ctx: EventContext, row: TestE) => void) => { - return this.tableCache.removeOnInsert(cb); - } - onDelete = (cb: (ctx: EventContext, row: TestE) => void) => { - return this.tableCache.onDelete(cb); - } - - removeOnDelete = (cb: (ctx: EventContext, row: TestE) => void) => { - return this.tableCache.removeOnDelete(cb); - } - - // Updates are only defined for tables with primary keys. - onUpdate = (cb: (ctx: EventContext, oldRow: TestE, newRow: TestE) => void) => { - return this.tableCache.onUpdate(cb); - } - - removeOnUpdate = (cb: (ctx: EventContext, onRow: TestE, newRow: TestE) => void) => { - return this.tableCache.removeOnUpdate(cb); - }} +export default __t.row({ + id: __t.u64().primaryKey(), + name: __t.string(), +}); ''' "test_e_type.ts" = ''' // THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE @@ -3846,65 +1064,16 @@ export class TestETableHandle implements __TableHandle /* eslint-disable */ /* tslint:disable */ import { - AlgebraicType as __AlgebraicTypeValue, - BinaryReader as __BinaryReader, - BinaryWriter as __BinaryWriter, - ClientCache as __ClientCache, - ConnectionId as __ConnectionId, - DbConnectionBuilder as __DbConnectionBuilder, - DbConnectionImpl as __DbConnectionImpl, - Identity as __Identity, - SubscriptionBuilderImpl as __SubscriptionBuilderImpl, - TableCache as __TableCache, - TimeDuration as __TimeDuration, - Timestamp as __Timestamp, - deepEqual as __deepEqual, - type AlgebraicType as __AlgebraicTypeType, - type AlgebraicTypeVariants as __AlgebraicTypeVariants, - type CallReducerFlags as __CallReducerFlags, - type ErrorContextInterface as __ErrorContextInterface, - type Event as __Event, - type EventContextInterface as __EventContextInterface, - type ReducerEventContextInterface as __ReducerEventContextInterface, - type SubscriptionEventContextInterface as __SubscriptionEventContextInterface, - type TableHandle as __TableHandle, + TypeBuilder as __TypeBuilder, + t as __t, + type AlgebraicTypeType as __AlgebraicTypeType, + type Infer as __Infer, } from "spacetimedb"; -export type TestE = { - id: bigint, - name: string, -}; -let _cached_TestE_type_value: __AlgebraicTypeType | null = null; - -/** - * An object for generated helper functions. - */ -export const TestE = { - /** - * A function which returns this type represented as an AlgebraicType. - * This function is derived from the AlgebraicType used to generate this type. - */ - getTypeScriptAlgebraicType(): __AlgebraicTypeType { - if (_cached_TestE_type_value) return _cached_TestE_type_value; - _cached_TestE_type_value = __AlgebraicTypeValue.Product({ elements: [] }); - _cached_TestE_type_value.value.elements.push( - { name: "id", algebraicType: __AlgebraicTypeValue.U64 }, - { name: "name", algebraicType: __AlgebraicTypeValue.String }, - ); - return _cached_TestE_type_value; - }, - - serialize(writer: __BinaryWriter, value: TestE): void { - __AlgebraicTypeValue.serializeValue(writer, TestE.getTypeScriptAlgebraicType(), value); - }, - - deserialize(reader: __BinaryReader): TestE { - return __AlgebraicTypeValue.deserializeValue(reader, TestE.getTypeScriptAlgebraicType()); - }, - -} - -export default TestE; +export default __t.object("TestE", { + id: __t.u64(), + name: __t.string(), +}); ''' @@ -3915,80 +1084,19 @@ export default TestE; /* eslint-disable */ /* tslint:disable */ import { - AlgebraicType as __AlgebraicTypeValue, - BinaryReader as __BinaryReader, - BinaryWriter as __BinaryWriter, - ClientCache as __ClientCache, - ConnectionId as __ConnectionId, - DbConnectionBuilder as __DbConnectionBuilder, - DbConnectionImpl as __DbConnectionImpl, - Identity as __Identity, - SubscriptionBuilderImpl as __SubscriptionBuilderImpl, - TableCache as __TableCache, - TimeDuration as __TimeDuration, - Timestamp as __Timestamp, - deepEqual as __deepEqual, - type AlgebraicType as __AlgebraicTypeType, - type AlgebraicTypeVariants as __AlgebraicTypeVariants, - type CallReducerFlags as __CallReducerFlags, - type ErrorContextInterface as __ErrorContextInterface, - type Event as __Event, - type EventContextInterface as __EventContextInterface, - type ReducerEventContextInterface as __ReducerEventContextInterface, - type SubscriptionEventContextInterface as __SubscriptionEventContextInterface, - type TableHandle as __TableHandle, + TypeBuilder as __TypeBuilder, + t as __t, + type AlgebraicTypeType as __AlgebraicTypeType, + type Infer as __Infer, } from "spacetimedb"; -import { TestFoobar } from "./test_foobar_type"; -import { Foobar } from "./foobar_type"; -// Mark import as potentially unused -declare type __keep_Foobar = Foobar; - -import { type EventContext, type Reducer, RemoteReducers, RemoteTables } from "."; -declare type __keep = [EventContext, Reducer, RemoteReducers, RemoteTables]; - -/** - * Table handle for the table `test_f`. - * - * Obtain a handle from the [`testF`] property on [`RemoteTables`], - * like `ctx.db.testF`. - * - * Users are encouraged not to explicitly reference this type, - * but to directly chain method calls, - * like `ctx.db.testF.on_insert(...)`. - */ -export class TestFTableHandle implements __TableHandle { - // phantom type to track the table name - readonly tableName!: TableName; - tableCache: __TableCache; - - constructor(tableCache: __TableCache) { - this.tableCache = tableCache; - } - - count(): number { - return this.tableCache.count(); - } - - iter(): Iterable { - return this.tableCache.iter(); - } - - onInsert = (cb: (ctx: EventContext, row: TestFoobar) => void) => { - return this.tableCache.onInsert(cb); - } - - removeOnInsert = (cb: (ctx: EventContext, row: TestFoobar) => void) => { - return this.tableCache.removeOnInsert(cb); - } - - onDelete = (cb: (ctx: EventContext, row: TestFoobar) => void) => { - return this.tableCache.onDelete(cb); - } - - removeOnDelete = (cb: (ctx: EventContext, row: TestFoobar) => void) => { - return this.tableCache.removeOnDelete(cb); - } -} +import Foobar from "./foobar_type"; + + +export default __t.row({ + get field() { + return Foobar; + }, +}); ''' "test_foobar_type.ts" = ''' // THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE @@ -3997,67 +1105,19 @@ export class TestFTableHandle implements __TableHandle /* eslint-disable */ /* tslint:disable */ import { - AlgebraicType as __AlgebraicTypeValue, - BinaryReader as __BinaryReader, - BinaryWriter as __BinaryWriter, - ClientCache as __ClientCache, - ConnectionId as __ConnectionId, - DbConnectionBuilder as __DbConnectionBuilder, - DbConnectionImpl as __DbConnectionImpl, - Identity as __Identity, - SubscriptionBuilderImpl as __SubscriptionBuilderImpl, - TableCache as __TableCache, - TimeDuration as __TimeDuration, - Timestamp as __Timestamp, - deepEqual as __deepEqual, - type AlgebraicType as __AlgebraicTypeType, - type AlgebraicTypeVariants as __AlgebraicTypeVariants, - type CallReducerFlags as __CallReducerFlags, - type ErrorContextInterface as __ErrorContextInterface, - type Event as __Event, - type EventContextInterface as __EventContextInterface, - type ReducerEventContextInterface as __ReducerEventContextInterface, - type SubscriptionEventContextInterface as __SubscriptionEventContextInterface, - type TableHandle as __TableHandle, + TypeBuilder as __TypeBuilder, + t as __t, + type AlgebraicTypeType as __AlgebraicTypeType, + type Infer as __Infer, } from "spacetimedb"; -import { Foobar } from "./foobar_type"; -// Mark import as potentially unused -declare type __keep_Foobar = Foobar; - +import Foobar from "./foobar_type"; -export type TestFoobar = { - field: Foobar, -}; -let _cached_TestFoobar_type_value: __AlgebraicTypeType | null = null; - -/** - * An object for generated helper functions. - */ -export const TestFoobar = { - /** - * A function which returns this type represented as an AlgebraicType. - * This function is derived from the AlgebraicType used to generate this type. - */ - getTypeScriptAlgebraicType(): __AlgebraicTypeType { - if (_cached_TestFoobar_type_value) return _cached_TestFoobar_type_value; - _cached_TestFoobar_type_value = __AlgebraicTypeValue.Product({ elements: [] }); - _cached_TestFoobar_type_value.value.elements.push( - { name: "field", algebraicType: Foobar.getTypeScriptAlgebraicType() }, - ); - return _cached_TestFoobar_type_value; - }, - serialize(writer: __BinaryWriter, value: TestFoobar): void { - __AlgebraicTypeValue.serializeValue(writer, TestFoobar.getTypeScriptAlgebraicType(), value); +export default __t.object("TestFoobar", { + get field() { + return Foobar; }, - - deserialize(reader: __BinaryReader): TestFoobar { - return __AlgebraicTypeValue.deserializeValue(reader, TestFoobar.getTypeScriptAlgebraicType()); - }, - -} - -export default TestFoobar; +}); ''' @@ -4068,81 +1128,29 @@ export default TestFoobar; /* eslint-disable */ /* tslint:disable */ import { - AlgebraicType as __AlgebraicTypeValue, - BinaryReader as __BinaryReader, - BinaryWriter as __BinaryWriter, - ClientCache as __ClientCache, - ConnectionId as __ConnectionId, - DbConnectionBuilder as __DbConnectionBuilder, - DbConnectionImpl as __DbConnectionImpl, - Identity as __Identity, - SubscriptionBuilderImpl as __SubscriptionBuilderImpl, - TableCache as __TableCache, - TimeDuration as __TimeDuration, - Timestamp as __Timestamp, - deepEqual as __deepEqual, - type AlgebraicType as __AlgebraicTypeType, - type AlgebraicTypeVariants as __AlgebraicTypeVariants, - type CallReducerFlags as __CallReducerFlags, - type ErrorContextInterface as __ErrorContextInterface, - type Event as __Event, - type EventContextInterface as __EventContextInterface, - type ReducerEventContextInterface as __ReducerEventContextInterface, - type SubscriptionEventContextInterface as __SubscriptionEventContextInterface, - type TableHandle as __TableHandle, + TypeBuilder as __TypeBuilder, + t as __t, + type AlgebraicTypeType as __AlgebraicTypeType, + type Infer as __Infer, } from "spacetimedb"; -import { TestA } from "./test_a_type"; -// Mark import as potentially unused -declare type __keep_TestA = TestA; -import { TestB } from "./test_b_type"; -// Mark import as potentially unused -declare type __keep_TestB = TestB; -import { NamespaceTestC } from "./namespace_test_c_type"; -// Mark import as potentially unused -declare type __keep_NamespaceTestC = NamespaceTestC; -import { NamespaceTestF } from "./namespace_test_f_type"; -// Mark import as potentially unused -declare type __keep_NamespaceTestF = NamespaceTestF; - -export type Test = { - arg: TestA, - arg2: TestB, - arg3: NamespaceTestC, - arg4: NamespaceTestF, -}; -let _cached_Test_type_value: __AlgebraicTypeType | null = null; - -/** - * An object for generated helper functions. - */ -export const Test = { - /** - * A function which returns this type represented as an AlgebraicType. - * This function is derived from the AlgebraicType used to generate this type. - */ - getTypeScriptAlgebraicType(): __AlgebraicTypeType { - if (_cached_Test_type_value) return _cached_Test_type_value; - _cached_Test_type_value = __AlgebraicTypeValue.Product({ elements: [] }); - _cached_Test_type_value.value.elements.push( - { name: "arg", algebraicType: TestA.getTypeScriptAlgebraicType() }, - { name: "arg2", algebraicType: TestB.getTypeScriptAlgebraicType() }, - { name: "arg3", algebraicType: NamespaceTestC.getTypeScriptAlgebraicType() }, - { name: "arg4", algebraicType: NamespaceTestF.getTypeScriptAlgebraicType() }, - ); - return _cached_Test_type_value; - }, +import TestA from "./test_a_type"; +import TestB from "./test_b_type"; +import NamespaceTestC from "./namespace_test_c_type"; +import NamespaceTestF from "./namespace_test_f_type"; - serialize(writer: __BinaryWriter, value: Test): void { - __AlgebraicTypeValue.serializeValue(writer, Test.getTypeScriptAlgebraicType(), value); +export default { + get arg() { + return TestA; }, - - deserialize(reader: __BinaryReader): Test { - return __AlgebraicTypeValue.deserializeValue(reader, Test.getTypeScriptAlgebraicType()); + get arg2() { + return TestB; }, - -} - -export default Test; - + get arg3() { + return NamespaceTestC; + }, + get arg4() { + return NamespaceTestF; + }, +}; ''' diff --git a/tools/gen-bindings/src/main.rs b/tools/gen-bindings/src/main.rs index 2a9aec9c157..308237a6ce8 100644 --- a/tools/gen-bindings/src/main.rs +++ b/tools/gen-bindings/src/main.rs @@ -69,7 +69,7 @@ fn main() -> Result<()> { let index_replacement = if let Some(index_replacement) = &args.index_replacement { index_replacement } else { - other_replacement + other_replacement }; // 5) Replace "spacetimedb" references @@ -87,11 +87,7 @@ fn main() -> Result<()> { ]), follow_symlinks: false, include_hidden: false, - ignore_globs: vec![ - "**/node_modules/**".into(), - "**/dist/**".into(), - "**/target/**".into(), - ], + ignore_globs: vec!["**/node_modules/**".into(), "**/dist/**".into(), "**/target/**".into()], }; let stats = replace_in_tree(&args.out_dir, index_replacement, other_replacement, &opts)?; diff --git a/tools/generate-client-api/src/main.rs b/tools/generate-client-api/src/main.rs index 0f6d35a1015..186832b6b54 100644 --- a/tools/generate-client-api/src/main.rs +++ b/tools/generate-client-api/src/main.rs @@ -27,10 +27,7 @@ fn run_capture(cmd: &str, args: &[&str]) -> Result { .output() .with_context(|| format!("Failed to start {cmd}"))?; if !out.status.success() { - return Err(anyhow!( - "Command failed: {cmd} {args:?} (exit {})", - out.status - )); + return Err(anyhow!("Command failed: {cmd} {args:?} (exit {})", out.status)); } Ok(String::from_utf8(out.stdout)?) } diff --git a/tools/replace-spacetimedb/src/lib.rs b/tools/replace-spacetimedb/src/lib.rs index af28c392cae..ff91bda9cfd 100644 --- a/tools/replace-spacetimedb/src/lib.rs +++ b/tools/replace-spacetimedb/src/lib.rs @@ -3,7 +3,7 @@ use ignore::{DirEntry, WalkBuilder}; use regex::Regex; use std::fs; use std::io; -use std::path::{Path}; +use std::path::Path; #[derive(Clone, Debug)] pub struct ReplaceOptions { @@ -119,15 +119,14 @@ pub fn replace_in_tree( }; // Count before replacing - let matches = re_single.find_iter(&content).count() - + re_double.find_iter(&content).count(); + let matches = re_single.find_iter(&content).count() + re_double.find_iter(&content).count(); if matches == 0 { continue; } // Do the replacements, preserving quote style let updated1 = re_single.replace_all(&content, format!("}} from '{}'", repl)); - let updated = re_double.replace_all(&updated1, format!("}} from \"{}\"", repl)); + let updated = re_double.replace_all(&updated1, format!("}} from \"{}\"", repl)); if options.dry_run { let which = if is_index_ts { "index.ts" } else { "*.ts" }; @@ -144,5 +143,8 @@ pub fn replace_in_tree( total_matches += matches; } - Ok(ReplaceStats { files_changed, occurrences: total_matches }) -} \ No newline at end of file + Ok(ReplaceStats { + files_changed, + occurrences: total_matches, + }) +} diff --git a/tools/replace-spacetimedb/src/main.rs b/tools/replace-spacetimedb/src/main.rs index 3f64d2b7f23..75dad4d2e37 100644 --- a/tools/replace-spacetimedb/src/main.rs +++ b/tools/replace-spacetimedb/src/main.rs @@ -51,7 +51,12 @@ fn main() { ignore_globs: args.ignore, }; - match replace_in_tree(&args.target_dir, &args.index_replacement, &args.other_replacement, &opts) { + match replace_in_tree( + &args.target_dir, + &args.index_replacement, + &args.other_replacement, + &opts, + ) { Ok(stats) => { println!( "✅ Replacement complete. Files changed: {} | Occurrences: {}", From a2ca10adaa1ce87c837b42a05f873f65f8428653 Mon Sep 17 00:00:00 2001 From: = Date: Tue, 11 Nov 2025 17:08:56 -0500 Subject: [PATCH 36/49] pnpm format --- .../examples/basic-react/package.json | 2 +- .../examples/quickstart-chat/src/App.tsx | 75 ++++++++++--------- 2 files changed, 39 insertions(+), 38 deletions(-) diff --git a/crates/bindings-typescript/examples/basic-react/package.json b/crates/bindings-typescript/examples/basic-react/package.json index 7ca43645e65..1c1d3d18f8f 100644 --- a/crates/bindings-typescript/examples/basic-react/package.json +++ b/crates/bindings-typescript/examples/basic-react/package.json @@ -15,7 +15,7 @@ "dependencies": { "spacetimedb": "workspace:*", "react": "^18.3.1", - "react-dom": "^18.3.1" + "react-dom": "^18.3.1" }, "devDependencies": { "@types/react": "^18.3.18", diff --git a/crates/bindings-typescript/examples/quickstart-chat/src/App.tsx b/crates/bindings-typescript/examples/quickstart-chat/src/App.tsx index bee83b9e697..808a24ee368 100644 --- a/crates/bindings-typescript/examples/quickstart-chat/src/App.tsx +++ b/crates/bindings-typescript/examples/quickstart-chat/src/App.tsx @@ -1,7 +1,13 @@ import React, { useState } from 'react'; import './App.css'; import { tables, reducers, Message } from './module_bindings'; -import { useSpacetimeDB, useTable, where, eq, useReducer } from 'spacetimedb/react'; +import { + useSpacetimeDB, + useTable, + where, + eq, + useReducer, +} from 'spacetimedb/react'; import { Identity, Infer, Timestamp } from 'spacetimedb'; export type PrettyMessage = { @@ -14,7 +20,9 @@ export type PrettyMessage = { function App() { const [newName, setNewName] = useState(''); const [settingName, setSettingName] = useState(false); - const [systemMessages, setSystemMessages] = useState([] as Infer[]); + const [systemMessages, setSystemMessages] = useState( + [] as Infer[] + ); const [newMessage, setNewMessage] = useState(''); const { identity, isActive: connected } = useSpacetimeDB(); @@ -27,41 +35,34 @@ function App() { // Subscribe to all online users in the chat // so we can show who's online and demonstrate // the `where` and `eq` query expressions - const onlineUsers = useTable( - tables.user, - where(eq('online', true)), - { - onInsert: user => { - // All users being inserted here are online - const name = user.name || user.identity.toHexString().substring(0, 8); - setSystemMessages(prev => [ - ...prev, - { - sender: Identity.zero(), - text: `${name} has connected.`, - sent: Timestamp.now(), - }, - ]); - }, - onDelete: user => { - // All users being deleted here are offline - const name = user.name || user.identity.toHexString().substring(0, 8); - setSystemMessages(prev => [ - ...prev, - { - sender: Identity.zero(), - text: `${name} has disconnected.`, - sent: Timestamp.now(), - }, - ]); - }, - } - ); - - const offlineUsers = useTable( - tables.user, - where(eq('online', false)) - ); + const onlineUsers = useTable(tables.user, where(eq('online', true)), { + onInsert: user => { + // All users being inserted here are online + const name = user.name || user.identity.toHexString().substring(0, 8); + setSystemMessages(prev => [ + ...prev, + { + sender: Identity.zero(), + text: `${name} has connected.`, + sent: Timestamp.now(), + }, + ]); + }, + onDelete: user => { + // All users being deleted here are offline + const name = user.name || user.identity.toHexString().substring(0, 8); + setSystemMessages(prev => [ + ...prev, + { + sender: Identity.zero(), + text: `${name} has disconnected.`, + sent: Timestamp.now(), + }, + ]); + }, + }); + + const offlineUsers = useTable(tables.user, where(eq('online', false))); const users = [...onlineUsers, ...offlineUsers]; const prettyMessages: PrettyMessage[] = messages From 9f7fe2c022c5d4f29b860951a0120036a4d66769 Mon Sep 17 00:00:00 2001 From: Tyler Cloutier Date: Tue, 11 Nov 2025 18:12:04 -0500 Subject: [PATCH 37/49] Code gen determinism and return value of useTable --- .../examples/quickstart-chat/src/App.tsx | 6 +-- .../bindings-typescript/src/react/useTable.ts | 49 ++++++++++--------- .../bindings-typescript/test-app/src/App.tsx | 4 +- .../src/pages/CounterPage.tsx | 2 +- .../src/pages/UserPage.tsx | 2 +- crates/codegen/src/typescript.rs | 6 ++- .../codegen__codegen_typescript.snap | 8 +-- .../06-typescript-quickstart.md | 6 +-- 8 files changed, 45 insertions(+), 38 deletions(-) diff --git a/crates/bindings-typescript/examples/quickstart-chat/src/App.tsx b/crates/bindings-typescript/examples/quickstart-chat/src/App.tsx index 808a24ee368..1da2737cd82 100644 --- a/crates/bindings-typescript/examples/quickstart-chat/src/App.tsx +++ b/crates/bindings-typescript/examples/quickstart-chat/src/App.tsx @@ -30,12 +30,12 @@ function App() { const sendMessage = useReducer(reducers.sendMessage); // Subscribe to all messages in the chat - const messages = useTable(tables.message); + const [messages] = useTable(tables.message); // Subscribe to all online users in the chat // so we can show who's online and demonstrate // the `where` and `eq` query expressions - const onlineUsers = useTable(tables.user, where(eq('online', true)), { + const [onlineUsers] = useTable(tables.user, where(eq('online', true)), { onInsert: user => { // All users being inserted here are online const name = user.name || user.identity.toHexString().substring(0, 8); @@ -62,7 +62,7 @@ function App() { }, }); - const offlineUsers = useTable(tables.user, where(eq('online', false))); + const [offlineUsers] = useTable(tables.user, where(eq('online', false))); const users = [...onlineUsers, ...offlineUsers]; const prettyMessages: PrettyMessage[] = messages diff --git a/crates/bindings-typescript/src/react/useTable.ts b/crates/bindings-typescript/src/react/useTable.ts index 98b4d55a68c..9d3aa16b808 100644 --- a/crates/bindings-typescript/src/react/useTable.ts +++ b/crates/bindings-typescript/src/react/useTable.ts @@ -210,7 +210,7 @@ export function useTable( tableDef: TableDef, where: Expr>>, callbacks?: UseTableCallbacks>> -): readonly Prettify>[]; +): [readonly Prettify>[], boolean]; /** * React hook to subscribe to a table in SpacetimeDB and receive live updates as rows are inserted, updated, or deleted. @@ -248,7 +248,7 @@ export function useTable( export function useTable( tableDef: TableDef, callbacks?: UseTableCallbacks>> -): readonly Prettify>[]; +): [readonly Prettify>[], boolean]; export function useTable( tableDef: TableDef, @@ -256,7 +256,7 @@ export function useTable( | Expr>> | UseTableCallbacks>, callbacks?: UseTableCallbacks> -): readonly Prettify>[] { +): [readonly Prettify>[], boolean] { type UseTableRowType = RowType; const tableName = tableDef.name; let whereClause: Expr> | undefined; @@ -290,27 +290,29 @@ export function useTable( (whereClause ? ` WHERE ${toString(whereClause)}` : ''); const latestTransactionEvent = useRef(null); - const lastSnapshotRef = useRef[] | null>( - null - ); + const lastSnapshotRef = useRef< + [readonly Prettify[], boolean] | null + >(null); const whereKey = whereClause ? toString(whereClause) : ''; - const computeSnapshot = - useCallback((): readonly Prettify[] => { - const connection = connectionState.getConnection(); - if (!connection) { - return []; - } - const table = connection.db[tableName]; - const result: readonly Prettify[] = whereClause - ? (Array.from(table.iter()).filter(row => - evaluate(whereClause, row as UseTableRowType) - ) as Prettify[]) - : (Array.from(table.iter()) as Prettify[]); - return result; - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [connectionState, tableName, whereKey, subscribeApplied]); + const computeSnapshot = useCallback((): [ + readonly Prettify[], + boolean, + ] => { + const connection = connectionState.getConnection(); + if (!connection) { + return [[], false]; + } + const table = connection.db[tableName]; + const result: readonly Prettify[] = whereClause + ? (Array.from(table.iter()).filter(row => + evaluate(whereClause, row as UseTableRowType) + ) as Prettify[]) + : (Array.from(table.iter()) as Prettify[]); + return [result, subscribeApplied]; + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [connectionState, tableName, whereKey, subscribeApplied]); useEffect(() => { const connection = connectionState.getConnection()!; @@ -423,7 +425,10 @@ export function useTable( ] ); - const getSnapshot = useCallback((): readonly Prettify[] => { + const getSnapshot = useCallback((): [ + readonly Prettify[], + boolean, + ] => { if (!lastSnapshotRef.current) { lastSnapshotRef.current = computeSnapshot(); } diff --git a/crates/bindings-typescript/test-app/src/App.tsx b/crates/bindings-typescript/test-app/src/App.tsx index 720504f78d8..0e7788c78ea 100644 --- a/crates/bindings-typescript/test-app/src/App.tsx +++ b/crates/bindings-typescript/test-app/src/App.tsx @@ -15,7 +15,7 @@ function getRandomInt(max: number) { function App() { const connection = useSpacetimeDB(); - const players = useTable(tables.player, where(eq('name', 'Hello')), { + const [players] = useTable(tables.player, where(eq('name', 'Hello')), { onInsert: row => { console.log('Player inserted:', row); }, @@ -24,7 +24,7 @@ function App() { useEffect(() => { setTimeout(() => { - console.log(Array.from(players)); + console.log(players); }, 5000); }, [connection, players]); diff --git a/crates/bindings-typescript/test-react-router-app/src/pages/CounterPage.tsx b/crates/bindings-typescript/test-react-router-app/src/pages/CounterPage.tsx index 034ba900866..b3d04a89369 100644 --- a/crates/bindings-typescript/test-react-router-app/src/pages/CounterPage.tsx +++ b/crates/bindings-typescript/test-react-router-app/src/pages/CounterPage.tsx @@ -2,7 +2,7 @@ import { useReducer, useTable } from '../../../src/react'; import { tables, reducers } from '../module_bindings'; export default function CounterPage() { - const counter = useTable(tables.counter); + const [counter] = useTable(tables.counter); const incrementCounter = useReducer(reducers.incrementCounter); const clearCounter = useReducer(reducers.clearCounter); diff --git a/crates/bindings-typescript/test-react-router-app/src/pages/UserPage.tsx b/crates/bindings-typescript/test-react-router-app/src/pages/UserPage.tsx index b73e004f791..1d0ede729b2 100644 --- a/crates/bindings-typescript/test-react-router-app/src/pages/UserPage.tsx +++ b/crates/bindings-typescript/test-react-router-app/src/pages/UserPage.tsx @@ -4,7 +4,7 @@ import { Infer } from '../../../src'; export default function UserPage() { const connection = useSpacetimeDB(); - const users = useTable(tables.user); + const [users] = useTable(tables.user); const identityHex = connection.identity?.toHexString(); const currentUser = users.find( diff --git a/crates/codegen/src/typescript.rs b/crates/codegen/src/typescript.rs index a803dd67b8a..ecfa08b8a06 100644 --- a/crates/codegen/src/typescript.rs +++ b/crates/codegen/src/typescript.rs @@ -508,8 +508,10 @@ fn write_table_opts(module: &ModuleDef, out: &mut Indenter, table: &TableDef) { writeln!(out, "],"); writeln!(out, "constraints: ["); out.indent(1); - // Unique constraints - for (_, constraint) in &table.constraints { + // Unique constraints sorted by name for determinism + let mut constraints: Vec<_> = table.constraints.iter().collect(); + constraints.sort_by_key(|(name, _)| *name); + for (_, constraint) in constraints { let columns: Vec<_> = constraint .data .unique_columns() // Option<&ColSet> diff --git a/crates/codegen/tests/snapshots/codegen__codegen_typescript.snap b/crates/codegen/tests/snapshots/codegen__codegen_typescript.snap index 94fc2c0b3fc..6c1422e9073 100644 --- a/crates/codegen/tests/snapshots/codegen__codegen_typescript.snap +++ b/crates/codegen/tests/snapshots/codegen__codegen_typescript.snap @@ -345,9 +345,9 @@ const tablesSchema = __schema( ] }, ], constraints: [ - { name: 'logged_out_player_player_id_key', constraint: 'unique', columns: ['player_id'] }, - { name: 'logged_out_player_name_key', constraint: 'unique', columns: ['name'] }, { name: 'logged_out_player_identity_key', constraint: 'unique', columns: ['identity'] }, + { name: 'logged_out_player_name_key', constraint: 'unique', columns: ['name'] }, + { name: 'logged_out_player_player_id_key', constraint: 'unique', columns: ['player_id'] }, ], }, PlayerRow), __table({ @@ -393,9 +393,9 @@ const tablesSchema = __schema( ] }, ], constraints: [ - { name: 'player_player_id_key', constraint: 'unique', columns: ['player_id'] }, - { name: 'player_name_key', constraint: 'unique', columns: ['name'] }, { name: 'player_identity_key', constraint: 'unique', columns: ['identity'] }, + { name: 'player_name_key', constraint: 'unique', columns: ['name'] }, + { name: 'player_player_id_key', constraint: 'unique', columns: ['player_id'] }, ], }, PlayerRow), __table({ diff --git a/docs/docs/07-Client SDK Languages/06-typescript-quickstart.md b/docs/docs/07-Client SDK Languages/06-typescript-quickstart.md index 38086d94373..2d436a32bfb 100644 --- a/docs/docs/07-Client SDK Languages/06-typescript-quickstart.md +++ b/docs/docs/07-Client SDK Languages/06-typescript-quickstart.md @@ -575,7 +575,7 @@ const setName = useReducer(reducers.setName); const sendMessage = useReducer(reducers.sendMessage); // Subscribe to all messages in the chat -const messages = useTable(tables.message); +const [messages] = useTable(tables.message); ``` Next replace `const onlineUsers: User[] = [];` with the following: @@ -584,7 +584,7 @@ Next replace `const onlineUsers: User[] = [];` with the following: // Subscribe to all online users in the chat // so we can show who's online and demonstrate // the `where` and `eq` query expressions -const onlineUsers = useTable( +const [onlineUsers] = useTable( tables.user, where(eq('online', true)) ); @@ -751,7 +751,7 @@ const prettyMessages: PrettyMessage[] = Array.from(messages) Finally, let's also subscribe to offline users so we can show them in the sidebar as well. Replace `const offlineUsers: User[] = [];` with: ```tsx -const offlineUsers = useTable( +const [offlineUsers] = useTable( tables.user, where(eq('online', false)) ); From 0461c707ed6eba1483af6a94e61d06c41c90053e Mon Sep 17 00:00:00 2001 From: Tyler Cloutier Date: Tue, 11 Nov 2025 19:28:38 -0500 Subject: [PATCH 38/49] Fixing tests --- crates/bindings-typescript/src/lib/indexes.ts | 4 +- crates/bindings-typescript/src/lib/table.ts | 9 +- modules/benchmarks-ts/src/circles.ts | 4 +- modules/benchmarks-ts/src/ia_loop.ts | 64 ++++--- modules/benchmarks-ts/src/load.ts | 2 +- modules/benchmarks-ts/src/schema.ts | 1 - modules/benchmarks-ts/src/synthetic.ts | 163 ++++++++++-------- modules/module-test-ts/src/index.ts | 28 +-- modules/sdk-test-ts/src/index.ts | 65 ++++--- 9 files changed, 171 insertions(+), 169 deletions(-) diff --git a/crates/bindings-typescript/src/lib/indexes.ts b/crates/bindings-typescript/src/lib/indexes.ts index 7cbef810435..ba9ad6a10dd 100644 --- a/crates/bindings-typescript/src/lib/indexes.ts +++ b/crates/bindings-typescript/src/lib/indexes.ts @@ -96,7 +96,7 @@ export interface UniqueIndex< I extends UntypedIndex, > extends ReadonlyUniqueIndex { delete(colVal: IndexVal): boolean; - update(colVal: RowType): RowType; + update(colVal: Prettify>): Prettify>; } /** @@ -108,7 +108,7 @@ export interface ReadonlyRangedIndex< > { filter( range: IndexScanRangeBounds - ): IterableIterator>; + ): IterableIterator>>; } /** diff --git a/crates/bindings-typescript/src/lib/table.ts b/crates/bindings-typescript/src/lib/table.ts index 20a37bf3988..e2aa54a42e2 100644 --- a/crates/bindings-typescript/src/lib/table.ts +++ b/crates/bindings-typescript/src/lib/table.ts @@ -169,8 +169,8 @@ export interface ReadonlyTableMethods { count(): bigint; /** Iterate over all rows in the TX state. Rust Iterator → TS IterableIterator. */ - iter(): IterableIterator>; - [Symbol.iterator](): IterableIterator>; + iter(): IterableIterator>>; + [Symbol.iterator](): IterableIterator>>; } /** @@ -185,10 +185,10 @@ export interface TableMethods * * If there are any unique or primary key columns in this table, may throw {@link UniqueAlreadyExists}. * * If there are any auto-incrementing columns in this table, may throw {@link AutoIncOverflow}. * */ - insert(row: RowType): RowType; + insert(row: Prettify>): Prettify>; /** Delete a row equal to `row`. Returns true if something was deleted. */ - delete(row: RowType): boolean; + delete(row: Prettify>): boolean; } /** @@ -252,7 +252,6 @@ export function table>( // implicit 1‑column indexes if (meta.indexType || isUnique) { - console.log('GAAAAAAH', name); const algo = meta.indexType ?? 'btree'; const id = colIds.get(name)!; let algorithm: Infer; diff --git a/modules/benchmarks-ts/src/circles.ts b/modules/benchmarks-ts/src/circles.ts index e1c021b0055..33a12a20c24 100644 --- a/modules/benchmarks-ts/src/circles.ts +++ b/modules/benchmarks-ts/src/circles.ts @@ -1,6 +1,6 @@ //! STDB module used for benchmarks based on "realistic" workloads we are focusing in improving. -import { type Load, newLoad, blackBox } from './load'; +import { newLoad, blackBox } from './load'; import { spacetimedb, type Entity, type Circle, type Food } from './schema'; import { Timestamp } from 'spacetimedb'; import { t } from 'spacetimedb/server'; @@ -117,7 +117,7 @@ const crossJoinCircleFood = spacetimedb.reducer( const foodEntity = entityId.find(food.entity_id); if (foodEntity == null) { - let string = JSON.stringify(circleEntity); + const string = JSON.stringify(circleEntity); throw new Error(`Entity not found: ${food.entity_id}`); } diff --git a/modules/benchmarks-ts/src/ia_loop.ts b/modules/benchmarks-ts/src/ia_loop.ts index 006bd134c11..c7c6289855c 100644 --- a/modules/benchmarks-ts/src/ia_loop.ts +++ b/modules/benchmarks-ts/src/ia_loop.ts @@ -1,6 +1,6 @@ // STDB module used for benchmarks based on "realistic" workloads we are focusing in improving. -import { blackBox, newLoad } from './load'; +import { newLoad } from './load'; import { type GameEnemyAiAgentState, type GameTargetableState, @@ -11,12 +11,8 @@ import { type Velocity, } from './schema'; import { - schema, - table, t, - type InferTypeOfRow, type ReducerCtx, - type Reducer, } from 'spacetimedb/server'; function newPosition( @@ -98,7 +94,7 @@ spacetimedb.reducer( const updatePositionWithVelocity = (ctx, { expected }) => { let count = 0; for (const velocity of ctx.db.velocity.iter()) { - let position = ctx.db.position.entity_id.find(velocity.entity_id); + const position = ctx.db.position.entity_id.find(velocity.entity_id); if (position == null) { continue; } @@ -125,36 +121,36 @@ const insertWorld = (ctx, { players }) => { const nextActionTimestamp = (i & 2) == 2 ? momentMilliseconds() + 2000n : momentMilliseconds(); - ctx.db.game_enemy_ai_agent_state.insert({ + ctx.db.gameEnemyAiAgentState.insert({ entity_id: id_n, next_action_timestamp: nextActionTimestamp, last_move_timestamps: [id_n, 0n, id_n * 2n], action: { tag: 'Idle', value: {} }, }); - ctx.db.game_live_targetable_state.insert({ + ctx.db.gameLiveTargetableState.insert({ entity_id: id_n, quad: id_n, }); - ctx.db.game_targetable_state.insert({ + ctx.db.gameTargetableState.insert({ entity_id: id_n, quad: id_n, }); - ctx.db.game_mobile_entity_state.insert({ + ctx.db.gameMobileEntityState.insert({ entity_id: id_n, location_x: id, location_y: id, timestamp: nextActionTimestamp, }); - ctx.db.game_enemy_state.insert({ + ctx.db.gameEnemyState.insert({ entity_id: id_n, herd_id: id, }); - ctx.db.game_herd_cache.insert({ + ctx.db.gameHerdCache.insert({ id, dimension_id: id, max_population: id * 4, @@ -176,12 +172,12 @@ function getTargetablesNearQuad( entityId: bigint, numPlayers: bigint ): GameTargetableState[] { - let result = []; + const result = []; for (let id = entityId; id < numPlayers; id++) { - for (const liveTargetable of ctx.db.game_live_targetable_state.quad.filter( + for (const liveTargetable of ctx.db.gameLiveTargetableState.quad.filter( id )) { - const targetable = ctx.db.game_targetable_state.entity_id.find( + const targetable = ctx.db.gameTargetableState.entity_id.find( liveTargetable.entity_id ); if (targetable == null) { @@ -203,11 +199,11 @@ function moveAgent( ) { const entityId = agent.entity_id; - const enemy = ctx.db.game_enemy_state.entity_id.find(entityId); + const enemy = ctx.db.gameEnemyState.entity_id.find(entityId); if (enemy == null) { throw new Error('GameEnemyState Entity ID not found'); } - ctx.db.game_enemy_state.entity_id.update(enemy); + ctx.db.gameEnemyState.entity_id.update(enemy); agent.next_action_timestamp = currentTimeMs + 2000n; @@ -216,23 +212,23 @@ function moveAgent( agent.last_move_timestamps.splice(0, 1); } - let targetable = ctx.db.game_targetable_state.entity_id.find(entityId); + const targetable = ctx.db.gameTargetableState.entity_id.find(entityId); if (targetable == null) { throw new Error('GameTargetableState Entity ID not found'); } - let newHash = calculateHash(targetable.quad); + const newHash = calculateHash(targetable.quad); targetable.quad = newHash; - ctx.db.game_targetable_state.entity_id.update(targetable); + ctx.db.gameTargetableState.entity_id.update(targetable); - if (ctx.db.game_live_targetable_state.entity_id.find(entityId) != null) { - ctx.db.game_live_targetable_state.entity_id.update({ + if (ctx.db.gameLiveTargetableState.entity_id.find(entityId) != null) { + ctx.db.gameLiveTargetableState.entity_id.update({ entity_id: entityId, quad: newHash, }); } const mobileEntityRes = - ctx.db.game_mobile_entity_state.entity_id.find(entityId); + ctx.db.gameMobileEntityState.entity_id.find(entityId); if (mobileEntityRes == null) { throw new Error('GameMobileEntityState Entity ID not found'); } @@ -243,9 +239,9 @@ function moveAgent( timestamp: agent.next_action_timestamp, }; - ctx.db.game_enemy_ai_agent_state.entity_id.update(agent); + ctx.db.gameEnemyAiAgentState.entity_id.update(agent); - ctx.db.game_mobile_entity_state.entity_id.update(mobileEntity); + ctx.db.gameMobileEntityState.entity_id.update(mobileEntity); } function agentLoop( @@ -257,17 +253,17 @@ function agentLoop( ) { const entityId = agent.entity_id; - const coordinates = ctx.db.game_mobile_entity_state.entity_id.find(entityId); + const coordinates = ctx.db.gameMobileEntityState.entity_id.find(entityId); if (coordinates == null) { throw new Error('GameMobileEntityState Entity ID not found'); } - const agentEntity = ctx.db.game_enemy_state.entity_id.find(entityId); + const agentEntity = ctx.db.gameEnemyState.entity_id.find(entityId); if (agentEntity == null) { throw new Error('GameEnemyState Entity ID not found'); } - const agentHerd = ctx.db.game_herd_cache.id.find(agentEntity.herd_id); + const agentHerd = ctx.db.gameHerdCache.id.find(agentEntity.herd_id); if (agentHerd == null) { throw new Error('GameHerdCache Entity ID not found'); } @@ -279,23 +275,23 @@ function agentLoop( const gameLoopEnemyIa = (ctx: ReducerCtx, { players }) => { let count = 0; - let currentTimeMs = momentMilliseconds(); + const currentTimeMs = momentMilliseconds(); - for (const agent of ctx.db.game_enemy_ai_agent_state.iter()) { - const agentTargetable = ctx.db.game_targetable_state.entity_id.find( + for (const agent of ctx.db.gameEnemyAiAgentState.iter()) { + const agentTargetable = ctx.db.gameTargetableState.entity_id.find( agent.entity_id ); if (agentTargetable == null) { throw new Error('No TargetableState for AgentState entity'); } - let surroundingAgents = getTargetablesNearQuad( + const surroundingAgents = getTargetablesNearQuad( ctx, agentTargetable.entity_id, players ); - agent.action = { tag: 'Fighting', value: {} }; + agent.action = { tag: 'Fighting' }; agentLoop(ctx, agent, agentTargetable, surroundingAgents, currentTimeMs); @@ -329,7 +325,7 @@ spacetimedb.reducer( const runGameIaLoop = (ctx, { initial_load }) => { const load = newLoad(initial_load); - gameLoopEnemyIa(ctx, load.numPlayers); + gameLoopEnemyIa(ctx, { players: load.numPlayers }); }; spacetimedb.reducer( 'run_game_ia_loop', diff --git a/modules/benchmarks-ts/src/load.ts b/modules/benchmarks-ts/src/load.ts index 0df68ce97ad..2d3d0747c5e 100644 --- a/modules/benchmarks-ts/src/load.ts +++ b/modules/benchmarks-ts/src/load.ts @@ -16,6 +16,6 @@ export function newLoad(initialLoad: number): Load { }; } -export function blackBox(x: any) { +export function blackBox(_x: any) { // TODO: actually do something to defeat optimizations? } diff --git a/modules/benchmarks-ts/src/schema.ts b/modules/benchmarks-ts/src/schema.ts index 9dfeb0826a4..12b8f277272 100644 --- a/modules/benchmarks-ts/src/schema.ts +++ b/modules/benchmarks-ts/src/schema.ts @@ -3,7 +3,6 @@ import { table, t, type Infer, - type InferTypeOfRow, type InferSchema, } from 'spacetimedb/server'; diff --git a/modules/benchmarks-ts/src/synthetic.ts b/modules/benchmarks-ts/src/synthetic.ts index 24f4d6bb266..a118d427449 100644 --- a/modules/benchmarks-ts/src/synthetic.ts +++ b/modules/benchmarks-ts/src/synthetic.ts @@ -33,15 +33,12 @@ import { btree_each_column_u32_u64_str_tRow } from './schema'; import { - schema, - table, t, - type InferTypeOfRow, } from 'spacetimedb/server'; // ---------- empty ---------- -spacetimedb.reducer('empty', (ctx, { }) => { }); +spacetimedb.reducer('empty', () => {}); // ---------- insert ---------- @@ -49,42 +46,42 @@ spacetimedb.reducer( 'insert_unique_0_u32_u64_str', { id: t.u32(), age: t.u64(), name: t.string() }, (ctx, { id, age, name }) => { - ctx.db.unique_0_u32_u64_str.insert({ id, name, age }); + ctx.db.unique0U32U64Str.insert({ id, name, age }); }); spacetimedb.reducer( 'insert_no_index_u32_u64_str', { id: t.u32(), age: t.u64(), name: t.string() }, (ctx, { id, age, name }) => { - ctx.db.no_index_u32_u64_str.insert({ id, name, age }); + ctx.db.noIndexU32U64Str.insert({ id, name, age }); }); spacetimedb.reducer( 'insert_btree_each_column_u32_u64_str', { id: t.u32(), age: t.u64(), name: t.string() }, (ctx, { id, age, name }) => { - ctx.db.btree_each_column_u32_u64_str.insert({ id, name, age }); + ctx.db.btreeEachColumnU32U64Str.insert({ id, name, age }); }); spacetimedb.reducer( 'insert_unique_0_u32_u64_u64', { id: t.u32(), x: t.u64(), y: t.u64() }, (ctx, { id, x, y }) => { - ctx.db.unique_0_u32_u64_u64.insert({ id, x, y }); + ctx.db.unique0U32U64U64.insert({ id, x, y }); }); spacetimedb.reducer( 'insert_no_index_u32_u64_u64', { id: t.u32(), x: t.u64(), y: t.u64() }, (ctx, { id, x, y }) => { - ctx.db.no_index_u32_u64_u64.insert({ id, x, y }); + ctx.db.noIndexU32U64U64.insert({ id, x, y }); }); spacetimedb.reducer( 'insert_btree_each_column_u32_u64_u64', { id: t.u32(), x: t.u64(), y: t.u64() }, (ctx, { id, x, y }) => { - ctx.db.btree_each_column_u32_u64_u64.insert({ id, x, y }); + ctx.db.btreeEachColumnU32U64U64.insert({ id, x, y }); }); // ---------- insert bulk ---------- @@ -92,54 +89,54 @@ spacetimedb.reducer( spacetimedb.reducer( 'insert_bulk_unique_0_u32_u64_u64', { locs: t.array(unique_0_u32_u64_u64_tRow) }, - (ctx, { id, locs }) => { + (ctx, { locs }) => { for (const loc of locs) { - ctx.db.unique_0_u32_u64_u64.insert(loc); + ctx.db.unique0U32U64U64.insert(loc); } }); spacetimedb.reducer( 'insert_bulk_no_index_u32_u64_u64', { locs: t.array(no_index_u32_u64_u64_tRow) }, - (ctx, { id, locs }) => { + (ctx, { locs }) => { for (const loc of locs) { - ctx.db.no_index_u32_u64_u64.insert(loc); + ctx.db.noIndexU32U64U64.insert(loc); } }); spacetimedb.reducer( 'insert_bulk_btree_each_column_u32_u64_u64', { locs: t.array(btree_each_column_u32_u64_u64_tRow) }, - (ctx, { id, locs }) => { + (ctx, { locs }) => { for (const loc of locs) { - ctx.db.btree_each_column_u32_u64_u64.insert(loc); + ctx.db.btreeEachColumnU32U64U64.insert(loc); } }); spacetimedb.reducer( 'insert_bulk_unique_0_u32_u64_str', { people: t.array(unique_0_u32_u64_str_tRow) }, - (ctx, { id, people }) => { + (ctx, { people }) => { for (const p of people) { - ctx.db.unique_0_u32_u64_str.insert(p); + ctx.db.unique0U32U64Str.insert(p); } }); spacetimedb.reducer( 'insert_bulk_no_index_u32_u64_str', { people: t.array(no_index_u32_u64_str_tRow) }, - (ctx, { id, people }) => { + (ctx, { people }) => { for (const p of people) { - ctx.db.no_index_u32_u64_str.insert(p); + ctx.db.noIndexU32U64Str.insert(p); } }); spacetimedb.reducer( 'insert_bulk_btree_each_column_u32_u64_str', { people: t.array(btree_each_column_u32_u64_str_tRow) }, - (ctx, { id, people }) => { + (ctx, { people }) => { for (const p of people) { - ctx.db.btree_each_column_u32_u64_str.insert(p); + ctx.db.btreeEachColumnU32U64Str.insert(p); } }); @@ -154,17 +151,17 @@ function assert(cond: boolean) { spacetimedb.reducer( 'update_bulk_unique_0_u32_u64_u64', { row_count: t.u32() }, - (ctx, { id, row_count }) => { + (ctx, { row_count }) => { let hit = 0; - for (const loc of ctx.db.unique_0_u32_u64_u64.iter()) { + for (const loc of ctx.db.unique0U32U64U64.iter()) { if (hit == row_count) { break; } hit += 1; - ctx.db.unique_0_u32_u64_u64.id?.update({ + ctx.db.unique0U32U64U64.id?.update({ id: loc.id, - x: loc.x + 1, + x: loc.x + 1n, y: loc.y, }); } @@ -175,18 +172,18 @@ spacetimedb.reducer( spacetimedb.reducer( 'update_bulk_unique_0_u32_u64_str', { row_count: t.u32() }, - (ctx, { id, row_count }) => { + (ctx, { row_count }) => { let hit = 0; - for (const p of ctx.db.unique_0_u32_u64_str.iter()) { + for (const p of ctx.db.unique0U32U64Str.iter()) { if (hit == row_count) { break; } hit += 1; - ctx.db.unique_0_u32_u64_str.id?.update({ + ctx.db.unique0U32U64Str.id?.update({ id: p.id, - x: p.name, - y: p.age + 1, + age: p.age + 1n, + name: p.name, }); } @@ -195,14 +192,14 @@ spacetimedb.reducer( // ---------- iterate ---------- -spacetimedb.reducer('iterate_unique_0_u32_u64_str', (ctx, { }) => { - for (const x of ctx.db.unique_0_u32_u64_str.iter()) { +spacetimedb.reducer('iterate_unique_0_u32_u64_str', ctx => { + for (const x of ctx.db.unique0U32U64Str.iter()) { blackBox(x); } }); -spacetimedb.reducer('iterate_unique_0_u32_u64_u64', (ctx, { }) => { - for (const x of ctx.db.unique_0_u32_u64_u64.iter()) { +spacetimedb.reducer('iterate_unique_0_u32_u64_u64', ctx => { + for (const x of ctx.db.unique0U32U64U64.iter()) { blackBox(x); } }); @@ -210,11 +207,11 @@ spacetimedb.reducer('iterate_unique_0_u32_u64_u64', (ctx, { }) => { // ---------- filtering ---------- spacetimedb.reducer('filter_unique_0_u32_u64_str_by_id', { id: t.u32() }, (ctx, { id }) => { - blackBox(ctx.db.unique_0_u32_u64_str.id?.find(id)); + blackBox(ctx.db.unique0U32U64Str.id?.find(id)); }); spacetimedb.reducer('filter_no_index_u32_u64_str_by_id', { id: t.u32() }, (ctx, { id }) => { - for (const r of ctx.db.filter_no_index_u32_u64_str_by_id.iter(id)) { + for (const r of ctx.db.noIndexU32U64Str.iter()) { if (r.id == id) { blackBox(r); } @@ -222,13 +219,16 @@ spacetimedb.reducer('filter_no_index_u32_u64_str_by_id', { id: t.u32() }, (ctx, }); spacetimedb.reducer('filter_btree_each_column_u32_u64_str_by_id', { id: t.u32() }, (ctx, { id }) => { - for (const r of ctx.db.btree_each_column_u32_u64_str.id?.filter(id)) { - blackBox(r); + const idIndex = ctx.db.btreeEachColumnU32U64Str.id; + if (idIndex) { + for (const r of idIndex.filter(id)) { + blackBox(r); + } } }); spacetimedb.reducer('filter_unique_0_u32_u64_str_by_name', { name: t.string() }, (ctx, { name }) => { - for (const r of ctx.db.unique_0_u32_u64_str.iter()) { + for (const r of ctx.db.unique0U32U64Str.iter()) { if (r.name == name) { blackBox(r); } @@ -236,7 +236,7 @@ spacetimedb.reducer('filter_unique_0_u32_u64_str_by_name', { name: t.string() }, }); spacetimedb.reducer('filter_no_index_u32_u64_str_by_name', { name: t.string() }, (ctx, { name }) => { - for (const r of ctx.db.no_index_u32_u64_str.iter()) { + for (const r of ctx.db.noIndexU32U64Str.iter()) { if (r.name == name) { blackBox(r); } @@ -244,17 +244,20 @@ spacetimedb.reducer('filter_no_index_u32_u64_str_by_name', { name: t.string() }, }); spacetimedb.reducer('filter_btree_each_column_u32_u64_str_by_name', { name: t.string() }, (ctx, { name }) => { - for (const r of ctx.db.btree_each_column_u32_u64_str.name?.filter()) { - blackBox(r); + const nameIndex = ctx.db.btreeEachColumnU32U64Str.name; + if (nameIndex) { + for (const r of nameIndex.filter(name)) { + blackBox(r); + } } }); spacetimedb.reducer('filter_unique_0_u32_u64_u64_by_id', { id: t.u32() }, (ctx, { id }) => { - blackBox(ctx.db.unique_0_u32_u64_u64.id?.find(id)); + blackBox(ctx.db.unique0U32U64U64.id?.find(id)); }); spacetimedb.reducer('filter_no_index_u32_u64_u64_by_id', { id: t.u32() }, (ctx, { id }) => { - for (const r of ctx.db.no_index_u32_u64_u64.iter()) { + for (const r of ctx.db.noIndexU32U64U64.iter()) { if (r.id == id) { blackBox(r); } @@ -262,13 +265,16 @@ spacetimedb.reducer('filter_no_index_u32_u64_u64_by_id', { id: t.u32() }, (ctx, }); spacetimedb.reducer('filter_btree_each_column_u32_u64_u64_by_id', { id: t.u32() }, (ctx, { id }) => { - for (const r of ctx.db.btree_each_column_u32_u64_u64.id?.filter(id)) { - blackBox(r); + const idIndex = ctx.db.btreeEachColumnU32U64U64.id; + if (idIndex) { + for (const r of idIndex.filter(id)) { + blackBox(r); + } } }); spacetimedb.reducer('filter_unique_0_u32_u64_u64_by_x', { x: t.u64() }, (ctx, { x }) => { - for (const r of ctx.db.unique_0_u32_u64_u64.iter()) { + for (const r of ctx.db.unique0U32U64U64.iter()) { if (r.x == x) { blackBox(r); } @@ -276,7 +282,7 @@ spacetimedb.reducer('filter_unique_0_u32_u64_u64_by_x', { x: t.u64() }, (ctx, { }); spacetimedb.reducer('filter_no_index_u32_u64_u64_by_x', { x: t.u64() }, (ctx, { x }) => { - for (const r of ctx.db.no_index_u32_u64_u64.iter()) { + for (const r of ctx.db.noIndexU32U64U64.iter()) { if (r.x == x) { blackBox(r); } @@ -284,13 +290,16 @@ spacetimedb.reducer('filter_no_index_u32_u64_u64_by_x', { x: t.u64() }, (ctx, { }); spacetimedb.reducer('filter_btree_each_column_u32_u64_u64_by_x', { x: t.u64() }, (ctx, { x }) => { - for (const r of ctx.db.btree_each_column_u32_u64_u64.x?.filter(x)) { - blackBox(r); + const xIndex = ctx.db.btreeEachColumnU32U64U64.x; + if (xIndex) { + for (const r of xIndex.filter(x)) { + blackBox(r); + } } }); spacetimedb.reducer('filter_unique_0_u32_u64_u64_by_y', { y: t.u64() }, (ctx, { y }) => { - for (const r of ctx.db.unique_0_u32_u64_u64.iter()) { + for (const r of ctx.db.unique0U32U64U64.iter()) { if (r.y == y) { blackBox(r); } @@ -298,7 +307,7 @@ spacetimedb.reducer('filter_unique_0_u32_u64_u64_by_y', { y: t.u64() }, (ctx, { }); spacetimedb.reducer('filter_no_index_u32_u64_u64_by_y', { y: t.u64() }, (ctx, { y }) => { - for (const r of ctx.db.no_index_u32_u64_u64.iter()) { + for (const r of ctx.db.noIndexU32U64U64.iter()) { if (r.y == y) { blackBox(r); } @@ -306,9 +315,11 @@ spacetimedb.reducer('filter_no_index_u32_u64_u64_by_y', { y: t.u64() }, (ctx, { }); spacetimedb.reducer('filter_btree_each_column_u32_u64_u64_by_y', { y: t.u64() }, (ctx, { y }) => { - for (const r of ctx.db.btree_each_column_u32_u64_u64.y?.filter(y)) { - blackBox(r); - + const yIndex = ctx.db.btreeEachColumnU32U64U64.y; + if (yIndex) { + for (const r of yIndex.filter(y)) { + blackBox(r); + } } }); @@ -318,11 +329,11 @@ spacetimedb.reducer('filter_btree_each_column_u32_u64_u64_by_y', { y: t.u64() }, // FIXME: current nonunique delete interface is UNUSABLE!!!! spacetimedb.reducer('delete_unique_0_u32_u64_str_by_id', { id: t.u32() }, (ctx, { id }) => { - ctx.db.unique_0_u32_u64_str.id?.delete(id); + ctx.db.unique0U32U64Str.id?.delete(id); }); spacetimedb.reducer('delete_unique_0_u32_u64_u64_by_id', { id: t.u32() }, (ctx, { id }) => { - ctx.db.unique_0_u32_u64_u64.id?.delete(id); + ctx.db.unique0U32U64U64.id?.delete(id); }); // ---------- clear table ---------- @@ -331,27 +342,27 @@ function unimplemented() { throw new Error('Modules currently have no interface to clear a table'); } -spacetimedb.reducer('clear_table_unique_0_u32_u64_str', (ctx, { }) => { +spacetimedb.reducer('clear_table_unique_0_u32_u64_str', () => { unimplemented(); }); -spacetimedb.reducer('clear_table_no_index_u32_u64_str', (ctx, { }) => { +spacetimedb.reducer('clear_table_no_index_u32_u64_str', () => { unimplemented(); }); -spacetimedb.reducer('clear_table_btree_each_column_u32_u64_str', (ctx, { }) => { +spacetimedb.reducer('clear_table_btree_each_column_u32_u64_str', () => { unimplemented(); }); -spacetimedb.reducer('clear_table_unique_0_u32_u64_u64', (ctx, { }) => { +spacetimedb.reducer('clear_table_unique_0_u32_u64_u64', () => { unimplemented(); }); -spacetimedb.reducer('clear_table_no_index_u32_u64_u64', (ctx, { }) => { +spacetimedb.reducer('clear_table_no_index_u32_u64_u64', () => { unimplemented(); }); -spacetimedb.reducer('clear_table_btree_each_column_u32_u64_u64', (ctx, { }) => { +spacetimedb.reducer('clear_table_btree_each_column_u32_u64_u64', () => { unimplemented(); }); @@ -359,33 +370,33 @@ spacetimedb.reducer('clear_table_btree_each_column_u32_u64_u64', (ctx, { }) => { // You need to inspect the module outputs to actually read the result from these. -spacetimedb.reducer('count_unique_0_u32_u64_str', (ctx, { }) => { - const count = ctx.db.unique_0_u32_u64_str.count(); +spacetimedb.reducer('count_unique_0_u32_u64_str', ctx => { + const count = ctx.db.unique0U32U64Str.count(); console.info!(`COUNT: ${count}`); }); -spacetimedb.reducer('count_no_index_u32_u64_str', (ctx, { }) => { - const count = ctx.db.no_index_u32_u64_str.count(); +spacetimedb.reducer('count_no_index_u32_u64_str', ctx => { + const count = ctx.db.noIndexU32U64Str.count(); console.info!(`COUNT: ${count}`); }); -spacetimedb.reducer('count_btree_each_column_u32_u64_str', (ctx, { }) => { - const count = ctx.db.btree_each_column_u32_u64_str.count(); +spacetimedb.reducer('count_btree_each_column_u32_u64_str', ctx => { + const count = ctx.db.btreeEachColumnU32U64Str.count(); console.info!(`COUNT: ${count}`); }); -spacetimedb.reducer('count_unique_0_u32_u64_u64', (ctx, { }) => { - const count = ctx.db.unique_0_u32_u64_u64.count(); +spacetimedb.reducer('count_unique_0_u32_u64_u64', ctx => { + const count = ctx.db.unique0U32U64U64.count(); console.info!(`COUNT: ${count}`); }); -spacetimedb.reducer('count_no_index_u32_u64_u64', (ctx, { }) => { - const count = ctx.db.no_index_u32_u64_u64.count(); +spacetimedb.reducer('count_no_index_u32_u64_u64', ctx => { + const count = ctx.db.noIndexU32U64U64.count(); console.info!(`COUNT: ${count}`); }); -spacetimedb.reducer('count_btree_each_column_u32_u64_u64', (ctx, { }) => { - const count = ctx.db.btree_each_column_u32_u64_u64.count(); +spacetimedb.reducer('count_btree_each_column_u32_u64_u64', ctx => { + const count = ctx.db.btreeEachColumnU32U64U64.count(); console.info!(`COUNT: ${count}`); }); diff --git a/modules/module-test-ts/src/index.ts b/modules/module-test-ts/src/index.ts index 57879732a00..659bde643eb 100644 --- a/modules/module-test-ts/src/index.ts +++ b/modules/module-test-ts/src/index.ts @@ -34,7 +34,7 @@ const testC = t.enum('Namespace.TestC', { type TestC = Infer; // Rust: const DEFAULT_TEST_C: TestC = TestC::Foo; -const DEFAULT_TEST_C: TestC = { tag: 'Foo', value: {} } as const; +const DEFAULT_TEST_C: TestC = { tag: 'Foo' } as const; // Rust: #[derive(SpacetimeType)] pub struct Baz { pub field: String } const Baz = t.object('Baz', { @@ -301,7 +301,7 @@ spacetimedb.reducer( // Insert test_a rows for (let i = 0; i < 1000; i++) { - ctx.db.test_a.insert({ + ctx.db.testA.insert({ x: (i >>> 0) + arg.x, y: (i >>> 0) + arg.y, z: 'Yo', @@ -315,14 +315,14 @@ spacetimedb.reducer( let numDeleted = 0; for (let x = 5; x < 10; x++) { // Prefer index deletion if available; fallback to filter+delete - for (const row of ctx.db.test_a.iter()) { + for (const row of ctx.db.testA.iter()) { if (row.x === x) { - if (ctx.db.test_a.delete(row)) numDeleted++; + if (ctx.db.testA.delete(row)) numDeleted++; } } } - const rowCountAfter = ctx.db.test_a.count(); + const rowCountAfter = ctx.db.testA.count(); if (Number(rowCountBefore) !== Number(rowCountAfter) + numDeleted) { console.error( `Started with ${rowCountBefore} rows, deleted ${numDeleted}, and wound up with ${rowCountAfter} rows... huh?` @@ -331,7 +331,7 @@ spacetimedb.reducer( // try_insert TestE { id: 0, name: "Tyler" } try { - const inserted = ctx.db.test_e.insert({ id: 0n, name: 'Tyler' }); + const inserted = ctx.db.testE.insert({ id: 0n, name: 'Tyler' }); console.info(`Inserted: ${JSON.stringify(inserted)}`); } catch (err) { console.info(`Error: ${String(err)}`); @@ -366,14 +366,14 @@ spacetimedb.reducer( // add_player(name) -> Result<(), String> spacetimedb.reducer('add_player', { name: t.string() }, (ctx, { name }) => { const rec = { id: 0n as bigint, name }; - const inserted = ctx.db.test_e.insert(rec); // id autoInc => always creates a new one + const inserted = ctx.db.testE.insert(rec); // id autoInc => always creates a new one // No-op re-upsert by id index if your bindings support it. - if (ctx.db.test_e.id?.update) ctx.db.test_e.id.update(inserted); + if (ctx.db.testE.id?.update) ctx.db.testE.id.update(inserted); }); // delete_player(id) -> Result<(), String> spacetimedb.reducer('delete_player', { id: t.u64() }, (ctx, { id }) => { - const ok = ctx.db.test_e.id.delete(id); + const ok = ctx.db.testE.id.delete(id); if (!ok) throw new Error(`No TestE row with id ${id}`); }); @@ -383,9 +383,9 @@ spacetimedb.reducer( { name: t.string() }, (ctx, { name }) => { let deleted = 0; - for (const row of ctx.db.test_e.iter()) { + for (const row of ctx.db.testE.iter()) { if (row.name === name) { - if (ctx.db.test_e.delete(row)) deleted++; + if (ctx.db.testE.delete(row)) deleted++; } } if (deleted === 0) @@ -403,12 +403,12 @@ spacetimedb.reducer('client_connected', {}, _ctx => { // add_private(name) spacetimedb.reducer('add_private', { name: t.string() }, (ctx, { name }) => { - ctx.db.private_table.insert({ name }); + ctx.db.privateTable.insert({ name }); }); // query_private() spacetimedb.reducer('query_private', {}, ctx => { - for (const row of ctx.db.private_table.iter()) { + for (const row of ctx.db.privateTable.iter()) { console.info(`Private, ${row.name}!`); } console.info('Private, World!'); @@ -419,7 +419,7 @@ spacetimedb.reducer('query_private', {}, ctx => { spacetimedb.reducer('test_btree_index_args', {}, ctx => { const s = 'String'; // Demonstrate scanning via iteration; prefer index access if bindings expose it. - for (const row of ctx.db.test_e.iter()) { + for (const row of ctx.db.testE.iter()) { if (row.name === s || row.name === 'str') { // no-op; exercising types } diff --git a/modules/sdk-test-ts/src/index.ts b/modules/sdk-test-ts/src/index.ts index 2dcb9de8c94..76bc93e1748 100644 --- a/modules/sdk-test-ts/src/index.ts +++ b/modules/sdk-test-ts/src/index.ts @@ -1,13 +1,10 @@ // ───────────────────────────────────────────────────────────────────────────── // IMPORTS // ───────────────────────────────────────────────────────────────────────────── +import { toCamelCase } from 'spacetimedb'; import { type RowObj, schema, t, table } from 'spacetimedb/server'; -const SimpleEnum = t.enum('SimpleEnum', { - Zero: t.unit(), - One: t.unit(), - Two: t.unit(), -}); +const SimpleEnum = t.enum('SimpleEnum', ['Zero', 'One', 'Two']); const EnumWithPayload = t.enum('EnumWithPayload', { U8: t.u8(), @@ -114,29 +111,29 @@ function tbl( reducers(spacetimedb) { if (ops.insert) { spacetimedb.reducer(ops.insert, row, (ctx, args) => { - (ctx.db[name] as any).insert({ ...args }); + (ctx.db[toCamelCase(name)] as any).insert({ ...args }); }); } if (ops.delete) { spacetimedb.reducer(ops.delete, row, (ctx, args) => { - (ctx.db[name] as any).delete({ ...args }); + (ctx.db[toCamelCase(name)] as any).delete({ ...args }); }); } if (ops.insert_or_panic) { spacetimedb.reducer(ops.insert_or_panic, row, (ctx, args) => { - (ctx.db[name] as any).insert({ ...args }); + (ctx.db[toCamelCase(name)] as any).insert({ ...args }); }); } if (ops.update_by) { const [reducer, col] = ops.update_by; spacetimedb.reducer(reducer, row, (ctx, args) => { - (ctx.db[name] as any)[col].update({ ...args }); + (ctx.db[toCamelCase(name)] as any)[col].update({ ...args }); }); } if (ops.delete_by) { const [reducer, col] = ops.delete_by; spacetimedb.reducer(reducer, { [col]: row[col] }, (ctx, args) => { - (ctx.db[name] as any)[col].delete(args[col as any]); + (ctx.db[toCamelCase(name)] as any)[col].delete(args[col as any]); }); } }, @@ -810,10 +807,10 @@ spacetimedb.reducer( 'update_pk_simple_enum', { a: SimpleEnum, data: t.i32() }, (ctx, { a, data }) => { - const o = ctx.db.pk_simple_enum.a.find(a); + const o = ctx.db.pkSimpleEnum.a.find(a); if (o == null) throw new Error('row not found'); o.data = data; - ctx.db.pk_simple_enum.a.update(o); + ctx.db.pkSimpleEnum.a.update(o); } ); @@ -822,7 +819,7 @@ spacetimedb.reducer( { rows: t.array(BTreeU32.rowType) }, (ctx, { rows }) => { for (const row of rows) { - ctx.db.btree_u32.insert(row); + ctx.db.btreeU32.insert(row); } } ); @@ -832,7 +829,7 @@ spacetimedb.reducer( { rows: t.array(BTreeU32.rowType) }, (ctx, { rows }) => { for (const row of rows) { - ctx.db.btree_u32.delete(row); + ctx.db.btreeU32.delete(row); } } ); @@ -842,10 +839,10 @@ spacetimedb.reducer( { pk_u32: t.array(PkU32), bt_u32: t.array(BTreeU32.rowType) }, (ctx, { pk_u32, bt_u32 }) => { for (const row of pk_u32) { - ctx.db.pk_u32.insert(row); + ctx.db.pkU32.insert(row); } for (const row of bt_u32) { - ctx.db.btree_u32.insert(row); + ctx.db.btreeU32.insert(row); } } ); @@ -857,8 +854,8 @@ spacetimedb.reducer( 'insert_unique_u32_update_pk_u32', { n: t.u32(), d_unique: t.i32(), d_pk: t.i32() }, (ctx, { n, d_unique, d_pk }) => { - ctx.db.unique_u32.insert({ n, data: d_unique }); - ctx.db.pk_u32.n.update({ n, data: d_pk }); + ctx.db.uniqueU32.insert({ n, data: d_unique }); + ctx.db.pkU32.n.update({ n, data: d_pk }); } ); @@ -871,24 +868,24 @@ spacetimedb.reducer( 'delete_pk_u32_insert_pk_u32_two', { n: t.u32(), data: t.i32() }, (ctx, { n, data }) => { - ctx.db.pk_u32_two.insert({ n, data }); - ctx.db.pk_u32.delete({ n, data }); + ctx.db.pkU32Two.insert({ n, data }); + ctx.db.pkU32.delete({ n, data }); } ); spacetimedb.reducer('insert_caller_one_identity', ctx => { - ctx.db.one_identity.insert({ i: ctx.sender }); + ctx.db.oneIdentity.insert({ i: ctx.sender }); }); spacetimedb.reducer('insert_caller_vec_identity', ctx => { - ctx.db.vec_identity.insert({ i: [ctx.sender] }); + ctx.db.vecIdentity.insert({ i: [ctx.sender] }); }); spacetimedb.reducer( 'insert_caller_unique_identity', { data: t.i32() }, (ctx, { data }) => { - ctx.db.unique_identity.insert({ i: ctx.sender, data }); + ctx.db.uniqueIdentity.insert({ i: ctx.sender, data }); } ); @@ -896,20 +893,20 @@ spacetimedb.reducer( 'insert_caller_pk_identity', { data: t.i32() }, (ctx, { data }) => { - ctx.db.pk_identity.insert({ i: ctx.sender, data }); + ctx.db.pkIdentity.insert({ i: ctx.sender, data }); } ); spacetimedb.reducer('insert_caller_one_connection_id', ctx => { if (!ctx.connectionId) throw new Error('No connection id in reducer context'); - ctx.db.one_connection_id.insert({ + ctx.db.oneConnectionId.insert({ a: ctx.connectionId, }); }); spacetimedb.reducer('insert_caller_vec_connection_id', ctx => { if (!ctx.connectionId) throw new Error('No connection id in reducer context'); - ctx.db.vec_connection_id.insert({ + ctx.db.vecConnectionId.insert({ a: [ctx.connectionId], }); }); @@ -920,7 +917,7 @@ spacetimedb.reducer( (ctx, { data }) => { if (!ctx.connectionId) throw new Error('No connection id in reducer context'); - ctx.db.unique_connection_id.insert({ + ctx.db.uniqueConnectionId.insert({ a: ctx.connectionId, data, }); @@ -933,7 +930,7 @@ spacetimedb.reducer( (ctx, { data }) => { if (!ctx.connectionId) throw new Error('No connection id in reducer context'); - ctx.db.pk_connection_id.insert({ + ctx.db.pkConnectionId.insert({ a: ctx.connectionId, data, }); @@ -941,14 +938,14 @@ spacetimedb.reducer( ); spacetimedb.reducer('insert_call_timestamp', ctx => { - ctx.db.one_timestamp.insert({ t: ctx.timestamp }); + ctx.db.oneTimestamp.insert({ t: ctx.timestamp }); }); spacetimedb.reducer( 'insert_primitives_as_strings', { s: EveryPrimitiveStruct }, (ctx, { s }) => { - ctx.db.vec_string.insert({ + ctx.db.vecString.insert({ s: [ s.a.toString(), s.b.toString(), @@ -1001,7 +998,7 @@ spacetimedb.reducer( 'insert_into_indexed_simple_enum', { n: SimpleEnum }, (ctx, { n }) => { - ctx.db.indexed_simple_enum.insert({ n }); + ctx.db.indexedSimpleEnum.insert({ n }); } ); @@ -1009,9 +1006,9 @@ spacetimedb.reducer( 'update_indexed_simple_enum', { a: SimpleEnum, b: SimpleEnum }, (ctx, { a, b }) => { - if (!ctx.db.indexed_simple_enum.n.filter(a).next().done) { - ctx.db.indexed_simple_enum.n.delete(a); - ctx.db.indexed_simple_enum.insert({ n: b }); + if (!ctx.db.indexedSimpleEnum.n.filter(a).next().done) { + ctx.db.indexedSimpleEnum.n.delete(a); + ctx.db.indexedSimpleEnum.insert({ n: b }); } } ); From 6d270cfb932434aa0ecbfb9773f64f4038b48b13 Mon Sep 17 00:00:00 2001 From: Tyler Cloutier Date: Tue, 11 Nov 2025 19:32:47 -0500 Subject: [PATCH 39/49] Fixed compile error --- crates/bindings-typescript/src/sdk/table_cache.ts | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/crates/bindings-typescript/src/sdk/table_cache.ts b/crates/bindings-typescript/src/sdk/table_cache.ts index ffc55702514..2bfbcc5b451 100644 --- a/crates/bindings-typescript/src/sdk/table_cache.ts +++ b/crates/bindings-typescript/src/sdk/table_cache.ts @@ -105,7 +105,7 @@ export class TableCacheImpl< idx: I ): ReadonlyIndex, I> { type TableDef = TableDefForTableName; - type Row = RowType; + type Row = Prettify>; // We do not yet support non-btree indexes if (idx.algorithm !== 'btree') { @@ -221,7 +221,7 @@ export class TableCacheImpl< * @returns The values of the rows in the table */ iter(): IterableIterator< - RowType> + Prettify>> > { function* generator( rows: Map< @@ -229,10 +229,12 @@ export class TableCacheImpl< [RowType>, number] > ): IterableIterator< - RowType> + Prettify>> > { for (const [row] of rows.values()) { - yield row; + yield row as Prettify< + RowType> + >; } } return generator(this.rows); @@ -243,7 +245,7 @@ export class TableCacheImpl< * @returns An iterator over the rows in the table */ [Symbol.iterator](): IterableIterator< - RowType> + Prettify>> > { return this.iter(); } From 93752400b6ace5ce0e012a1ca3220f5b11fa9aa6 Mon Sep 17 00:00:00 2001 From: Tyler Cloutier Date: Tue, 11 Nov 2025 19:58:53 -0500 Subject: [PATCH 40/49] Dovos --- crates/bindings-typescript/src/sdk/db_connection_impl.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/crates/bindings-typescript/src/sdk/db_connection_impl.ts b/crates/bindings-typescript/src/sdk/db_connection_impl.ts index a7e3a1082e8..b04d6fdfabf 100644 --- a/crates/bindings-typescript/src/sdk/db_connection_impl.ts +++ b/crates/bindings-typescript/src/sdk/db_connection_impl.ts @@ -213,9 +213,11 @@ export class DbConnectionImpl this.ws.onclose = () => { this.#emitter.emit('disconnect', this); + this.isActive = false; }; this.ws.onerror = (e: ErrorEvent) => { this.#emitter.emit('connectError', this, e); + this.isActive = false; }; this.ws.onopen = this.#handleOnOpen.bind(this); this.ws.onmessage = this.#handleOnMessage.bind(this); From 767d5f97e4329a543d5e1d7a36dd7b4c0f2f68c4 Mon Sep 17 00:00:00 2001 From: Noa Date: Wed, 12 Nov 2025 12:20:12 -0600 Subject: [PATCH 41/49] Use views in codegen --- crates/codegen/src/typescript.rs | 47 ++++++++++++++----- crates/codegen/src/util.rs | 29 +++++++++++- .../codegen__codegen_typescript.snap | 9 ++++ 3 files changed, 70 insertions(+), 15 deletions(-) diff --git a/crates/codegen/src/typescript.rs b/crates/codegen/src/typescript.rs index ecfa08b8a06..14dd4fb4c4d 100644 --- a/crates/codegen/src/typescript.rs +++ b/crates/codegen/src/typescript.rs @@ -1,5 +1,6 @@ use crate::util::{ - is_reducer_invokable, iter_indexes, iter_reducers, iter_tables, iter_types, print_auto_generated_version_comment, + is_reducer_invokable, iter_constraints, iter_indexes, iter_reducers, iter_table_and_view_names, iter_tables, + iter_types, iter_views, print_auto_generated_version_comment, }; use crate::OutputFile; @@ -7,6 +8,7 @@ use super::util::{collect_case, print_auto_generated_file_comment, type_ref_name use std::collections::BTreeSet; use std::fmt::{self, Write}; +use std::iter; use std::ops::Deref; use convert_case::{Case, Casing}; @@ -14,7 +16,7 @@ use spacetimedb_lib::sats::layout::PrimitiveType; use spacetimedb_lib::sats::AlgebraicTypeRef; use spacetimedb_primitives::ColId; use spacetimedb_schema::def::{ - BTreeAlgorithm, IndexAlgorithm, ModuleDef, ReducerDef, ScopedTypeName, TableDef, TypeDef, + BTreeAlgorithm, ConstraintDef, IndexAlgorithm, IndexDef, ModuleDef, ReducerDef, ScopedTypeName, TableDef, TypeDef, }; use spacetimedb_schema::identifier::Identifier; use spacetimedb_schema::schema::TableSchema; @@ -193,10 +195,9 @@ impl Lang for TypeScript { writeln!(out); writeln!(out, "// Import and reexport all table handle types"); - for table in iter_tables(module) { - let table_name = &table.name; + for table_name in iter_table_and_view_names(module) { let table_module_name = table_module_name(table_name); - let table_name_pascalcase = table.name.deref().to_case(Case::Pascal); + let table_name_pascalcase = table_name.deref().to_case(Case::Pascal); // TODO: This really shouldn't be necessary. We could also have `table()` accept // `__t.object(...)`s. writeln!(out, "import {table_name_pascalcase}Row from \"./{table_module_name}\";"); @@ -222,7 +223,23 @@ impl Lang for TypeScript { let row_type_name = type_ref_name(module, type_ref); writeln!(out, "__table({{"); out.indent(1); - write_table_opts(module, out, table); + write_table_opts( + module, + out, + type_ref, + &table.name, + iter_indexes(table), + iter_constraints(table), + ); + out.dedent(1); + writeln!(out, "}}, {}Row),", row_type_name); + } + for view in iter_views(module) { + let type_ref = view.product_type_ref; + let row_type_name = type_ref_name(module, type_ref); + writeln!(out, "__table({{"); + out.indent(1); + write_table_opts(module, out, type_ref, &view.name, iter::empty(), iter::empty()); out.dedent(1); writeln!(out, "}}, {}Row),", row_type_name); } @@ -460,13 +477,19 @@ fn define_body_for_product( out.newline(); } -fn write_table_opts(module: &ModuleDef, out: &mut Indenter, table: &TableDef) { - let type_ref = table.product_type_ref; +fn write_table_opts<'a>( + module: &ModuleDef, + out: &mut Indenter, + type_ref: AlgebraicTypeRef, + name: &Identifier, + indexes: impl Iterator, + constraints: impl Iterator, +) { let product_def = module.typespace_for_generate()[type_ref].as_product().unwrap(); - writeln!(out, "name: '{}',", table.name.deref()); + writeln!(out, "name: '{}',", name.deref()); writeln!(out, "indexes: ["); out.indent(1); - for index_def in iter_indexes(table) { + for index_def in indexes { if index_def.generated() { // Skip system-defined indexes continue; @@ -509,9 +532,7 @@ fn write_table_opts(module: &ModuleDef, out: &mut Indenter, table: &TableDef) { writeln!(out, "constraints: ["); out.indent(1); // Unique constraints sorted by name for determinism - let mut constraints: Vec<_> = table.constraints.iter().collect(); - constraints.sort_by_key(|(name, _)| *name); - for (_, constraint) in constraints { + for constraint in constraints { let columns: Vec<_> = constraint .data .unique_columns() // Option<&ColSet> diff --git a/crates/codegen/src/util.rs b/crates/codegen/src/util.rs index 1065fc39152..2a0bcca4ca2 100644 --- a/crates/codegen/src/util.rs +++ b/crates/codegen/src/util.rs @@ -12,8 +12,11 @@ use spacetimedb_lib::sats::layout::PrimitiveType; use spacetimedb_lib::version; use spacetimedb_lib::{db::raw_def::v9::Lifecycle, sats::AlgebraicTypeRef}; use spacetimedb_primitives::ColList; -use spacetimedb_schema::type_for_generate::ProductTypeDef; -use spacetimedb_schema::{def::ProcedureDef, schema::TableSchema}; +use spacetimedb_schema::{def::ViewDef, type_for_generate::ProductTypeDef}; +use spacetimedb_schema::{ + def::{ConstraintDef, ProcedureDef}, + schema::TableSchema, +}; use spacetimedb_schema::{ def::{IndexDef, TableDef, TypeDef}, type_for_generate::TypespaceForGenerate, @@ -112,6 +115,24 @@ pub(super) fn iter_tables(module: &ModuleDef) -> impl Iterator module.tables().sorted_by_key(|table| &table.name) } +/// Iterate over all the [`ViewDef`]s defined by the module, in alphabetical order by name. +/// +/// Sorting is necessary to have deterministic reproducible codegen. +pub(super) fn iter_views(module: &ModuleDef) -> impl Iterator { + module.views().sorted_by_key(|view| &view.name) +} + +/// Iterate over the names of all the tables and views defined by the module, in alphabetical order. +/// +/// Sorting is necessary to have deterministic reproducible codegen. +pub(super) fn iter_table_and_view_names(module: &ModuleDef) -> impl Iterator { + itertools::chain( + module.tables().map(|table| &table.name), + module.views().map(|view| &view.name), + ) + .sorted() +} + pub(super) fn iter_unique_cols<'a>( typespace: &'a TypespaceForGenerate, schema: &'a TableSchema, @@ -133,6 +154,10 @@ pub(super) fn iter_indexes(table: &TableDef) -> impl Iterator table.indexes.values().sorted_by_key(|index| &index.name) } +pub(super) fn iter_constraints(table: &TableDef) -> impl Iterator { + table.constraints.values().sorted_by_key(|constraint| &constraint.name) +} + /// Iterate over all the [`TypeDef`]s defined by the module, in alphabetical order by name. /// /// Sorting is necessary to have deterministic reproducible codegen. diff --git a/crates/codegen/tests/snapshots/codegen__codegen_typescript.snap b/crates/codegen/tests/snapshots/codegen__codegen_typescript.snap index 6c1422e9073..6315fbf26a5 100644 --- a/crates/codegen/tests/snapshots/codegen__codegen_typescript.snap +++ b/crates/codegen/tests/snapshots/codegen__codegen_typescript.snap @@ -267,6 +267,8 @@ import HasSpecialStuffRow from "./has_special_stuff_table"; export { HasSpecialStuffRow }; import LoggedOutPlayerRow from "./logged_out_player_table"; export { LoggedOutPlayerRow }; +import MyPlayerRow from "./my_player_table"; +export { MyPlayerRow }; import PersonRow from "./person_table"; export { PersonRow }; import PkMultiIdentityRow from "./pk_multi_identity_table"; @@ -465,6 +467,13 @@ const tablesSchema = __schema( constraints: [ ], }, TestFoobarRow), + __table({ + name: 'my_player', + indexes: [ + ], + constraints: [ + ], + }, PlayerRow), ); const reducersSchema = __reducers( From d7dd8ba5383f7eb7cd17002d9fe7177d4c6a44fa Mon Sep 17 00:00:00 2001 From: = Date: Fri, 14 Nov 2025 12:15:35 -0500 Subject: [PATCH 42/49] Fixed failing tests --- .../src/lib/algebraic_type.ts | 2 +- .../src/lib/type_builders.ts | 115 ++++++++++-------- 2 files changed, 67 insertions(+), 50 deletions(-) diff --git a/crates/bindings-typescript/src/lib/algebraic_type.ts b/crates/bindings-typescript/src/lib/algebraic_type.ts index 2f8b4bdbba3..82a95287eee 100644 --- a/crates/bindings-typescript/src/lib/algebraic_type.ts +++ b/crates/bindings-typescript/src/lib/algebraic_type.ts @@ -443,7 +443,7 @@ export const SumType = { const variant = value['tag']; const index = ty.variants.findIndex(v => v.name === variant); if (index < 0) { - throw `Can't serialize a sum type, couldn't find ${value.tag} tag`; + throw `Can't serialize a sum type, couldn't find ${value.tag} tag ${JSON.stringify(value)} in variants ${JSON.stringify(ty)}`; } writer.writeU8(index); AlgebraicType.serializeValue( diff --git a/crates/bindings-typescript/src/lib/type_builders.ts b/crates/bindings-typescript/src/lib/type_builders.ts index 86b51032fd5..180ae67a5ae 100644 --- a/crates/bindings-typescript/src/lib/type_builders.ts +++ b/crates/bindings-typescript/src/lib/type_builders.ts @@ -1236,9 +1236,14 @@ export class ProductBuilder readonly elements: Elements; constructor(elements: Elements, name?: string) { function elementsArrayFromElementsObj(obj: Obj) { - return Object.entries(obj).map(([name, value]) => ({ - name, - algebraicType: value.algebraicType, + return Object.keys(obj).map(key => ({ + name: key, + // Lazily resolve the underlying object's algebraicType. + // This will call obj[key].algebraicType only when someone + // actually reads this property. + get algebraicType() { + return obj[key].algebraicType; + }, })); } super( @@ -1321,12 +1326,16 @@ class SumBuilderImpl extends TypeBuilder< function variantsArrayFromVariantsObj( variants: Variants ) { - return Object.entries(variants).map(([name, value]) => ({ - name, - algebraicType: value.algebraicType, + return (Object.keys(variants) as Array).map(key => ({ + name: key as string, + // Lazily resolve the underlying object's algebraicType. + // This will call obj[key].algebraicType only when someone + // actually reads this property. + get algebraicType() { + return variants[key].algebraicType; + }, })); } - super( AlgebraicType.Sum({ variants: variantsArrayFromVariantsObj(variants), @@ -1336,48 +1345,56 @@ class SumBuilderImpl extends TypeBuilder< this.variants = variants; this.typeName = name; - // ---- Runtime unit detection ---- - // Adjust this to your real shape if needed. - // From your code, you have `value.algebraicType` available. - function isUnitRuntime(v: any): boolean { - // common patterns — tweak as necessary: - if (!v || !v.algebraicType) return false; - const t = v.algebraicType; - return t.tag === 'Unit' || t.kind === 'Unit' || t.type === 'Unit'; - } - - // wire dynamic per-variant methods - // e.g. mySumBuilder.Foo(value) - for (const key of Object.keys(variants) as Array) { - const variant = variants[key]; - - if (isUnitRuntime(variant)) { - // Unit: expose a read-only VALUE (no call) - const constant = this.create(key as any) as EnumValue< - typeof key, - Variants[typeof key] - >; - Object.defineProperty(this, key, { - value: constant, - writable: false, - enumerable: true, - configurable: false, - }); - } else { - // Payload: expose a function(value) -> EnumValue - const fn = ((value: any) => - this.create(key as any, value)) as VariantConstructor< - typeof key & string, - Variants[typeof key] - >; - Object.defineProperty(this, key, { - value: fn, - writable: false, - enumerable: true, - configurable: false, - }); - } - } + // // ---- Runtime unit detection ---- + // // Adjust this to your real shape if needed. + // // From your code, you have `value.algebraicType` available. + // function isUnitRuntime(v: TypeBuilder): boolean { + // const t = v.algebraicType; + // return t.tag === 'Product' && t.value.elements.length === 0; + // } + + // for (const key of Object.keys(variants) as Array) { + // const desc = Object.getOwnPropertyDescriptor(variants, key); + + // const isAccessor = + // !!desc && (typeof desc.get === 'function' || typeof desc.set === 'function'); + + // let isUnit = false; + + // if (!isAccessor) { + // // Only read variants[key] if it's a *data* property + // // otherwise assume non-unit because it's a getter + // const variant = variants[key]; + // isUnit = isUnitRuntime(variant); + // } + + // if (isUnit) { + // // Unit: expose a read-only VALUE (no call) + // const constant = this.create(key as any) as EnumValue< + // typeof key, + // Variants[typeof key] + // >; + // Object.defineProperty(this, key, { + // value: constant, + // writable: false, + // enumerable: true, + // configurable: false, + // }); + // } else { + // const fn = ((value: any) => + // this.create(key as any, value)) as VariantConstructor< + // typeof key & string, + // Variants[typeof key] + // >; + + // Object.defineProperty(this, key, { + // value: fn, + // writable: false, + // enumerable: true, + // configurable: false, + // }); + // } + // } } /** From 88ae27702da78bdae58e5f87445af40302b87dc2 Mon Sep 17 00:00:00 2001 From: = Date: Fri, 14 Nov 2025 12:25:12 -0500 Subject: [PATCH 43/49] Forgot to uncomment code --- .../src/lib/type_builders.ts | 101 +++++++++--------- .../tests/binary_read_write.test.ts | 10 +- 2 files changed, 56 insertions(+), 55 deletions(-) diff --git a/crates/bindings-typescript/src/lib/type_builders.ts b/crates/bindings-typescript/src/lib/type_builders.ts index 180ae67a5ae..791169b6700 100644 --- a/crates/bindings-typescript/src/lib/type_builders.ts +++ b/crates/bindings-typescript/src/lib/type_builders.ts @@ -1345,56 +1345,57 @@ class SumBuilderImpl extends TypeBuilder< this.variants = variants; this.typeName = name; - // // ---- Runtime unit detection ---- - // // Adjust this to your real shape if needed. - // // From your code, you have `value.algebraicType` available. - // function isUnitRuntime(v: TypeBuilder): boolean { - // const t = v.algebraicType; - // return t.tag === 'Product' && t.value.elements.length === 0; - // } - - // for (const key of Object.keys(variants) as Array) { - // const desc = Object.getOwnPropertyDescriptor(variants, key); - - // const isAccessor = - // !!desc && (typeof desc.get === 'function' || typeof desc.set === 'function'); - - // let isUnit = false; - - // if (!isAccessor) { - // // Only read variants[key] if it's a *data* property - // // otherwise assume non-unit because it's a getter - // const variant = variants[key]; - // isUnit = isUnitRuntime(variant); - // } - - // if (isUnit) { - // // Unit: expose a read-only VALUE (no call) - // const constant = this.create(key as any) as EnumValue< - // typeof key, - // Variants[typeof key] - // >; - // Object.defineProperty(this, key, { - // value: constant, - // writable: false, - // enumerable: true, - // configurable: false, - // }); - // } else { - // const fn = ((value: any) => - // this.create(key as any, value)) as VariantConstructor< - // typeof key & string, - // Variants[typeof key] - // >; - - // Object.defineProperty(this, key, { - // value: fn, - // writable: false, - // enumerable: true, - // configurable: false, - // }); - // } - // } + // ---- Runtime unit detection ---- + // Adjust this to your real shape if needed. + // From your code, you have `value.algebraicType` available. + function isUnitRuntime(v: TypeBuilder): boolean { + const t = v.algebraicType; + return t.tag === 'Product' && t.value.elements.length === 0; + } + + for (const key of Object.keys(variants) as Array) { + const desc = Object.getOwnPropertyDescriptor(variants, key); + + const isAccessor = + !!desc && + (typeof desc.get === 'function' || typeof desc.set === 'function'); + + let isUnit = false; + + if (!isAccessor) { + // Only read variants[key] if it's a *data* property + // otherwise assume non-unit because it's a getter + const variant = variants[key]; + isUnit = isUnitRuntime(variant); + } + + if (isUnit) { + // Unit: expose a read-only VALUE (no call) + const constant = this.create(key as any) as EnumValue< + typeof key, + Variants[typeof key] + >; + Object.defineProperty(this, key, { + value: constant, + writable: false, + enumerable: true, + configurable: false, + }); + } else { + const fn = ((value: any) => + this.create(key as any, value)) as VariantConstructor< + typeof key & string, + Variants[typeof key] + >; + + Object.defineProperty(this, key, { + value: fn, + writable: false, + enumerable: true, + configurable: false, + }); + } + } } /** diff --git a/crates/bindings-typescript/tests/binary_read_write.test.ts b/crates/bindings-typescript/tests/binary_read_write.test.ts index 77a9b024f4c..a4dde2aa0aa 100644 --- a/crates/bindings-typescript/tests/binary_read_write.test.ts +++ b/crates/bindings-typescript/tests/binary_read_write.test.ts @@ -131,22 +131,22 @@ describe('BinaryReader/Writer', () => { username: 'sally', }; const binary = [...encodeUser(user1)].concat([...encodeUser(user2)]); - const transactionUpdate = ServerMessage.create('TransactionUpdate', { - status: UpdateStatus.create('Committed', { + const transactionUpdate = ServerMessage.TransactionUpdate({ + status: UpdateStatus.Committed({ tables: [ { tableId: 35, tableName: 'user', numRows: BigInt(1), updates: [ - CompressableQueryUpdate.create('Uncompressed', { + CompressableQueryUpdate.Uncompressed({ deletes: { - sizeHint: RowSizeHint.create('FixedSize', 0), // not used + sizeHint: RowSizeHint.FixedSize(0), // not used rowsData: new Uint8Array([]), }, // FIXME: this test is evil: an initial subscription can never contain deletes or updates. inserts: { - sizeHint: RowSizeHint.create('FixedSize', 0), // not used + sizeHint: RowSizeHint.FixedSize(0), // not used rowsData: new Uint8Array(binary), }, }), From efdddc37c6feeecb670450e1c20ccaa073057174 Mon Sep 17 00:00:00 2001 From: = Date: Fri, 14 Nov 2025 12:41:05 -0500 Subject: [PATCH 44/49] Regenerated bindings --- .../examples/basic-react/src/module_bindings/index.ts | 4 ++-- .../examples/empty/src/module_bindings/index.ts | 4 ++-- .../examples/quickstart-chat/src/module_bindings/index.ts | 4 ++-- crates/bindings-typescript/src/sdk/client_api/index.ts | 4 ++-- .../bindings-typescript/test-app/src/module_bindings/index.ts | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/crates/bindings-typescript/examples/basic-react/src/module_bindings/index.ts b/crates/bindings-typescript/examples/basic-react/src/module_bindings/index.ts index 8dccaeb0421..76310c73395 100644 --- a/crates/bindings-typescript/examples/basic-react/src/module_bindings/index.ts +++ b/crates/bindings-typescript/examples/basic-react/src/module_bindings/index.ts @@ -1,7 +1,7 @@ // THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE // WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. -// This was generated using spacetimedb cli version 1.7.0 (commit fe91e78ecbfb9714b563a08a5290db6a780f1bc3). +// This was generated using spacetimedb cli version 1.8.0 (commit 3f1ec77822a11345de517e72dbcefe06cc9277d4). /* eslint-disable */ /* tslint:disable */ @@ -68,7 +68,7 @@ const reducersSchema = __reducers( const REMOTE_MODULE = { versionInfo: { - cliVersion: '1.7.0' as const, + cliVersion: '1.8.0' as const, }, tables: tablesSchema.schemaType.tables, reducers: reducersSchema.reducersType.reducers, diff --git a/crates/bindings-typescript/examples/empty/src/module_bindings/index.ts b/crates/bindings-typescript/examples/empty/src/module_bindings/index.ts index 8dccaeb0421..76310c73395 100644 --- a/crates/bindings-typescript/examples/empty/src/module_bindings/index.ts +++ b/crates/bindings-typescript/examples/empty/src/module_bindings/index.ts @@ -1,7 +1,7 @@ // THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE // WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. -// This was generated using spacetimedb cli version 1.7.0 (commit fe91e78ecbfb9714b563a08a5290db6a780f1bc3). +// This was generated using spacetimedb cli version 1.8.0 (commit 3f1ec77822a11345de517e72dbcefe06cc9277d4). /* eslint-disable */ /* tslint:disable */ @@ -68,7 +68,7 @@ const reducersSchema = __reducers( const REMOTE_MODULE = { versionInfo: { - cliVersion: '1.7.0' as const, + cliVersion: '1.8.0' as const, }, tables: tablesSchema.schemaType.tables, reducers: reducersSchema.reducersType.reducers, diff --git a/crates/bindings-typescript/examples/quickstart-chat/src/module_bindings/index.ts b/crates/bindings-typescript/examples/quickstart-chat/src/module_bindings/index.ts index c7e54e38d83..54c2f50c27a 100644 --- a/crates/bindings-typescript/examples/quickstart-chat/src/module_bindings/index.ts +++ b/crates/bindings-typescript/examples/quickstart-chat/src/module_bindings/index.ts @@ -1,7 +1,7 @@ // THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE // WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. -// This was generated using spacetimedb cli version 1.7.0 (commit fe91e78ecbfb9714b563a08a5290db6a780f1bc3). +// This was generated using spacetimedb cli version 1.8.0 (commit 3f1ec77822a11345de517e72dbcefe06cc9277d4). /* eslint-disable */ /* tslint:disable */ @@ -83,7 +83,7 @@ const reducersSchema = __reducers( const REMOTE_MODULE = { versionInfo: { - cliVersion: '1.7.0' as const, + cliVersion: '1.8.0' as const, }, tables: tablesSchema.schemaType.tables, reducers: reducersSchema.reducersType.reducers, diff --git a/crates/bindings-typescript/src/sdk/client_api/index.ts b/crates/bindings-typescript/src/sdk/client_api/index.ts index 54996337bfe..44df46a6154 100644 --- a/crates/bindings-typescript/src/sdk/client_api/index.ts +++ b/crates/bindings-typescript/src/sdk/client_api/index.ts @@ -1,7 +1,7 @@ // THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE // WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. -// This was generated using spacetimedb cli version 1.7.0 (commit fe91e78ecbfb9714b563a08a5290db6a780f1bc3). +// This was generated using spacetimedb cli version 1.8.0 (commit 3f1ec77822a11345de517e72dbcefe06cc9277d4). /* eslint-disable */ /* tslint:disable */ @@ -107,7 +107,7 @@ const reducersSchema = __reducers(); const REMOTE_MODULE = { versionInfo: { - cliVersion: '1.7.0' as const, + cliVersion: '1.8.0' as const, }, tables: tablesSchema.schemaType.tables, reducers: reducersSchema.reducersType.reducers, diff --git a/crates/bindings-typescript/test-app/src/module_bindings/index.ts b/crates/bindings-typescript/test-app/src/module_bindings/index.ts index fd80b80658c..6937e805325 100644 --- a/crates/bindings-typescript/test-app/src/module_bindings/index.ts +++ b/crates/bindings-typescript/test-app/src/module_bindings/index.ts @@ -1,7 +1,7 @@ // THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE // WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. -// This was generated using spacetimedb cli version 1.7.0 (commit fe91e78ecbfb9714b563a08a5290db6a780f1bc3). +// This was generated using spacetimedb cli version 1.8.0 (commit 3f1ec77822a11345de517e72dbcefe06cc9277d4). /* eslint-disable */ /* tslint:disable */ @@ -98,7 +98,7 @@ const reducersSchema = __reducers( const REMOTE_MODULE = { versionInfo: { - cliVersion: '1.7.0' as const, + cliVersion: '1.8.0' as const, }, tables: tablesSchema.schemaType.tables, reducers: reducersSchema.reducersType.reducers, From 903f3a8942b508a1199c388e77811b27d413255f Mon Sep 17 00:00:00 2001 From: = Date: Fri, 14 Nov 2025 12:56:49 -0500 Subject: [PATCH 45/49] cargo insta review --- crates/codegen/tests/snapshots/codegen__codegen_typescript.snap | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/codegen/tests/snapshots/codegen__codegen_typescript.snap b/crates/codegen/tests/snapshots/codegen__codegen_typescript.snap index 6315fbf26a5..dbfa3cf1f33 100644 --- a/crates/codegen/tests/snapshots/codegen__codegen_typescript.snap +++ b/crates/codegen/tests/snapshots/codegen__codegen_typescript.snap @@ -494,7 +494,7 @@ const reducersSchema = __reducers( const REMOTE_MODULE = { versionInfo: { - cliVersion: "1.7.0" as const, + cliVersion: "1.8.0" as const, }, tables: tablesSchema.schemaType.tables, reducers: reducersSchema.reducersType.reducers, From 0527836c24e8dd813d514d3ccdd4fd316e42babf Mon Sep 17 00:00:00 2001 From: = Date: Sat, 15 Nov 2025 18:00:58 -0500 Subject: [PATCH 46/49] Hopefully fix tests --- crates/bindings-typescript/src/lib/reducers.ts | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/crates/bindings-typescript/src/lib/reducers.ts b/crates/bindings-typescript/src/lib/reducers.ts index c7ec2b06aba..fad36d108f7 100644 --- a/crates/bindings-typescript/src/lib/reducers.ts +++ b/crates/bindings-typescript/src/lib/reducers.ts @@ -6,7 +6,11 @@ import type { Identity } from './identity'; import type { Timestamp } from './timestamp'; import type { UntypedReducersDef } from '../sdk/reducers'; import type { DbView } from '../server/db_view'; -import { MODULE_DEF, type UntypedSchemaDef } from './schema'; +import { + MODULE_DEF, + registerTypesRecursively, + type UntypedSchemaDef, +} from './schema'; import { ColumnBuilder, RowBuilder, @@ -136,6 +140,12 @@ export function pushReducer( } existingReducers.add(name); + if (!(params instanceof RowBuilder)) { + params = new RowBuilder(params); + } + + registerTypesRecursively(params); + const paramType: ProductType = { elements: Object.entries(params).map(([n, c]) => ({ name: n, From db58418a769b1fc91b9c703471aed6c1d678b3b0 Mon Sep 17 00:00:00 2001 From: = Date: Sat, 15 Nov 2025 21:05:57 -0500 Subject: [PATCH 47/49] Somethin still ain'r raight --- .../bindings-typescript/src/lib/reducers.ts | 18 +++---- crates/bindings-typescript/src/lib/schema.ts | 49 ++++++++++++++----- crates/bindings-typescript/src/lib/table.ts | 5 ++ .../src/lib/type_builders.ts | 6 +-- crates/bindings-typescript/src/lib/views.ts | 33 +++++++++++-- 5 files changed, 84 insertions(+), 27 deletions(-) diff --git a/crates/bindings-typescript/src/lib/reducers.ts b/crates/bindings-typescript/src/lib/reducers.ts index fad36d108f7..bf8d0822483 100644 --- a/crates/bindings-typescript/src/lib/reducers.ts +++ b/crates/bindings-typescript/src/lib/reducers.ts @@ -1,4 +1,4 @@ -import type { ProductType } from './algebraic_type'; +import { AlgebraicType, type ProductType } from './algebraic_type'; import Lifecycle from './autogen/lifecycle_type'; import type RawReducerDefV9 from './autogen/raw_reducer_def_v_9_type'; import type { ConnectionId } from './connection_id'; @@ -9,6 +9,7 @@ import type { DbView } from '../server/db_view'; import { MODULE_DEF, registerTypesRecursively, + resolveType, type UntypedSchemaDef, } from './schema'; import { @@ -20,7 +21,7 @@ import { type TypeBuilder, } from './type_builders'; import type { ReducerSchema } from './reducer_schema'; -import { toCamelCase } from './util'; +import { toCamelCase, toPascalCase } from './util'; import type { CamelCase } from './type_util'; /** @@ -144,18 +145,15 @@ export function pushReducer( params = new RowBuilder(params); } - registerTypesRecursively(params); + if (params.typeName === undefined) { + params.typeName = toPascalCase(name); + } - const paramType: ProductType = { - elements: Object.entries(params).map(([n, c]) => ({ - name: n, - algebraicType: c.algebraicType, - })), - }; + registerTypesRecursively(params); MODULE_DEF.reducers.push({ name, - params: paramType, + params: params.algebraicType.value, lifecycle, // <- lifecycle flag lands here }); diff --git a/crates/bindings-typescript/src/lib/schema.ts b/crates/bindings-typescript/src/lib/schema.ts index e5b7abf149e..8d523b53fe9 100644 --- a/crates/bindings-typescript/src/lib/schema.ts +++ b/crates/bindings-typescript/src/lib/schema.ts @@ -1,17 +1,19 @@ import type RawTableDefV9 from './autogen/raw_table_def_v_9_type'; import type Typespace from './autogen/typespace_type'; import { + ArrayBuilder, // eslint-disable-next-line @typescript-eslint/no-unused-vars ColumnBuilder, + OptionBuilder, ProductBuilder, RefBuilder, RowBuilder, SumBuilder, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + TypeBuilder, type ElementsObj, type Infer, type RowObj, - // eslint-disable-next-line @typescript-eslint/no-unused-vars - type TypeBuilder, type VariantsObj, } from './type_builders'; import type { UntypedTableDef } from './table'; @@ -32,7 +34,7 @@ import { import type RawScopedTypeNameV9 from './autogen/raw_scoped_type_name_v_9_type'; import type { CamelCase } from './type_util'; import type { TableSchema } from './table_schema'; -import { toCamelCase } from './util'; +import { toCamelCase, toPascalCase } from './util'; import { defineView, type AnonymousViewFn, @@ -187,7 +189,30 @@ export function registerTypesRecursively( | RowBuilder ): RefBuilder { const ty = typeBuilder.algebraicType; - const name = typeBuilder.typeName; + // NB! You must ensure that all TypeBuilder passed into this function + // have a name. This function ensures that nested types always have a + // name by assigning them one if they are missing it. + let name = typeBuilder.typeName; + if (name === undefined) { + if (typeBuilder instanceof RowBuilder) { + throw new Error( + `Missing type name for RowBuilder ${JSON.stringify(typeBuilder)}` + ); + } + if (typeBuilder instanceof ProductBuilder) { + throw new Error( + `Missing type name for ProductBuilder ${JSON.stringify(typeBuilder)}` + ); + } + if (typeBuilder instanceof SumBuilder) { + throw new Error( + `Missing type name for SumBuilder ${JSON.stringify(typeBuilder)}` + ); + } + throw new Error( + `Missing type name for TypeBuilder ${JSON.stringify(typeBuilder)}` + ); + } let r = COMPOUND_TYPES.get(ty); if (r != null) { @@ -207,6 +232,9 @@ export function registerTypesRecursively( ) { continue; } + if (elem instanceof RowBuilder && !elem.typeName) { + throw new Error(`Missing type name for nested RowBuilder ${name}`); + } typeBuilder.row[name] = new ColumnBuilder( registerTypesRecursively(elem), {} @@ -240,17 +268,16 @@ export function registerTypesRecursively( } } - // Add to typespace and return a Ref type r = new RefBuilder(MODULE_DEF.typespace.types.length); MODULE_DEF.typespace.types.push(ty); COMPOUND_TYPES.set(ty, r); - if (name !== undefined) - MODULE_DEF.types.push({ - name: splitName(name), - ty: r.ref, - customOrdering: true, - }); + MODULE_DEF.types.push({ + name: splitName(name), + ty: r.ref, + customOrdering: true, + }); + return r; } diff --git a/crates/bindings-typescript/src/lib/table.ts b/crates/bindings-typescript/src/lib/table.ts index e2aa54a42e2..ae166467c9a 100644 --- a/crates/bindings-typescript/src/lib/table.ts +++ b/crates/bindings-typescript/src/lib/table.ts @@ -29,6 +29,7 @@ import { type TypeBuilder, } from './type_builders'; import type { Prettify } from './type_util'; +import { toPascalCase } from './util'; export type AlgebraicTypeRef = number; type ColId = number; @@ -226,6 +227,10 @@ export function table>( row = new RowBuilder(row); } + if (row.typeName === undefined) { + row.typeName = toPascalCase(name); + } + const rowTypeRef = registerTypesRecursively(row); row.algebraicType.value.elements.forEach((elem, i) => { diff --git a/crates/bindings-typescript/src/lib/type_builders.ts b/crates/bindings-typescript/src/lib/type_builders.ts index 791169b6700..b4d2ac5552d 100644 --- a/crates/bindings-typescript/src/lib/type_builders.ts +++ b/crates/bindings-typescript/src/lib/type_builders.ts @@ -1143,7 +1143,7 @@ export class ArrayBuilder> /** * The phantom element type of the array for TypeScript */ - readonly element!: Element; + element!: Element; constructor(element: Element) { super(AlgebraicType.Array(element.algebraicType)); @@ -1194,7 +1194,7 @@ export class OptionBuilder> /** * The phantom value type of the option for TypeScript */ - readonly value!: Value; + value!: Value; constructor(value: Value) { let innerType: InferSpacetimeTypeOfTypeBuilder; @@ -1275,7 +1275,7 @@ export class RowBuilder extends TypeBuilder< } > { readonly row: CoerceRow; - readonly typeName: string | undefined; + typeName: string | undefined; constructor(row: Row, name?: string) { const mappedRow = Object.fromEntries( Object.entries(row).map(([colName, builder]) => [ diff --git a/crates/bindings-typescript/src/lib/views.ts b/crates/bindings-typescript/src/lib/views.ts index 21900b222e7..e3cc77aa434 100644 --- a/crates/bindings-typescript/src/lib/views.ts +++ b/crates/bindings-typescript/src/lib/views.ts @@ -6,10 +6,22 @@ import { import type { Identity } from '../lib/identity'; import type { OptionAlgebraicType } from '../lib/option'; import type { ParamsObj } from './reducers'; -import { MODULE_DEF, type UntypedSchemaDef } from './schema'; +import { + MODULE_DEF, + registerTypesRecursively, + type UntypedSchemaDef, +} from './schema'; import type { ReadonlyTable } from './table'; -import type { Infer, InferTypeOfRow, TypeBuilder } from './type_builders'; -import { bsatnBaseSize } from './util'; +import { + ArrayBuilder, + OptionBuilder, + ProductBuilder, + RowBuilder, + type Infer, + type InferTypeOfRow, + type TypeBuilder, +} from './type_builders'; +import { bsatnBaseSize, toPascalCase } from './util'; export type ViewCtx = Readonly<{ sender: Identity; @@ -65,6 +77,21 @@ export function defineView< ? AnonymousViewFn : ViewFn ) { + const paramsBuilder = new RowBuilder(params, toPascalCase(opts.name)); + + registerTypesRecursively(paramsBuilder); + + // Register return types if they are product types + if (ret instanceof ArrayBuilder) { + if (ret.element instanceof ProductBuilder) { + ret.element = registerTypesRecursively(ret.element); + } + } else if (ret instanceof OptionBuilder) { + if (ret.value instanceof ProductBuilder) { + ret.value = registerTypesRecursively(ret.value); + } + } + const paramType = { elements: Object.entries(params).map(([n, c]) => ({ name: n, From 7511d339e435eee96ee279861e6f8c2512f4e875 Mon Sep 17 00:00:00 2001 From: Noa Date: Mon, 17 Nov 2025 16:56:56 -0600 Subject: [PATCH 48/49] Fix errors --- .../bindings-typescript/src/lib/reducers.ts | 7 +- crates/bindings-typescript/src/lib/schema.ts | 134 +++++++++--------- crates/bindings-typescript/src/lib/table.ts | 23 +-- .../src/lib/type_builders.ts | 60 ++++---- crates/bindings-typescript/src/lib/views.ts | 30 +--- 5 files changed, 114 insertions(+), 140 deletions(-) diff --git a/crates/bindings-typescript/src/lib/reducers.ts b/crates/bindings-typescript/src/lib/reducers.ts index bf8d0822483..70342997532 100644 --- a/crates/bindings-typescript/src/lib/reducers.ts +++ b/crates/bindings-typescript/src/lib/reducers.ts @@ -1,4 +1,4 @@ -import { AlgebraicType, type ProductType } from './algebraic_type'; +import { ProductType } from './algebraic_type'; import Lifecycle from './autogen/lifecycle_type'; import type RawReducerDefV9 from './autogen/raw_reducer_def_v_9_type'; import type { ConnectionId } from './connection_id'; @@ -149,11 +149,12 @@ export function pushReducer( params.typeName = toPascalCase(name); } - registerTypesRecursively(params); + const ref = registerTypesRecursively(params); + const paramsType = resolveType(MODULE_DEF.typespace, ref).value; MODULE_DEF.reducers.push({ name, - params: params.algebraicType.value, + params: paramsType, lifecycle, // <- lifecycle flag lands here }); diff --git a/crates/bindings-typescript/src/lib/schema.ts b/crates/bindings-typescript/src/lib/schema.ts index 8d523b53fe9..07c1b513d84 100644 --- a/crates/bindings-typescript/src/lib/schema.ts +++ b/crates/bindings-typescript/src/lib/schema.ts @@ -13,6 +13,7 @@ import { TypeBuilder, type ElementsObj, type Infer, + type InferSpacetimeTypeOfTypeBuilder, type RowObj, type VariantsObj, } from './type_builders'; @@ -28,13 +29,15 @@ import { import type RawModuleDefV9 from './autogen/raw_module_def_v_9_type'; import { AlgebraicType, + ProductType, + SumType, type AlgebraicTypeType, type AlgebraicTypeVariants, } from './algebraic_type'; import type RawScopedTypeNameV9 from './autogen/raw_scoped_type_name_v_9_type'; import type { CamelCase } from './type_util'; import type { TableSchema } from './table_schema'; -import { toCamelCase, toPascalCase } from './util'; +import { toCamelCase } from './util'; import { defineView, type AnonymousViewFn, @@ -155,7 +158,7 @@ export const MODULE_DEF: Infer = { const COMPOUND_TYPES = new Map< AlgebraicTypeVariants.Product | AlgebraicTypeVariants.Sum, - RefBuilder + RefBuilder >(); /** @@ -166,7 +169,7 @@ const COMPOUND_TYPES = new Map< */ export function resolveType( typespace: Infer, - typeBuilder: TypeBuilder + typeBuilder: RefBuilder ): AT { let ty: AlgebraicType = typeBuilder.algebraicType; while (ty.tag === 'Ref') { @@ -182,35 +185,46 @@ export function resolveType( * @param ty * @returns */ -export function registerTypesRecursively( - typeBuilder: +export function registerTypesRecursively< + T extends TypeBuilder, +>( + typeBuilder: T +): T extends SumBuilder | ProductBuilder | RowBuilder + ? RefBuilder, InferSpacetimeTypeOfTypeBuilder> + : T { + if ( + (typeBuilder instanceof ProductBuilder && !isUnit(typeBuilder)) || + typeBuilder instanceof SumBuilder || + typeBuilder instanceof RowBuilder + ) { + return registerCompoundTypeRecursively(typeBuilder) as any; + } else if (typeBuilder instanceof OptionBuilder) { + return new OptionBuilder( + registerTypesRecursively(typeBuilder.value) + ) as any; + } else if (typeBuilder instanceof ArrayBuilder) { + return new ArrayBuilder( + registerTypesRecursively(typeBuilder.element) + ) as any; + } else { + return typeBuilder as any; + } +} + +function registerCompoundTypeRecursively< + T extends | SumBuilder | ProductBuilder - | RowBuilder -): RefBuilder { + | RowBuilder, +>(typeBuilder: T): RefBuilder, InferSpacetimeTypeOfTypeBuilder> { const ty = typeBuilder.algebraicType; // NB! You must ensure that all TypeBuilder passed into this function // have a name. This function ensures that nested types always have a // name by assigning them one if they are missing it. - let name = typeBuilder.typeName; + const name = typeBuilder.typeName; if (name === undefined) { - if (typeBuilder instanceof RowBuilder) { - throw new Error( - `Missing type name for RowBuilder ${JSON.stringify(typeBuilder)}` - ); - } - if (typeBuilder instanceof ProductBuilder) { - throw new Error( - `Missing type name for ProductBuilder ${JSON.stringify(typeBuilder)}` - ); - } - if (typeBuilder instanceof SumBuilder) { - throw new Error( - `Missing type name for SumBuilder ${JSON.stringify(typeBuilder)}` - ); - } throw new Error( - `Missing type name for TypeBuilder ${JSON.stringify(typeBuilder)}` + `Missing type name for ${typeBuilder.constructor.name ?? 'TypeBuilder'} ${JSON.stringify(typeBuilder)}` ); } @@ -221,57 +235,42 @@ export function registerTypesRecursively( } // Recursively register nested compound types + const newTy = + typeBuilder instanceof RowBuilder || typeBuilder instanceof ProductBuilder + ? ({ + tag: 'Product', + value: { elements: [] }, + } as AlgebraicTypeVariants.Product) + : ({ tag: 'Sum', value: { variants: [] } } as AlgebraicTypeVariants.Sum); + + r = new RefBuilder(MODULE_DEF.typespace.types.length); + MODULE_DEF.typespace.types.push(newTy); + + COMPOUND_TYPES.set(ty, r); + if (typeBuilder instanceof RowBuilder) { for (const [name, elem] of Object.entries(typeBuilder.row)) { - if ( - !( - elem instanceof ProductBuilder || - elem instanceof SumBuilder || - elem instanceof RowBuilder - ) - ) { - continue; - } - if (elem instanceof RowBuilder && !elem.typeName) { - throw new Error(`Missing type name for nested RowBuilder ${name}`); - } - typeBuilder.row[name] = new ColumnBuilder( - registerTypesRecursively(elem), - {} - ); + (newTy.value as ProductType).elements.push({ + name, + algebraicType: registerTypesRecursively(elem.typeBuilder).algebraicType, + }); } } else if (typeBuilder instanceof ProductBuilder) { for (const [name, elem] of Object.entries(typeBuilder.elements)) { - if ( - !( - elem instanceof ProductBuilder || - elem instanceof SumBuilder || - elem instanceof RowBuilder - ) - ) { - continue; - } - typeBuilder.elements[name] = registerTypesRecursively(elem); + (newTy.value as ProductType).elements.push({ + name, + algebraicType: registerTypesRecursively(elem).algebraicType, + }); } } else if (typeBuilder instanceof SumBuilder) { for (const [name, variant] of Object.entries(typeBuilder.variants)) { - if ( - !( - variant instanceof ProductBuilder || - variant instanceof SumBuilder || - variant instanceof RowBuilder - ) - ) { - continue; - } - typeBuilder.variants[name] = registerTypesRecursively(variant); + (newTy.value as SumType).variants.push({ + name, + algebraicType: registerTypesRecursively(variant).algebraicType, + }); } } - r = new RefBuilder(MODULE_DEF.typespace.types.length); - MODULE_DEF.typespace.types.push(ty); - - COMPOUND_TYPES.set(ty, r); MODULE_DEF.types.push({ name: splitName(name), ty: r.ref, @@ -281,6 +280,13 @@ export function registerTypesRecursively( return r; } +function isUnit(typeBuilder: ProductBuilder): boolean { + return ( + typeBuilder.typeName == null && + typeBuilder.algebraicType.value.elements.length === 0 + ); +} + export function splitName(name: string): Infer { const scope = name.split('.'); return { name: scope.pop()!, scope }; diff --git a/crates/bindings-typescript/src/lib/table.ts b/crates/bindings-typescript/src/lib/table.ts index ae166467c9a..803f1585851 100644 --- a/crates/bindings-typescript/src/lib/table.ts +++ b/crates/bindings-typescript/src/lib/table.ts @@ -12,12 +12,7 @@ import type { IndexOpts, ReadonlyIndexes, } from './indexes'; -import { - registerTypesRecursively, - MODULE_DEF, - resolveType, - splitName, -} from './schema'; +import { registerTypesRecursively } from './schema'; import type { TableSchema } from './table_schema'; import { RowBuilder, @@ -365,20 +360,10 @@ export function table>( tableAccess: { tag: isPublic ? 'Public' : 'Private' }, }; - if (row.typeName === undefined) { - MODULE_DEF.types.push({ - customOrdering: true, - name: splitName(name), - ty: rowTypeRef.ref, - }); - } - const productType = { - elements: resolveType(MODULE_DEF.typespace, row).value.elements.map( - elem => { - return { name: elem.name, algebraicType: elem.algebraicType }; - } - ), + elements: row.algebraicType.value.elements.map(elem => { + return { name: elem.name, algebraicType: elem.algebraicType }; + }), }; return { diff --git a/crates/bindings-typescript/src/lib/type_builders.ts b/crates/bindings-typescript/src/lib/type_builders.ts index b4d2ac5552d..77246981264 100644 --- a/crates/bindings-typescript/src/lib/type_builders.ts +++ b/crates/bindings-typescript/src/lib/type_builders.ts @@ -109,7 +109,6 @@ type ObjectType = { }; export type VariantsObj = Record>; -type UnitBuilder = ProductBuilder<{}>; type SimpleVariantsObj = Record; type IsUnit = B extends UnitBuilder ? true : false; @@ -1140,13 +1139,11 @@ export class ArrayBuilder> > implements Defaultable>, any> { - /** - * The phantom element type of the array for TypeScript - */ - element!: Element; + element: Element; constructor(element: Element) { super(AlgebraicType.Array(element.algebraicType)); + this.element = element; } default( value: Array> @@ -1191,19 +1188,11 @@ export class OptionBuilder> OptionAlgebraicType> > { - /** - * The phantom value type of the option for TypeScript - */ - value!: Value; + value: Value; constructor(value: Value) { - let innerType: InferSpacetimeTypeOfTypeBuilder; - if (value instanceof ColumnBuilder) { - innerType = value.typeBuilder.algebraicType; - } else { - innerType = value.algebraicType; - } - super(Option.getAlgebraicType(innerType)); + super(Option.getAlgebraicType(value.algebraicType)); + this.value = value; } default( value: InferTypeOfTypeBuilder | undefined @@ -1267,6 +1256,15 @@ export class ProductBuilder } } +class UnitBuilder extends TypeBuilder< + {}, + { tag: 'Product'; value: { elements: [] } } +> { + constructor() { + super({ tag: 'Product', value: { elements: [] } }); + } +} + export class RowBuilder extends TypeBuilder< RowType, { @@ -1286,9 +1284,11 @@ export class RowBuilder extends TypeBuilder< ]) ) as CoerceRow; - const elements = Object.entries(mappedRow).map(([name, builder]) => ({ + const elements = Object.keys(mappedRow).map(name => ({ name, - algebraicType: builder.typeBuilder.algebraicType, + get algebraicType() { + return mappedRow[name].typeBuilder.algebraicType; + }, })); super(AlgebraicType.Product({ elements })); @@ -1345,14 +1345,6 @@ class SumBuilderImpl extends TypeBuilder< this.variants = variants; this.typeName = name; - // ---- Runtime unit detection ---- - // Adjust this to your real shape if needed. - // From your code, you have `value.algebraicType` available. - function isUnitRuntime(v: TypeBuilder): boolean { - const t = v.algebraicType; - return t.tag === 'Product' && t.value.elements.length === 0; - } - for (const key of Object.keys(variants) as Array) { const desc = Object.getOwnPropertyDescriptor(variants, key); @@ -1366,7 +1358,7 @@ class SumBuilderImpl extends TypeBuilder< // Only read variants[key] if it's a *data* property // otherwise assume non-unit because it's a getter const variant = variants[key]; - isUnit = isUnitRuntime(variant); + isUnit = variant instanceof UnitBuilder; } if (isUnit) { @@ -1431,7 +1423,8 @@ export const SumBuilder: { new ( variants: Variants, name?: string - ): SumBuilderImpl & SumBuilderVariantConstructors; + ): SumBuilder; + [Symbol.hasInstance](x: any): x is SumBuilder; } = SumBuilderImpl as any; class SimpleSumBuilderImpl @@ -2910,8 +2903,13 @@ export class TimeDurationColumnBuilder< } } -export class RefBuilder extends TypeBuilder { +export class RefBuilder extends TypeBuilder< + Type, + AlgebraicTypeVariants.Ref +> { readonly ref: number; + /** The phantom type of the pointee of this ref. */ + private readonly __spacetimeType!: SpacetimeType; constructor(ref: number) { super(AlgebraicType.Ref(ref)); this.ref = ref; @@ -2973,7 +2971,7 @@ const enumImpl = ((nameOrObj: any, maybeObj?: any) => { if (Array.isArray(obj)) { const simpleVariantsObj: Record = {}; for (const variant of obj) { - simpleVariantsObj[variant] = new ProductBuilder({}); + simpleVariantsObj[variant] = new UnitBuilder(); } return new SimpleSumBuilderImpl(simpleVariantsObj, name); } @@ -3196,7 +3194,7 @@ export const t = { * @returns A new {@link ProductBuilder} instance with no fields. */ unit(): UnitBuilder { - return new ProductBuilder({}); + return new UnitBuilder(); }, /** diff --git a/crates/bindings-typescript/src/lib/views.ts b/crates/bindings-typescript/src/lib/views.ts index e3cc77aa434..862037392db 100644 --- a/crates/bindings-typescript/src/lib/views.ts +++ b/crates/bindings-typescript/src/lib/views.ts @@ -9,13 +9,11 @@ import type { ParamsObj } from './reducers'; import { MODULE_DEF, registerTypesRecursively, + resolveType, type UntypedSchemaDef, } from './schema'; import type { ReadonlyTable } from './table'; import { - ArrayBuilder, - OptionBuilder, - ProductBuilder, RowBuilder, type Infer, type InferTypeOfRow, @@ -79,26 +77,13 @@ export function defineView< ) { const paramsBuilder = new RowBuilder(params, toPascalCase(opts.name)); - registerTypesRecursively(paramsBuilder); - // Register return types if they are product types - if (ret instanceof ArrayBuilder) { - if (ret.element instanceof ProductBuilder) { - ret.element = registerTypesRecursively(ret.element); - } - } else if (ret instanceof OptionBuilder) { - if (ret.value instanceof ProductBuilder) { - ret.value = registerTypesRecursively(ret.value); - } - } + let returnType = registerTypesRecursively(ret).algebraicType; - const paramType = { - elements: Object.entries(params).map(([n, c]) => ({ - name: n, - algebraicType: - 'typeBuilder' in c ? c.typeBuilder.algebraicType : c.algebraicType, - })), - }; + const { value: paramType } = resolveType( + MODULE_DEF.typespace, + registerTypesRecursively(paramsBuilder) + ); MODULE_DEF.miscExports.push({ tag: 'View', @@ -108,11 +93,10 @@ export function defineView< isPublic: opts.public, isAnonymous: anon, params: paramType, - returnType: ret.algebraicType, + returnType, }, }); - let returnType = ret.algebraicType; if (returnType.tag == 'Sum') { const originalFn = fn; fn = ((ctx: ViewCtx, args: InferTypeOfRow) => { From 178b1bbaaff7821df15f0a7ee598ec29ae01d932 Mon Sep 17 00:00:00 2001 From: Tyler Cloutier Date: Mon, 17 Nov 2025 22:48:28 -0500 Subject: [PATCH 49/49] typo --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e9d13f72335..64fa9419780 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ "format": "pnpm --filter ./crates/bindings-typescript run format && pnpm --filter ./docs run format && pnpm --filter ./crates/bindings-typescript/examples/quickstart-chat run format && pnpm --filter ./crates/bindings-typescript/test-app run format", "lint": "pnpm --filter ./crates/bindings-typescript run lint && pnpm --filter ./docs run lint && pnpm --filter ./crates/bindings-typescript/examples/quickstart-chat run lint && pnpm --filter ./crates/bindings-typescript/test-app run lint", "build": "pnpm --filter ./crates/bindings-typescript run build && pnpm --filter ./docs run build && pnpm --filter ./crates/bindings-typescript/examples/quickstart-chat run build && pnpm --filter ./crates/bindings-typescript/test-app run build", - "test": "pnpm --filter ./crates/bindings-typescript run test && pnpm --filter ./docs run test && && pnpm --filter ./crates/bindings-typescript/examples/quickstart-chat run test && pnpm --filter ./crates/bindings-typescript/test-app run test", + "test": "pnpm --filter ./crates/bindings-typescript run test && pnpm --filter ./docs run test && pnpm --filter ./crates/bindings-typescript/examples/quickstart-chat run test && pnpm --filter ./crates/bindings-typescript/test-app run test", "generate": "pnpm --filter ./crates/bindings-typescript run generate && pnpm --filter ./docs run generate && pnpm --filter ./crates/bindings-typescript/examples/quickstart-chat run generate && pnpm --filter ./crates/bindings-typescript/test-app run generate", "clean": "pnpm -r exec rimraf dist .tsbuildinfo coverage" },