Skip to content

Parametrized queries not working for Electric.Client.poll/4 in embedded mode #4302

@evanob

Description

@evanob

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":

{: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.merges 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions