Refactor SQL bulk-put to shared multi-row INSERT engine#654
Merged
Conversation
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011jSSGKf1DQhuF1vK31Jb7u
…mantics Documents the shared BaseSqlTabularStorage bulk-insert engine (one multi-row INSERT ... RETURNING * per chunk) used by the SQLite, Postgres, and DuckDB tabular backends, plus the duplicate-primary-key semantics (last-write-wins, one put event per distinct committed row) now shared by those backends and by the Supabase putBulk dedup fix. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011jSSGKf1DQhuF1vK31Jb7u
…sh docs - resolveBulkAutoKey now strips a client-supplied auto-generated key under clientProvidedKeys 'never' so the server assigns it, matching single-row put - guard runBulkPut against empty input - refresh stale SQLite/Postgres putBulk docstrings (now one multi-row INSERT per chunk, not per-row) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011jSSGKf1DQhuF1vK31Jb7u
…pabaseTabularStorage - Updated the primaryKeyFingerprint method call to explicitly cast the row as Record<string, unknown> for better type safety.
Coverage Report
File Coverage
|
||||||||||||||||||||||||||||||||||||||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Consolidates per-row
INSERTloops in SQLite, Postgres, and DuckDBputBulkimplementations into a shared multi-row bulk-insert engine inBaseSqlTabularStorage. Each chunk now executes as a singleINSERT … VALUES (…),(…),… RETURNING *statement instead of N separate statements, improving throughput while preserving atomicity, ordering, and event semantics.Key Changes
New
BulkPutDialectinterface inBaseSqlTabularStorage: Captures dialect-specific SQL generation (quote character, placeholder format,INSERT INTOclause, conflict handling, UUID minting policy) for the shared engine.Shared bulk-put engine (
runBulkPut,buildBulkPutValues,buildBulkCells,bulkKeyOf,resolveBulkAutoKey):maxBulkParams)aligned(per-input-position) anddistinct(per-committed-row) results for correct event emissionPer-backend dialect implementations:
sqliteBulkDialect()— backtick quotes,?placeholders,INSERT OR REPLACEorON CONFLICTupsert, client-side UUID mintingpostgresBulkDialect()— double-quote quotes,$Nplaceholders,ON CONFLICT … DO UPDATEupsert, server-side UUID defaultsduckdbBulkDialect()— double-quote quotes,$Nplaceholders,ON CONFLICT … DO UPDATEupsert, client-side UUID mintingUpdated
_putBulkInternalimplementations: All three backends now callrunBulkPutwith their dialect, replacing per-row insert loops. Transaction handling (BEGIN/COMMIT/ROLLBACK) and event deferral remain unchanged.New test suite (
genericSqlBulkPutTests): Validates duplicate-key deduplication, event emission (one per distinct row), and all-or-nothing rollback semantics across all SQL backends.Extended generic tests: Added coverage for batches larger than SQL parameter limits, last-write-wins deduplication, and composite key collision avoidance.
Notable Implementation Details
Key matching: Uses
bulkKeyOf()to stringify primary-key columns (afterjsToSqlValueconversion) so returned rows can be matched back to input rows even when the server assigns keys. Keyed batches use a Map; unkeyed batches fall back to response order.Auto-key resolution: Respects
clientProvidedKeyspolicy ("always", "if-missing", "never") andautoGeneratedKeyStrategy("uuid", "integer"). Client-side UUID minting happens here; server-side defaults bindDEFAULTliterals in the VALUES clause.Parameter chunking: Calculates
perRowParamsfrom the first row's column count, then chunks toMath.max(1, Math.floor(maxBulkParams / perRowParams))rows per statement.Atomicity preserved: SQLite uses manual
BEGIN/COMMIT(notdb.transaction(), which requires sync body); Postgres and DuckDB wrap chunks in explicit transactions. Rollback emitsrollbackevent with emptyids(batch fully reverted).Event deferral:
putevents fire only fordistinctrows after all chunks commit, matching single-rowputsemantics.Backward Compatibility
All changes are internal refactors. Public API (
putBulksignature, return type, event semantics) is unchanged. Behavior is identical except:https://claude.ai/code/session_011jSSGKf1DQhuF1vK31Jb7u