SQLRules Plugin System¶
Purpose¶
The SQLRules plugin system allows applications and libraries to extend the compiler without modifying SQLRules itself.
Plugins may register:
New constraint translators
Dialect-specific translators (overrides for the same IR operators)
The core package remains small while advanced functionality lives in plugins. Compiler passes, type registration, and entry-point discovery are reserved for later releases.
Design Goals¶
Zero-cost when unused
Deterministic compilation
Stable public extension API (
PLUGIN_API_VERSION)No monkey-patching
Explicit registration
Architecture¶
SQLRules Compiler
│
┌─────────┴─────────┐
▼ ▼
Built-in Registry Plugin register()
│ │
└─────────┬─────────┘
▼
Translator Dispatch
▼
SQLAlchemy Expressions
Plugin Interface¶
A plugin is a Python object that exposes name, api_version, and
register(registry).
from sqlrules import PLUGIN_API_VERSION, TranslatorRegistry, pattern_text
class CompanyPlugin:
name = "company"
api_version = PLUGIN_API_VERSION
def register(self, registry: TranslatorRegistry) -> None:
registry.register_constraint(
"pattern",
lambda c, col, ctx: col.op("~")(pattern_text(c.value)[0]),
on_conflict="replace",
)
api_version must equal sqlrules.PLUGIN_API_VERSION ("1").
Version policy¶
API v1 includes PatternSpec for pattern and TypeSpec for
type_check constraint values. Always use pattern_text /
type_spec; do not assume bare str / type values.
Bump PLUGIN_API_VERSION when changing translator signatures, registry
methods, or IR value types for built-in operators. Core package minor
bumps alone do not change the plugin API version.
register_type, register_dialect, and register_compiler_pass
are not implemented on TranslatorRegistry in API v1. Do not probe
with hasattr.
Markers¶
Dialect-oriented constraints use sqlrules.markers (for example
JsonContains, ArrayContains). Markers implement the
ConstraintMarker protocol (operator, value) and are extracted into
IR. Plugins register translators for those operator names.
ConstraintMarker is intentionally duck-typed (@runtime_checkable).
Prefer the official marker dataclasses so operator names stay stable.
Frozen operator names: json_contains, json_has_key, array_contains,
array_overlap, range_contains, range_overlap, fulltext_match.
Registry API¶
registry.register_constraint(
operator="pattern",
translator=translate_pattern,
on_conflict="raise", # or "replace" / "ignore"
)
Legacy alias:
registry.register("pattern", translate_pattern, replace=False)
Introspection: registry.operators(), operator in registry, registry.copy().
Invalid translators raise InvalidTranslatorError. Duplicate operators
raise RegistryError unless on_conflict / replace allows otherwise.
register_type, register_dialect, and register_compiler_pass are
not present on TranslatorRegistry in API v1 — do not probe with
hasattr.
Using Plugins¶
SQLRules does not auto-discover plugins. Register them explicitly:
from sqlrules import Compiler
from sqlrules_postgresql import PostgresPlugin
compiler = Compiler(
plugins=[PostgresPlugin()],
dialect="postgresql", # optional hint for translators
on_conflict="raise", # default when plugins call register()
)
rules = compiler.compile(MyModel, table)
Module-level sqlrules.compile(...) does not accept plugins; use
Compiler when you need extensions.
When plugins= is set, the compiler copies the base registry first so
caller-owned registries are never mutated.
Dialect Plugins¶
Official packages (monorepo under packages/):
sqlrules-postgresql— regex, JSONB, ARRAY, rangesqlrules-sqlite— REGEXP helper + JSONsqlrules-mysql— REGEXP, JSON, full-textsqlrules-mssql— JSON +LENlength overrides
Conflict Resolution¶
Compiler(on_conflict=...) sets the default for plugin register() calls:
Mode |
Behavior |
|---|---|
|
|
|
Overwrite existing translator |
|
Keep the existing translator |
Plugins may still pass an explicit on_conflict= to
register_constraint.
Version Compatibility¶
from sqlrules import PLUGIN_API_VERSION # "1"
Major plugin API changes increment this value. Mismatched plugins raise
PluginError at compiler construction.
Conformance Testing¶
from sqlrules.conformance import run_basic_conformance
from sqlrules_postgresql import PostgresPlugin
run_basic_conformance(PostgresPlugin(), operator="pattern")
Helpers also cover API version checks, builtin preservation, and
deterministic translation. Pass model= / table= / field= when
conformance-checking non-pattern operators.
Security¶
Plugins execute Python code. SQLRules does not sandbox plugins. Install only trusted plugins.
Non-Goals¶
The plugin system does not support:
Runtime SQL execution
Database connections
Automatic package downloads / entry-point discovery
Dynamic code generation
Compiler pass plugins (future)
Design Principles¶
Small core
Extensible architecture
Explicit registration
Stable plugin API
Pure compiler extensions
Deterministic behavior