diff --git a/crates/bindings-typescript/src/sdk/db_connection_impl.ts b/crates/bindings-typescript/src/sdk/db_connection_impl.ts index c2c26123bfe..ffef108d936 100644 --- a/crates/bindings-typescript/src/sdk/db_connection_impl.ts +++ b/crates/bindings-typescript/src/sdk/db_connection_impl.ts @@ -158,6 +158,10 @@ export class DbConnectionImpl #reducerCallInfo = new Map(); #procedureCallbacks = new Map(); #rowDeserializers: Record>; + #rowIdMetadata: Record< + string, + { primaryKeyColName?: string; primaryKeyColType?: AlgebraicType } + >; #reducerArgsSerializers: Record< string, { serialize: Serializer; deserialize: Deserializer } @@ -205,6 +209,7 @@ export class DbConnectionImpl this.#emitter = emitter; this.#rowDeserializers = Object.create(null); + this.#rowIdMetadata = Object.create(null); this.#sourceNameToTableDef = Object.create(null); for (const table of Object.values(remoteModule.tables)) { this.#rowDeserializers[table.sourceName] = ProductType.makeDeserializer( @@ -213,6 +218,15 @@ export class DbConnectionImpl this.#sourceNameToTableDef[table.sourceName] = table as Values< RemoteModule['tables'] >; + const primaryKeyColumn = Object.entries(table.columns).find( + ([, column]) => column.columnMetadata.isPrimaryKey + ); + this.#rowIdMetadata[table.sourceName] = primaryKeyColumn + ? { + primaryKeyColName: primaryKeyColumn[0], + primaryKeyColType: primaryKeyColumn[1].typeBuilder.algebraicType, + } + : {}; } this.#reducerArgsSerializers = Object.create(null); @@ -302,8 +316,6 @@ export class DbConnectionImpl #makeReducers(def: RemoteModule): ReducersView { const out: Record = {}; - const writer = new BinaryWriter(1024); - for (const reducer of def.reducers) { const reducerName = reducer.name; const key = reducer.accessorName; @@ -312,6 +324,7 @@ export class DbConnectionImpl this.#reducerArgsSerializers[reducerName]; (out as any)[key] = (params: InferTypeOfRow) => { + const writer = this.#reducerArgsEncoder; writer.clear(); serializeArgs(writer, params); const argsBuffer = writer.getBuffer(); @@ -428,20 +441,13 @@ export class DbConnectionImpl const rows: Operation[] = []; const deserializeRow = this.#rowDeserializers[tableName]; - const table = this.#sourceNameToTableDef[tableName]; - // TODO: performance - const columnsArray = Object.entries(table.columns); - const primaryKeyColumnEntry = columnsArray.find( - col => col[1].columnMetadata.isPrimaryKey - ); + const { primaryKeyColName, primaryKeyColType } = + this.#rowIdMetadata[tableName]; let previousOffset = 0; while (reader.remaining > 0) { const row = deserializeRow(reader); let rowId: ComparablePrimitive | undefined = undefined; - if (primaryKeyColumnEntry !== undefined) { - const primaryKeyColName = primaryKeyColumnEntry[0]; - const primaryKeyColType = - primaryKeyColumnEntry[1].typeBuilder.algebraicType; + if (primaryKeyColName !== undefined && primaryKeyColType !== undefined) { rowId = AlgebraicType.intoMapKey( primaryKeyColType, row[primaryKeyColName] @@ -548,6 +554,7 @@ export class DbConnectionImpl } } + #reducerArgsEncoder = new BinaryWriter(1024); #clientMessageEncoder = new BinaryWriter(1024); #sendMessage(message: ClientMessage): void { const writer = this.#clientMessageEncoder; @@ -906,7 +913,8 @@ export class DbConnectionImpl _paramsType: ProductType, params: object ): Promise { - const writer = new BinaryWriter(1024); + const writer = this.#reducerArgsEncoder; + writer.clear(); this.#reducerArgsSerializers[reducerName].serialize(writer, params); const argsBuffer = writer.getBuffer(); return this.callReducer(reducerName, argsBuffer, params); diff --git a/crates/bindings-typescript/src/sdk/table_cache.ts b/crates/bindings-typescript/src/sdk/table_cache.ts index 17ce4b42548..42645daaecf 100644 --- a/crates/bindings-typescript/src/sdk/table_cache.ts +++ b/crates/bindings-typescript/src/sdk/table_cache.ts @@ -66,6 +66,7 @@ export class TableCacheImpl< TableName extends TableNamesOf, > implements ClientTableCoreImplementable { + private readonly hasPrimaryKey: boolean; private rows: Map< ComparablePrimitive, [RowType>, number] @@ -83,6 +84,9 @@ export class TableCacheImpl< this.tableDef = tableDef; this.rows = new Map(); this.emitter = new EventEmitter(); + this.hasPrimaryKey = Object.values(this.tableDef.columns).some( + col => col.columnMetadata.isPrimaryKey === true + ); // Build index views from the resolved runtime index metadata. // // We intentionally use `resolvedIndexes` rather than `indexes`: @@ -281,11 +285,7 @@ export class TableCacheImpl< return pendingCallbacks; } - // TODO: performance - const hasPrimaryKey = Object.values(this.tableDef.columns).some( - col => col.columnMetadata.isPrimaryKey === true - ); - if (hasPrimaryKey) { + if (this.hasPrimaryKey) { const insertMap = new Map< ComparablePrimitive, [