Current section
Files
Jump to
Current section
Files
src/mochi@types.erl
-module(mochi@types).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/mochi/types.gleam").
-export([to_dynamic/1, record/1, option/1, field/2, object/1, description/2, field_description/2, deprecated/2, deprecated_no_reason/1, string/3, id/3, optional_id/3, int/3, float/3, bool/3, datetime/3, optional_datetime/3, date/3, optional_date/3, uuid/3, optional_uuid/3, email/3, optional_email/3, url/3, optional_url/3, json/3, optional_json/3, optional_string/3, optional_int/3, optional_float/3, optional_bool/3, nullable/1, list_string/3, list_int/3, list_float/3, list_bool/3, list_id/3, non_null_list_string/3, non_null_list_int/3, non_null_list_float/3, object_field/4, list_object/4, non_null_field/4, non_null_string/3, non_null_int/3, non_null_float/3, non_null_bool/3, field_with_args/6, build_direct/1, encoder/1, build/2, build_with_encoder/2, enum_type/1, enum_description/2, value/2, value_with_desc/3, deprecated_value/2, deprecated_value_with_reason/3, build_enum/1, enum_mapping/2, enum_mapping_with_desc/3, enum_from_mappings/2, enum_from_mappings_with_desc/3, input/1, input_description/2, input_field/4, input_string/3, input_int/3, input_float/3, input_bool/3, input_id/3, input_optional_string/3, input_optional_int/3, input_optional_float/3, input_optional_bool/3, input_field_with_default/5, build_input/1]).
-export_type([type_builder/1, type_field/1, enum_builder/0, enum_value/0, enum_mapping/1, input_builder/0, input_field/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.
?MODULEDOC(
" Type definition helpers for Code First GraphQL.\n"
"\n"
" This module provides builders for creating GraphQL types from Gleam types\n"
" with minimal boilerplate, plus helpers for Dynamic conversion.\n"
"\n"
" ## Object Type Builder\n"
"\n"
" ```gleam\n"
" let user_type = types.object(\"User\")\n"
" |> types.description(\"A user in the system\")\n"
" |> types.id(\"id\", fn(u: User) { u.id })\n"
" |> types.string(\"name\", fn(u: User) { u.name })\n"
" |> types.int(\"age\", fn(u: User) { u.age })\n"
" |> types.build(decode_user)\n"
" ```\n"
"\n"
" ## Enum Builder\n"
"\n"
" ```gleam\n"
" let role_enum = types.enum_type(\"Role\")\n"
" |> types.value(\"ADMIN\")\n"
" |> types.value(\"USER\")\n"
" |> types.deprecated_value_with_reason(\"GUEST\", \"Use USER instead\")\n"
" |> types.build_enum\n"
" ```\n"
"\n"
" ## Dynamic Conversion Helpers\n"
"\n"
" Use these when building DataLoader encoders or custom resolvers:\n"
"\n"
" ```gleam\n"
" fn user_to_dynamic(u: User) -> Dynamic {\n"
" types.record([\n"
" types.field(\"id\", u.id),\n"
" types.field(\"name\", u.name),\n"
" #(\"profile\", profile_to_dynamic(u.profile)),\n"
" #(\"age\", types.option(u.age)), // Option(Int) -> null if None\n"
" ])\n"
" }\n"
" ```\n"
).
-type type_builder(FKX) :: {type_builder,
binary(),
gleam@option:option(binary()),
list(type_field(FKX))}.
-type type_field(FKY) :: {type_field,
binary(),
gleam@option:option(binary()),
mochi@schema:field_type(),
fun((FKY) -> gleam@dynamic:dynamic_()),
boolean(),
gleam@option:option(binary())} |
{type_field_with_args,
binary(),
gleam@option:option(binary()),
mochi@schema:field_type(),
list(mochi@schema:argument_definition()),
fun((FKY, mochi@args:args(), mochi@schema:execution_context()) -> {ok,
gleam@dynamic:dynamic_()} |
{error, binary()}),
boolean(),
gleam@option:option(binary())}.
-type enum_builder() :: {enum_builder,
binary(),
gleam@option:option(binary()),
list(enum_value())}.
-type enum_value() :: {enum_value,
binary(),
gleam@option:option(binary()),
boolean(),
gleam@option:option(binary())}.
-type enum_mapping(FKZ) :: {enum_mapping,
FKZ,
binary(),
gleam@option:option(binary())}.
-type input_builder() :: {input_builder,
binary(),
gleam@option:option(binary()),
list(input_field())}.
-type input_field() :: {input_field,
binary(),
gleam@option:option(binary()),
mochi@schema:field_type(),
gleam@option:option(gleam@dynamic:dynamic_())}.
-file("src/mochi/types.gleam", 61).
?DOC(
" Convert any Gleam value to Dynamic\n"
" This uses unsafe_coerce under the hood\n"
).
-spec to_dynamic(any()) -> gleam@dynamic:dynamic_().
to_dynamic(Value) ->
gleam_stdlib:identity(Value).
-file("src/mochi/types.gleam", 81).
?DOC(
" Build a Dynamic dict from a list of field tuples\n"
"\n"
" This is a convenience helper for creating DataLoader encoders.\n"
"\n"
" ## Example\n"
"\n"
" ```gleam\n"
" fn user_to_dynamic(u: User) -> Dynamic {\n"
" types.record([\n"
" #(\"id\", types.to_dynamic(u.id)),\n"
" #(\"name\", types.to_dynamic(u.name)),\n"
" #(\"email\", types.to_dynamic(u.email)),\n"
" ])\n"
" }\n"
" ```\n"
).
-spec record(list({binary(), gleam@dynamic:dynamic_()})) -> gleam@dynamic:dynamic_().
record(Fields) ->
gleam_stdlib:identity(maps:from_list(Fields)).
-file("src/mochi/types.gleam", 92).
?DOC(
" Convert an Option to Dynamic (None becomes Nil/null)\n"
"\n"
" ## Example\n"
"\n"
" ```gleam\n"
" #(\"age\", types.option(user.age))\n"
" ```\n"
).
-spec option(gleam@option:option(any())) -> gleam@dynamic:dynamic_().
option(Opt) ->
case Opt of
{some, V} ->
gleam_stdlib:identity(V);
none ->
gleam_stdlib:identity(nil)
end.
-file("src/mochi/types.gleam", 109).
?DOC(
" Shorthand: wrap a value in to_dynamic with a field name\n"
"\n"
" ## Example\n"
"\n"
" ```gleam\n"
" types.record([\n"
" types.field(\"id\", user.id),\n"
" types.field(\"name\", user.name),\n"
" ])\n"
" ```\n"
).
-spec field(binary(), any()) -> {binary(), gleam@dynamic:dynamic_()}.
field(Name, Value) ->
{Name, gleam_stdlib:identity(Value)}.
-file("src/mochi/types.gleam", 150).
?DOC(" Create a new type builder\n").
-spec object(binary()) -> type_builder(any()).
object(Name) ->
{type_builder, Name, none, []}.
-file("src/mochi/types.gleam", 155).
?DOC(" Add description to type\n").
-spec description(type_builder(FLI), binary()) -> type_builder(FLI).
description(Builder, Desc) ->
{type_builder,
erlang:element(2, Builder),
{some, Desc},
erlang:element(4, Builder)}.
-file("src/mochi/types.gleam", 194).
-spec set_field_description(type_field(FLU), binary()) -> type_field(FLU).
set_field_description(Field, Desc) ->
case Field of
{type_field, _, _, _, _, _, _} ->
{type_field,
erlang:element(2, Field),
{some, Desc},
erlang:element(4, Field),
erlang:element(5, Field),
erlang:element(6, Field),
erlang:element(7, Field)};
{type_field_with_args, _, _, _, _, _, _, _} ->
{type_field_with_args,
erlang:element(2, Field),
{some, Desc},
erlang:element(4, Field),
erlang:element(5, Field),
erlang:element(6, Field),
erlang:element(7, Field),
erlang:element(8, Field)}
end.
-file("src/mochi/types.gleam", 183).
-spec field_description(type_builder(FLR), binary()) -> type_builder(FLR).
field_description(Builder, Desc) ->
case erlang:element(4, Builder) of
[] ->
Builder;
[F | Rest] ->
{type_builder,
erlang:element(2, Builder),
erlang:element(3, Builder),
[set_field_description(F, Desc) | Rest]}
end.
-file("src/mochi/types.gleam", 201).
-spec mark_deprecated(type_field(FLX), boolean(), gleam@option:option(binary())) -> type_field(FLX).
mark_deprecated(Field, Is_deprecated, Reason) ->
case Field of
{type_field, _, _, _, _, _, _} ->
{type_field,
erlang:element(2, Field),
erlang:element(3, Field),
erlang:element(4, Field),
erlang:element(5, Field),
Is_deprecated,
Reason};
{type_field_with_args, _, _, _, _, _, _, _} ->
{type_field_with_args,
erlang:element(2, Field),
erlang:element(3, Field),
erlang:element(4, Field),
erlang:element(5, Field),
erlang:element(6, Field),
Is_deprecated,
Reason}
end.
-file("src/mochi/types.gleam", 160).
?DOC(" Mark the most recently added field as deprecated with a reason.\n").
-spec deprecated(type_builder(FLL), binary()) -> type_builder(FLL).
deprecated(Builder, Reason) ->
case erlang:element(4, Builder) of
[] ->
Builder;
[Field | Rest] ->
{type_builder,
erlang:element(2, Builder),
erlang:element(3, Builder),
[mark_deprecated(Field, true, {some, Reason}) | Rest]}
end.
-file("src/mochi/types.gleam", 172).
?DOC(" Mark the most recently added field as deprecated without a reason.\n").
-spec deprecated_no_reason(type_builder(FLO)) -> type_builder(FLO).
deprecated_no_reason(Builder) ->
case erlang:element(4, Builder) of
[] ->
Builder;
[Field | Rest] ->
{type_builder,
erlang:element(2, Builder),
erlang:element(3, Builder),
[mark_deprecated(Field, true, none) | Rest]}
end.
-file("src/mochi/types.gleam", 222).
-spec add_field(
type_builder(FMB),
binary(),
gleam@option:option(binary()),
mochi@schema:field_type(),
fun((FMB) -> gleam@dynamic:dynamic_())
) -> type_builder(FMB).
add_field(Builder, Name, Description, Field_type, Extractor) ->
{type_builder,
erlang:element(2, Builder),
erlang:element(3, Builder),
[{type_field, Name, Description, Field_type, Extractor, false, none} |
erlang:element(4, Builder)]}.
-file("src/mochi/types.gleam", 243).
?DOC(" Add a string field\n").
-spec string(type_builder(FMF), binary(), fun((FMF) -> binary())) -> type_builder(FMF).
string(Builder, Name, Extractor) ->
add_field(
Builder,
Name,
none,
mochi@schema:string_type(),
fun(A) -> gleam_stdlib:identity(Extractor(A)) end
).
-file("src/mochi/types.gleam", 254).
?DOC(" Add an ID field\n").
-spec id(type_builder(FMI), binary(), fun((FMI) -> binary())) -> type_builder(FMI).
id(Builder, Name, Extractor) ->
add_field(
Builder,
Name,
none,
mochi@schema:non_null(mochi@schema:id_type()),
fun(A) -> gleam_stdlib:identity(Extractor(A)) end
).
-file("src/mochi/types.gleam", 265).
?DOC(" Add a nullable ID field\n").
-spec optional_id(
type_builder(FML),
binary(),
fun((FML) -> gleam@option:option(binary()))
) -> type_builder(FML).
optional_id(Builder, Name, Extractor) ->
add_field(
Builder,
Name,
none,
mochi@schema:id_type(),
fun(A) -> option(Extractor(A)) end
).
-file("src/mochi/types.gleam", 276).
?DOC(" Add an int field\n").
-spec int(type_builder(FMP), binary(), fun((FMP) -> integer())) -> type_builder(FMP).
int(Builder, Name, Extractor) ->
add_field(
Builder,
Name,
none,
mochi@schema:int_type(),
fun(A) -> gleam_stdlib:identity(Extractor(A)) end
).
-file("src/mochi/types.gleam", 287).
?DOC(" Add a float field\n").
-spec float(type_builder(FMS), binary(), fun((FMS) -> float())) -> type_builder(FMS).
float(Builder, Name, Extractor) ->
add_field(
Builder,
Name,
none,
mochi@schema:float_type(),
fun(A) -> gleam_stdlib:identity(Extractor(A)) end
).
-file("src/mochi/types.gleam", 298).
?DOC(" Add a boolean field\n").
-spec bool(type_builder(FMV), binary(), fun((FMV) -> boolean())) -> type_builder(FMV).
bool(Builder, Name, Extractor) ->
add_field(
Builder,
Name,
none,
mochi@schema:boolean_type(),
fun(A) -> gleam_stdlib:identity(Extractor(A)) end
).
-file("src/mochi/types.gleam", 312).
-spec datetime(type_builder(FMY), binary(), fun((FMY) -> binary())) -> type_builder(FMY).
datetime(Builder, Name, Extractor) ->
add_field(
Builder,
Name,
none,
mochi@schema:datetime_type(),
fun(A) -> gleam_stdlib:identity(Extractor(A)) end
).
-file("src/mochi/types.gleam", 322).
-spec optional_datetime(
type_builder(FNB),
binary(),
fun((FNB) -> gleam@option:option(binary()))
) -> type_builder(FNB).
optional_datetime(Builder, Name, Extractor) ->
add_field(
Builder,
Name,
none,
mochi@schema:datetime_type(),
fun(A) -> option(Extractor(A)) end
).
-file("src/mochi/types.gleam", 332).
-spec date(type_builder(FNF), binary(), fun((FNF) -> binary())) -> type_builder(FNF).
date(Builder, Name, Extractor) ->
add_field(
Builder,
Name,
none,
mochi@schema:date_type(),
fun(A) -> gleam_stdlib:identity(Extractor(A)) end
).
-file("src/mochi/types.gleam", 342).
-spec optional_date(
type_builder(FNI),
binary(),
fun((FNI) -> gleam@option:option(binary()))
) -> type_builder(FNI).
optional_date(Builder, Name, Extractor) ->
add_field(
Builder,
Name,
none,
mochi@schema:date_type(),
fun(A) -> option(Extractor(A)) end
).
-file("src/mochi/types.gleam", 352).
-spec uuid(type_builder(FNM), binary(), fun((FNM) -> binary())) -> type_builder(FNM).
uuid(Builder, Name, Extractor) ->
add_field(
Builder,
Name,
none,
mochi@schema:uuid_type(),
fun(A) -> gleam_stdlib:identity(Extractor(A)) end
).
-file("src/mochi/types.gleam", 362).
-spec optional_uuid(
type_builder(FNP),
binary(),
fun((FNP) -> gleam@option:option(binary()))
) -> type_builder(FNP).
optional_uuid(Builder, Name, Extractor) ->
add_field(
Builder,
Name,
none,
mochi@schema:uuid_type(),
fun(A) -> option(Extractor(A)) end
).
-file("src/mochi/types.gleam", 372).
-spec email(type_builder(FNT), binary(), fun((FNT) -> binary())) -> type_builder(FNT).
email(Builder, Name, Extractor) ->
add_field(
Builder,
Name,
none,
mochi@schema:email_type(),
fun(A) -> gleam_stdlib:identity(Extractor(A)) end
).
-file("src/mochi/types.gleam", 382).
-spec optional_email(
type_builder(FNW),
binary(),
fun((FNW) -> gleam@option:option(binary()))
) -> type_builder(FNW).
optional_email(Builder, Name, Extractor) ->
add_field(
Builder,
Name,
none,
mochi@schema:email_type(),
fun(A) -> option(Extractor(A)) end
).
-file("src/mochi/types.gleam", 392).
-spec url(type_builder(FOA), binary(), fun((FOA) -> binary())) -> type_builder(FOA).
url(Builder, Name, Extractor) ->
add_field(
Builder,
Name,
none,
mochi@schema:url_type(),
fun(A) -> gleam_stdlib:identity(Extractor(A)) end
).
-file("src/mochi/types.gleam", 402).
-spec optional_url(
type_builder(FOD),
binary(),
fun((FOD) -> gleam@option:option(binary()))
) -> type_builder(FOD).
optional_url(Builder, Name, Extractor) ->
add_field(
Builder,
Name,
none,
mochi@schema:url_type(),
fun(A) -> option(Extractor(A)) end
).
-file("src/mochi/types.gleam", 412).
-spec json(type_builder(FOH), binary(), fun((FOH) -> gleam@dynamic:dynamic_())) -> type_builder(FOH).
json(Builder, Name, Extractor) ->
add_field(Builder, Name, none, mochi@schema:json_type(), Extractor).
-file("src/mochi/types.gleam", 420).
-spec optional_json(
type_builder(FOK),
binary(),
fun((FOK) -> gleam@option:option(gleam@dynamic:dynamic_()))
) -> type_builder(FOK).
optional_json(Builder, Name, Extractor) ->
add_field(
Builder,
Name,
none,
mochi@schema:json_type(),
fun(A) -> option(Extractor(A)) end
).
-file("src/mochi/types.gleam", 432).
?DOC(
" Add an optional string field. `None` becomes JSON `null`; `Some(v)` becomes\n"
" the string value. Use this for nullable GraphQL fields.\n"
).
-spec optional_string(
type_builder(FOO),
binary(),
fun((FOO) -> gleam@option:option(binary()))
) -> type_builder(FOO).
optional_string(Builder, Name, Extractor) ->
add_field(
Builder,
Name,
none,
mochi@schema:string_type(),
fun(A) -> option(Extractor(A)) end
).
-file("src/mochi/types.gleam", 444).
?DOC(
" Add an optional int field. `None` becomes JSON `null`; `Some(v)` becomes\n"
" the int value.\n"
).
-spec optional_int(
type_builder(FOS),
binary(),
fun((FOS) -> gleam@option:option(integer()))
) -> type_builder(FOS).
optional_int(Builder, Name, Extractor) ->
add_field(
Builder,
Name,
none,
mochi@schema:int_type(),
fun(A) -> option(Extractor(A)) end
).
-file("src/mochi/types.gleam", 456).
?DOC(
" Add an optional float field. `None` becomes JSON `null`; `Some(v)` becomes\n"
" the float value.\n"
).
-spec optional_float(
type_builder(FOW),
binary(),
fun((FOW) -> gleam@option:option(float()))
) -> type_builder(FOW).
optional_float(Builder, Name, Extractor) ->
add_field(
Builder,
Name,
none,
mochi@schema:float_type(),
fun(A) -> option(Extractor(A)) end
).
-file("src/mochi/types.gleam", 468).
?DOC(
" Add an optional bool field. `None` becomes JSON `null`; `Some(v)` becomes\n"
" the bool value.\n"
).
-spec optional_bool(
type_builder(FPA),
binary(),
fun((FPA) -> gleam@option:option(boolean()))
) -> type_builder(FPA).
optional_bool(Builder, Name, Extractor) ->
add_field(
Builder,
Name,
none,
mochi@schema:boolean_type(),
fun(A) -> option(Extractor(A)) end
).
-file("src/mochi/types.gleam", 499).
?DOC(
" A decoder that returns `None` when the value is nil/null and otherwise runs\n"
" the inner decoder.\n"
"\n"
" ## Example\n"
"\n"
" ```gleam\n"
" use email <- decode.optional_field(\"email\", None, types.nullable(decode.string))\n"
" ```\n"
).
-spec nullable(gleam@dynamic@decode:decoder(FPE)) -> gleam@dynamic@decode:decoder(gleam@option:option(FPE)).
nullable(Inner) ->
gleam@dynamic@decode:optional(Inner).
-file("src/mochi/types.gleam", 506).
?DOC(" Add a list of strings field\n").
-spec list_string(type_builder(FPI), binary(), fun((FPI) -> list(binary()))) -> type_builder(FPI).
list_string(Builder, Name, Extractor) ->
add_field(
Builder,
Name,
none,
mochi@schema:list_type(mochi@schema:string_type()),
fun(A) -> gleam_stdlib:identity(Extractor(A)) end
).
-file("src/mochi/types.gleam", 517).
?DOC(" Add a list of ints field\n").
-spec list_int(type_builder(FPM), binary(), fun((FPM) -> list(integer()))) -> type_builder(FPM).
list_int(Builder, Name, Extractor) ->
add_field(
Builder,
Name,
none,
mochi@schema:list_type(mochi@schema:int_type()),
fun(A) -> gleam_stdlib:identity(Extractor(A)) end
).
-file("src/mochi/types.gleam", 527).
-spec list_float(type_builder(FPQ), binary(), fun((FPQ) -> list(float()))) -> type_builder(FPQ).
list_float(Builder, Name, Extractor) ->
add_field(
Builder,
Name,
none,
mochi@schema:list_type(mochi@schema:float_type()),
fun(A) -> gleam_stdlib:identity(Extractor(A)) end
).
-file("src/mochi/types.gleam", 537).
-spec list_bool(type_builder(FPU), binary(), fun((FPU) -> list(boolean()))) -> type_builder(FPU).
list_bool(Builder, Name, Extractor) ->
add_field(
Builder,
Name,
none,
mochi@schema:list_type(mochi@schema:boolean_type()),
fun(A) -> gleam_stdlib:identity(Extractor(A)) end
).
-file("src/mochi/types.gleam", 547).
-spec list_id(type_builder(FPY), binary(), fun((FPY) -> list(binary()))) -> type_builder(FPY).
list_id(Builder, Name, Extractor) ->
add_field(
Builder,
Name,
none,
mochi@schema:list_type(mochi@schema:id_type()),
fun(A) -> gleam_stdlib:identity(Extractor(A)) end
).
-file("src/mochi/types.gleam", 557).
-spec non_null_list_string(
type_builder(FQC),
binary(),
fun((FQC) -> list(binary()))
) -> type_builder(FQC).
non_null_list_string(Builder, Name, Extractor) ->
add_field(
Builder,
Name,
none,
mochi@schema:non_null(
mochi@schema:list_type(mochi@schema:string_type())
),
fun(A) -> gleam_stdlib:identity(Extractor(A)) end
).
-file("src/mochi/types.gleam", 571).
-spec non_null_list_int(
type_builder(FQG),
binary(),
fun((FQG) -> list(integer()))
) -> type_builder(FQG).
non_null_list_int(Builder, Name, Extractor) ->
add_field(
Builder,
Name,
none,
mochi@schema:non_null(mochi@schema:list_type(mochi@schema:int_type())),
fun(A) -> gleam_stdlib:identity(Extractor(A)) end
).
-file("src/mochi/types.gleam", 585).
-spec non_null_list_float(
type_builder(FQK),
binary(),
fun((FQK) -> list(float()))
) -> type_builder(FQK).
non_null_list_float(Builder, Name, Extractor) ->
add_field(
Builder,
Name,
none,
mochi@schema:non_null(mochi@schema:list_type(mochi@schema:float_type())),
fun(A) -> gleam_stdlib:identity(Extractor(A)) end
).
-file("src/mochi/types.gleam", 600).
?DOC(" Add a related object field\n").
-spec object_field(
type_builder(FQO),
binary(),
binary(),
fun((FQO) -> gleam@dynamic:dynamic_())
) -> type_builder(FQO).
object_field(Builder, Name, Type_name, Extractor) ->
add_field(
Builder,
Name,
none,
mochi@schema:named_type(Type_name),
Extractor
).
-file("src/mochi/types.gleam", 610).
?DOC(" Add a list of related objects field\n").
-spec list_object(
type_builder(FQR),
binary(),
binary(),
fun((FQR) -> gleam@dynamic:dynamic_())
) -> type_builder(FQR).
list_object(Builder, Name, Type_name, Extractor) ->
add_field(
Builder,
Name,
none,
mochi@schema:list_type(mochi@schema:named_type(Type_name)),
Extractor
).
-file("src/mochi/types.gleam", 626).
?DOC(" Add a non-null field\n").
-spec non_null_field(
type_builder(FQU),
binary(),
mochi@schema:field_type(),
fun((FQU) -> gleam@dynamic:dynamic_())
) -> type_builder(FQU).
non_null_field(Builder, Name, Field_type, Extractor) ->
add_field(Builder, Name, none, mochi@schema:non_null(Field_type), Extractor).
-file("src/mochi/types.gleam", 640).
?DOC(" Add a non-null string field\n").
-spec non_null_string(type_builder(FQX), binary(), fun((FQX) -> binary())) -> type_builder(FQX).
non_null_string(Builder, Name, Extractor) ->
add_field(
Builder,
Name,
none,
mochi@schema:non_null(mochi@schema:string_type()),
fun(A) -> gleam_stdlib:identity(Extractor(A)) end
).
-file("src/mochi/types.gleam", 651).
?DOC(" Add a non-null int field\n").
-spec non_null_int(type_builder(FRA), binary(), fun((FRA) -> integer())) -> type_builder(FRA).
non_null_int(Builder, Name, Extractor) ->
add_field(
Builder,
Name,
none,
mochi@schema:non_null(mochi@schema:int_type()),
fun(A) -> gleam_stdlib:identity(Extractor(A)) end
).
-file("src/mochi/types.gleam", 662).
?DOC(" Add a non-null float field\n").
-spec non_null_float(type_builder(FRD), binary(), fun((FRD) -> float())) -> type_builder(FRD).
non_null_float(Builder, Name, Extractor) ->
add_field(
Builder,
Name,
none,
mochi@schema:non_null(mochi@schema:float_type()),
fun(A) -> gleam_stdlib:identity(Extractor(A)) end
).
-file("src/mochi/types.gleam", 673).
?DOC(" Add a non-null bool field\n").
-spec non_null_bool(type_builder(FRG), binary(), fun((FRG) -> boolean())) -> type_builder(FRG).
non_null_bool(Builder, Name, Extractor) ->
add_field(
Builder,
Name,
none,
mochi@schema:non_null(mochi@schema:boolean_type()),
fun(A) -> gleam_stdlib:identity(Extractor(A)) end
).
-file("src/mochi/types.gleam", 702).
?DOC(
" Add a field with arguments and custom resolver\n"
"\n"
" ```gleam\n"
" types.object(\"User\")\n"
" |> types.field_with_args(\n"
" name: \"posts\",\n"
" returns: schema.list_type(schema.named_type(\"Post\")),\n"
" args: [schema.arg(\"limit\", schema.int_type())],\n"
" desc: \"User's posts with optional limit\",\n"
" resolve: fn(user, args, ctx) {\n"
" let limit = query.get_optional_int(args, \"limit\")\n"
" get_user_posts(user.id, limit)\n"
" },\n"
" )\n"
" ```\n"
).
-spec field_with_args(
type_builder(FRJ),
binary(),
mochi@schema:field_type(),
list(mochi@schema:argument_definition()),
binary(),
fun((FRJ, mochi@args:args(), mochi@schema:execution_context()) -> {ok,
gleam@dynamic:dynamic_()} |
{error, binary()})
) -> type_builder(FRJ).
field_with_args(Builder, Name, Field_type, Args, Description, Resolver) ->
Field = {type_field_with_args,
Name,
{some, Description},
Field_type,
Args,
Resolver,
false,
none},
{type_builder,
erlang:element(2, Builder),
erlang:element(3, Builder),
[Field | erlang:element(4, Builder)]}.
-file("src/mochi/types.gleam", 829).
-spec apply_deprecation(
mochi@schema:field_definition(),
boolean(),
gleam@option:option(binary())
) -> mochi@schema:field_definition().
apply_deprecation(Field, Is_deprecated, Deprecation_reason) ->
case Is_deprecated of
false ->
Field;
true ->
case Deprecation_reason of
{some, Reason} ->
mochi@schema:deprecated(Field, Reason);
none ->
mochi@schema:deprecated_no_reason(Field)
end
end.
-file("src/mochi/types.gleam", 844).
-spec to_field_def_direct(type_field(any())) -> mochi@schema:field_definition().
to_field_def_direct(F) ->
case F of
{type_field,
Name,
Description,
Field_type,
Extractor,
Is_deprecated,
Deprecation_reason} ->
Resolver = fun(Info) -> case erlang:element(2, Info) of
{some, Parent_dyn} ->
{ok, Extractor(gleam_stdlib:identity(Parent_dyn))};
none ->
{error, <<"No parent value"/utf8>>}
end end,
Base = begin
_pipe = mochi@schema:field_def(Name, Field_type),
mochi@schema:resolver(_pipe, Resolver)
end,
With_desc = case Description of
{some, Desc} ->
mochi@schema:field_description(Base, Desc);
none ->
Base
end,
apply_deprecation(With_desc, Is_deprecated, Deprecation_reason);
{type_field_with_args,
Name@1,
Description@1,
Field_type@1,
Args,
Field_resolver,
Is_deprecated@1,
Deprecation_reason@1} ->
Resolver@1 = fun(Info@1) -> case erlang:element(2, Info@1) of
{some, Parent_dyn@1} ->
Field_resolver(
gleam_stdlib:identity(Parent_dyn@1),
erlang:element(4, Info@1),
erlang:element(5, Info@1)
);
none ->
{error, <<"No parent value"/utf8>>}
end end,
Base@1 = begin
_pipe@1 = mochi@schema:field_def(Name@1, Field_type@1),
mochi@schema:resolver(_pipe@1, Resolver@1)
end,
With_args = gleam@list:fold(
Args,
Base@1,
fun(Field, Arg) -> mochi@schema:argument(Field, Arg) end
),
With_desc@1 = case Description@1 of
{some, Desc@1} ->
mochi@schema:field_description(With_args, Desc@1);
none ->
With_args
end,
apply_deprecation(
With_desc@1,
Is_deprecated@1,
Deprecation_reason@1
)
end.
-file("src/mochi/types.gleam", 810).
?DOC(
" Generate an encoder function from a TypeBuilder\n"
"\n"
" The encoder uses the same extractors defined for each field,\n"
" so you don't need to write the same field mappings twice.\n"
"\n"
" ## Example\n"
"\n"
" ```gleam\n"
" let user_builder = types.object(\"User\")\n"
" |> types.id(\"id\", fn(u: User) { u.id })\n"
" |> types.string(\"name\", fn(u: User) { u.name })\n"
"\n"
" let user_type = types.build(user_builder, decode_user)\n"
" let user_encoder = types.encoder(user_builder)\n"
"\n"
" // user_encoder(User(\"1\", \"Alice\")) produces:\n"
" // {\"id\": \"1\", \"name\": \"Alice\"}\n"
" ```\n"
" Build the TypeBuilder into an ObjectType using identity coerce instead of a\n"
" decoder. This eliminates the encode/decode roundtrip — no Dict is built per\n"
" object and no Dict lookups are done per field. The encoder is just\n"
" `to_dynamic` (a BEAM no-op).\n"
"\n"
" Safe as long as the resolver returns values of type `a` and the extractors\n"
" are defined for the same type `a`. Do not use when resolvers return\n"
" pre-encoded Dicts.\n"
).
-spec build_direct(type_builder(FRX)) -> {mochi@schema:object_type(),
fun((FRX) -> gleam@dynamic:dynamic_())}.
build_direct(Builder) ->
Schema_fields = gleam@list:map(
lists:reverse(erlang:element(4, Builder)),
fun(F) -> to_field_def_direct(F) end
),
Base_obj = mochi@schema:object(erlang:element(2, Builder)),
With_desc = case erlang:element(3, Builder) of
{some, D} ->
mochi@schema:description(Base_obj, D);
none ->
Base_obj
end,
Object_type = gleam@list:fold(
Schema_fields,
With_desc,
fun(Obj, Field) -> mochi@schema:field(Obj, Field) end
),
{Object_type, fun gleam_stdlib:identity/1}.
-file("src/mochi/types.gleam", 900).
-spec encoder(type_builder(FSC)) -> fun((FSC) -> gleam@dynamic:dynamic_()).
encoder(Builder) ->
fun(Value) ->
Field_pairs = gleam@list:filter_map(
erlang:element(4, Builder),
fun(F) -> case F of
{type_field, Name, _, _, Extractor, _, _} ->
{ok, {Name, Extractor(Value)}};
{type_field_with_args, _, _, _, _, _, _, _} ->
{error, nil}
end end
),
gleam_stdlib:identity(maps:from_list(Field_pairs))
end.
-file("src/mochi/types.gleam", 914).
-spec to_field_def(
type_field(FSE),
fun((gleam@dynamic:dynamic_()) -> {ok, FSE} | {error, binary()})
) -> mochi@schema:field_definition().
to_field_def(F, Decoder) ->
case F of
{type_field,
Name,
Description,
Field_type,
Extractor,
Is_deprecated,
Deprecation_reason} ->
Resolver = fun(Info) -> case erlang:element(2, Info) of
{some, Parent_dyn} ->
gleam@result:map(Decoder(Parent_dyn), Extractor);
none ->
{error, <<"No parent value"/utf8>>}
end end,
Base = begin
_pipe = mochi@schema:field_def(Name, Field_type),
mochi@schema:resolver(_pipe, Resolver)
end,
With_desc = case Description of
{some, Desc} ->
mochi@schema:field_description(Base, Desc);
none ->
Base
end,
apply_deprecation(With_desc, Is_deprecated, Deprecation_reason);
{type_field_with_args,
Name@1,
Description@1,
Field_type@1,
Args,
Field_resolver,
Is_deprecated@1,
Deprecation_reason@1} ->
Resolver@1 = fun(Info@1) -> case erlang:element(2, Info@1) of
{some, Parent_dyn@1} ->
gleam@result:'try'(
Decoder(Parent_dyn@1),
fun(Parent) ->
Field_resolver(
Parent,
erlang:element(4, Info@1),
erlang:element(5, Info@1)
)
end
);
none ->
{error, <<"No parent value"/utf8>>}
end end,
Base@1 = begin
_pipe@1 = mochi@schema:field_def(Name@1, Field_type@1),
mochi@schema:resolver(_pipe@1, Resolver@1)
end,
With_args = gleam@list:fold(
Args,
Base@1,
fun(Field, Arg) -> mochi@schema:argument(Field, Arg) end
),
With_desc@1 = case Description@1 of
{some, Desc@1} ->
mochi@schema:field_description(With_args, Desc@1);
none ->
With_args
end,
apply_deprecation(
With_desc@1,
Is_deprecated@1,
Deprecation_reason@1
)
end.
-file("src/mochi/types.gleam", 729).
?DOC(" Build the TypeBuilder into an ObjectType with a decoder\n").
-spec build(
type_builder(FRP),
fun((gleam@dynamic:dynamic_()) -> {ok, FRP} | {error, binary()})
) -> mochi@schema:object_type().
build(Builder, Decoder) ->
Schema_fields = gleam@list:map(
lists:reverse(erlang:element(4, Builder)),
fun(F) -> to_field_def(F, Decoder) end
),
Base_obj = mochi@schema:object(erlang:element(2, Builder)),
With_desc = case erlang:element(3, Builder) of
{some, D} ->
mochi@schema:description(Base_obj, D);
none ->
Base_obj
end,
gleam@list:fold(
Schema_fields,
With_desc,
fun(Obj, Field) -> mochi@schema:field(Obj, Field) end
).
-file("src/mochi/types.gleam", 775).
?DOC(
" Build the TypeBuilder into an ObjectType and auto-generated encoder\n"
"\n"
" This is the recommended way to build types - it generates both the\n"
" schema type and an encoder function from the same field definitions,\n"
" eliminating redundant code.\n"
"\n"
" ## Example\n"
"\n"
" ```gleam\n"
" pub type User {\n"
" User(id: String, name: String, age: Int)\n"
" }\n"
"\n"
" let #(user_type, user_encoder) = types.object(\"User\")\n"
" |> types.id(\"id\", fn(u: User) { u.id })\n"
" |> types.string(\"name\", fn(u: User) { u.name })\n"
" |> types.int(\"age\", fn(u: User) { u.age })\n"
" |> types.build_with_encoder(decode_user)\n"
"\n"
" // Use user_type in schema, user_encoder in resolvers\n"
" query.query(\n"
" name: \"user\",\n"
" returns: schema.named_type(\"User\"),\n"
" resolve: fn(_ctx) { Ok(User(\"1\", \"Alice\", 30)) },\n"
" encode: user_encoder, // Auto-generated!\n"
" )\n"
" ```\n"
).
-spec build_with_encoder(
type_builder(FRT),
fun((gleam@dynamic:dynamic_()) -> {ok, FRT} | {error, binary()})
) -> {mochi@schema:object_type(), fun((FRT) -> gleam@dynamic:dynamic_())}.
build_with_encoder(Builder, Decoder) ->
Object_type = build(Builder, Decoder),
Encoder_fn = encoder(Builder),
{Object_type, Encoder_fn}.
-file("src/mochi/types.gleam", 1004).
?DOC(" Create a new enum builder\n").
-spec enum_type(binary()) -> enum_builder().
enum_type(Name) ->
{enum_builder, Name, none, []}.
-file("src/mochi/types.gleam", 1009).
?DOC(" Add description to enum\n").
-spec enum_description(enum_builder(), binary()) -> enum_builder().
enum_description(Builder, Desc) ->
{enum_builder,
erlang:element(2, Builder),
{some, Desc},
erlang:element(4, Builder)}.
-file("src/mochi/types.gleam", 1014).
?DOC(" Add an enum value\n").
-spec value(enum_builder(), binary()) -> enum_builder().
value(Builder, Name) ->
{enum_builder,
erlang:element(2, Builder),
erlang:element(3, Builder),
[{enum_value, Name, none, false, none} | erlang:element(4, Builder)]}.
-file("src/mochi/types.gleam", 1022).
?DOC(" Add an enum value with description\n").
-spec value_with_desc(enum_builder(), binary(), binary()) -> enum_builder().
value_with_desc(Builder, Name, Desc) ->
{enum_builder,
erlang:element(2, Builder),
erlang:element(3, Builder),
[{enum_value, Name, {some, Desc}, false, none} |
erlang:element(4, Builder)]}.
-file("src/mochi/types.gleam", 1034).
?DOC(" Add a deprecated enum value\n").
-spec deprecated_value(enum_builder(), binary()) -> enum_builder().
deprecated_value(Builder, Name) ->
{enum_builder,
erlang:element(2, Builder),
erlang:element(3, Builder),
[{enum_value, Name, none, true, none} | erlang:element(4, Builder)]}.
-file("src/mochi/types.gleam", 1042).
?DOC(" Add a deprecated enum value with reason\n").
-spec deprecated_value_with_reason(enum_builder(), binary(), binary()) -> enum_builder().
deprecated_value_with_reason(Builder, Name, Reason) ->
{enum_builder,
erlang:element(2, Builder),
erlang:element(3, Builder),
[{enum_value, Name, none, true, {some, Reason}} |
erlang:element(4, Builder)]}.
-file("src/mochi/types.gleam", 1054).
?DOC(" Build the enum type\n").
-spec build_enum(enum_builder()) -> mochi@schema:enum_type().
build_enum(Builder) ->
Enum_values = gleam@list:fold(
lists:reverse(erlang:element(4, Builder)),
maps:new(),
fun(Acc, V) ->
Value_def = {enum_value_definition,
erlang:element(2, V),
erlang:element(3, V),
gleam_stdlib:identity(erlang:element(2, V)),
erlang:element(4, V),
erlang:element(5, V)},
gleam@dict:insert(Acc, erlang:element(2, V), Value_def)
end
),
{enum_type,
erlang:element(2, Builder),
erlang:element(3, Builder),
Enum_values}.
-file("src/mochi/types.gleam", 1085).
?DOC(" Create an enum mapping\n").
-spec enum_mapping(FSI, binary()) -> enum_mapping(FSI).
enum_mapping(Gleam_value, Graphql_name) ->
{enum_mapping, Gleam_value, Graphql_name, none}.
-file("src/mochi/types.gleam", 1094).
?DOC(" Create an enum mapping with description\n").
-spec enum_mapping_with_desc(FSK, binary(), binary()) -> enum_mapping(FSK).
enum_mapping_with_desc(Gleam_value, Graphql_name, Desc) ->
{enum_mapping, Gleam_value, Graphql_name, {some, Desc}}.
-file("src/mochi/types.gleam", 1137).
?DOC(
" Build an enum type from mappings with bidirectional coercion functions\n"
"\n"
" Returns a tuple of:\n"
" - The EnumType for schema registration\n"
" - A function to convert Gleam value to GraphQL string\n"
" - A function to convert GraphQL string to Gleam value\n"
"\n"
" ```gleam\n"
" pub type Status {\n"
" Active\n"
" Inactive\n"
" Pending\n"
" }\n"
"\n"
" let #(enum_type, to_graphql, from_graphql) = types.enum_from_mappings(\n"
" \"Status\",\n"
" [\n"
" types.enum_mapping(Active, \"ACTIVE\"),\n"
" types.enum_mapping(Inactive, \"INACTIVE\"),\n"
" types.enum_mapping_with_desc(Pending, \"PENDING\", \"Awaiting approval\"),\n"
" ],\n"
" )\n"
"\n"
" // Use in schema\n"
" query.new()\n"
" |> query.add_enum(enum_type)\n"
"\n"
" // Convert values\n"
" to_graphql(Active) // -> \"ACTIVE\"\n"
" from_graphql(\"ACTIVE\") // -> Ok(Active)\n"
" ```\n"
).
-spec enum_from_mappings(binary(), list(enum_mapping(FSM))) -> {mochi@schema:enum_type(),
fun((FSM) -> binary()),
fun((binary()) -> {ok, FSM} | {error, binary()})}.
enum_from_mappings(Name, Mappings) ->
Enum_values = gleam@list:fold(
Mappings,
maps:new(),
fun(Acc, M) ->
Value_def = {enum_value_definition,
erlang:element(3, M),
erlang:element(4, M),
gleam_stdlib:identity(erlang:element(3, M)),
false,
none},
gleam@dict:insert(Acc, erlang:element(3, M), Value_def)
end
),
Enum_type = {enum_type, Name, none, Enum_values},
To_graphql = fun(Value) ->
case gleam@list:find(
Mappings,
fun(M@1) ->
gleam_stdlib:identity(erlang:element(2, M@1)) =:= gleam_stdlib:identity(
Value
)
end
) of
{ok, M@2} ->
erlang:element(3, M@2);
{error, _} ->
<<""/utf8>>
end
end,
From_graphql = fun(Gql_name) ->
case gleam@list:find(
Mappings,
fun(M@3) -> erlang:element(3, M@3) =:= Gql_name end
) of
{ok, M@4} ->
{ok, erlang:element(2, M@4)};
{error, _} ->
{error, <<"Unknown enum value: "/utf8, Gql_name/binary>>}
end
end,
{Enum_type, To_graphql, From_graphql}.
-file("src/mochi/types.gleam", 1180).
?DOC(" Build an enum type from mappings with description\n").
-spec enum_from_mappings_with_desc(binary(), binary(), list(enum_mapping(FSR))) -> {mochi@schema:enum_type(),
fun((FSR) -> binary()),
fun((binary()) -> {ok, FSR} | {error, binary()})}.
enum_from_mappings_with_desc(Name, Description, Mappings) ->
{Enum_type, To_graphql, From_graphql} = enum_from_mappings(Name, Mappings),
Enum_type_with_desc = {enum_type,
erlang:element(2, Enum_type),
{some, Description},
erlang:element(4, Enum_type)},
{Enum_type_with_desc, To_graphql, From_graphql}.
-file("src/mochi/types.gleam", 1225).
?DOC(
" Create a new input type builder\n"
"\n"
" ```gleam\n"
" let create_user_input = types.input(\"CreateUserInput\")\n"
" |> types.input_description(\"Input for creating a new user\")\n"
" |> types.input_string(\"name\", \"User's full name\")\n"
" |> types.input_string(\"email\", \"User's email address\")\n"
" |> types.input_optional_int(\"age\", \"User's age\")\n"
" |> types.build_input\n"
" ```\n"
).
-spec input(binary()) -> input_builder().
input(Name) ->
{input_builder, Name, none, []}.
-file("src/mochi/types.gleam", 1230).
?DOC(" Add description to input type\n").
-spec input_description(input_builder(), binary()) -> input_builder().
input_description(Builder, Desc) ->
{input_builder,
erlang:element(2, Builder),
{some, Desc},
erlang:element(4, Builder)}.
-file("src/mochi/types.gleam", 1316).
?DOC(" Add a field with custom type to input\n").
-spec input_field(
input_builder(),
binary(),
mochi@schema:field_type(),
binary()
) -> input_builder().
input_field(Builder, Name, Field_type, Desc) ->
Field = {input_field, Name, {some, Desc}, Field_type, none},
{input_builder,
erlang:element(2, Builder),
erlang:element(3, Builder),
[Field | erlang:element(4, Builder)]}.
-file("src/mochi/types.gleam", 1235).
?DOC(" Add a required string field to input\n").
-spec input_string(input_builder(), binary(), binary()) -> input_builder().
input_string(Builder, Name, Desc) ->
input_field(
Builder,
Name,
mochi@schema:non_null(mochi@schema:string_type()),
Desc
).
-file("src/mochi/types.gleam", 1244).
?DOC(" Add a required int field to input\n").
-spec input_int(input_builder(), binary(), binary()) -> input_builder().
input_int(Builder, Name, Desc) ->
input_field(
Builder,
Name,
mochi@schema:non_null(mochi@schema:int_type()),
Desc
).
-file("src/mochi/types.gleam", 1253).
?DOC(" Add a required float field to input\n").
-spec input_float(input_builder(), binary(), binary()) -> input_builder().
input_float(Builder, Name, Desc) ->
input_field(
Builder,
Name,
mochi@schema:non_null(mochi@schema:float_type()),
Desc
).
-file("src/mochi/types.gleam", 1262).
?DOC(" Add a required bool field to input\n").
-spec input_bool(input_builder(), binary(), binary()) -> input_builder().
input_bool(Builder, Name, Desc) ->
input_field(
Builder,
Name,
mochi@schema:non_null(mochi@schema:boolean_type()),
Desc
).
-file("src/mochi/types.gleam", 1271).
?DOC(" Add a required ID field to input\n").
-spec input_id(input_builder(), binary(), binary()) -> input_builder().
input_id(Builder, Name, Desc) ->
input_field(
Builder,
Name,
mochi@schema:non_null(mochi@schema:id_type()),
Desc
).
-file("src/mochi/types.gleam", 1280).
?DOC(" Add an optional string field to input\n").
-spec input_optional_string(input_builder(), binary(), binary()) -> input_builder().
input_optional_string(Builder, Name, Desc) ->
input_field(Builder, Name, mochi@schema:string_type(), Desc).
-file("src/mochi/types.gleam", 1289).
?DOC(" Add an optional int field to input\n").
-spec input_optional_int(input_builder(), binary(), binary()) -> input_builder().
input_optional_int(Builder, Name, Desc) ->
input_field(Builder, Name, mochi@schema:int_type(), Desc).
-file("src/mochi/types.gleam", 1298).
?DOC(" Add an optional float field to input\n").
-spec input_optional_float(input_builder(), binary(), binary()) -> input_builder().
input_optional_float(Builder, Name, Desc) ->
input_field(Builder, Name, mochi@schema:float_type(), Desc).
-file("src/mochi/types.gleam", 1307).
?DOC(" Add an optional bool field to input\n").
-spec input_optional_bool(input_builder(), binary(), binary()) -> input_builder().
input_optional_bool(Builder, Name, Desc) ->
input_field(Builder, Name, mochi@schema:boolean_type(), Desc).
-file("src/mochi/types.gleam", 1333).
?DOC(" Add a field with custom type and default value to input\n").
-spec input_field_with_default(
input_builder(),
binary(),
mochi@schema:field_type(),
gleam@dynamic:dynamic_(),
binary()
) -> input_builder().
input_field_with_default(Builder, Name, Field_type, Default, Desc) ->
Field = {input_field, Name, {some, Desc}, Field_type, {some, Default}},
{input_builder,
erlang:element(2, Builder),
erlang:element(3, Builder),
[Field | erlang:element(4, Builder)]}.
-file("src/mochi/types.gleam", 1351).
?DOC(" Build the input type into a schema InputObjectType\n").
-spec build_input(input_builder()) -> mochi@schema:input_object_type().
build_input(Builder) ->
Schema_fields = gleam@list:fold(
lists:reverse(erlang:element(4, Builder)),
maps:new(),
fun(Acc, F) ->
Field_def = {input_field_definition,
erlang:element(2, F),
erlang:element(3, F),
erlang:element(4, F),
erlang:element(5, F)},
gleam@dict:insert(Acc, erlang:element(2, F), Field_def)
end
),
{input_object_type,
erlang:element(2, Builder),
erlang:element(3, Builder),
Schema_fields}.