Current section

Files

Jump to
electric lib electric replication eval env known_functions.ex
Raw

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("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
end