electric-sql / electric-sql/electric
Parametrized queries not working for `Electric.Client.poll/4` in embedded mode
- Dominant language
- TypeScript
- Stars
- 10.4k
- Forks
- 375
- Avg merge
- 3d 1h
- Merged PRs (30d)
- 18
Description
**Versions**
- Client: `electric_client` (Elixir) 0.10.1
- Electric: 1.6.2 (also reproducible on `main`)
**Bug description**
A `ShapeDefinition` whose `where:` clause uses positional parameters (`$1`, `$2`, …) with `params:` substitution works over HTTP but fails under `Electric.Client.embedded/1` with `"At location N: parameter $1 was not provided"`:
```elixir
{:ok, client} = Electric.Client.embedded()
shape =
Electric.Client.ShapeDefinition.new!("things",
where: "organization_id IN ($1::uuid, $2::uuid)",
params: %{1 => uuid_a, 2 => uuid_b}
)
Electric.Client.poll(client, shape, Electric.Client.ShapeState.new(offset: "now"))
# => {:error, %Electric.Client.Error{
# message: %{errors: %{where: ["At location 20: parameter $1 was not provided"]}}, ...}}
```
Root cause: `ShapeDefinition.params/2` defaults to `format: :query` and emits bracket-flat keys (`%{"params[1]" => ..., "params[2]" => ...}`) — correct for HTTP, where Plug's `fetch_query_params` re-nests them into `%{"params" => %{"1" => ..., "2" => ...}}` before `Electric.Shapes.Api.Params`'s Ecto cast sees them. `Electric.Client.Embedded.request_to_params/1` skips Plug and `Map.merge`s the bracket-flat map straight into `Api.validate/2`; the Ecto schema has no field `"params[1]"`, silently drops both keys, and the SQL parser then rejects `$1`.
**Expected behavior**
`Electric.Client.Embedded` should accept the same `ShapeDefinition` shape as `Electric.Client.Fetch.HTTP` does, including parameterized `where:` clauses. Fix is to re-nest one level of bracket keys in `Embedded.request_to_params/1` before handing off to `Api.validate/2` — equivalent to what Plug does for the HTTP path.
Contributor guide
Assessment
This issue has not been assessed yet.