# `Electric.Replication.Eval.Lookups`
[🔗](https://github.com/electric-sql/electric/tree/%40core/sync-service%401.6.2/packages/sync-service/lib/electric/replication/eval/lookups.ex#L1)

# `expand_variadic_function_overload`

```elixir
@spec expand_variadic_function_overload(map(), non_neg_integer()) :: map()
```

Expand a variadic function definition to a concrete call arity.

# `pick_concrete_function_overload`

```elixir
@spec pick_concrete_function_overload(
  list(),
  [struct()],
  Electric.Replication.Eval.Env.t()
) ::
  {:ok, term()} | :error
```

Given multiple possible function overloads (same name and arity), try to
find a concrete implementation that matches the argument types.

Rules for picking a function overload closely mimic those outlined in [postgres
documentation](https://www.postgresql.org/docs/current/typeconv-func.html):

1. Check if there is an overload where all variable types match exactly
2. Check if only one overload remains based on implicit conversion rules
   (unknowns are considered always matching), discard those that cannot
   be applied even after implicit conversion
3. Check if only one overload remains based on most exact type matches
4. Keep overloads that accept most preferred types in each conversion spot
5. If there are any unknowns, for each position first look for any overloads that
   accept `string` category, and if none found, check if all overloads accept
   the same type category. If that fails, keep all overloads, or pick any that
   don't accept picked category
6. If there are both unknown and known arguments, and all known arguments have
   the same type category, assume unknowns have the same type category and look
   for overloads that fit.

If exactly one overload matched after those steps, pick it, otherwise fail.

# `pick_concrete_operator_overload`

```elixir
@spec pick_concrete_operator_overload(
  list(),
  [struct()],
  Electric.Replication.Eval.Env.t()
) ::
  {:ok, term()} | :error
```

Given multiple possible operator overloads (same name and arity), try to
find a concrete implementation that matches the argument types.

Operators can only be 1 or 2-arity.

Rules for picking a operation overload closely mimic those outlined in [postgres
documentation](https://www.postgresql.org/docs/current/typeconv-oper.html), and
mostly match `pick_concrete_function_overload/3`.

# `pick_union_type`

Given a list of types, get a candidate type that best represents the union of all types.

Algorithm implements Postgres type resolution for `UNION`, `CASE`, and related constructs, like
`ARRAY[]` constructor syntax. They are outlined in
[documentation](https://www.postgresql.org/docs/current/typeconv-union-case.html).

1. If all inputs are of the same type, and it is not unknown, resolve as that type.
2. If any input is of a domain type, treat it as being of the domain's base type for all subsequent steps.
3. If all inputs are of type unknown, resolve as type text (the preferred type of the string category).
   Otherwise, unknown inputs are ignored for the purposes of the remaining rules.
4. If the non-unknown inputs are not all of the same type category, fail.
5. Select the first non-unknown input type as the candidate type, then consider each other non-unknown input type, left to right.
   If the candidate type can be implicitly converted to the other type but not vice-versa, select the other type as the new
   candidate type. Then continue considering the remaining inputs.
   If, at any stage of this process, a preferred type is selected, stop considering additional inputs.
6. Convert all inputs to the final candidate type. Fail if there is not an implicit conversion from a given input type to the candidate type.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
