-module(galchemy@schema@introspection@postgres). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src\\galchemy\\schema\\introspection\\postgres.gleam"). -export([default_options/0, only_schemas/2, include_system_schemas/1, column_row_decoder/0, index_row_decoder/0, constraint_row_decoder/0, compile_columns_query/1, compile_query/1, compile_constraints_query/1, compile_indexes_query/1, to_columns_query/1, to_query/1, to_constraints_query/1, to_indexes_query/1, rows_to_snapshot/3, introspect/2]). -export_type([introspection_options/0, column_row/0, constraint_kind/0, constraint_row/0, index_row/0, introspection_error/0]). -type introspection_options() :: {introspection_options, list(binary()), boolean()}. -type column_row() :: {column_row, binary(), binary(), binary(), integer(), boolean(), binary(), binary(), gleam@option:option(integer()), gleam@option:option(integer()), gleam@option:option(integer()), gleam@option:option(integer()), gleam@option:option(binary())}. -type constraint_kind() :: primary_key_constraint | unique_constraint | foreign_key_constraint. -type constraint_row() :: {constraint_row, binary(), binary(), binary(), constraint_kind(), binary(), integer(), gleam@option:option(binary()), gleam@option:option(binary()), gleam@option:option(binary())}. -type index_row() :: {index_row, binary(), binary(), binary(), boolean(), binary()}. -type introspection_error() :: {columns_query_error, pog:query_error()} | {constraints_query_error, pog:query_error()} | {indexes_query_error, pog:query_error()}. -file("src\\galchemy\\schema\\introspection\\postgres.gleam", 68). -spec default_options() -> introspection_options(). default_options() -> {introspection_options, [], false}. -file("src\\galchemy\\schema\\introspection\\postgres.gleam", 72). -spec only_schemas(introspection_options(), list(binary())) -> introspection_options(). only_schemas(Options, Schemas) -> {introspection_options, Schemas, erlang:element(3, Options)}. -file("src\\galchemy\\schema\\introspection\\postgres.gleam", 79). -spec include_system_schemas(introspection_options()) -> introspection_options(). include_system_schemas(Options) -> {introspection_options, erlang:element(2, Options), true}. -file("src\\galchemy\\schema\\introspection\\postgres.gleam", 255). -spec column_row_decoder() -> gleam@dynamic@decode:decoder(column_row()). column_row_decoder() -> _pipe = gleam@dynamic@decode:at( [0], {decoder, fun gleam@dynamic@decode:decode_string/1} ), gleam@dynamic@decode:then( _pipe, fun(Schema_name) -> _pipe@1 = gleam@dynamic@decode:at( [1], {decoder, fun gleam@dynamic@decode:decode_string/1} ), gleam@dynamic@decode:then( _pipe@1, fun(Table_name) -> _pipe@2 = gleam@dynamic@decode:at( [2], {decoder, fun gleam@dynamic@decode:decode_string/1} ), gleam@dynamic@decode:then( _pipe@2, fun(Column_name) -> _pipe@3 = gleam@dynamic@decode:at( [3], {decoder, fun gleam@dynamic@decode:decode_int/1} ), gleam@dynamic@decode:then( _pipe@3, fun(Ordinal_position) -> _pipe@4 = gleam@dynamic@decode:at( [4], {decoder, fun gleam@dynamic@decode:decode_bool/1} ), gleam@dynamic@decode:then( _pipe@4, fun(Is_nullable) -> _pipe@5 = gleam@dynamic@decode:at( [5], {decoder, fun gleam@dynamic@decode:decode_string/1} ), gleam@dynamic@decode:then( _pipe@5, fun(Data_type) -> _pipe@6 = gleam@dynamic@decode:at( [6], {decoder, fun gleam@dynamic@decode:decode_string/1} ), gleam@dynamic@decode:then( _pipe@6, fun(Udt_name) -> _pipe@7 = gleam@dynamic@decode:at( [7], gleam@dynamic@decode:optional( {decoder, fun gleam@dynamic@decode:decode_int/1} ) ), gleam@dynamic@decode:then( _pipe@7, fun( Character_maximum_length ) -> _pipe@8 = gleam@dynamic@decode:at( [8], gleam@dynamic@decode:optional( {decoder, fun gleam@dynamic@decode:decode_int/1} ) ), gleam@dynamic@decode:then( _pipe@8, fun( Numeric_precision ) -> _pipe@9 = gleam@dynamic@decode:at( [9], gleam@dynamic@decode:optional( {decoder, fun gleam@dynamic@decode:decode_int/1} ) ), gleam@dynamic@decode:then( _pipe@9, fun( Numeric_scale ) -> _pipe@10 = gleam@dynamic@decode:at( [10], gleam@dynamic@decode:optional( {decoder, fun gleam@dynamic@decode:decode_int/1} ) ), gleam@dynamic@decode:then( _pipe@10, fun( Datetime_precision ) -> _pipe@11 = gleam@dynamic@decode:at( [11], gleam@dynamic@decode:optional( {decoder, fun gleam@dynamic@decode:decode_string/1} ) ), gleam@dynamic@decode:map( _pipe@11, fun( Column_default ) -> {column_row, Schema_name, Table_name, Column_name, Ordinal_position, Is_nullable, Data_type, Udt_name, Character_maximum_length, Numeric_precision, Numeric_scale, Datetime_precision, Column_default} end ) end ) end ) end ) end ) end ) end ) end ) end ) end ) end ) end ). -file("src\\galchemy\\schema\\introspection\\postgres.gleam", 349). -spec index_row_decoder() -> gleam@dynamic@decode:decoder(index_row()). index_row_decoder() -> _pipe = gleam@dynamic@decode:at( [0], {decoder, fun gleam@dynamic@decode:decode_string/1} ), gleam@dynamic@decode:then( _pipe, fun(Schema_name) -> _pipe@1 = gleam@dynamic@decode:at( [1], {decoder, fun gleam@dynamic@decode:decode_string/1} ), gleam@dynamic@decode:then( _pipe@1, fun(Table_name) -> _pipe@2 = gleam@dynamic@decode:at( [2], {decoder, fun gleam@dynamic@decode:decode_string/1} ), gleam@dynamic@decode:then( _pipe@2, fun(Index_name) -> _pipe@3 = gleam@dynamic@decode:at( [3], {decoder, fun gleam@dynamic@decode:decode_bool/1} ), gleam@dynamic@decode:then( _pipe@3, fun(Is_unique) -> _pipe@4 = gleam@dynamic@decode:at( [4], {decoder, fun gleam@dynamic@decode:decode_string/1} ), gleam@dynamic@decode:map( _pipe@4, fun(Definition) -> {index_row, Schema_name, Table_name, Index_name, Is_unique, Definition} end ) end ) end ) end ) end ). -file("src\\galchemy\\schema\\introspection\\postgres.gleam", 404). -spec compile_system_filter(binary(), boolean()) -> binary(). compile_system_filter(Qualifier, Include_system_schemas) -> case Include_system_schemas of true -> <<""/utf8>>; false -> <<<<" AND "/utf8, Qualifier/binary>>/binary, " NOT IN ('pg_catalog', 'information_schema')"/utf8>> end. -file("src\\galchemy\\schema\\introspection\\postgres.gleam", 542). -spec collect_constraint_rows( list(constraint_row()), binary(), binary(), binary(), list(constraint_row()) ) -> {list(constraint_row()), list(constraint_row())}. collect_constraint_rows(Rows, Schema_name, Table_name, Constraint_name, Acc) -> case Rows of [] -> {Acc, []}; [Row | Rest] -> case ((erlang:element(2, Row) =:= Schema_name) andalso (erlang:element( 3, Row ) =:= Table_name)) andalso (erlang:element(4, Row) =:= Constraint_name) of true -> collect_constraint_rows( Rest, Schema_name, Table_name, Constraint_name, [Row | Acc] ); false -> {Acc, Rows} end end. -file("src\\galchemy\\schema\\introspection\\postgres.gleam", 737). -spec empty_table( binary(), binary(), list(galchemy@schema@model:column_schema()) ) -> galchemy@schema@model:table_schema(). empty_table(Schema_name, Table_name, Columns) -> {table_schema, Schema_name, Table_name, Columns, none, [], [], []}. -file("src\\galchemy\\schema\\introspection\\postgres.gleam", 715). -spec upsert_table( list(galchemy@schema@model:table_schema()), binary(), binary(), fun((galchemy@schema@model:table_schema()) -> galchemy@schema@model:table_schema()) ) -> list(galchemy@schema@model:table_schema()). upsert_table(Tables, Schema_name, Table_name, Updater) -> case Tables of [] -> [Updater(empty_table(Schema_name, Table_name, []))]; [Table_schema | Rest] -> case (erlang:element(2, Table_schema) =:= Schema_name) andalso (erlang:element( 3, Table_schema ) =:= Table_name) of true -> [Updater(Table_schema) | Rest]; false -> [Table_schema | upsert_table(Rest, Schema_name, Table_name, Updater)] end end. -file("src\\galchemy\\schema\\introspection\\postgres.gleam", 662). -spec apply_index_rows( list(galchemy@schema@model:table_schema()), list(index_row()) ) -> list(galchemy@schema@model:table_schema()). apply_index_rows(Tables, Rows) -> case Rows of [] -> Tables; [Row | Rest] -> Next_tables = upsert_table( Tables, erlang:element(2, Row), erlang:element(3, Row), fun(Table_schema) -> {table_schema, erlang:element(2, Table_schema), erlang:element(3, Table_schema), erlang:element(4, Table_schema), erlang:element(5, Table_schema), erlang:element(6, Table_schema), erlang:element(7, Table_schema), lists:append( erlang:element(8, Table_schema), [{index_schema, erlang:element(4, Row), erlang:element(5, Row), erlang:element(6, Row)}] )} end ), apply_index_rows(Next_tables, Rest) end. -file("src\\galchemy\\schema\\introspection\\postgres.gleam", 783). -spec infer_array_item_type(binary()) -> galchemy@schema@model:column_type(). infer_array_item_type(Udt_name) -> case Udt_name of <<"_int2"/utf8>> -> small_int_type; <<"_int4"/utf8>> -> integer_type; <<"_int8"/utf8>> -> big_int_type; <<"_bool"/utf8>> -> boolean_type; <<"_text"/utf8>> -> text_type; <<"_varchar"/utf8>> -> {var_char_type, none}; <<"_timestamp"/utf8>> -> {timestamp_type, false}; <<"_timestamptz"/utf8>> -> {timestamp_type, true}; <<"_time"/utf8>> -> {time_type, false}; <<"_timetz"/utf8>> -> {time_type, true}; <<"_date"/utf8>> -> date_type; <<"_float4"/utf8>> -> real_type; <<"_float8"/utf8>> -> double_precision_type; <<"_numeric"/utf8>> -> {numeric_type, none, none}; <<"_json"/utf8>> -> json_type; <<"_jsonb"/utf8>> -> jsonb_type; <<"_uuid"/utf8>> -> uuid_type; <<"_bytea"/utf8>> -> bytea_type; _ -> {custom_type, Udt_name} end. -file("src\\galchemy\\schema\\introspection\\postgres.gleam", 753). -spec infer_column_type(column_row()) -> galchemy@schema@model:column_type(). infer_column_type(Row) -> case erlang:element(7, Row) of <<"smallint"/utf8>> -> small_int_type; <<"integer"/utf8>> -> integer_type; <<"bigint"/utf8>> -> big_int_type; <<"boolean"/utf8>> -> boolean_type; <<"text"/utf8>> -> text_type; <<"character varying"/utf8>> -> {var_char_type, erlang:element(9, Row)}; <<"timestamp without time zone"/utf8>> -> {timestamp_type, false}; <<"timestamp with time zone"/utf8>> -> {timestamp_type, true}; <<"time without time zone"/utf8>> -> {time_type, false}; <<"time with time zone"/utf8>> -> {time_type, true}; <<"date"/utf8>> -> date_type; <<"real"/utf8>> -> real_type; <<"double precision"/utf8>> -> double_precision_type; <<"numeric"/utf8>> -> {numeric_type, erlang:element(10, Row), erlang:element(11, Row)}; <<"json"/utf8>> -> json_type; <<"jsonb"/utf8>> -> jsonb_type; <<"uuid"/utf8>> -> uuid_type; <<"bytea"/utf8>> -> bytea_type; <<"ARRAY"/utf8>> -> {array_type, infer_array_item_type(erlang:element(8, Row))}; _ -> {custom_type, erlang:element(8, Row)} end. -file("src\\galchemy\\schema\\introspection\\postgres.gleam", 807). -spec constraint_kind_from_string(binary()) -> constraint_kind(). constraint_kind_from_string(Value) -> case Value of <<"PRIMARY KEY"/utf8>> -> primary_key_constraint; <<"UNIQUE"/utf8>> -> unique_constraint; <<"FOREIGN KEY"/utf8>> -> foreign_key_constraint; _ -> Message = <<"Unsupported constraint kind: "/utf8, Value/binary>>, erlang:error(#{gleam_error => panic, message => Message, file => <>, module => <<"galchemy/schema/introspection/postgres"/utf8>>, function => <<"constraint_kind_from_string"/utf8>>, line => 814}) end. -file("src\\galchemy\\schema\\introspection\\postgres.gleam", 308). -spec constraint_row_decoder() -> gleam@dynamic@decode:decoder(constraint_row()). constraint_row_decoder() -> _pipe = gleam@dynamic@decode:at( [0], {decoder, fun gleam@dynamic@decode:decode_string/1} ), gleam@dynamic@decode:then( _pipe, fun(Schema_name) -> _pipe@1 = gleam@dynamic@decode:at( [1], {decoder, fun gleam@dynamic@decode:decode_string/1} ), gleam@dynamic@decode:then( _pipe@1, fun(Table_name) -> _pipe@2 = gleam@dynamic@decode:at( [2], {decoder, fun gleam@dynamic@decode:decode_string/1} ), gleam@dynamic@decode:then( _pipe@2, fun(Constraint_name) -> _pipe@3 = gleam@dynamic@decode:at( [3], {decoder, fun gleam@dynamic@decode:decode_string/1} ), gleam@dynamic@decode:then( _pipe@3, fun(Kind_name) -> _pipe@4 = gleam@dynamic@decode:at( [4], {decoder, fun gleam@dynamic@decode:decode_string/1} ), gleam@dynamic@decode:then( _pipe@4, fun(Column_name) -> _pipe@5 = gleam@dynamic@decode:at( [5], {decoder, fun gleam@dynamic@decode:decode_int/1} ), gleam@dynamic@decode:then( _pipe@5, fun(Ordinal_position) -> _pipe@6 = gleam@dynamic@decode:at( [6], gleam@dynamic@decode:optional( {decoder, fun gleam@dynamic@decode:decode_string/1} ) ), gleam@dynamic@decode:then( _pipe@6, fun(Referenced_schema) -> _pipe@7 = gleam@dynamic@decode:at( [7], gleam@dynamic@decode:optional( {decoder, fun gleam@dynamic@decode:decode_string/1} ) ), gleam@dynamic@decode:then( _pipe@7, fun( Referenced_table ) -> _pipe@8 = gleam@dynamic@decode:at( [8], gleam@dynamic@decode:optional( {decoder, fun gleam@dynamic@decode:decode_string/1} ) ), gleam@dynamic@decode:map( _pipe@8, fun( Referenced_column ) -> {constraint_row, Schema_name, Table_name, Constraint_name, constraint_kind_from_string( Kind_name ), Column_name, Ordinal_position, Referenced_schema, Referenced_table, Referenced_column} end ) end ) end ) end ) end ) end ) end ) end ) end ). -file("src\\galchemy\\schema\\introspection\\postgres.gleam", 819). -spec option_or_panic(gleam@option:option(NGF), binary()) -> NGF. option_or_panic(Value, Message) -> case Value of {some, Inner} -> Inner; none -> erlang:error(#{gleam_error => panic, message => Message, file => <>, module => <<"galchemy/schema/introspection/postgres"/utf8>>, function => <<"option_or_panic"/utf8>>, line => 822}) end. -file("src\\galchemy\\schema\\introspection\\postgres.gleam", 833). -spec join_strings_loop(list(binary()), binary(), binary()) -> binary(). join_strings_loop(Parts, Acc, Sep) -> case Parts of [] -> Acc; [Part | Rest] -> join_strings_loop( Rest, <<<>/binary, Part/binary>>, Sep ) end. -file("src\\galchemy\\schema\\introspection\\postgres.gleam", 826). -spec join_strings(list(binary()), binary()) -> binary(). join_strings(Parts, Sep) -> case Parts of [] -> <<""/utf8>>; [First | Rest] -> join_strings_loop(Rest, First, Sep) end. -file("src\\galchemy\\schema\\introspection\\postgres.gleam", 844). -spec reverse_loop(list(NGM), list(NGM)) -> list(NGM). reverse_loop(Items, Acc) -> case Items of [] -> Acc; [Item | Rest] -> reverse_loop(Rest, [Item | Acc]) end. -file("src\\galchemy\\schema\\introspection\\postgres.gleam", 840). -spec reverse(list(NGJ)) -> list(NGJ). reverse(Items) -> reverse_loop(Items, []). -file("src\\galchemy\\schema\\introspection\\postgres.gleam", 437). -spec schema_placeholders(list(binary()), integer(), list(binary())) -> list(binary()). schema_placeholders(Schemas, Next_index, Acc) -> case Schemas of [] -> reverse(Acc); [_ | Rest] -> schema_placeholders( Rest, Next_index + 1, [<<"$"/utf8, (erlang:integer_to_binary(Next_index))/binary>> | Acc] ) end. -file("src\\galchemy\\schema\\introspection\\postgres.gleam", 415). -spec compile_schema_filter(binary(), list(binary())) -> {binary(), list(galchemy@ast@expression:sql_value())}. compile_schema_filter(Qualifier, Schemas) -> case Schemas of [] -> {<<""/utf8>>, []}; _ -> Placeholders = schema_placeholders(Schemas, 1, []), Params = gleam@list:map( Schemas, fun(Field@0) -> {text, Field@0} end ), {<<<<<<<<" AND "/utf8, Qualifier/binary>>/binary, " IN ("/utf8>>/binary, (join_strings(Placeholders, <<", "/utf8>>))/binary>>/binary, ")"/utf8>>, Params} end. -file("src\\galchemy\\schema\\introspection\\postgres.gleam", 89). -spec compile_columns_query(introspection_options()) -> galchemy@sql@compiler:compiled_query(). compile_columns_query(Options) -> {introspection_options, Schemas, Include_system_schemas} = Options, Base_sql = <<<<<<<<<<<<<<<<"SELECT c.table_schema, c.table_name, c.column_name, c.ordinal_position, "/utf8, "(c.is_nullable = 'YES') AS is_nullable, "/utf8>>/binary, "c.data_type, c.udt_name, c.character_maximum_length, "/utf8>>/binary, "c.numeric_precision, c.numeric_scale, c.datetime_precision, c.column_default "/utf8>>/binary, "FROM information_schema.columns AS c "/utf8>>/binary, "INNER JOIN information_schema.tables AS t "/utf8>>/binary, "ON t.table_schema = c.table_schema "/utf8>>/binary, "AND t.table_name = c.table_name "/utf8>>/binary, "WHERE t.table_type = 'BASE TABLE'"/utf8>>, System_filter_sql = compile_system_filter( <<"c.table_schema"/utf8>>, Include_system_schemas ), {Schema_filter_sql, Params} = compile_schema_filter( <<"c.table_schema"/utf8>>, Schemas ), {compiled_query, <<<<<>/binary, Schema_filter_sql/binary>>/binary, " ORDER BY c.table_schema, c.table_name, c.ordinal_position"/utf8>>, Params}. -file("src\\galchemy\\schema\\introspection\\postgres.gleam", 85). -spec compile_query(introspection_options()) -> galchemy@sql@compiler:compiled_query(). compile_query(Options) -> compile_columns_query(Options). -file("src\\galchemy\\schema\\introspection\\postgres.gleam", 122). -spec compile_constraints_query(introspection_options()) -> galchemy@sql@compiler:compiled_query(). compile_constraints_query(Options) -> {introspection_options, Schemas, Include_system_schemas} = Options, Base_sql = <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"SELECT tc.table_schema, tc.table_name, tc.constraint_name, tc.constraint_type, "/utf8, "kcu.column_name, kcu.ordinal_position, "/utf8>>/binary, "ccu.table_schema AS referenced_schema, "/utf8>>/binary, "ccu.table_name AS referenced_table, "/utf8>>/binary, "ccu.column_name AS referenced_column "/utf8>>/binary, "FROM information_schema.table_constraints AS tc "/utf8>>/binary, "INNER JOIN information_schema.key_column_usage AS kcu "/utf8>>/binary, "ON tc.constraint_schema = kcu.constraint_schema "/utf8>>/binary, "AND tc.constraint_name = kcu.constraint_name "/utf8>>/binary, "AND tc.table_schema = kcu.table_schema "/utf8>>/binary, "AND tc.table_name = kcu.table_name "/utf8>>/binary, "LEFT JOIN information_schema.referential_constraints AS rc "/utf8>>/binary, "ON tc.constraint_schema = rc.constraint_schema "/utf8>>/binary, "AND tc.constraint_name = rc.constraint_name "/utf8>>/binary, "LEFT JOIN information_schema.key_column_usage AS ccu "/utf8>>/binary, "ON rc.unique_constraint_schema = ccu.constraint_schema "/utf8>>/binary, "AND rc.unique_constraint_name = ccu.constraint_name "/utf8>>/binary, "AND kcu.position_in_unique_constraint = ccu.ordinal_position "/utf8>>/binary, "WHERE tc.constraint_type IN ('PRIMARY KEY', 'UNIQUE', 'FOREIGN KEY')"/utf8>>, System_filter_sql = compile_system_filter( <<"tc.table_schema"/utf8>>, Include_system_schemas ), {Schema_filter_sql, Params} = compile_schema_filter( <<"tc.table_schema"/utf8>>, Schemas ), {compiled_query, <<<<<>/binary, Schema_filter_sql/binary>>/binary, " ORDER BY tc.table_schema, tc.table_name, tc.constraint_name, kcu.ordinal_position"/utf8>>, Params}. -file("src\\galchemy\\schema\\introspection\\postgres.gleam", 165). -spec compile_indexes_query(introspection_options()) -> galchemy@sql@compiler:compiled_query(). compile_indexes_query(Options) -> {introspection_options, Schemas, Include_system_schemas} = Options, Base_sql = <<<<<<<<<<<<<<"SELECT ns.nspname AS table_schema, tbl.relname AS table_name, "/utf8, "idx.relname AS index_name, ind.indisunique AS is_unique, "/utf8>>/binary, "pg_get_indexdef(ind.indexrelid) AS index_definition "/utf8>>/binary, "FROM pg_index AS ind "/utf8>>/binary, "INNER JOIN pg_class AS tbl ON tbl.oid = ind.indrelid "/utf8>>/binary, "INNER JOIN pg_namespace AS ns ON ns.oid = tbl.relnamespace "/utf8>>/binary, "INNER JOIN pg_class AS idx ON idx.oid = ind.indexrelid "/utf8>>/binary, "WHERE tbl.relkind = 'r' AND NOT ind.indisprimary"/utf8>>, System_filter_sql = compile_system_filter( <<"ns.nspname"/utf8>>, Include_system_schemas ), {Schema_filter_sql, Params} = compile_schema_filter( <<"ns.nspname"/utf8>>, Schemas ), {compiled_query, <<<<<>/binary, Schema_filter_sql/binary>>/binary, " ORDER BY ns.nspname, tbl.relname, idx.relname"/utf8>>, Params}. -file("src\\galchemy\\schema\\introspection\\postgres.gleam", 201). -spec to_columns_query(introspection_options()) -> pog:'query'(column_row()). to_columns_query(Options) -> pog:returning( galchemy@sql@postgres:to_query_from_compiled( compile_columns_query(Options) ), column_row_decoder() ). -file("src\\galchemy\\schema\\introspection\\postgres.gleam", 197). -spec to_query(introspection_options()) -> pog:'query'(column_row()). to_query(Options) -> to_columns_query(Options). -file("src\\galchemy\\schema\\introspection\\postgres.gleam", 208). -spec to_constraints_query(introspection_options()) -> pog:'query'(constraint_row()). to_constraints_query(Options) -> pog:returning( galchemy@sql@postgres:to_query_from_compiled( compile_constraints_query(Options) ), constraint_row_decoder() ). -file("src\\galchemy\\schema\\introspection\\postgres.gleam", 217). -spec to_indexes_query(introspection_options()) -> pog:'query'(index_row()). to_indexes_query(Options) -> pog:returning( galchemy@sql@postgres:to_query_from_compiled( compile_indexes_query(Options) ), index_row_decoder() ). -file("src\\galchemy\\schema\\introspection\\postgres.gleam", 374). -spec execute_columns_query(pog:connection(), introspection_options()) -> {ok, list(column_row())} | {error, introspection_error()}. execute_columns_query(Connection, Options) -> case pog:execute(to_columns_query(Options), Connection) of {ok, {returned, _, Rows}} -> {ok, Rows}; {error, Error} -> {error, {columns_query_error, Error}} end. -file("src\\galchemy\\schema\\introspection\\postgres.gleam", 384). -spec execute_constraints_query(pog:connection(), introspection_options()) -> {ok, list(constraint_row())} | {error, introspection_error()}. execute_constraints_query(Connection, Options) -> case pog:execute(to_constraints_query(Options), Connection) of {ok, {returned, _, Rows}} -> {ok, Rows}; {error, Error} -> {error, {constraints_query_error, Error}} end. -file("src\\galchemy\\schema\\introspection\\postgres.gleam", 394). -spec execute_indexes_query(pog:connection(), introspection_options()) -> {ok, list(index_row())} | {error, introspection_error()}. execute_indexes_query(Connection, Options) -> case pog:execute(to_indexes_query(Options), Connection) of {ok, {returned, _, Rows}} -> {ok, Rows}; {error, Error} -> {error, {indexes_query_error, Error}} end. -file("src\\galchemy\\schema\\introspection\\postgres.gleam", 498). -spec column_rows_to_columns( list(column_row()), list(galchemy@schema@model:column_schema()) ) -> list(galchemy@schema@model:column_schema()). column_rows_to_columns(Rows, Acc) -> case Rows of [] -> reverse(Acc); [Row | Rest] -> column_rows_to_columns( Rest, [{column_schema, erlang:element(4, Row), infer_column_type(Row), erlang:element(6, Row), erlang:element(13, Row), erlang:element(5, Row)} | Acc] ) end. -file("src\\galchemy\\schema\\introspection\\postgres.gleam", 466). -spec collect_table_rows( list(column_row()), binary(), binary(), list(column_row()) ) -> {galchemy@schema@model:table_schema(), list(column_row())}. collect_table_rows(Rows, Schema_name, Table_name, Acc) -> case Rows of [] -> {empty_table( Schema_name, Table_name, column_rows_to_columns(reverse(Acc), []) ), []}; [Row | Rest] -> case (erlang:element(2, Row) =:= Schema_name) andalso (erlang:element( 3, Row ) =:= Table_name) of true -> collect_table_rows( Rest, Schema_name, Table_name, [Row | Acc] ); false -> {empty_table( Schema_name, Table_name, column_rows_to_columns(reverse(Acc), []) ), Rows} end end. -file("src\\galchemy\\schema\\introspection\\postgres.gleam", 452). -spec column_rows_to_tables( list(column_row()), list(galchemy@schema@model:table_schema()) ) -> list(galchemy@schema@model:table_schema()). column_rows_to_tables(Rows, Acc) -> case Rows of [] -> reverse(Acc); [First | Rest] -> {Table_schema, Remaining_rows} = collect_table_rows( Rest, erlang:element(2, First), erlang:element(3, First), [First] ), column_rows_to_tables(Remaining_rows, [Table_schema | Acc]) end. -file("src\\galchemy\\schema\\introspection\\postgres.gleam", 688). -spec constraint_columns(list(constraint_row()), list(binary())) -> list(binary()). constraint_columns(Rows, Acc) -> case Rows of [] -> reverse(Acc); [Row | Rest] -> constraint_columns(Rest, [erlang:element(6, Row) | Acc]) end. -file("src\\galchemy\\schema\\introspection\\postgres.gleam", 589). -spec add_primary_key(list(constraint_row())) -> fun((galchemy@schema@model:table_schema()) -> galchemy@schema@model:table_schema()). add_primary_key(Rows) -> fun(Table_schema) -> case Rows of [] -> Table_schema; [First | _] -> {table_schema, erlang:element(2, Table_schema), erlang:element(3, Table_schema), erlang:element(4, Table_schema), {some, {primary_key, erlang:element(4, First), constraint_columns(Rows, [])}}, erlang:element(6, Table_schema), erlang:element(7, Table_schema), erlang:element(8, Table_schema)} end end. -file("src\\galchemy\\schema\\introspection\\postgres.gleam", 607). -spec add_unique_constraint(list(constraint_row())) -> fun((galchemy@schema@model:table_schema()) -> galchemy@schema@model:table_schema()). add_unique_constraint(Rows) -> fun(Table_schema) -> case Rows of [] -> Table_schema; [First | _] -> {table_schema, erlang:element(2, Table_schema), erlang:element(3, Table_schema), erlang:element(4, Table_schema), erlang:element(5, Table_schema), lists:append( erlang:element(6, Table_schema), [{unique_constraint, erlang:element(4, First), constraint_columns(Rows, [])}] ), erlang:element(7, Table_schema), erlang:element(8, Table_schema)} end end. -file("src\\galchemy\\schema\\introspection\\postgres.gleam", 698). -spec foreign_key_columns(list(constraint_row()), list(binary())) -> list(binary()). foreign_key_columns(Rows, Acc) -> case Rows of [] -> reverse(Acc); [Row | Rest] -> Referenced_column = option_or_panic( erlang:element(10, Row), <<"Foreign key referenced column is missing"/utf8>> ), foreign_key_columns(Rest, [Referenced_column | Acc]) end. -file("src\\galchemy\\schema\\introspection\\postgres.gleam", 627). -spec add_foreign_key(list(constraint_row())) -> fun((galchemy@schema@model:table_schema()) -> galchemy@schema@model:table_schema()). add_foreign_key(Rows) -> fun(Table_schema) -> case Rows of [] -> Table_schema; [First | _] -> Referenced_schema = option_or_panic( erlang:element(8, First), <<"Foreign key referenced schema is missing"/utf8>> ), Referenced_table = option_or_panic( erlang:element(9, First), <<"Foreign key referenced table is missing"/utf8>> ), {table_schema, erlang:element(2, Table_schema), erlang:element(3, Table_schema), erlang:element(4, Table_schema), erlang:element(5, Table_schema), erlang:element(6, Table_schema), lists:append( erlang:element(7, Table_schema), [{foreign_key, erlang:element(4, First), constraint_columns(Rows, []), Referenced_schema, Referenced_table, foreign_key_columns(Rows, [])}] ), erlang:element(8, Table_schema)} end end. -file("src\\galchemy\\schema\\introspection\\postgres.gleam", 571). -spec apply_constraint_group( list(galchemy@schema@model:table_schema()), list(constraint_row()) ) -> list(galchemy@schema@model:table_schema()). apply_constraint_group(Tables, Rows) -> case Rows of [] -> Tables; [First | _] -> Updater = case erlang:element(5, First) of primary_key_constraint -> add_primary_key(Rows); unique_constraint -> add_unique_constraint(Rows); foreign_key_constraint -> add_foreign_key(Rows) end, upsert_table( Tables, erlang:element(2, First), erlang:element(3, First), Updater ) end. -file("src\\galchemy\\schema\\introspection\\postgres.gleam", 518). -spec apply_constraint_rows( list(galchemy@schema@model:table_schema()), list(constraint_row()) ) -> list(galchemy@schema@model:table_schema()). apply_constraint_rows(Tables, Rows) -> case Rows of [] -> Tables; [First | Rest] -> {Same_constraint_rows, Remaining_rows} = collect_constraint_rows( Rest, erlang:element(2, First), erlang:element(3, First), erlang:element(4, First), [First] ), Next_tables = apply_constraint_group( Tables, reverse(Same_constraint_rows) ), apply_constraint_rows(Next_tables, Remaining_rows) end. -file("src\\galchemy\\schema\\introspection\\postgres.gleam", 244). -spec rows_to_snapshot( list(column_row()), list(constraint_row()), list(index_row()) ) -> galchemy@schema@model:schema_snapshot(). rows_to_snapshot(Columns, Constraints, Indexes) -> Base_tables = column_rows_to_tables(Columns, []), Tables_with_constraints = apply_constraint_rows(Base_tables, Constraints), Tables_with_indexes = apply_index_rows(Tables_with_constraints, Indexes), {schema_snapshot, Tables_with_indexes}. -file("src\\galchemy\\schema\\introspection\\postgres.gleam", 224). -spec introspect(pog:connection(), introspection_options()) -> {ok, galchemy@schema@model:schema_snapshot()} | {error, introspection_error()}. introspect(Connection, Options) -> case execute_columns_query(Connection, Options) of {ok, Columns} -> case execute_constraints_query(Connection, Options) of {ok, Constraints} -> case execute_indexes_query(Connection, Options) of {ok, Indexes} -> {ok, rows_to_snapshot(Columns, Constraints, Indexes)}; {error, Error} -> {error, Error} end; {error, Error@1} -> {error, Error@1} end; {error, Error@2} -> {error, Error@2} end.