Packages
electric
0.9.4
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/postgres/inspector.ex
defmodule Electric.Postgres.Inspector do
alias Electric.Replication.Eval.Parser
@type relation :: Electric.relation()
@type relation_id :: Electric.relation_id()
@type column_info :: %{
name: String.t(),
type: String.t(),
type_mod: integer() | nil,
formatted_type: String.t(),
pk_position: non_neg_integer() | nil,
type_id: {typid :: non_neg_integer(), typmod :: integer()},
array_dimensions: non_neg_integer(),
not_null: boolean(),
array_type: String.t()
}
@type relation_info :: %{
relation_id: relation_id(),
relation: relation()
}
@callback load_relation(String.t(), opts :: term()) ::
{:ok, relation_info()} | {:error, String.t()}
@callback load_column_info(relation(), opts :: term()) ::
{:ok, [column_info()]} | :table_not_found
@callback clean(relation(), opts :: term()) :: true
@type inspector :: {module(), opts :: term()}
@doc """
Expects the table name provided by the user
and validates that the table exists and returns the relation.
The table name can be quoted or unquoted and can optionally be qualified,
e.g. `users` would return `{"public", "users"}`,
`usErs` would return `{"public", "users"}`,
`"Users"` would return `{"public", "Users"}`,
`some_schema.users` would return `{"some_schema", "users"}`.
"""
@spec load_relation(String.t(), inspector()) :: {:ok, relation_info()} | {:error, String.t()}
def load_relation(table, {module, opts}),
do: module.load_relation(table, opts)
@doc """
Load column information about a given table using a provided inspector.
"""
@spec load_column_info(relation(), inspector()) :: {:ok, [column_info()]} | :table_not_found
def load_column_info(relation, {module, opts}) do
module.load_column_info(relation, opts)
end
@doc """
Clean up all information about a given relation using a provided inspector.
"""
@spec clean(relation(), inspector()) :: true
def clean(relation, {module, opts}), do: module.clean(relation, opts)
@doc """
Get columns that should be considered a PK for table. If the table
has no PK, then we're considering all columns as identifying.
"""
@spec get_pk_cols([column_info(), ...]) :: [String.t(), ...]
def get_pk_cols([_ | _] = columns) do
columns
|> Enum.reject(&is_nil(&1.pk_position))
|> Enum.sort_by(& &1.pk_position)
|> Enum.map(& &1.name)
|> case do
[] -> Enum.map(columns, & &1.name)
results -> results
end
end
@doc """
Convert a column list into something that can be used by
`Electric.Replication.Eval.Parser.parse_and_validate_expression/2`
"""
@spec columns_to_expr([column_info(), ...]) :: Parser.refs_map()
def columns_to_expr(columns) when is_list(columns) do
Map.new(columns, fn
%{name: name, array_type: arr_type} when not is_nil(arr_type) ->
{[name], {:array, atom_type(arr_type)}}
%{name: name, type: type} ->
{[name], atom_type(type)}
end)
end
defp atom_type(type) when is_binary(type), do: String.to_atom(type)
defp atom_type(type) when is_atom(type), do: type
end