Ectomancer.SchemaIntrospection (Ectomancer v1.2.1)

Copy Markdown View Source

Compile-time Ecto schema introspection for generating MCP tools.

This module provides utilities to read Ecto schema metadata at compile time and use it to generate MCP-compatible tool definitions.

Example

schema_info = Ectomancer.SchemaIntrospection.analyze(MyApp.Accounts.User)
# Returns: %{
#   fields: [:id, :email, :name, :inserted_at, :updated_at],
#   types: %{id: :id, email: :string, name: :string, ...},
#   associations: [%{field: :posts, cardinality: :many, related: MyApp.Blog.Post}],
#   primary_key: [:id]
# }

Supported Ecto Types

  • :string - String values
  • :integer - Integer values
  • :float / :decimal - Number values
  • :boolean - Boolean values
  • :date - Date values
  • :time / :time_usec - Time values
  • :naive_datetime / :naive_datetime_usec - Naive datetime values
  • :utc_datetime / :utc_datetime_usec - UTC datetime values
  • Ecto.UUID - UUID values
  • {:array, inner} - Array values
  • :map - Map/object values
  • Embeds - Embedded schemas

Summary

Functions

Analyzes an Ecto schema module and returns its metadata.

Returns true if the module is an Ecto schema.

Gets field information including type and nullable status.

Gets all associations for a schema module.

Returns the primary key field(s) for a schema.

Detects if a schema has a soft-delete field (e.g., deleted_at, archived_at).

Converts an Ecto type to a human-readable string representation.

Returns all fields except associations and primary key fields.

Functions

analyze(schema_module)

@spec analyze(module()) :: %{
  fields: [atom()],
  types: %{required(atom()) => any()},
  associations: [%{field: atom(), cardinality: atom(), related: module()}],
  primary_key: [atom()],
  embedded: boolean()
}

Analyzes an Ecto schema module and returns its metadata.

Parameters

  • schema_module - The Ecto schema module to analyze

Returns

A map containing:

  • :fields - List of field names (atoms)
  • :types - Map of field names to their Ecto types
  • :associations - List of association information
  • :primary_key - List of primary key field names
  • :embedded - Boolean indicating if this is an embedded schema

Examples

iex> Ectomancer.SchemaIntrospection.analyze(MyApp.Accounts.User)
%{
  fields: [:id, :email, :name, :role, :inserted_at, :updated_at],
  types: %{
    id: :id,
    email: :string,
    name: :string,
    role: :string,
    inserted_at: :utc_datetime,
    updated_at: :utc_datetime
  },
  associations: [
    %{field: :posts, cardinality: :many, related: MyApp.Blog.Post}
  ],
  primary_key: [:id],
  embedded: false
}

ecto_schema?(module)

@spec ecto_schema?(module()) :: boolean()

Returns true if the module is an Ecto schema.

Examples

iex> Ectomancer.SchemaIntrospection.ecto_schema?(MyApp.Accounts.User)
true

iex> Ectomancer.SchemaIntrospection.ecto_schema?(String)
false

field_info(schema_module, field)

@spec field_info(module(), atom()) :: %{type: any(), nullable: boolean()}

Gets field information including type and nullable status.

Examples

iex> Ectomancer.SchemaIntrospection.field_info(MyApp.Accounts.User, :email)
%{type: :string, nullable: false}

get_associations(schema_module)

@spec get_associations(module()) :: [
  %{field: atom(), cardinality: atom(), related: module()}
]

Gets all associations for a schema module.

Returns a list of maps with association metadata.

primary_key(schema_module)

@spec primary_key(module()) :: [atom()]

Returns the primary key field(s) for a schema.

Examples

iex> Ectomancer.SchemaIntrospection.primary_key(MyApp.Accounts.User)
[:id]

iex> Ectomancer.SchemaIntrospection.primary_key(MyApp.CompositeKeyModel)
[:org_id, :user_id]

soft_delete_field(schema_module)

@spec soft_delete_field(module()) :: atom() | nil

Detects if a schema has a soft-delete field (e.g., deleted_at, archived_at).

Returns the field name (atom) if found, nil otherwise. Only datetime-type fields are considered valid soft-delete markers.

Examples

iex> Ectomancer.SchemaIntrospection.soft_delete_field(MyApp.Accounts.User)
:deleted_at

iex> Ectomancer.SchemaIntrospection.soft_delete_field(MyApp.Blog.Post)
nil

type_to_string(type)

@spec type_to_string(any()) :: String.t()

Converts an Ecto type to a human-readable string representation.

Examples

iex> Ectomancer.SchemaIntrospection.type_to_string(:string)
"string"

iex> Ectomancer.SchemaIntrospection.type_to_string({:array, :string})
"array of string"

iex> Ectomancer.SchemaIntrospection.type_to_string(Ecto.UUID)
"uuid"

writable_fields(schema_module)

@spec writable_fields(module()) :: [atom()]

Returns all fields except associations and primary key fields.

Useful for generating create/update forms.

Examples

iex> Ectomancer.SchemaIntrospection.writable_fields(MyApp.Accounts.User)
[:email, :name, :role]