AshDyan.DataLayer behaviour (AshDyan v0.6.0)

Copy Markdown View Source

Behaviour describing what analysis capabilities a given Ash data layer supports.

AshDyan ships with implementations for AshPostgres, AshClickhouse, AshScylla, AshSqlite, and Ash.DataLayer.Simple (ETS). Other data layers fall back to a conservative default that supports only :frequency and :aggregate.

The capability check is surfaced explicitly via AshDyan.supports?/2 so callers can discover data-layer limits before issuing a query.

Custom capability modules may also implement capabilities/1 to describe the query primitives and aggregation strategy their adapter provides. This metadata is available through capabilities/1; supports?/2 remains the boolean gate used by the engine.

Extending with third-party data layers

The mapping from an Ash data-layer module to its AshDyan.DataLayer capability implementation is config-mergeable, so a downstream app can register its own data layer without patching AshDyan:

config :ash_dyan, :data_layer_capabilities, %{
  MyApp.CustomDataLayer => MyApp.AshDyan.CustomCapabilities
}

Or via an extension:

defmodule MyApp.AshDyan.Extension do
  @behaviour AshDyan.Extension

  def data_layer_capabilities do
    %{
      MyApp.CustomDataLayer => MyApp.AshDyan.CustomCapabilities
    }
  end
end

config :ash_dyan, :extensions, [MyApp.AshDyan.Extension]

Summary

Functions

Return normalized query and aggregation metadata for a resource's data layer.

Return capability metadata for an explicit data-layer module.

Resolve the capability module for a data-layer module.

Resolve the data-layer capability module for a resource.

Returns true if the resource's data layer supports the capability.

Types

capability_info()

@type capability_info() :: %{
  analyses: %{optional(AshDyan.capability()) => boolean()},
  query: %{optional(:filter | :select | :limit | :timeout | :sort) => boolean()},
  aggregation: %{
    optional(:mode) => :in_memory | :pushdown | :hybrid,
    optional(:functions) => [atom()]
  }
}

Callbacks

capabilities(module)

(optional)
@callback capabilities(module()) :: capability_info()

Describe query and aggregation primitives supplied by the adapter.

paginate(t, pos_integer, pos_integer)

(optional)
@callback paginate(Ash.Query.t(), pos_integer(), pos_integer()) ::
  {:ok, Ash.Query.t()} | {:error, term()}

pushdown_aggregate(t, atom, atom)

(optional)
@callback pushdown_aggregate(Ash.Query.t(), atom(), atom()) ::
  {:ok, Ash.Query.t()} | :not_supported

pushdown_time_bucket(t, atom, time_bucket)

(optional)
@callback pushdown_time_bucket(Ash.Query.t(), atom(), AshDyan.time_bucket()) ::
  {:ok, Ash.Query.t()} | :not_supported

Optional callback for SQL-pushdown of time bucketing.

A data layer that can express a time bucket natively (e.g. Postgres date_trunc) implements this and returns {:ok, query}. The default returns :not_supported, in which case the engine falls back to in-memory bucketing.

stream(t, keyword, keyword)

(optional)
@callback stream(Ash.Query.t(), keyword(), keyword()) ::
  {:ok, Enumerable.t()} | {:error, term()}

supports?(module, capability)

@callback supports?(module(), AshDyan.capability()) :: boolean()

Functions

capabilities(resource)

@spec capabilities(module()) :: capability_info()

Return normalized query and aggregation metadata for a resource's data layer.

Custom capability modules can implement capabilities/1 and return partial sections; omitted sections are filled with conservative defaults. This lets an adapter advertise native aggregate functions or query features without changing AshDyan's public request format.

capabilities_for_data_layer(data_layer, resource)

@spec capabilities_for_data_layer(module(), module()) :: capability_info()

Return capability metadata for an explicit data-layer module.

for_data_layer(data_layer)

@spec for_data_layer(module()) :: module()

Resolve the capability module for a data-layer module.

for_resource(resource)

@spec for_resource(module()) :: module()

Resolve the data-layer capability module for a resource.

Built-in mappings are merged with config :ash_dyan, :data_layer_capabilities and extension configurations, so third-party data layers can register their own capability module.

supports?(resource, capability)

@spec supports?(module(), AshDyan.capability()) :: boolean()

Returns true if the resource's data layer supports the capability.