Lotus.Middleware (Lotus v0.16.5)

Copy Markdown View Source

Generic middleware pipeline for query execution and schema discovery hooks.

Each middleware module implements init/1 and call/2, following the standard Plug pattern:

defmodule MyApp.AuditPlug do
  def init(opts), do: opts

  def call(payload, opts) do
    {:cont, payload}   # continue to next middleware
    # or
    {:halt, "reason"}  # stop pipeline, Lotus returns {:error, reason}
  end
end

Pipeline Events

EventTriggered
:before_queryAfter preflight visibility check, before SQL execution
:after_queryAfter execution, before result returned to caller
:after_list_schemasAfter schema discovery and visibility filtering
:after_list_tablesAfter table discovery and visibility filtering
:after_get_table_schemaAfter table schema introspection and column visibility
:after_list_relationsAfter relation discovery and visibility filtering

Configuration

config :lotus,
  middleware: %{
    before_query: [
      {MyApp.AccessControlPlug, []},
      {MyApp.QueryAuditPlug, [repo: MyApp.AuditRepo]}
    ],
    after_query: [
      {MyApp.QueryAuditPlug, [repo: MyApp.AuditRepo]}
    ],
    after_list_tables: [
      {MyApp.TableFilterPlug, []}
    ]
  }

Context

A :context key carries opaque user data (e.g. the current user) through to middleware. Lotus never inspects this value.

Summary

Functions

Compiles all middleware by calling init/1 on each module and stores the result in :persistent_term for fast runtime access.

Runs the middleware pipeline for the given event.

Types

compiled_entry()

@type compiled_entry() :: {module(), term()}

event()

@type event() ::
  :before_query
  | :after_query
  | :after_list_schemas
  | :after_list_tables
  | :after_get_table_schema
  | :after_list_relations

middleware_spec()

@type middleware_spec() :: {module(), keyword()}

pipeline_result()

@type pipeline_result() :: {:cont, map()} | {:halt, term()}

Functions

compile(middleware_config)

@spec compile(map()) :: :ok

Compiles all middleware by calling init/1 on each module and stores the result in :persistent_term for fast runtime access.

run(event, payload)

@spec run(event(), map()) :: {:cont, map()} | {:halt, term()}

Runs the middleware pipeline for the given event.

Returns {:cont, payload} if all middleware passed, or {:halt, reason} if any middleware halted the pipeline.

When no middleware is configured for the event, returns {:cont, payload} with zero overhead beyond the map lookup.