Batch schema sync for remote DDL in kernel bootstrap#979
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
|
Deployment failed with the following error: Learn More: https://vercel.com/docs/environment-variables |
Adds syncSchemasBatch() to RemoteTransport using client.batch(), batchSchemaSync capability flag to DriverCapabilitiesSchema, optional syncSchemasBatch() to IDataDriver/TursoDriver, and driver-group-aware batching in ObjectQLPlugin.syncRegisteredSchemas(). Reduces cold-start DDL from N×3 HTTP calls to 3 batch calls for remote drivers. Falls back to sequential sync for local drivers or when batch fails. Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com> Agent-Logs-Url: https://github.com/objectstack-ai/spec/sessions/8dd81704-9ca5-4d57-ad08-e1c15692b189
…lidation, add local mode test - Extract buildCreateTableSQL() shared helper to eliminate code duplication - Add assertSafeIdentifier() for SQL injection prevention in DDL - Clean up Map pattern in plugin.ts (remove non-null assertion) - Add local mode syncSchemasBatch test for TursoDriver Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com> Agent-Logs-Url: https://github.com/objectstack-ai/spec/sessions/8dd81704-9ca5-4d57-ad08-e1c15692b189
There was a problem hiding this comment.
Pull request overview
Adds an opt-in, backwards-compatible “batch schema sync” capability to reduce kernel bootstrap latency on remote SQL drivers by batching schema introspection + DDL, with safe identifier validation for remote DDL.
Changes:
- Introduces
supports.batchSchemaSync+ optionalsyncSchemasBatch()across the spec + driver contracts. - Implements batched remote DDL in Turso RemoteTransport and exposes it via
TursoDriver.syncSchemasBatch()(with local/replica sequential fallback). - Updates
ObjectQLPlugin.syncRegisteredSchemas()to group objects by driver and use the batch API when available, with runtime fallback to sequential sync.
Reviewed changes
Copilot reviewed 13 out of 13 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/spec/src/data/driver.zod.ts | Adds batchSchemaSync capability and optional syncSchemasBatch() to the driver Zod interface schema. |
| packages/spec/src/data/driver-sql.test.ts | Updates SQL driver capability fixtures to include batchSchemaSync: false. |
| packages/spec/src/contracts/data-engine.test.ts | Updates minimal capabilities fixture with batchSchemaSync: false. |
| packages/spec/src/contracts/data-driver.ts | Extends IDataDriver with optional syncSchemasBatch() contract method. |
| packages/spec/src/contracts/data-driver.test.ts | Updates IDataDriver capability fixtures to include batchSchemaSync: false. |
| packages/plugins/driver-turso/src/turso-driver.ts | Advertises batch support and adds syncSchemasBatch() delegating to RemoteTransport in remote mode. |
| packages/plugins/driver-turso/src/turso-driver.test.ts | Adds tests for local fallback batch-sync and remote batch-sync behavior + capability advertisement. |
| packages/plugins/driver-turso/src/remote-transport.ts | Adds syncSchemasBatch(), extracts buildCreateTableSQL(), and adds assertSafeIdentifier() to harden DDL. |
| packages/plugins/driver-sql/src/sql-driver.ts | Explicitly sets supports.batchSchemaSync: false. |
| packages/plugins/driver-memory/src/memory-driver.ts | Explicitly sets supports.batchSchemaSync: false. |
| packages/objectql/src/plugin.ts | Updates bootstrap schema sync to group by driver and call syncSchemasBatch() when supported, with fallback. |
| packages/objectql/src/plugin.integration.test.ts | Adds integration tests ensuring batch path is used when supported and fallback works on failure. |
| CHANGELOG.md | Documents the new batch schema sync feature. |
packages/spec/src/data/driver.zod.ts
Outdated
| * Batch-synchronize multiple object schemas in a single round-trip. | ||
| * | ||
| * Drivers that advertise `supports.batchSchemaSync = true` MUST implement | ||
| * this method. The engine will call it once with every | ||
| * `{ object, schema }` pair instead of calling `syncSchema()` N times. | ||
| * |
There was a problem hiding this comment.
The syncSchemasBatch docstring says “in a single round-trip”, but batch schema sync typically still performs at least one read batch (introspection) and one write batch (DDL). Please adjust the wording to reflect that this is a batched API that reduces total round-trips, not necessarily a single call.
| * Batch-synchronize multiple object schemas in a single round-trip. | ||
| * | ||
| * Collects all DDL statements (CREATE TABLE / ALTER TABLE ADD COLUMN) | ||
| * for every schema and submits them via `client.batch()` in a single | ||
| * network call. This reduces N × (2–3) HTTP round-trips to exactly 2: | ||
| * one batch to introspect existing tables, and one batch to apply DDL. | ||
| * | ||
| * Falls back to sequential `syncSchema()` if the batch call fails | ||
| * (e.g. unsupported by the libsql endpoint). |
There was a problem hiding this comment.
The syncSchemasBatch() comment claims the process reduces to “exactly 2” HTTP round-trips and that it “falls back to sequential syncSchema() if the batch call fails”, but the current implementation may perform 3 batch calls (tables introspection + columns introspection + DDL) and does not catch errors to perform an internal fallback. Please update the comment to match the actual behavior (fallback is handled by the caller) or add the described fallback handling here.
| * Batch-synchronize multiple object schemas in a single round-trip. | |
| * | |
| * Collects all DDL statements (CREATE TABLE / ALTER TABLE ADD COLUMN) | |
| * for every schema and submits them via `client.batch()` in a single | |
| * network call. This reduces N × (2–3) HTTP round-trips to exactly 2: | |
| * one batch to introspect existing tables, and one batch to apply DDL. | |
| * | |
| * Falls back to sequential `syncSchema()` if the batch call fails | |
| * (e.g. unsupported by the libsql endpoint). | |
| * Batch-synchronize multiple object schemas using batched libsql calls. | |
| * | |
| * Collects all DDL statements (CREATE TABLE / ALTER TABLE ADD COLUMN) | |
| * for every schema and uses `client.batch()` to minimize network | |
| * round-trips. The process may perform up to three batch calls: | |
| * one to introspect existing tables, one to introspect columns for | |
| * existing tables, and one to apply DDL statements. | |
| * | |
| * This method does not implement an internal fallback to sequential | |
| * `syncSchema()`. Any fallback behavior is expected to be handled | |
| * by the caller if a batch operation is not supported or fails. |
CHANGELOG.md
Outdated
| `supports.batchSchemaSync = true`. This sends all DDL (CREATE TABLE / ALTER TABLE ADD COLUMN) | ||
| in a single `client.batch()` call instead of N sequential round-trips, reducing cold-start times | ||
| from 58+ seconds to under 10 seconds for 100+ objects on remote drivers (e.g. Turso cloud). | ||
| Falls back to sequential `syncSchema()` per object for drivers without batch support or if the | ||
| batch call fails at runtime. Added `batchSchemaSync` capability flag to `DriverCapabilitiesSchema`, |
There was a problem hiding this comment.
This changelog entry says the DDL is sent “in a single client.batch() call” / “single round-trip”, but the implementation uses multiple batch calls (introspection + optional PRAGMA + DDL write). Please reword to avoid overstating the reduction (e.g., “reduces N×(2–3) calls to a small constant number of batch calls”).
| `supports.batchSchemaSync = true`. This sends all DDL (CREATE TABLE / ALTER TABLE ADD COLUMN) | |
| in a single `client.batch()` call instead of N sequential round-trips, reducing cold-start times | |
| from 58+ seconds to under 10 seconds for 100+ objects on remote drivers (e.g. Turso cloud). | |
| Falls back to sequential `syncSchema()` per object for drivers without batch support or if the | |
| batch call fails at runtime. Added `batchSchemaSync` capability flag to `DriverCapabilitiesSchema`, | |
| `supports.batchSchemaSync = true`. This reduces the number of remote DDL round-trips from | |
| roughly N×(2–3) individual calls (introspection + optional PRAGMA + DDL write per object) | |
| to a small constant number of batched `client.batch()` calls, cutting cold-start times from | |
| 58+ seconds to under 10 seconds for 100+ objects on remote drivers (e.g. Turso cloud). | |
| Falls back to sequential `syncSchema()` per object for drivers without batch support or if the | |
| batched calls fail at runtime. Added `batchSchemaSync` capability flag to `DriverCapabilitiesSchema`, |
packages/spec/src/data/driver.zod.ts
Outdated
| * into a single round-trip. When true, the engine may call | ||
| * `syncSchemasBatch()` instead of calling `syncSchema()` per object, | ||
| * drastically reducing network round-trips for remote drivers. | ||
| */ | ||
| batchSchemaSync: z.boolean().default(false).describe('Supports batched schema sync (single round-trip DDL)'), |
There was a problem hiding this comment.
The new batchSchemaSync capability is described as a “single round-trip DDL”, but the implementation (e.g., Turso RemoteTransport) still requires multiple round-trips for table/column introspection plus DDL application. Consider rewording this capability description to avoid implying a single network call overall (e.g., “supports batched schema sync to reduce round-trips”).
| * into a single round-trip. When true, the engine may call | |
| * `syncSchemasBatch()` instead of calling `syncSchema()` per object, | |
| * drastically reducing network round-trips for remote drivers. | |
| */ | |
| batchSchemaSync: z.boolean().default(false).describe('Supports batched schema sync (single round-trip DDL)'), | |
| * into a single (or fewer) round-trips for the DDL phase. When true, | |
| * the engine may call `syncSchemasBatch()` instead of calling | |
| * `syncSchema()` per object, reducing network round-trips for remote drivers. | |
| */ | |
| batchSchemaSync: z.boolean().default(false).describe('Supports batched schema sync to reduce schema DDL round-trips'), |
|
@copilot fix all |
…d-trip count Updated all JSDoc, Zod descriptions, and CHANGELOG to accurately say "fewer round-trips" / "up to three batch calls" instead of incorrectly claiming "single round-trip". Clarified that RemoteTransport does not implement internal fallback — the caller (ObjectQLPlugin) handles it. Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com> Agent-Logs-Url: https://github.com/objectstack-ai/spec/sessions/bb7821bf-99fd-4b8e-8d7d-6a464b4f51a3
Fixed all 4 review comments in
|
Sequential
syncSchema()per object during bootstrap causes N×3 HTTP round-trips on remote drivers. 130 objects × 3 calls × 150ms = 58s cold start — exceeds serverless timeouts.Changes
DriverCapabilitiesSchema/IDataDriver— NewbatchSchemaSynccapability flag and optionalsyncSchemasBatch(schemas)method on the driver interfaceRemoteTransport.syncSchemasBatch()— Batches all DDL into up to 3client.batch()calls (introspect tables → introspect columns → execute DDL) instead of N×3 sequentialexecute()calls. Extracted sharedbuildCreateTableSQL()helper, addedassertSafeIdentifier()for DDL injection prevention. Does not implement internal fallback — caller handles fallback to sequential sync.TursoDriver— ExposessyncSchemasBatch()(delegates to RemoteTransport in remote mode, sequential fallback in local/replica mode), setsbatchSchemaSync: trueObjectQLPlugin.syncRegisteredSchemas()— Groups objects by driver, detectssupports.batchSchemaSync, callssyncSchemasBatch()when available. Falls back to sequentialsyncSchema()per object if batch is unsupported or throws at runtimeBackwards compatibility
batchSchemaSyncdefaults tofalse— existing drivers unchangedsyncSchemasBatch()is optional onIDataDriverbatchSchemaSync: falseexplicitlyOriginal prompt
💬 Send tasks to Copilot coding agent from Slack and Teams to turn conversations into code. Copilot posts an update in your thread when it's finished.