# This file generated by `dagger_codegen`. Please DO NOT EDIT.
defmodule Dagger.TypeDef do
  @moduledoc """
  A definition of a parameter or return type in a Module.
  """

  use Dagger.Core.Base, kind: :object, name: "TypeDef"

  alias Dagger.Core.Client
  alias Dagger.Core.QueryBuilder, as: QB

  @derive Dagger.ID

  defstruct [:query_builder, :client]

  @type t() :: %__MODULE__{}

  @doc """
  If kind is ENUM, the enum-specific type definition. If kind is not ENUM, this will be null.
  """
  @spec as_enum(t()) :: Dagger.EnumTypeDef.t() | nil
  def as_enum(%__MODULE__{} = type_def) do
    query_builder =
      type_def.query_builder |> QB.select("asEnum")

    %Dagger.EnumTypeDef{
      query_builder: query_builder,
      client: type_def.client
    }
  end

  @doc """
  If kind is INPUT, the input-specific type definition. If kind is not INPUT, this will be null.
  """
  @spec as_input(t()) :: Dagger.InputTypeDef.t() | nil
  def as_input(%__MODULE__{} = type_def) do
    query_builder =
      type_def.query_builder |> QB.select("asInput")

    %Dagger.InputTypeDef{
      query_builder: query_builder,
      client: type_def.client
    }
  end

  @doc """
  If kind is INTERFACE, the interface-specific type definition. If kind is not INTERFACE, this will be null.
  """
  @spec as_interface(t()) :: Dagger.InterfaceTypeDef.t() | nil
  def as_interface(%__MODULE__{} = type_def) do
    query_builder =
      type_def.query_builder |> QB.select("asInterface")

    %Dagger.InterfaceTypeDef{
      query_builder: query_builder,
      client: type_def.client
    }
  end

  @doc """
  If kind is LIST, the list-specific type definition. If kind is not LIST, this will be null.
  """
  @spec as_list(t()) :: Dagger.ListTypeDef.t() | nil
  def as_list(%__MODULE__{} = type_def) do
    query_builder =
      type_def.query_builder |> QB.select("asList")

    %Dagger.ListTypeDef{
      query_builder: query_builder,
      client: type_def.client
    }
  end

  @doc """
  If kind is OBJECT, the object-specific type definition. If kind is not OBJECT, this will be null.
  """
  @spec as_object(t()) :: Dagger.ObjectTypeDef.t() | nil
  def as_object(%__MODULE__{} = type_def) do
    query_builder =
      type_def.query_builder |> QB.select("asObject")

    %Dagger.ObjectTypeDef{
      query_builder: query_builder,
      client: type_def.client
    }
  end

  @doc """
  If kind is SCALAR, the scalar-specific type definition. If kind is not SCALAR, this will be null.
  """
  @spec as_scalar(t()) :: Dagger.ScalarTypeDef.t() | nil
  def as_scalar(%__MODULE__{} = type_def) do
    query_builder =
      type_def.query_builder |> QB.select("asScalar")

    %Dagger.ScalarTypeDef{
      query_builder: query_builder,
      client: type_def.client
    }
  end

  @doc """
  A unique identifier for this TypeDef.
  """
  @spec id(t()) :: {:ok, Dagger.TypeDefID.t()} | {:error, term()}
  def id(%__MODULE__{} = type_def) do
    query_builder =
      type_def.query_builder |> QB.select("id")

    Client.execute(type_def.client, query_builder)
  end

  @doc """
  The kind of type this is (e.g. primitive, list, object).
  """
  @spec kind(t()) :: {:ok, Dagger.TypeDefKind.t()} | {:error, term()}
  def kind(%__MODULE__{} = type_def) do
    query_builder =
      type_def.query_builder |> QB.select("kind")

    case Client.execute(type_def.client, query_builder) do
      {:ok, enum} -> {:ok, Dagger.TypeDefKind.from_string(enum)}
      error -> error
    end
  end

  @doc """
  Whether this type can be set to null. Defaults to false.
  """
  @spec optional(t()) :: {:ok, boolean()} | {:error, term()}
  def optional(%__MODULE__{} = type_def) do
    query_builder =
      type_def.query_builder |> QB.select("optional")

    Client.execute(type_def.client, query_builder)
  end

  @doc """
  Adds a function for constructing a new instance of an Object TypeDef, failing if the type is not an object.
  """
  @spec with_constructor(t(), Dagger.Function.t()) :: Dagger.TypeDef.t()
  def with_constructor(%__MODULE__{} = type_def, function) do
    query_builder =
      type_def.query_builder
      |> QB.select("withConstructor")
      |> QB.put_arg("function", Dagger.ID.id!(function))

    %Dagger.TypeDef{
      query_builder: query_builder,
      client: type_def.client
    }
  end

  @doc """
  Returns a TypeDef of kind Enum with the provided name.

  Note that an enum's values may be omitted if the intent is only to refer to an enum. This is how functions are able to return their own, or any other circular reference.
  """
  @spec with_enum(t(), String.t(), [
          {:description, String.t() | nil},
          {:source_map, Dagger.SourceMapID.t() | nil}
        ]) :: Dagger.TypeDef.t()
  def with_enum(%__MODULE__{} = type_def, name, optional_args \\ []) do
    query_builder =
      type_def.query_builder
      |> QB.select("withEnum")
      |> QB.put_arg("name", name)
      |> QB.maybe_put_arg("description", optional_args[:description])
      |> QB.maybe_put_arg("sourceMap", optional_args[:source_map])

    %Dagger.TypeDef{
      query_builder: query_builder,
      client: type_def.client
    }
  end

  @doc """
  Adds a static value for an Enum TypeDef, failing if the type is not an enum.
  """
  @spec with_enum_member(t(), String.t(), [
          {:value, String.t() | nil},
          {:description, String.t() | nil},
          {:source_map, Dagger.SourceMapID.t() | nil}
        ]) :: Dagger.TypeDef.t()
  def with_enum_member(%__MODULE__{} = type_def, name, optional_args \\ []) do
    query_builder =
      type_def.query_builder
      |> QB.select("withEnumMember")
      |> QB.put_arg("name", name)
      |> QB.maybe_put_arg("value", optional_args[:value])
      |> QB.maybe_put_arg("description", optional_args[:description])
      |> QB.maybe_put_arg("sourceMap", optional_args[:source_map])

    %Dagger.TypeDef{
      query_builder: query_builder,
      client: type_def.client
    }
  end

  @deprecated """
  Use `with_enum_member` instead
  """
  @doc """
  Adds a static value for an Enum TypeDef, failing if the type is not an enum.
  """
  @spec with_enum_value(t(), String.t(), [
          {:description, String.t() | nil},
          {:source_map, Dagger.SourceMapID.t() | nil}
        ]) :: Dagger.TypeDef.t()
  def with_enum_value(%__MODULE__{} = type_def, value, optional_args \\ []) do
    query_builder =
      type_def.query_builder
      |> QB.select("withEnumValue")
      |> QB.put_arg("value", value)
      |> QB.maybe_put_arg("description", optional_args[:description])
      |> QB.maybe_put_arg("sourceMap", optional_args[:source_map])

    %Dagger.TypeDef{
      query_builder: query_builder,
      client: type_def.client
    }
  end

  @doc """
  Adds a static field for an Object TypeDef, failing if the type is not an object.
  """
  @spec with_field(t(), String.t(), Dagger.TypeDef.t(), [
          {:description, String.t() | nil},
          {:source_map, Dagger.SourceMapID.t() | nil}
        ]) :: Dagger.TypeDef.t()
  def with_field(%__MODULE__{} = type_def_, name, type_def, optional_args \\ []) do
    query_builder =
      type_def_.query_builder
      |> QB.select("withField")
      |> QB.put_arg("name", name)
      |> QB.put_arg("typeDef", Dagger.ID.id!(type_def))
      |> QB.maybe_put_arg("description", optional_args[:description])
      |> QB.maybe_put_arg("sourceMap", optional_args[:source_map])

    %Dagger.TypeDef{
      query_builder: query_builder,
      client: type_def_.client
    }
  end

  @doc """
  Adds a function for an Object or Interface TypeDef, failing if the type is not one of those kinds.
  """
  @spec with_function(t(), Dagger.Function.t()) :: Dagger.TypeDef.t()
  def with_function(%__MODULE__{} = type_def, function) do
    query_builder =
      type_def.query_builder
      |> QB.select("withFunction")
      |> QB.put_arg("function", Dagger.ID.id!(function))

    %Dagger.TypeDef{
      query_builder: query_builder,
      client: type_def.client
    }
  end

  @doc """
  Returns a TypeDef of kind Interface with the provided name.
  """
  @spec with_interface(t(), String.t(), [
          {:description, String.t() | nil},
          {:source_map, Dagger.SourceMapID.t() | nil}
        ]) :: Dagger.TypeDef.t()
  def with_interface(%__MODULE__{} = type_def, name, optional_args \\ []) do
    query_builder =
      type_def.query_builder
      |> QB.select("withInterface")
      |> QB.put_arg("name", name)
      |> QB.maybe_put_arg("description", optional_args[:description])
      |> QB.maybe_put_arg("sourceMap", optional_args[:source_map])

    %Dagger.TypeDef{
      query_builder: query_builder,
      client: type_def.client
    }
  end

  @doc """
  Sets the kind of the type.
  """
  @spec with_kind(t(), Dagger.TypeDefKind.t()) :: Dagger.TypeDef.t()
  def with_kind(%__MODULE__{} = type_def, kind) do
    query_builder =
      type_def.query_builder |> QB.select("withKind") |> QB.put_arg("kind", kind)

    %Dagger.TypeDef{
      query_builder: query_builder,
      client: type_def.client
    }
  end

  @doc """
  Returns a TypeDef of kind List with the provided type for its elements.
  """
  @spec with_list_of(t(), Dagger.TypeDef.t()) :: Dagger.TypeDef.t()
  def with_list_of(%__MODULE__{} = type_def, element_type) do
    query_builder =
      type_def.query_builder
      |> QB.select("withListOf")
      |> QB.put_arg("elementType", Dagger.ID.id!(element_type))

    %Dagger.TypeDef{
      query_builder: query_builder,
      client: type_def.client
    }
  end

  @doc """
  Returns a TypeDef of kind Object with the provided name.

  Note that an object's fields and functions may be omitted if the intent is only to refer to an object. This is how functions are able to return their own object, or any other circular reference.
  """
  @spec with_object(t(), String.t(), [
          {:description, String.t() | nil},
          {:source_map, Dagger.SourceMapID.t() | nil}
        ]) :: Dagger.TypeDef.t()
  def with_object(%__MODULE__{} = type_def, name, optional_args \\ []) do
    query_builder =
      type_def.query_builder
      |> QB.select("withObject")
      |> QB.put_arg("name", name)
      |> QB.maybe_put_arg("description", optional_args[:description])
      |> QB.maybe_put_arg("sourceMap", optional_args[:source_map])

    %Dagger.TypeDef{
      query_builder: query_builder,
      client: type_def.client
    }
  end

  @doc """
  Sets whether this type can be set to null.
  """
  @spec with_optional(t(), boolean()) :: Dagger.TypeDef.t()
  def with_optional(%__MODULE__{} = type_def, optional) do
    query_builder =
      type_def.query_builder |> QB.select("withOptional") |> QB.put_arg("optional", optional)

    %Dagger.TypeDef{
      query_builder: query_builder,
      client: type_def.client
    }
  end

  @doc """
  Returns a TypeDef of kind Scalar with the provided name.
  """
  @spec with_scalar(t(), String.t(), [{:description, String.t() | nil}]) :: Dagger.TypeDef.t()
  def with_scalar(%__MODULE__{} = type_def, name, optional_args \\ []) do
    query_builder =
      type_def.query_builder
      |> QB.select("withScalar")
      |> QB.put_arg("name", name)
      |> QB.maybe_put_arg("description", optional_args[:description])

    %Dagger.TypeDef{
      query_builder: query_builder,
      client: type_def.client
    }
  end
end

defimpl Jason.Encoder, for: Dagger.TypeDef do
  def encode(type_def, opts) do
    {:ok, id} = Dagger.TypeDef.id(type_def)
    Jason.Encode.string(id, opts)
  end
end

defimpl Nestru.Decoder, for: Dagger.TypeDef do
  def decode_fields_hint(_struct, _context, id) do
    {:ok, Dagger.Client.load_type_def_from_id(Dagger.Global.dag(), id)}
  end
end
