2023-12-15 11:10:11 +13:00
defmodule AshPostgres.MigrationGenerator.AshFunctions do
2024-07-10 11:57:38 +12:00
@latest_version 4
2023-12-15 11:10:11 +13:00
def latest_version , do : @latest_version
@moduledoc false
def install ( nil ) do
"""
execute ( \ " \" \"
CREATE OR REPLACE FUNCTION ash_elixir_or ( left BOOLEAN , in right ANYCOMPATIBLE , out f1 ANYCOMPATIBLE )
AS $ $ SELECT COALESCE ( NULLIF ( $ 1 , FALSE ) , $ 2 ) $ $
LANGUAGE SQL
IMMUTABLE ;
\ " \" \" )
execute ( \ " \" \"
CREATE OR REPLACE FUNCTION ash_elixir_or ( left ANYCOMPATIBLE , in right ANYCOMPATIBLE , out f1 ANYCOMPATIBLE )
AS $ $ SELECT COALESCE ( $ 1 , $ 2 ) $ $
LANGUAGE SQL
IMMUTABLE ;
\ " \" \" )
execute ( \ " \" \"
CREATE OR REPLACE FUNCTION ash_elixir_and ( left BOOLEAN , in right ANYCOMPATIBLE , out f1 ANYCOMPATIBLE ) AS $ $
SELECT CASE
WHEN $ 1 IS TRUE THEN $ 2
ELSE $ 1
END $ $
LANGUAGE SQL
IMMUTABLE ;
\ " \" \" )
execute ( \ " \" \"
CREATE OR REPLACE FUNCTION ash_elixir_and ( left ANYCOMPATIBLE , in right ANYCOMPATIBLE , out f1 ANYCOMPATIBLE ) AS $ $
SELECT CASE
WHEN $ 1 IS NOT NULL THEN $ 2
ELSE $ 1
END $ $
LANGUAGE SQL
IMMUTABLE ;
\ " \" \" )
execute ( \ " \" \"
CREATE OR REPLACE FUNCTION ash_trim_whitespace ( arr text [ ] )
RETURNS text [ ] AS $ $
DECLARE
start_index INT = 1 ;
end_index INT = array_length ( arr , 1 ) ;
BEGIN
WHILE start_index <= end_index AND arr [ start_index ] = ' ' LOOP
start_index := start_index + 1 ;
END LOOP ;
WHILE end_index >= start_index AND arr [ end_index ] = ' ' LOOP
end_index := end_index - 1 ;
END LOOP ;
IF start_index > end_index THEN
RETURN ARRAY [ ] :: text [ ] ;
ELSE
RETURN arr [ start_index : end_index ] ;
END IF ;
END ; $ $
LANGUAGE plpgsql
IMMUTABLE ;
\ " \" \" )
#{ash_raise_error()}
2024-07-10 11:57:38 +12:00
#{uuid_generate_v7()}
2023-12-15 11:10:11 +13:00
"""
end
def install ( 0 ) do
"""
execute ( \ " \" \"
ALTER FUNCTION ash_elixir_or ( left BOOLEAN , in right ANYCOMPATIBLE , out f1 ANYCOMPATIBLE ) IMMUTABLE
\ " \" \" )
execute ( \ " \" \"
ALTER FUNCTION ash_elixir_or ( left ANYCOMPATIBLE , in right ANYCOMPATIBLE , out f1 ANYCOMPATIBLE ) IMMUTABLE
\ " \" \" )
execute ( \ " \" \"
ALTER FUNCTION ash_elixir_and ( left BOOLEAN , in right ANYCOMPATIBLE , out f1 ANYCOMPATIBLE ) IMMUTABLE
\ " \" \" )
execute ( \ " \" \"
ALTER FUNCTION ash_elixir_and ( left ANYCOMPATIBLE , in right ANYCOMPATIBLE , out f1 ANYCOMPATIBLE ) IMMUTABLE
\ " \" \" )
#{ash_raise_error()}
2024-07-10 11:57:38 +12:00
#{uuid_generate_v7()}
2023-12-15 11:10:11 +13:00
execute ( \ " \" \"
CREATE OR REPLACE FUNCTION ash_trim_whitespace ( arr text [ ] )
RETURNS text [ ] AS $ $
DECLARE
start_index INT = 1 ;
end_index INT = array_length ( arr , 1 ) ;
BEGIN
WHILE start_index <= end_index AND arr [ start_index ] = ' ' LOOP
start_index := start_index + 1 ;
END LOOP ;
WHILE end_index >= start_index AND arr [ end_index ] = ' ' LOOP
end_index := end_index - 1 ;
END LOOP ;
IF start_index > end_index THEN
RETURN ARRAY [ ] :: text [ ] ;
ELSE
RETURN arr [ start_index : end_index ] ;
END IF ;
END ; $ $
LANGUAGE plpgsql
IMMUTABLE ;
\ " \" \" )
"""
end
def install ( 1 ) do
2024-07-10 11:57:38 +12:00
"""
#{ash_raise_error()}
#{uuid_generate_v7()}
"""
2023-12-15 11:10:11 +13:00
end
2024-01-01 02:40:30 +13:00
def install ( 2 ) do
2024-07-10 11:57:38 +12:00
"""
#{ash_raise_error()}
#{uuid_generate_v7()}
"""
end
def install ( 3 ) do
uuid_generate_v7 ( )
end
def drop ( 3 ) do
" execute( \" DROP FUNCTION IF EXISTS uuid_generate_v7(), timestamp_from_uuid_v7(uuid) \" ) "
2024-01-01 02:40:30 +13:00
end
def drop ( 2 ) do
2024-07-10 11:57:38 +12:00
"""
#{ash_raise_error()}
" execute( \" DROP FUNCTION IF EXISTS uuid_generate_v7(), timestamp_from_uuid_v7(uuid) \" ) "
"""
2024-01-01 02:40:30 +13:00
end
2023-12-15 11:10:11 +13:00
def drop ( 1 ) do
2024-07-10 11:57:38 +12:00
" execute( \" DROP FUNCTION IF EXISTS uuid_generate_v7(), timestamp_from_uuid_v7(uuid), ash_raise_error(jsonb), ash_raise_error(jsonb, ANYCOMPATIBLE) \" ) "
2023-12-15 11:10:11 +13:00
end
def drop ( 0 ) do
2024-07-10 11:57:38 +12:00
" execute( \" DROP FUNCTION IF EXISTS uuid_generate_v7(), timestamp_from_uuid_v7(uuid), ash_raise_error(jsonb), ash_raise_error(jsonb, ANYCOMPATIBLE), ash_trim_whitespace(text[]) \" ) "
2023-12-15 11:10:11 +13:00
end
def drop ( nil ) do
2024-07-10 11:57:38 +12:00
" execute( \" DROP FUNCTION IF EXISTS uuid_generate_v7(), timestamp_from_uuid_v7(uuid), ash_raise_error(jsonb), ash_raise_error(jsonb, ANYCOMPATIBLE), ash_elixir_and(BOOLEAN, ANYCOMPATIBLE), ash_elixir_and(ANYCOMPATIBLE, ANYCOMPATIBLE), ash_elixir_or(ANYCOMPATIBLE, ANYCOMPATIBLE), ash_elixir_or(BOOLEAN, ANYCOMPATIBLE), ash_trim_whitespace(text[]) \" ) "
2023-12-15 11:10:11 +13:00
end
2024-07-10 12:52:25 +12:00
defp ash_raise_error ( ) do
prefix = " ash_error: "
2024-01-01 02:40:30 +13:00
2023-12-15 11:10:11 +13:00
"""
execute ( \ " \" \"
CREATE OR REPLACE FUNCTION ash_raise_error ( json_data jsonb )
RETURNS BOOLEAN AS $ $
BEGIN
-- Raise an error with the provided JSON data .
-- The JSON object is converted to text for inclusion in the error message .
2024-01-01 02:40:30 +13:00
RAISE EXCEPTION ' #{ prefix } % ' , json_data :: text ;
2023-12-15 11:10:11 +13:00
RETURN NULL ;
END ;
$ $ LANGUAGE plpgsql ;
\ " \" \" )
execute ( \ " \" \"
2023-12-16 02:48:20 +13:00
CREATE OR REPLACE FUNCTION ash_raise_error ( json_data jsonb , type_signal ANYCOMPATIBLE )
2023-12-15 11:10:11 +13:00
RETURNS ANYCOMPATIBLE AS $ $
BEGIN
-- Raise an error with the provided JSON data .
-- The JSON object is converted to text for inclusion in the error message .
2024-01-01 02:40:30 +13:00
RAISE EXCEPTION ' #{ prefix } % ' , json_data :: text ;
2023-12-15 11:10:11 +13:00
RETURN NULL ;
END ;
$ $ LANGUAGE plpgsql ;
\ " \" \" )
"""
end
2024-07-10 11:57:38 +12:00
defp uuid_generate_v7 do
"""
execute ( \ " \" \"
CREATE OR REPLACE FUNCTION uuid_generate_v7 ( )
RETURNS UUID
AS $ $
DECLARE
timestamp TIMESTAMPTZ ;
microseconds INT ;
BEGIN
timestamp = clock_timestamp ( ) ;
microseconds = ( cast ( extract ( microseconds FROM timestamp ) :: INT - ( floor ( extract ( milliseconds FROM timestamp ) ) :: INT * 1000 ) AS DOUBLE PRECISION ) * 4.096 ) :: INT ;
RETURN encode (
set_byte (
set_byte (
overlay ( uuid_send ( gen_random_uuid ( ) ) placing substring ( int8send ( floor ( extract ( epoch FROM timestamp ) * 1000 ) :: BIGINT ) FROM 3 ) FROM 1 FOR 6
) ,
6 , ( b ' 0111 ' || ( microseconds >> 8 ) :: bit ( 4 ) ) :: bit ( 8 ) :: int
) ,
7 , microseconds :: bit ( 8 ) :: int
) ,
' hex ' ) :: UUID ;
END
$ $
LANGUAGE PLPGSQL
VOLATILE ;
\ " \" \" )
execute ( \ " \" \"
CREATE OR REPLACE FUNCTION timestamp_from_uuid_v7 ( _uuid uuid )
RETURNS TIMESTAMP WITHOUT TIME ZONE
AS $ $
SELECT to_timestamp ( ( ' x0000 ' || substr ( _uuid :: TEXT , 1 , 8 ) || substr ( _uuid :: TEXT , 10 , 4 ) ) :: BIT ( 64 ) :: BIGINT :: NUMERIC / 1000 ) ;
$ $
LANGUAGE SQL
IMMUTABLE PARALLEL SAFE STRICT LEAKPROOF ;
\ " \" \" )
"""
end
2023-12-15 11:10:11 +13:00
end