/edgedb_ecto

PoC: Ecto helper for EdgeDB

Primary LanguageElixir

EdgeDBEcto - helper to simplify work with EdgeDB and Ecto

NOTE: This project is not an EdgeDB adapter for Ecto.

WARNING: It is very likely that this project will be archived after the implementation of the *.edgeql RFC in the Elixir client itself. Use this project at your own risk.

This project makes working with EdgeDB in Elixir a little easier by providing a mapper for data from EdgeDB to Ecto schemas.

It also provides a module to generate functions for all your EdgeQL queries stored in your application's priv/edgeql/ folder, and support (though quite limited) for Ecto.Multi.

EdgeDBEcto.Queries will read your EdgeQL queries from priv/edgeql/<domain>/<query_name>.edgeql and generate a <root_module_name>.<domain_module_name>.<query_function_name>/2 function for each query.

Example usage:

dbschema/default.esdl:

module default {
    type User {
        property name -> str
        multi link friends -> User;
    }
}

priv/edgeql/accounts/get_user_by_id.esdl:

# edgedb = :query_single!
# mapper = MyApp.Accounts.User

select User {
  id,
  name,
  friends: {
    id,
    name,
  },
}
filter .id = <uuid>$id

edgedb directive will be used to determine which function the client should use for the query. It must be in atom form.

mapper directive will define an Ecto schema to map the result from the EdgeDB client to an Ecto schema.


lib/my_app/accounts/user.ex:

defmodule MyApp.Accounts.User do
    use Ecto.Schema
    use EdgeDBEcto.Mapper

    @type t() :: %__MODULE__{
        id: binary(),
        name: String.t() | nil,
        friends: list(t()) | Ecto.Association.NotLoaded.t()
    }

    # we need custom config for :id because in EdgeDB its UUID
    @primary_key {:id, :binary_id, autogenerate: false}

    schema "default::User" do
        field :name, :string

        has_many :friends, User
    end
end

lib/my_app/edgedb.ex:

defmodule MyApp.EdgeDB do
    use EdgeDBEcto,
        name: __MODULE__,
        queries: true,
        otp_app: :my_app
end

:name will be used in query functions as an implicit name for the EdgeDB client. You can manually pass it or a separate connection from the client to the query function via the :conn option.

:queries when set to true will autogenerate the query function from EdgeQL queries located in the priv/edgeql/<domain> directory of the application.

:otp_app is the name of the application in which EdgeDBEcto will search for queries. Required if :queries is set to true.


lib/my_app/accounts.ex:

defmodule MyApp.Accounts do
    alias MyApp.Accounts.User

    @spec get_user(binary()) :: User.t()
    def get_user(id) do
        MyApp.EdgeDB.Accounts.get_user(id: id)
    end
end