Commit b2f4828
feat(server): support array-of-arrays parameter shape for multi-row VALUES (#117)
* feat(server): support array-of-arrays parameter shape for multi-row VALUES
Previously `substitute_sql_params` rendered a flat scalar array as the
pgvector / VECTOR text literal `[v1, v2, …]` and rejected anything more
deeply nested. That meant a pipeline could only insert one row per call
unless the YAML hardcoded a fixed number of named parameters — a
non-starter for batched WAL replay where the consumer chooses batch
size dynamically.
This patch teaches the renderer that an array whose every element is
itself an array is a multi-row tuple list:
{"rows": [["a", [0.1, 0.2]], ["b", [0.3, 0.4]]]}
becomes `('a', [0.1, 0.2]), ('b', [0.3, 0.4])`, so a pipeline like
INSERT INTO docs (id, embedding) VALUES {rows}
handles arbitrary batch sizes without changing its YAML. Inner arrays
inside a row tuple (the embedding cell here) render as the bracketed
scalar form so `VECTOR` and pgvector columns accept them as text
literals — same shape used by single-row inserts. Mixed-shape arrays
(some scalar, some array elements) are explicitly rejected as
Unsupported rather than silently emitting malformed SQL.
Pre-existing flat-array behaviour is preserved; the new path only
fires when *every* element is an array.
Adds 6 unit tests covering scalar-only batches, batches with a vector
cell, single-row-batch edge case, quote escaping, the
mixed-shape rejection path, and a regression test for the legacy flat
vector-literal shape.
Adds a "Parameter shapes" section to docs/pipelines.md documenting the
JSON value → SQL literal mapping including the new tuple-list form,
plus three runnable example pipelines:
- docs/postgres/pipelines/batch_insert_users.yaml
- docs/seekdb/pipelines/batch_insert_users.yaml
- docs/seekdb/pipelines/batch_insert_docs_with_embeddings.yaml
Verified: cargo build -p skardi-server clean; cargo test -p
skardi-server --lib passes 109/109.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* test: cover Bool / Null / fallback scalar_to_sql arms
Codecov flagged 3 uncovered lines in the new helper — the Bool, Null,
and `other` fallback arms in scalar_to_sql. The existing tuple-list
tests only exercise Number, String, and nested Array cells.
Adds one focused test that puts a Bool, a Null, and a Value::Object
side-by-side in a row tuple so all three branches fire through
row_cell_to_sql's `_ => scalar_to_sql(v)` path. The Object-fallback
assertion locks in the pre-existing JSON-form behaviour as the
documented contract for unexpected shapes — a future change has to
be deliberate.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix check
* fix(sql_validator): allow `VALUES {rows}` placeholder shape at load time
The runtime renderer in `substitute_sql_params` expands an array-of-arrays
parameter into a multi-row tuple list (`(c1, c2), (c1, c2)`) so a pipeline
like `INSERT INTO docs (...) VALUES {rows}` can batch-insert without
hardcoding row count in YAML. But `preprocess_parameters` in the load-time
SQL validator always substituted `{name}` with the quoted scalar literal
`'__PARAM__'`, so the same template parsed as `VALUES '__PARAM__'` and
sqlparser rejected it with `Expected: (, found: '__PARAM__'`. Result:
skardi-server crashed during config load, the container restarted in a
loop, and any pipeline using the new tuple-list shape was unloadable.
Switch the placeholder to `(NULL)`, which parses both as a scalar
expression (`WHERE x = (NULL)`) and as a single-row VALUES tuple
(`VALUES (NULL)`), so the validator accepts every shape the runtime
renderer can emit. The validator only checks DDL/access-mode
restrictions, not types or arity, so the choice of literal is purely
about parseability.
Adds a regression test covering `VALUES {rows}` (with and without an
`ON CONFLICT` tail) and confirming access-mode enforcement still fires
on the tuple-list shape against a read-only table.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fmt
* add tests for all data sources
* add more tests
* no ci change
* ci: restore pgvector image and docs table seed for postgres tests
Reinstates the `pgvector/pgvector:pg16` image and `docs` table seed
that test_insert_multi_row_values_with_vector_cell relies on for
introspecting an `embedding vector(4)` column.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* ci: free more disk space to avoid linker SIGBUS on smaller runner VMs
GitHub-hosted runners sometimes assign a 72 GB-rootfs VM (vs the 145 GB
pool), leaving only ~25 GB free after the toolchains. The
coverage-instrumented `--all-features` link step exhausts that and LLD
crashes with `ld terminated with signal 7 [Bus error]`. Remove
additional preinstalled toolchains (Android SDK, CodeQL, PowerShell,
Chromium, node_modules, vendor SDKs) and unused docker images so the
link has headroom on either VM type.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>1 parent 495a20e commit b2f4828
20 files changed
Lines changed: 1225 additions & 22 deletions
File tree
- .github/workflows
- crates
- server/src
- skardi/src
- pipeline
- sources
- providers
- lance
- mongo
- redis
- seekdb
- sqlite
- sqlx/pg
- docs
- mongo/pipelines
- mysql/pipelines
- postgres/pipelines
- redis/pipelines
- seekdb/pipelines
- sqlite/pipelines
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
52 | 52 | | |
53 | 53 | | |
54 | 54 | | |
55 | | - | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
56 | 61 | | |
57 | 62 | | |
58 | 63 | | |
| |||
126 | 131 | | |
127 | 132 | | |
128 | 133 | | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
129 | 139 | | |
130 | 140 | | |
131 | 141 | | |
132 | 142 | | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
133 | 150 | | |
| 151 | + | |
134 | 152 | | |
135 | 153 | | |
136 | 154 | | |
| |||
184 | 202 | | |
185 | 203 | | |
186 | 204 | | |
| 205 | + | |
187 | 206 | | |
188 | 207 | | |
189 | 208 | | |
| |||
223 | 242 | | |
224 | 243 | | |
225 | 244 | | |
| 245 | + | |
| 246 | + | |
| 247 | + | |
| 248 | + | |
| 249 | + | |
| 250 | + | |
| 251 | + | |
| 252 | + | |
| 253 | + | |
| 254 | + | |
226 | 255 | | |
227 | 256 | | |
228 | 257 | | |
| |||
0 commit comments