Trogon.Commanded.ObjectId (Trogon.Commanded v0.37.0)

Copy Markdown View Source

Macro for defining type-safe, domain-specific object IDs.

ObjectIds are type-safe identifiers that combine a human-readable prefix with a value, stored as {prefix}{separator}{id} (e.g., "user_abc-123").

Usage

defmodule MyApp.UserId do
  use Trogon.Commanded.ObjectId,
    object_type: "user"
end

# Create
user_id = MyApp.UserId.new("abc-123")
#=> %MyApp.UserId{id: "abc-123"}

# Convert to string
to_string(user_id)
#=> "user_abc-123"

# Parse
MyApp.UserId.parse("user_abc-123")
#=> {:ok, %MyApp.UserId{id: "abc-123"}}

Type Safety

Each ObjectId type is a separate struct, providing compile-time and runtime type safety:

def process_user(%MyApp.UserId{} = id), do: ...
def process_order(%MyApp.OrderId{} = id), do: ...

process_user(MyApp.OrderId.new("123"))  #=> FunctionClauseError!

Proto-driven ObjectId

When using trogon_proto with trogon/object_id/v1alpha1/options.proto, you can derive object_type and separator from proto enum value extensions:

defmodule MyApp.TicketId do
  use Trogon.Commanded.ObjectId,
    proto: {Acme.Type.V1.ObjectType, :OBJECT_TYPE_TICKET},
    storage_format: :drop_prefix,
    validate: :uuid
end

This reads object_type and separator from the proto annotation and forwards them along with any additional options you provide.

Ecto Integration

ObjectIds implement Ecto.Type, so you can use them directly in schemas:

schema "users" do
  field :id, MyApp.UserId
end

Summary

Functions

Defines a type-safe ObjectId module.

Returns true if term is an ObjectId struct; otherwise returns false.

Functions

__using__(opts)

(macro)

Defines a type-safe ObjectId module.

Options

  • :object_type (String.t/0) - Required. The object type (e.g., "user", "order").

  • :separator (String.t/0) - Separator between prefix and id. The default value is "_".

  • :storage_format - Database storage format.

    • :full - Store complete string (e.g., "user_abc-123")
    • :drop_prefix - Store only the id (e.g., "abc-123") The default value is :full.
  • :json_format - JSON encoding format.

    • :full - Encode complete string (e.g., "user_abc-123")
    • :drop_prefix - Encode only the id (e.g., "abc-123") The default value is :full.
  • :validate - Validation for the raw id value (without prefix).

    • nil - No validation (default)
    • :uuid - Validates that the id is a valid UUID
    • :integer - Validates that the id is a valid integer string
    • {Module, :function} - Custom validator (compile-time optimized direct call). The function receives the raw id value and returns :ok or {:error, reason}. The default value is nil.

Examples

defmodule MyApp.UserId do
  use Trogon.Commanded.ObjectId, object_type: "user"
end

defmodule MyApp.OrderId do
  use Trogon.Commanded.ObjectId, object_type: "order", separator: "#"
end

defmodule MyApp.AccountId do
  use Trogon.Commanded.ObjectId, object_type: "acct", storage_format: :drop_prefix
end

# With UUID validation
defmodule MyApp.ProductId do
  use Trogon.Commanded.ObjectId, object_type: "product", validate: :uuid
end

# With integer validation
defmodule MyApp.SequenceId do
  use Trogon.Commanded.ObjectId, object_type: "seq", validate: :integer
end

# With custom validator (compile-time optimized)
defmodule MyApp.CustomId do
  use Trogon.Commanded.ObjectId,
    object_type: "custom",
    validate: {MyValidator, :check}
end

is_object_id(term)

(macro)

Returns true if term is an ObjectId struct; otherwise returns false.

Allowed in guard tests.

Examples

iex> is_object_id(%MyApp.UserId{id: "abc-123"})
true

iex> is_object_id(%{id: "abc-123"})
false