Packages
electric
1.0.12
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/replication/eval/env/known_functions.ex
defmodule Electric.Replication.Eval.Env.KnownFunctions do
use Electric.Replication.Eval.KnownDefinition
alias PgInterop.Interval
alias Electric.Replication.PostgresInterop.Casting
alias Electric.Replication.Eval.Env.BasicTypes
## "input" functions
defpostgres("int2(text) -> int2", delegate: &Casting.parse_int2/1)
defpostgres("int4(text) -> int4", delegate: &Casting.parse_int4/1)
defpostgres("int8(text) -> int8", delegate: &Casting.parse_int8/1)
defpostgres("float4(text) -> float4", delegate: &Casting.parse_float8/1)
defpostgres("float8(text) -> float8", delegate: &Casting.parse_float8/1)
defpostgres("numeric(text) -> numeric", delegate: &Casting.parse_float8/1)
defpostgres("bool(text) -> bool", delegate: &Casting.parse_bool/1)
defpostgres("uuid(text) -> uuid", delegate: &Casting.parse_uuid/1)
defpostgres("text(text) -> text", delegate: &BasicTypes.noop/1)
defpostgres("date(text) -> date", delegate: &Casting.parse_date/1)
defpostgres("time(text) -> time", delegate: &Casting.parse_time/1)
defpostgres("timestamp(text) -> timestamp", delegate: &Casting.parse_timestamp/1)
defpostgres("timestamptz(text) -> timestamp", delegate: &Casting.parse_timestamptz/1)
defpostgres("interval(text) -> interval", delegate: &Interval.parse!/1)
## "output" functions
defpostgres("int2out(int2) -> text", delegate: &Integer.to_string/1)
defpostgres("int4out(int4) -> text", delegate: &Integer.to_string/1)
defpostgres("int8out(int8) -> text", delegate: &Integer.to_string/1)
defpostgres("float4out(float4) -> text", delegate: &Float.to_string/1)
defpostgres("float8out(float8) -> text", delegate: &Float.to_string/1)
defpostgres("numericout(numeric) -> text", delegate: &Float.to_string/1)
defpostgres("dateout(date) -> text", delegate: &Date.to_iso8601/1)
defpostgres("timeout(time) -> text", delegate: &Time.to_iso8601/1)
defpostgres("timestampout(timestamp) -> text", delegate: &NaiveDateTime.to_iso8601/1)
defpostgres("intervalout(interval) -> text", delegate: &PgInterop.Interval.format/1)
defpostgres "boolout(bool) -> text" do
def bool_out(true), do: "t"
def bool_out(false), do: "f"
end
defpostgres("uuidout(uuid) -> text", delegate: &BasicTypes.noop/1)
## Comparison functions
defcompare("*numeric_type*", using: Kernel)
defcompare("text", using: Kernel)
defcompare("uuid", using: Kernel)
defcompare("date", using: &Date.compare/2)
defcompare("time", using: &Time.compare/2)
defcompare("timestamp", using: &NaiveDateTime.compare/2)
defcompare("timestamptz", using: &DateTime.compare/2)
defpostgres("bool = bool -> bool", delegate: &Kernel.==/2)
defpostgres("bool <> bool -> bool", delegate: &Kernel.!=/2)
defpostgres("interval = interval -> bool", delegate: &Kernel.==/2)
defpostgres("interval <> interval -> bool", delegate: &Kernel.!=/2)
## Numeric functions
defpostgres("+ *numeric_type* -> *numeric_type*", delegate: &Kernel.+/1)
defpostgres("- *numeric_type* -> *numeric_type*", delegate: &Kernel.-/1)
defpostgres("*numeric_type* + *numeric_type* -> *numeric_type*", delegate: &Kernel.+/2)
defpostgres("*numeric_type* - *numeric_type* -> *numeric_type*", delegate: &Kernel.-/2)
defpostgres("*integral_type* / *integral_type* -> bool", delegate: &Kernel.div/2)
defpostgres("float8 / float8 -> bool", delegate: &Kernel.//2)
defpostgres("numeric ^ numeric -> numeric", delegate: &Float.pow/2)
defpostgres("float8 ^ float8 -> float8", delegate: &Float.pow/2)
defpostgres("|/ float8 -> float8", delegate: &:math.sqrt/1)
defpostgres("@ *numeric_type* -> *numeric_type*", delegate: &:erlang.abs/1)
defpostgres("*integral_type* & *integral_type* -> *integral_type*", delegate: &Bitwise.band/2)
defpostgres("*integral_type* | *integral_type* -> *integral_type*", delegate: &Bitwise.bor/2)
defpostgres("*integral_type* # *integral_type* -> *integral_type*", delegate: &Bitwise.bxor/2)
## String functions
defpostgres "text || text -> text" do
# Can't do `delegate: &Kernel.<>/2`, because it's a macro that gets converted to local function call
def text_concat(t1, t2) when is_binary(t1) and is_binary(t2) do
t1 <> t2
end
end
defpostgres("lower(text) -> text", delegate: &String.downcase/1)
defpostgres("upper(text) -> text", delegate: &String.upcase/1)
defpostgres("text ~~ text -> bool", delegate: &Casting.like?/2)
defpostgres("text ~~* text -> bool", delegate: &Casting.ilike?/2)
defpostgres "text !~~ text -> bool" do
def not_like?(text1, text2), do: not Casting.like?(text1, text2)
end
defpostgres "text !~~* text -> bool" do
def not_ilike?(text1, text2), do: not Casting.ilike?(text1, text2)
end
## Date functions
defpostgres("date + int8 -> date", commutative?: true, delegate: &Date.add/2)
defpostgres("date - date -> int8", delegate: &Date.diff/2)
defpostgres "date - int8 -> date" do
def date_subtract(date, int), do: Date.add(date, -int)
end
defpostgres("date + time -> timestamp", commutative?: true, delegate: &NaiveDateTime.new!/2)
defpostgres("interval + interval -> interval", delegate: &Interval.add/2)
defpostgres("date + interval -> timestamp",
commutative?: true,
delegate: &Interval.add_to_date/2
)
defpostgres("timestamp + interval -> timestamp",
commutative?: true,
delegate: &Interval.add_to_date/2
)
defpostgres("timestamptz + interval -> timestamptz",
commutative?: true,
delegate: &Interval.add_to_date/2
)
defpostgres("time + interval -> time", commutative?: true, delegate: &Interval.add_to_time/2)
defpostgres("date - interval -> timestamp", delegate: &Interval.subtract_from_date/2)
defpostgres("timestamp - interval -> timestamp", delegate: &Interval.subtract_from_date/2)
defpostgres("timestamptz - interval -> timestamptz", delegate: &Interval.subtract_from_date/2)
defpostgres("interval - interval -> interval", delegate: &Interval.subtract/2)
defpostgres("timestamp - timestamp -> interval", delegate: &Interval.datetime_diff/2)
defpostgres("timestamptz - timestamptz -> interval", delegate: &Interval.datetime_diff/2)
defpostgres("interval * float8 -> interval", commutative?: true, delegate: &Interval.scale/2)
defpostgres("justify_days(interval) -> interval", delegate: &Interval.justify_days/1)
defpostgres("justify_hours(interval) -> interval", delegate: &Interval.justify_hours/1)
defpostgres("justify_interval(interval) -> interval", delegate: &Interval.justify_interval/1)
defpostgres "timezone(text, timestamp) -> timestamptz" do
def timestamptz_from_naive(tz, datetime), do: DateTime.from_naive!(datetime, tz)
end
defpostgres "timezone(text, timestamptz) -> timestamp" do
def naive_from_timestamptz(tz, datetime),
do: datetime |> DateTime.shift_zone!(tz) |> DateTime.to_naive()
end
## Array functions
defpostgres("anyarray = anyarray -> bool", delegate: &Kernel.==/2)
defpostgres("anyarray <> anyarray -> bool", delegate: &Kernel.!=/2)
defpostgres("anycompatiblearray || anycompatiblearray -> anycompatiblearray",
delegate: &PgInterop.Array.concat_arrays/2
)
defpostgres("array_cat(anycompatiblearray, anycompatiblearray) -> anycompatiblearray",
delegate: &PgInterop.Array.concat_arrays/2
)
defpostgres("anycompatible || anycompatiblearray -> anycompatiblearray",
delegate: &PgInterop.Array.array_prepend/2
)
defpostgres("array_prepend(anycompatible, anycompatiblearray) -> anycompatiblearray",
delegate: &PgInterop.Array.array_prepend/2
)
defpostgres("anycompatiblearray || anycompatible -> anycompatiblearray",
delegate: &PgInterop.Array.array_append/2
)
defpostgres("array_append(anycompatiblearray, anycompatible) -> anycompatiblearray",
delegate: &PgInterop.Array.array_append/2
)
defpostgres("array_ndims(anyarray) -> int4", delegate: &PgInterop.Array.get_array_dim/1)
defpostgres "anyarray @> anyarray -> bool" do
def left_array_contains_right?(left, right) do
MapSet.subset?(MapSet.new(List.flatten(right)), MapSet.new(List.flatten(left)))
end
end
defpostgres "anyarray <@ anyarray -> bool" do
def right_array_contains_left?(left, right) do
MapSet.subset?(MapSet.new(List.flatten(left)), MapSet.new(List.flatten(right)))
end
end
defpostgres "anyarray && anyarray -> bool" do
def arrays_overlap?(left, right) when left == [] or right == [], do: false
def arrays_overlap?(left, right) when is_list(left) and is_list(right),
do: arrays_overlap?(MapSet.new(List.flatten(left)), MapSet.new(List.flatten(right)))
def arrays_overlap?(%MapSet{} = left, right) do
Enum.any?(right, fn
elem when is_list(elem) -> arrays_overlap?(left, elem)
elem -> MapSet.member?(left, elem)
end)
end
end
end