Packages
electric
1.2.2
1.7.8
1.7.7
1.7.6
1.7.5
1.7.4
1.7.3
1.7.2
1.7.1
1.7.0
1.6.10
1.6.9
1.6.8
1.6.7
1.6.6
1.6.5
1.6.4
1.6.3
1.6.2
1.6.1
1.6.0
1.5.1
1.5.0
1.4.16
1.4.16-beta-1
1.4.15
1.4.14
1.4.13
1.4.12
1.4.11
1.4.10
1.4.8
1.4.7
1.4.6
1.4.5
1.4.4
1.4.3
1.4.2
1.4.1
1.4.0
1.3.4
1.3.3
1.3.2
1.2.4
1.2.3
1.2.2
1.2.1
1.2.0
1.1.14
1.1.13
1.1.12
1.1.11
1.1.10
1.1.9
1.1.8
1.1.7
1.1.6
retired
1.1.5
retired
1.1.4
retired
1.1.3
retired
1.1.2
1.1.1
1.1.0
1.0.24
1.0.23
1.0.22
1.0.21
1.0.20
1.0.19
1.0.18
1.0.17
1.0.15
1.0.13
1.0.12
1.0.11
1.0.10
1.0.9
1.0.5
1.0.4
1.0.3
1.0.2
1.0.1
1.0.0
1.0.0-beta.23
1.0.0-beta.22
1.0.0-beta.20
1.0.0-beta.19
1.0.0-beta.18
1.0.0-beta.17
1.0.0-beta.16
1.0.0-beta.15
1.0.0-beta.14
1.0.0-beta.13
1.0.0-beta.12
1.0.0-beta.11
1.0.0-beta.10
1.0.0-beta.9
1.0.0-beta.8
1.0.0-beta.7
1.0.0-beta.6
1.0.0-beta.5
1.0.0-beta.4
1.0.0-beta.3
1.0.0-beta.2
1.0.0-beta.1
0.9.5
0.9.4
0.9.3
0.9.2
0.9.1
0.9.0
0.8.1
0.8.0
0.7.7
0.7.6
0.7.5
0.7.4
0.7.3
0.7.2
0.7.1
0.7.0
0.6.3
0.6.2
0.6.1
0.5.2
0.4.4
Postgres sync engine. Sync little subsets of your Postgres data into local apps and services.
Current section
Files
Jump to
Current section
Files
lib/electric/shapes/shape/subset.ex
defmodule Electric.Shapes.Shape.Subset do
alias Electric.Postgres.Inspector
alias Electric.Replication.Eval.Parser
alias Electric.Shapes.Shape.Validators
defstruct [
:order_by,
:limit,
:offset,
:where
]
@schema_options [
order_by: [type: :string],
limit: [type: :pos_integer],
offset: [type: :non_neg_integer],
where: [type: :string],
params: [type: {:map, :string, :string}, default: %{}]
]
|> NimbleOptions.new!()
def new(shape, fields, opts) do
inspector = Access.fetch!(opts, :inspector)
with {:ok, fields} <- NimbleOptions.validate(Map.new(fields), @schema_options),
{:ok, columns} <- load_column_info(shape, inspector),
:ok <- validate_order_by(fields[:order_by], columns),
refs = Inspector.columns_to_expr(columns),
{:ok, where} <- validate_where_clause(fields[:where], fields[:params], refs) do
{:ok,
%__MODULE__{
order_by: fields[:order_by],
limit: fields[:limit],
offset: fields[:offset],
where: where
}}
else
{:error, %NimbleOptions.ValidationError{message: reason, key: key}} ->
{:error, {key, reason}}
{:error, reason} ->
{:error, reason}
end
end
defp load_column_info(%{root_table_id: table_oid, root_table: table}, inspector) do
case Inspector.load_column_info(table_oid, inspector) do
:table_not_found ->
{:error,
{:order_by,
"Table #{Electric.Utils.inspect_relation(table)} does not exist. " <>
"If the table name contains capitals or special characters you must quote it."}}
{:ok, columns} ->
{:ok, columns}
end
end
defp validate_order_by(nil, _columns), do: :ok
defp validate_order_by(order_by, columns) do
case Parser.validate_order_by(order_by, columns) do
:ok -> :ok
{:error, reason} -> {:error, {:order_by, reason}}
end
end
defp validate_where_clause(nil, _params, _refs), do: {:ok, nil}
defp validate_where_clause(where, params, refs) do
with {:ok, where} <- Parser.parse_query(where),
{:ok, subqueries} <- Parser.extract_subqueries(where),
:ok <- assert_no_subqueries(subqueries),
:ok <- Validators.validate_parameters(params),
{:ok, where} <- Parser.validate_where_ast(where, params: params, refs: refs),
{:ok, where} <- Validators.validate_where_return_type(where) do
{:ok, where}
else
{:error, reason} -> {:error, {:where, reason}}
end
end
defp assert_no_subqueries([]), do: :ok
defp assert_no_subqueries(_), do: {:error, "Subqueries are not allowed in subsets"}
end