Configuration management for Lotus.
Handles loading and validating configuration from the application environment
using NimbleOptions.
Required Configuration
Lotus requires a storage repository where it will store query definitions:
config :lotus,
storage_repo: MyApp.Repo # Where Lotus stores its query definitionsData Sources Configuration
Configure named data sources that Lotus can execute queries against:
config :lotus,
data_sources: %{
"primary" => MyApp.Repo,
"analytics" => MyApp.AnalyticsRepo,
"warehouse" => MyApp.WarehouseRepo
}Visibility Configuration
Control which schemas and tables are accessible through Lotus with visibility rules:
config :lotus,
# Schema-level rules (higher precedence)
schema_visibility: %{
postgres: [
allow: ["public", ~r/^tenant_/], # Only public + tenant schemas
deny: ["legacy"] # Block legacy schema
],
mysql: [
# In MySQL, schemas = databases
allow: ["app_db", "analytics_db"],
deny: ["staging_db"]
]
},
# Table-level rules (lower precedence)
table_visibility: %{
default: [
deny: ["user_passwords", "api_keys", ~r/^audit_/]
],
postgres: [
allow: [
{"public", ~r/^dim_/}, # Dimension tables only
{"analytics", ~r/.*/} # All analytics tables
]
]
}Key Principle: Schema visibility gates table visibility. If a schema is denied, all tables within it are blocked regardless of table-level rules.
Database-Specific Schema Behavior:
- PostgreSQL: True namespaced schemas within a database (
public,reporting, etc.) - MySQL: Schemas = Databases (when you connect to MySQL, you can access multiple databases)
- SQLite: Schema-less (visibility rules don't apply)
See the Visibility Guide for detailed configuration examples.
Optional Configuration
config :lotus,
default_source: "primary", # Default data source for queries
unique_names: false, # Defaults to true
read_only: false # Defaults to true; set to false to allow writes
Summary
Functions
Returns AI configuration keyword list.
Returns whether AI features are enabled.
Returns the entire validated configuration as a map.
Returns whether the given source is allowed to return
{:unrestricted, _} from extract_accessed_resources/2 without being
blocked by preflight.
Returns cache adapter module if configured.
Returns the cache configuration.
Returns the cache entry options the operator set in :cache config.
Returns the configured cache key builder module.
Returns the cache namespace.
Returns cache settings for a specific profile.
Returns column visibility rules for a specific source.
Returns the configured data sources.
Returns the globally configured default cache profile.
Returns the default data source as a {name, module} tuple.
Returns the globally configured default page size for windowed pagination, if any.
Gets a configuration value by key.
Gets a data source by name.
Lists the names of all configured data sources.
Loads and validates the Lotus configuration.
Returns middleware configuration map, or empty map if not configured.
Returns whether queries are restricted to read-only operations.
Re-reads configuration from the application environment, validates it, and
refreshes the cached value in :persistent_term.
Returns the configured Ecto repository.
Returns table visibility rules for a specific source.
Returns schema visibility rules for a specific source.
Returns the list of external source adapter modules.
Returns the configured source resolver module.
Return whether the given adapter module is trusted to contribute
free-form text (:syntax_notes, :error_patterns) to AI prompts.
Returns whether unique query names are enforced.
Returns the configured visibility resolver module.
Types
@type cache_config() :: %{ optional(:cachex_opts) => keyword(), adapter: module() | nil, namespace: String.t(), profiles: %{required(atom()) => keyword()}, compress: boolean(), max_bytes: non_neg_integer(), lock_timeout: non_neg_integer(), default_ttl_ms: non_neg_integer(), default_profile: atom(), key_builder: module() }
@type t() :: %{ storage_repo: module(), read_only: boolean(), unique_names: boolean(), data_sources: %{required(String.t()) => module() | map()}, default_source: String.t() | nil, default_page_size: pos_integer() | nil, table_visibility: map(), column_visibility: map(), schema_visibility: map(), allow_unrestricted_resources: boolean(), cache: cache_config(), ai: keyword() | map() | nil, source_adapters: [module()], trusted_source_adapters: [module()], source_resolver: module(), visibility_resolver: module(), middleware: %{required(atom()) => [{module(), term()}]} }
Functions
@spec ai() :: keyword()
Returns AI configuration keyword list.
@spec ai_enabled?() :: boolean()
Returns whether AI features are enabled.
Returns the entire validated configuration as a map.
Useful for debugging or inspection.
Returns whether the given source is allowed to return
{:unrestricted, _} from extract_accessed_resources/2 without being
blocked by preflight.
Resolution order:
- If the source's
data_sourcesentry is a config map with an explicit booleanallow_unrestricted_resources, that value wins for the source —trueopts it in,falsetightens it even when the global flag is on. - Otherwise falls back to the top-level
:allow_unrestricted_resourcesflag.
The per-source override is symmetric on purpose: an operator who sets
false on a single source while running a permissive global default
should be able to trust that the source stays locked down.
Used by Lotus.Preflight.authorize/4 to gate non-SQL adapters whose
engines enforce visibility at a layer Lotus can't introspect.
@spec cache_adapter() :: {:ok, module()} | :error
Returns cache adapter module if configured.
@spec cache_config() :: cache_config() | nil
Returns the cache configuration.
@spec cache_entry_options() :: keyword()
Returns the cache entry options the operator set in :cache config.
These apply to every cached entry unless a caller overrides them in a
per-call :cache option:
:max_bytes- skip writing an entry whose encoded size exceeds this:compress- store the entry compressed:lock_timeout- how long a caller waits for whichever process is already computing the same key, before computing it itself
Only keys that are actually configured are returned, so the cache adapter keeps deciding the default for anything left unset.
@spec cache_key_builder() :: module()
Returns the configured cache key builder module.
Falls back to Lotus.Cache.KeyBuilder.Default when not configured.
@spec cache_namespace() :: String.t()
Returns the cache namespace.
Returns cache settings for a specific profile.
Falls back to built-in defaults for :results, :schema, and :options profiles. Users can override these defaults in their configuration.
Returns column visibility rules for a specific source.
Falls back to default rules if source-specific rules are not configured.
Returns the configured data sources.
@spec default_cache_profile() :: atom()
Returns the globally configured default cache profile.
Falls back to :results if none configured.
Returns the default data source as a {name, module} tuple.
- If default_source is configured, returns that source
- If default_source is not configured, returns the first available source
- If no data sources are configured, raises an error
@spec default_page_size() :: pos_integer() | nil
Returns the globally configured default page size for windowed pagination, if any.
When nil, Lotus uses its built-in default page size.
Gets a configuration value by key.
Returns the configuration for the given key from the application environment.
Gets a data source by name.
Returns the source module or raises if not found.
@spec list_data_source_names() :: [String.t()]
Lists the names of all configured data sources.
Loads and validates the Lotus configuration.
When called with no arguments, returns a cached, pre-validated configuration
from :persistent_term, validating and caching it on first access. When
called with an explicit keyword list, always validates the supplied options
without touching the cache.
Raises ArgumentError if the configuration is invalid.
@spec middleware() :: map()
Returns middleware configuration map, or empty map if not configured.
@spec read_only?() :: boolean()
Returns whether queries are restricted to read-only operations.
Re-reads configuration from the application environment, validates it, and
refreshes the cached value in :persistent_term.
Call this whenever :lotus application environment changes after boot
(e.g. in tests that use Application.put_env/3).
@spec repo!() :: module()
Returns the configured Ecto repository.
Returns table visibility rules for a specific source.
Falls back to default rules if source-specific rules are not configured.
Returns schema visibility rules for a specific source.
Falls back to default rules if source-specific rules are not configured.
@spec source_adapters() :: [module()]
Returns the list of external source adapter modules.
@spec source_resolver() :: module()
Returns the configured source resolver module.
Return whether the given adapter module is trusted to contribute
free-form text (:syntax_notes, :error_patterns) to AI prompts.
Always-trusted: the built-in Lotus.Source.Adapters.Ecto and the
first-party per-dialect adapters it exposes via builtin_adapters/0
(Postgres, MySQL, SQLite3). Additional modules can be trusted via
config :lotus, :trusted_source_adapters, [MyAdapter].
Untrusted adapters still supply a :language identifier to the
prompt — just not the free-form fields.
@spec unique_names?() :: boolean()
Returns whether unique query names are enforced.
@spec visibility_resolver() :: module()
Returns the configured visibility resolver module.