Selecto.Config.Overlay (Selecto v0.4.3)

Merges overlay configurations into base domain configurations.

Overlays provide a flexible way to customize domain configurations at compile-time or runtime without modifying the base configuration. This is particularly useful for:

  • Separating generated code from user customizations
  • Multi-tenant applications with per-tenant configurations
  • Feature flags that change available filters or columns
  • A/B testing different domain configurations
  • Environment-specific domain customizations

merge-strategy

Merge Strategy

  • Column configurations: Deep merge - overlay extends/overrides base column properties
  • Filters: Additive merge - both base and overlay filters are available
  • Functions: Deep merge - overlay can add or override named UDF specs
  • Query members (query_members.ctes/values/subqueries): Deep merge - overlay can add or override named query-member presets without replacing the full registry
  • Schemas (schemas): Deep merge - overlay can add/override schema entries without replacing the full schemas map
  • Joins (joins): Deep merge - overlay can add/override join entries without replacing the full joins map
  • Source associations (source.associations): Deep merge - overlay can add or override root associations without replacing the full source map
  • Redact fields: Union - unique list of all redacted fields
  • Other fields: Shallow merge - overlay takes precedence

examples

Examples

basic-overlay-merge

Basic Overlay Merge

base = %{
  source: %{
    columns: %{
      price: %{type: :decimal}
    },
    redact_fields: []
  },
  filters: %{}
}

overlay = %{
  columns: %{
    price: %{
      label: "Product Price",
      format: :currency
    }
  },
  redact_fields: [:internal_notes]
}

merged = Selecto.Config.Overlay.merge(base, overlay)
# => %{
#   source: %{
#     columns: %{
#       price: %{type: :decimal, label: "Product Price", format: :currency}
#     },
#     redact_fields: [:internal_notes]
#   },
#   filters: %{}
# }

runtime-multi-tenant-configuration

Runtime Multi-Tenant Configuration

defmodule MyApp.ProductDomain do
  def domain(tenant_id) do
    base_domain()
    |> Selecto.Config.Overlay.merge(tenant_overlay(tenant_id))
  end

  defp tenant_overlay("premium"), do: %{
    columns: %{price: %{format: :currency_with_symbol}}
  }

  defp tenant_overlay(_), do: %{}
end

compile-time-customization-generated-domains

Compile-Time Customization (Generated Domains)

# Generated by selecto_mix
defmodule MyApp.SelectoDomains.ProductDomain do
  def domain do
    base_domain()
    |> Selecto.Config.Overlay.merge(overlay())
  end

  # Generated base configuration
  defp base_domain, do: %{...}

  # User-defined overlay
  defp overlay do
    if Code.ensure_loaded?(MyApp.SelectoDomains.Overlays.ProductDomainOverlay) do
      MyApp.SelectoDomains.Overlays.ProductDomainOverlay.overlay()
    else
      %{}
    end
  end
end

Link to this section Summary

Functions

Merges an overlay configuration into a base domain configuration.

Link to this section Functions

Link to this function

merge(base, overlay)

Merges an overlay configuration into a base domain configuration.

The overlay is intelligently merged based on the semantics of each configuration key:

  • Columns are deep-merged to allow fine-grained property overrides
  • Filters are combined additively
  • Redact fields are unioned
  • Other fields use overlay value if present

Returns the merged configuration map.

parameters

Parameters

  • base - The base domain configuration map
  • overlay - The overlay configuration map to merge in

examples

Examples

iex> base = %{source: %{columns: %{id: %{type: :integer}}, redact_fields: []}}
iex> overlay = %{columns: %{id: %{label: "ID"}}}
iex> Selecto.Config.Overlay.merge(base, overlay)
%{source: %{columns: %{id: %{type: :integer, label: "ID"}}, redact_fields: []}}