-module(cquill@codegen@type_mapping). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/cquill/codegen/type_mapping.gleam"). -export([render_type/1, render_qualified_type/1, get_imports/1, collect_imports/1, pascal_case/1, map_postgres_type/4, map_column/6, snake_case/1, is_nullable_type/1, is_list_type/1, is_custom_type/1, unwrap_option/1, unwrap_list/1, types_equal/2]). -export_type([gleam_type/0, column_meta/0, type_mapping_error/0]). -if(?OTP_RELEASE >= 27). -define(MODULEDOC(Str), -moduledoc(Str)). -define(DOC(Str), -doc(Str)). -else. -define(MODULEDOC(Str), -compile([])). -define(DOC(Str), -compile([])). -endif. -type gleam_type() :: gleam_int | gleam_float | gleam_string | gleam_bool | gleam_bit_array | gleam_time | gleam_date | gleam_time_of_day | gleam_decimal | gleam_uuid | gleam_json | {gleam_list, gleam_type()} | {gleam_option, gleam_type()} | {gleam_custom, binary(), binary()}. -type column_meta() :: {column_meta, gleam_type(), boolean(), binary(), binary(), binary(), boolean()}. -type type_mapping_error() :: {unknown_type, binary(), binary()} | {unsupported_array, binary()}. -file("src/cquill/codegen/type_mapping.gleam", 403). ?DOC(" Detect if a column is auto-generated based on type and default\n"). -spec detect_auto_generated(binary(), gleam@option:option(binary())) -> boolean(). detect_auto_generated(Data_type, Column_default) -> Lowercase_type = string:lowercase(Data_type), Is_serial = case Lowercase_type of <<"serial"/utf8>> -> true; <<"serial2"/utf8>> -> true; <<"serial4"/utf8>> -> true; <<"smallserial"/utf8>> -> true; <<"bigserial"/utf8>> -> true; <<"serial8"/utf8>> -> true; _ -> false end, Has_sequence_default = case Column_default of {some, Default_expr} -> gleam_stdlib:contains_string( string:lowercase(Default_expr), <<"nextval"/utf8>> ); none -> false end, Has_auto_default = case Column_default of {some, Default_expr@1} -> Lower = string:lowercase(Default_expr@1), (((gleam_stdlib:contains_string(Lower, <<"now()"/utf8>>) orelse gleam_stdlib:contains_string( Lower, <<"current_timestamp"/utf8>> )) orelse gleam_stdlib:contains_string(Lower, <<"current_date"/utf8>>)) orelse gleam_stdlib:contains_string( Lower, <<"gen_random_uuid"/utf8>> )) orelse gleam_stdlib:contains_string(Lower, <<"uuid_generate"/utf8>>); none -> false end, (Is_serial orelse Has_sequence_default) orelse Has_auto_default. -file("src/cquill/codegen/type_mapping.gleam", 444). ?DOC(" Render a GleamType as a Gleam type string for code generation\n"). -spec render_type(gleam_type()) -> binary(). render_type(Gleam_type) -> case Gleam_type of gleam_int -> <<"Int"/utf8>>; gleam_float -> <<"Float"/utf8>>; gleam_string -> <<"String"/utf8>>; gleam_bool -> <<"Bool"/utf8>>; gleam_bit_array -> <<"BitArray"/utf8>>; gleam_time -> <<"Time"/utf8>>; gleam_date -> <<"Date"/utf8>>; gleam_time_of_day -> <<"TimeOfDay"/utf8>>; gleam_decimal -> <<"Decimal"/utf8>>; gleam_uuid -> <<"Uuid"/utf8>>; gleam_json -> <<"Json"/utf8>>; {gleam_list, Element_type} -> <<<<"List("/utf8, (render_type(Element_type))/binary>>/binary, ")"/utf8>>; {gleam_option, Inner_type} -> <<<<"Option("/utf8, (render_type(Inner_type))/binary>>/binary, ")"/utf8>>; {gleam_custom, _, Type_name} -> Type_name end. -file("src/cquill/codegen/type_mapping.gleam", 464). ?DOC(" Render a GleamType as a fully qualified Gleam type string (with imports)\n"). -spec render_qualified_type(gleam_type()) -> binary(). render_qualified_type(Gleam_type) -> case Gleam_type of gleam_int -> <<"Int"/utf8>>; gleam_float -> <<"Float"/utf8>>; gleam_string -> <<"String"/utf8>>; gleam_bool -> <<"Bool"/utf8>>; gleam_bit_array -> <<"BitArray"/utf8>>; gleam_time -> <<"birl.Time"/utf8>>; gleam_date -> <<"birl.Date"/utf8>>; gleam_time_of_day -> <<"birl.TimeOfDay"/utf8>>; gleam_decimal -> <<"decimal.Decimal"/utf8>>; gleam_uuid -> <<"uuid.Uuid"/utf8>>; gleam_json -> <<"json.Json"/utf8>>; {gleam_list, Element_type} -> <<<<"List("/utf8, (render_qualified_type(Element_type))/binary>>/binary, ")"/utf8>>; {gleam_option, Inner_type} -> <<<<"option.Option("/utf8, (render_qualified_type(Inner_type))/binary>>/binary, ")"/utf8>>; {gleam_custom, Module, Type_name} -> <<<>/binary, Type_name/binary>> end. -file("src/cquill/codegen/type_mapping.gleam", 486). ?DOC(" Get the imports needed for a GleamType\n"). -spec get_imports(gleam_type()) -> list(binary()). get_imports(Gleam_type) -> case Gleam_type of gleam_int -> []; gleam_float -> []; gleam_string -> []; gleam_bool -> []; gleam_bit_array -> []; gleam_time -> [<<"birl"/utf8>>]; gleam_date -> [<<"birl"/utf8>>]; gleam_time_of_day -> [<<"birl"/utf8>>]; gleam_decimal -> [<<"decimal"/utf8>>]; gleam_uuid -> [<<"uuid"/utf8>>]; gleam_json -> [<<"gleam/json"/utf8>>]; {gleam_list, Element_type} -> get_imports(Element_type); {gleam_option, Inner_type} -> [<<"gleam/option"/utf8>> | get_imports(Inner_type)]; {gleam_custom, Module, _} -> [Module] end. -file("src/cquill/codegen/type_mapping.gleam", 500). ?DOC(" Collect all unique imports needed for a list of column metadata\n"). -spec collect_imports(list(column_meta())) -> list(binary()). collect_imports(Columns) -> _pipe = Columns, _pipe@1 = gleam@list:flat_map( _pipe, fun(Col) -> get_imports(erlang:element(2, Col)) end ), _pipe@2 = gleam@list:unique(_pipe@1), gleam@list:sort(_pipe@2, fun gleam@string:compare/2). -file("src/cquill/codegen/type_mapping.gleam", 520). ?DOC(" Capitalize the first letter of a string\n"). -spec capitalize_first(binary()) -> binary(). capitalize_first(S) -> case gleam_stdlib:string_pop_grapheme(S) of {ok, {First, Rest}} -> <<(string:uppercase(First))/binary, Rest/binary>>; {error, _} -> S end. -file("src/cquill/codegen/type_mapping.gleam", 512). ?DOC(" Convert snake_case to PascalCase\n"). -spec pascal_case(binary()) -> binary(). pascal_case(Input) -> _pipe = Input, _pipe@1 = gleam@string:split(_pipe, <<"_"/utf8>>), _pipe@2 = gleam@list:map(_pipe@1, fun capitalize_first/1), gleam@string:join(_pipe@2, <<""/utf8>>). -file("src/cquill/codegen/type_mapping.gleam", 218). ?DOC(" Map array element types\n"). -spec map_element_type(binary(), list(binary())) -> {ok, gleam_type()} | {error, type_mapping_error()}. map_element_type(Element_udt, Enum_names) -> Lowercase_udt = string:lowercase(Element_udt), case Lowercase_udt of <<"int4"/utf8>> -> {ok, gleam_int}; <<"int"/utf8>> -> {ok, gleam_int}; <<"integer"/utf8>> -> {ok, gleam_int}; <<"int2"/utf8>> -> {ok, gleam_int}; <<"smallint"/utf8>> -> {ok, gleam_int}; <<"int8"/utf8>> -> {ok, gleam_int}; <<"bigint"/utf8>> -> {ok, gleam_int}; <<"float4"/utf8>> -> {ok, gleam_float}; <<"real"/utf8>> -> {ok, gleam_float}; <<"float8"/utf8>> -> {ok, gleam_float}; <<"double precision"/utf8>> -> {ok, gleam_float}; <<"numeric"/utf8>> -> {ok, gleam_decimal}; <<"decimal"/utf8>> -> {ok, gleam_decimal}; <<"varchar"/utf8>> -> {ok, gleam_string}; <<"character varying"/utf8>> -> {ok, gleam_string}; <<"bpchar"/utf8>> -> {ok, gleam_string}; <<"char"/utf8>> -> {ok, gleam_string}; <<"character"/utf8>> -> {ok, gleam_string}; <<"text"/utf8>> -> {ok, gleam_string}; <<"name"/utf8>> -> {ok, gleam_string}; <<"bool"/utf8>> -> {ok, gleam_bool}; <<"boolean"/utf8>> -> {ok, gleam_bool}; <<"bytea"/utf8>> -> {ok, gleam_bit_array}; <<"timestamp"/utf8>> -> {ok, gleam_time}; <<"timestamptz"/utf8>> -> {ok, gleam_time}; <<"date"/utf8>> -> {ok, gleam_date}; <<"time"/utf8>> -> {ok, gleam_time_of_day}; <<"timetz"/utf8>> -> {ok, gleam_time_of_day}; <<"uuid"/utf8>> -> {ok, gleam_uuid}; <<"json"/utf8>> -> {ok, gleam_json}; <<"jsonb"/utf8>> -> {ok, gleam_json}; _ -> case gleam@list:contains(Enum_names, Element_udt) of true -> {ok, {gleam_custom, <<"schema/enums"/utf8>>, pascal_case(Element_udt)}}; false -> {error, {unknown_type, Element_udt, Element_udt}} end end. -file("src/cquill/codegen/type_mapping.gleam", 199). ?DOC(" Map an array type based on its element type (from udt_name with _ prefix)\n"). -spec map_array_type(binary(), list(binary())) -> {ok, gleam_type()} | {error, type_mapping_error()}. map_array_type(Udt_name, Enum_names) -> case gleam_stdlib:string_starts_with(Udt_name, <<"_"/utf8>>) of true -> Element_udt = gleam@string:drop_start(Udt_name, 1), case map_element_type(Element_udt, Enum_names) of {ok, Element_type} -> {ok, {gleam_list, Element_type}}; {error, _} -> {error, {unsupported_array, Element_udt}} end; false -> {error, {unsupported_array, Udt_name}} end. -file("src/cquill/codegen/type_mapping.gleam", 279). ?DOC(" Map user-defined types (primarily enums)\n"). -spec map_user_defined_type(binary(), list(binary())) -> {ok, gleam_type()} | {error, type_mapping_error()}. map_user_defined_type(Udt_name, Enum_names) -> case gleam@list:contains(Enum_names, Udt_name) of true -> {ok, {gleam_custom, <<"schema/enums"/utf8>>, pascal_case(Udt_name)}}; false -> {ok, {gleam_custom, <<"schema/types"/utf8>>, pascal_case(Udt_name)}} end. -file("src/cquill/codegen/type_mapping.gleam", 295). ?DOC(" Try to map by udt_name when data_type is not specific enough\n"). -spec map_by_udt_name(binary(), list(binary())) -> {ok, gleam_type()} | {error, type_mapping_error()}. map_by_udt_name(Udt_name, Enum_names) -> case Udt_name of <<"int4"/utf8>> -> {ok, gleam_int}; <<"int"/utf8>> -> {ok, gleam_int}; <<"int2"/utf8>> -> {ok, gleam_int}; <<"int8"/utf8>> -> {ok, gleam_int}; <<"float4"/utf8>> -> {ok, gleam_float}; <<"float8"/utf8>> -> {ok, gleam_float}; <<"numeric"/utf8>> -> {ok, gleam_decimal}; <<"varchar"/utf8>> -> {ok, gleam_string}; <<"bpchar"/utf8>> -> {ok, gleam_string}; <<"text"/utf8>> -> {ok, gleam_string}; <<"name"/utf8>> -> {ok, gleam_string}; <<"bool"/utf8>> -> {ok, gleam_bool}; <<"bytea"/utf8>> -> {ok, gleam_bit_array}; <<"timestamp"/utf8>> -> {ok, gleam_time}; <<"timestamptz"/utf8>> -> {ok, gleam_time}; <<"date"/utf8>> -> {ok, gleam_date}; <<"time"/utf8>> -> {ok, gleam_time_of_day}; <<"timetz"/utf8>> -> {ok, gleam_time_of_day}; <<"uuid"/utf8>> -> {ok, gleam_uuid}; <<"json"/utf8>> -> {ok, gleam_json}; <<"jsonb"/utf8>> -> {ok, gleam_json}; _ -> case gleam_stdlib:string_starts_with(Udt_name, <<"_"/utf8>>) of true -> map_array_type(Udt_name, Enum_names); false -> case gleam@list:contains(Enum_names, Udt_name) of true -> {ok, {gleam_custom, <<"schema/enums"/utf8>>, pascal_case(Udt_name)}}; false -> {error, {unknown_type, <<"unknown"/utf8>>, Udt_name}} end end end. -file("src/cquill/codegen/type_mapping.gleam", 128). ?DOC(" Map a PostgreSQL type to a base Gleam type (without Option wrapper)\n"). -spec map_base_type(binary(), binary(), list(binary())) -> {ok, gleam_type()} | {error, type_mapping_error()}. map_base_type(Data_type, Udt_name, Enum_names) -> Lowercase_data_type = string:lowercase(Data_type), Lowercase_udt_name = string:lowercase(Udt_name), case Lowercase_data_type of <<"integer"/utf8>> -> {ok, gleam_int}; <<"int"/utf8>> -> {ok, gleam_int}; <<"int4"/utf8>> -> {ok, gleam_int}; <<"smallint"/utf8>> -> {ok, gleam_int}; <<"int2"/utf8>> -> {ok, gleam_int}; <<"bigint"/utf8>> -> {ok, gleam_int}; <<"int8"/utf8>> -> {ok, gleam_int}; <<"serial"/utf8>> -> {ok, gleam_int}; <<"serial4"/utf8>> -> {ok, gleam_int}; <<"smallserial"/utf8>> -> {ok, gleam_int}; <<"serial2"/utf8>> -> {ok, gleam_int}; <<"bigserial"/utf8>> -> {ok, gleam_int}; <<"serial8"/utf8>> -> {ok, gleam_int}; <<"real"/utf8>> -> {ok, gleam_float}; <<"float4"/utf8>> -> {ok, gleam_float}; <<"double precision"/utf8>> -> {ok, gleam_float}; <<"float8"/utf8>> -> {ok, gleam_float}; <<"numeric"/utf8>> -> {ok, gleam_decimal}; <<"decimal"/utf8>> -> {ok, gleam_decimal}; <<"character varying"/utf8>> -> {ok, gleam_string}; <<"varchar"/utf8>> -> {ok, gleam_string}; <<"character"/utf8>> -> {ok, gleam_string}; <<"char"/utf8>> -> {ok, gleam_string}; <<"bpchar"/utf8>> -> {ok, gleam_string}; <<"text"/utf8>> -> {ok, gleam_string}; <<"name"/utf8>> -> {ok, gleam_string}; <<"boolean"/utf8>> -> {ok, gleam_bool}; <<"bool"/utf8>> -> {ok, gleam_bool}; <<"bytea"/utf8>> -> {ok, gleam_bit_array}; <<"timestamp without time zone"/utf8>> -> {ok, gleam_time}; <<"timestamp"/utf8>> -> {ok, gleam_time}; <<"timestamp with time zone"/utf8>> -> {ok, gleam_time}; <<"timestamptz"/utf8>> -> {ok, gleam_time}; <<"date"/utf8>> -> {ok, gleam_date}; <<"time without time zone"/utf8>> -> {ok, gleam_time_of_day}; <<"time"/utf8>> -> {ok, gleam_time_of_day}; <<"time with time zone"/utf8>> -> {ok, gleam_time_of_day}; <<"timetz"/utf8>> -> {ok, gleam_time_of_day}; <<"interval"/utf8>> -> {ok, gleam_string}; <<"uuid"/utf8>> -> {ok, gleam_uuid}; <<"json"/utf8>> -> {ok, gleam_json}; <<"jsonb"/utf8>> -> {ok, gleam_json}; <<"array"/utf8>> -> map_array_type(Lowercase_udt_name, Enum_names); <<"user-defined"/utf8>> -> map_user_defined_type(Udt_name, Enum_names); _ -> map_by_udt_name(Lowercase_udt_name, Enum_names) end. -file("src/cquill/codegen/type_mapping.gleam", 109). ?DOC( " Map a PostgreSQL column to its corresponding Gleam type\n" "\n" " Parameters:\n" " - data_type: The PostgreSQL data type (e.g., \"integer\", \"character varying\")\n" " - udt_name: The underlying type name (e.g., \"int4\", \"varchar\", or enum name)\n" " - is_nullable: Whether the column allows NULL values\n" " - enum_names: List of known enum type names in the schema\n" "\n" " Returns:\n" " - Ok(GleamType) with the mapped type (wrapped in Option if nullable)\n" " - Error(TypeMappingError) if the type cannot be mapped\n" ). -spec map_postgres_type(binary(), binary(), boolean(), list(binary())) -> {ok, gleam_type()} | {error, type_mapping_error()}. map_postgres_type(Data_type, Udt_name, Is_nullable, Enum_names) -> gleam@result:'try'( map_base_type(Data_type, Udt_name, Enum_names), fun(Base_type) -> Final_type = case Is_nullable of true -> {gleam_option, Base_type}; false -> Base_type end, {ok, Final_type} end ). -file("src/cquill/codegen/type_mapping.gleam", 375). ?DOC( " Map an introspected column to full column metadata\n" "\n" " Parameters:\n" " - column_name: The column name\n" " - data_type: PostgreSQL data type\n" " - udt_name: Underlying type name\n" " - is_nullable: Whether the column allows NULL\n" " - column_default: Default value expression (if any)\n" " - enum_names: List of known enum type names\n" "\n" " Returns:\n" " - Ok(ColumnMeta) with full metadata\n" " - Error(TypeMappingError) if type cannot be mapped\n" ). -spec map_column( binary(), binary(), binary(), boolean(), gleam@option:option(binary()), list(binary()) ) -> {ok, column_meta()} | {error, type_mapping_error()}. map_column( Column_name, Data_type, Udt_name, Is_nullable, Column_default, Enum_names ) -> gleam@result:'try'( map_postgres_type(Data_type, Udt_name, Is_nullable, Enum_names), fun(Gleam_type) -> Is_auto_generated = detect_auto_generated(Data_type, Column_default), {ok, {column_meta, Gleam_type, Is_auto_generated, Data_type, Udt_name, Column_name, Is_nullable}} end ). -file("src/cquill/codegen/type_mapping.gleam", 541). ?DOC(" Check if a character is uppercase\n"). -spec is_uppercase(binary()) -> boolean(). is_uppercase(Char) -> (Char =:= string:uppercase(Char)) andalso (Char /= string:lowercase(Char)). -file("src/cquill/codegen/type_mapping.gleam", 528). ?DOC(" Convert PascalCase or snake_case to snake_case\n"). -spec snake_case(binary()) -> binary(). snake_case(Input) -> _pipe = Input, _pipe@1 = gleam@string:to_graphemes(_pipe), gleam@list:index_fold( _pipe@1, <<""/utf8>>, fun(Acc, Char, Index) -> case {is_uppercase(Char), Index} of {true, 0} -> string:lowercase(Char); {true, _} -> <<<>/binary, (string:lowercase(Char))/binary>>; {false, _} -> <> end end ). -file("src/cquill/codegen/type_mapping.gleam", 550). ?DOC(" Check if a GleamType is nullable (wrapped in Option)\n"). -spec is_nullable_type(gleam_type()) -> boolean(). is_nullable_type(Gleam_type) -> case Gleam_type of {gleam_option, _} -> true; _ -> false end. -file("src/cquill/codegen/type_mapping.gleam", 558). ?DOC(" Check if a GleamType is a list type\n"). -spec is_list_type(gleam_type()) -> boolean(). is_list_type(Gleam_type) -> case Gleam_type of {gleam_list, _} -> true; _ -> false end. -file("src/cquill/codegen/type_mapping.gleam", 566). ?DOC(" Check if a GleamType is a custom type (enum or user-defined)\n"). -spec is_custom_type(gleam_type()) -> boolean(). is_custom_type(Gleam_type) -> case Gleam_type of {gleam_custom, _, _} -> true; {gleam_option, {gleam_custom, _, _}} -> true; {gleam_list, {gleam_custom, _, _}} -> true; _ -> false end. -file("src/cquill/codegen/type_mapping.gleam", 576). ?DOC(" Get the inner type from an Option type\n"). -spec unwrap_option(gleam_type()) -> gleam_type(). unwrap_option(Gleam_type) -> case Gleam_type of {gleam_option, Inner} -> Inner; Other -> Other end. -file("src/cquill/codegen/type_mapping.gleam", 584). ?DOC(" Get the element type from a List type\n"). -spec unwrap_list(gleam_type()) -> gleam_type(). unwrap_list(Gleam_type) -> case Gleam_type of {gleam_list, Element} -> Element; Other -> Other end. -file("src/cquill/codegen/type_mapping.gleam", 592). ?DOC(" Check if two GleamTypes are equal\n"). -spec types_equal(gleam_type(), gleam_type()) -> boolean(). types_equal(Type_a, Type_b) -> case {Type_a, Type_b} of {gleam_int, gleam_int} -> true; {gleam_float, gleam_float} -> true; {gleam_string, gleam_string} -> true; {gleam_bool, gleam_bool} -> true; {gleam_bit_array, gleam_bit_array} -> true; {gleam_time, gleam_time} -> true; {gleam_date, gleam_date} -> true; {gleam_time_of_day, gleam_time_of_day} -> true; {gleam_decimal, gleam_decimal} -> true; {gleam_uuid, gleam_uuid} -> true; {gleam_json, gleam_json} -> true; {{gleam_list, A}, {gleam_list, B}} -> types_equal(A, B); {{gleam_option, A@1}, {gleam_option, B@1}} -> types_equal(A@1, B@1); {{gleam_custom, Mod_a, Name_a}, {gleam_custom, Mod_b, Name_b}} -> (Mod_a =:= Mod_b) andalso (Name_a =:= Name_b); {_, _} -> false end.