@@ -10,6 +10,7 @@ import {
1010import {
1111 RawModuleDef ,
1212 ViewResultHeader ,
13+ type RawReducerDefV10 ,
1314 type RawTableDefV10 ,
1415 type Typespace ,
1516} from '../lib/autogen/types' ;
@@ -27,6 +28,7 @@ import {
2728 type UniqueIndex ,
2829} from '../lib/indexes' ;
2930import { callProcedure } from './procedures' ;
31+ import type { Reducers } from './reducers' ;
3032import {
3133 type AuthCtx ,
3234 type JsonObject ,
@@ -42,7 +44,7 @@ import type { DbView } from './db_view';
4244import { getErrorConstructor , SenderError } from './errors' ;
4345import { Range , type Bound } from './range' ;
4446import { makeRandom , type Random } from './rng' ;
45- import type { SchemaInner } from './schema' ;
47+ import type { MountedDispatchInfo , SchemaInner } from './schema' ;
4648
4749const { freeze } = Object ;
4850
@@ -212,13 +214,17 @@ export const ReducerCtxImpl = class ReducerCtx<
212214 me : InstanceType < typeof this > ,
213215 sender : Identity ,
214216 timestamp : Timestamp ,
215- connectionId : ConnectionId | null
217+ connectionId : ConnectionId | null ,
218+ dbView ?: DbView < any >
216219 ) {
217220 me . sender = sender ;
218221 me . timestamp = timestamp ;
219222 me . connectionId = connectionId ;
220223 me . #uuidCounter = undefined ;
221224 me . #senderAuth = undefined ;
225+ if ( dbView !== undefined ) {
226+ me . db = dbView ;
227+ }
222228 }
223229
224230 get databaseIdentity ( ) {
@@ -272,21 +278,55 @@ export const callUserFunction = function __spacetimedb_end_short_backtrace<
272278 return fn ( ...args ) ;
273279} ;
274280
281+ type FlatMountDispatch = {
282+ reducerFns : Reducers ;
283+ reducerDefs : RawReducerDefV10 [ ] ;
284+ tables : Array < { accessorName : string ; tableDef : RawTableDefV10 } > ;
285+ typespace : Typespace ;
286+ dbView_ : DbView < any > | undefined ;
287+ } ;
288+
289+ function flattenMountDispatches (
290+ dispatches : MountedDispatchInfo [ ]
291+ ) : FlatMountDispatch [ ] {
292+ const result : FlatMountDispatch [ ] = [ ] ;
293+ for ( const d of dispatches ) {
294+ result . push ( {
295+ reducerFns : d . reducerFns ,
296+ reducerDefs : d . reducerDefs ,
297+ tables : d . tables ,
298+ typespace : d . typespace ,
299+ dbView_ : undefined ,
300+ } ) ;
301+ result . push ( ...flattenMountDispatches ( d . subDispatches ) ) ;
302+ }
303+ return result ;
304+ }
305+
275306export const makeHooks = ( schema : SchemaInner ) : ModuleHooks =>
276307 new ModuleHooksImpl ( schema ) ;
277308
278309class ModuleHooksImpl implements ModuleHooks {
279310 #schema: SchemaInner ;
280311 #dbView_: DbView < any > | undefined ;
281312 #reducerArgsDeserializers;
282- /** Cache the `ReducerCtx` object to avoid allocating anew for ever reducer call. */
313+ #consumerReducerCount: number ;
314+ #flatMounts: FlatMountDispatch [ ] ;
315+ /** Cache the `ReducerCtx` object to avoid allocating anew for every reducer call. */
283316 #reducerCtx_: InstanceType < typeof ReducerCtxImpl > | undefined ;
284317
285318 constructor ( schema : SchemaInner ) {
286319 this . #schema = schema ;
287- this . #reducerArgsDeserializers = schema . moduleDef . reducers . map (
320+ this . #consumerReducerCount = schema . reducers . length ;
321+ this . #flatMounts = flattenMountDispatches ( schema . mountedDispatchInfos ) ;
322+
323+ const consumerDeserializers = schema . moduleDef . reducers . map (
288324 ( { params } ) => ProductType . makeDeserializer ( params , schema . typespace )
289325 ) ;
326+ const mountedDeserializers = this . #flatMounts. flatMap ( ( { reducerDefs, typespace } ) =>
327+ reducerDefs . map ( ( { params } ) => ProductType . makeDeserializer ( params , typespace ) )
328+ ) ;
329+ this . #reducerArgsDeserializers = [ ...consumerDeserializers , ...mountedDeserializers ] ;
290330 }
291331
292332 get #dbView( ) {
@@ -300,6 +340,18 @@ class ModuleHooksImpl implements ModuleHooks {
300340 ) ) ;
301341 }
302342
343+ #getMountDbView( mountIdx : number ) : DbView < any > {
344+ const m = this . #flatMounts[ mountIdx ] ;
345+ return ( m . dbView_ ??= freeze (
346+ Object . fromEntries (
347+ m . tables . map ( ( { accessorName, tableDef } ) => [
348+ accessorName ,
349+ makeTableView ( m . typespace , tableDef ) ,
350+ ] )
351+ )
352+ ) ) ;
353+ }
354+
303355 get #reducerCtx( ) {
304356 return ( this . #reducerCtx_ ??= new ReducerCtxImpl (
305357 Identity . zero ( ) ,
@@ -333,19 +385,42 @@ class ModuleHooksImpl implements ModuleHooks {
333385 timestamp : bigint ,
334386 argsBuf : DataView
335387 ) : void {
336- const moduleCtx = this . #schema;
337388 const deserializeArgs = this . #reducerArgsDeserializers[ reducerId ] ;
338389 BINARY_READER . reset ( argsBuf ) ;
339390 const args = deserializeArgs ( BINARY_READER ) ;
340391 const senderIdentity = new Identity ( sender ) ;
392+
393+ let fn : ( ( ...args : any [ ] ) => any ) | undefined ;
394+ let dbView : DbView < any > ;
395+
396+ if ( reducerId < this . #consumerReducerCount) {
397+ fn = this . #schema. reducers [ reducerId ] ;
398+ dbView = this . #dbView;
399+ } else {
400+ let offset = this . #consumerReducerCount;
401+ for ( let i = 0 ; i < this . #flatMounts. length ; i ++ ) {
402+ const m = this . #flatMounts[ i ] ;
403+ if ( reducerId < offset + m . reducerFns . length ) {
404+ fn = m . reducerFns [ reducerId - offset ] ;
405+ dbView = this . #getMountDbView( i ) ;
406+ break ;
407+ }
408+ offset += m . reducerFns . length ;
409+ }
410+ if ( fn === undefined ) {
411+ throw new RangeError ( `unknown reducerId ${ reducerId } ` ) ;
412+ }
413+ }
414+
341415 const ctx = this . #reducerCtx;
342416 ReducerCtxImpl . reset (
343417 ctx ,
344418 senderIdentity ,
345419 new Timestamp ( timestamp ) ,
346- ConnectionId . nullIfZero ( new ConnectionId ( connId ) )
420+ ConnectionId . nullIfZero ( new ConnectionId ( connId ) ) ,
421+ dbView !
347422 ) ;
348- callUserFunction ( moduleCtx . reducers [ reducerId ] , ctx , args ) ;
423+ callUserFunction ( fn , ctx , args ) ;
349424 }
350425
351426 __call_view__ (
0 commit comments