sqlrules 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. sqlrules-0.1.0/.gitignore +19 -0
  2. sqlrules-0.1.0/CHANGELOG.md +51 -0
  3. sqlrules-0.1.0/CONTRIBUTING.md +53 -0
  4. sqlrules-0.1.0/LICENSE +21 -0
  5. sqlrules-0.1.0/PKG-INFO +127 -0
  6. sqlrules-0.1.0/README.md +89 -0
  7. sqlrules-0.1.0/docs/API.md +75 -0
  8. sqlrules-0.1.0/docs/ARCHITECTURE.md +25 -0
  9. sqlrules-0.1.0/docs/COMPILER.md +168 -0
  10. sqlrules-0.1.0/docs/CONSTRAINTS.md +20 -0
  11. sqlrules-0.1.0/docs/CONTRIBUTING.md +10 -0
  12. sqlrules-0.1.0/docs/DESIGN_DECISIONS.md +472 -0
  13. sqlrules-0.1.0/docs/DIALECT_SUPPORT.md +220 -0
  14. sqlrules-0.1.0/docs/ERRORS.md +184 -0
  15. sqlrules-0.1.0/docs/INTERNAL_API.md +249 -0
  16. sqlrules-0.1.0/docs/MILESTONES.md +276 -0
  17. sqlrules-0.1.0/docs/NON_GOALS.md +15 -0
  18. sqlrules-0.1.0/docs/PERFORMANCE.md +235 -0
  19. sqlrules-0.1.0/docs/PHILOSOPHY.md +13 -0
  20. sqlrules-0.1.0/docs/PLUGIN_SYSTEM.md +251 -0
  21. sqlrules-0.1.0/docs/ROADMAP.md +33 -0
  22. sqlrules-0.1.0/docs/SPEC.md +66 -0
  23. sqlrules-0.1.0/docs/TESTING.md +28 -0
  24. sqlrules-0.1.0/docs/TRANSLATORS.md +225 -0
  25. sqlrules-0.1.0/docs/TYPE_SUPPORT.md +245 -0
  26. sqlrules-0.1.0/docs/VISION.md +19 -0
  27. sqlrules-0.1.0/docs/index.md +43 -0
  28. sqlrules-0.1.0/pyproject.toml +102 -0
  29. sqlrules-0.1.0/src/sqlrules/__init__.py +37 -0
  30. sqlrules-0.1.0/src/sqlrules/columns.py +76 -0
  31. sqlrules-0.1.0/src/sqlrules/compiler.py +82 -0
  32. sqlrules-0.1.0/src/sqlrules/constraints.py +256 -0
  33. sqlrules-0.1.0/src/sqlrules/errors.py +97 -0
  34. sqlrules-0.1.0/src/sqlrules/inspectors.py +54 -0
  35. sqlrules-0.1.0/src/sqlrules/ir.py +28 -0
  36. sqlrules-0.1.0/src/sqlrules/py.typed +0 -0
  37. sqlrules-0.1.0/src/sqlrules/translators.py +150 -0
  38. sqlrules-0.1.0/tests/conftest.py +17 -0
  39. sqlrules-0.1.0/tests/test_correctness.py +283 -0
  40. sqlrules-0.1.0/tests/test_coverage_edges.py +85 -0
  41. sqlrules-0.1.0/tests/test_errors.py +87 -0
  42. sqlrules-0.1.0/tests/test_helpers.py +17 -0
  43. sqlrules-0.1.0/tests/test_literal_enum.py +32 -0
  44. sqlrules-0.1.0/tests/test_numeric_constraints.py +23 -0
  45. sqlrules-0.1.0/tests/test_string_constraints.py +17 -0
  46. sqlrules-0.1.0/tests/test_v01_features.py +180 -0
@@ -0,0 +1,19 @@
1
+ .venv/
2
+ venv/
3
+ __pycache__/
4
+ *.py[cod]
5
+ *$py.class
6
+ .pytest_cache/
7
+ .mypy_cache/
8
+ .ruff_cache/
9
+ .coverage
10
+ .coverage.*
11
+ htmlcov/
12
+ dist/
13
+ build/
14
+ *.egg-info/
15
+ .DS_Store
16
+ .idea/
17
+ .vscode/
18
+ *.swp
19
+ *.swo
@@ -0,0 +1,51 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0/).
7
+
8
+ ## [0.1.0] - 2026-07-10
9
+
10
+ ### Added
11
+
12
+ - Public API: `compile()`, `where()`, `flatten()`, and `Compiler`
13
+ - Constraint support: `gt`, `ge`, `lt`, `le`, `multiple_of`, `min_length`,
14
+ `max_length`, `Literal`, and `Enum`
15
+ - Equivalent Pydantic forms: `Interval`, `conint`/`constr`, `Len`, and
16
+ `StringConstraints` (supported attributes only)
17
+ - Fail-fast handling for unsupported metadata (`pattern`, validators,
18
+ decimal precision) and unsupported types (containers, UUID, time,
19
+ timedelta)
20
+ - Field alias resolution when binding SQLAlchemy columns (`alias`,
21
+ `validation_alias`, and `serialization_alias` string forms)
22
+ - Unsupported-constraint policies: `raise` (default), `warn`, and `ignore`
23
+ for unknown **operators** (unsupported types always raise)
24
+ - Exception hierarchy rooted at `SQLRulesError`
25
+ - Column resolution for SQLAlchemy `Table` objects, ORM attributes, and
26
+ explicit `column_map`
27
+ - Documentation for the compiler, translators, errors, types, and roadmap
28
+
29
+ ### Fixed
30
+
31
+ - Column resolution no longer treats non-column `Table` attributes (such as
32
+ `name` or `is_selectable`) as columns, which previously produced invalid
33
+ SQL or Python `bool` values in the rules dict
34
+ - `Annotated[T, ...] | None` / `Optional[Annotated[T, ...]]` now unwraps
35
+ nested metadata correctly
36
+ - String `validation_alias` / `serialization_alias` participate in column
37
+ binding
38
+ - `multiple_of` values `<= 0` are rejected
39
+ - Length constraints on non-`str` fields and numeric constraints on `str` /
40
+ `bool` fields are rejected
41
+
42
+ ### Changed
43
+
44
+ - Alias candidates are preferred over the Python field name when binding
45
+ columns
46
+ - Unconstrained fields are skipped and no longer require a matching column
47
+ - Packaging URLs point at `eddiethedean/sqlrules`
48
+ - Docs clarify that `on_unsupported` does not soften unsupported types;
49
+ plugin / two-phase compile designs are marked as future
50
+
51
+ [0.1.0]: https://github.com/eddiethedean/sqlrules/releases/tag/v0.1.0
@@ -0,0 +1,53 @@
1
+ # Contributing
2
+
3
+ Thanks for helping improve SQLRules.
4
+
5
+ ## Principles
6
+
7
+ - Keep the public API minimal.
8
+ - Every feature must map directly to SQLAlchemy expressions.
9
+ - Unsupported Pydantic features should not be approximated.
10
+ - Prefer fail-fast behavior over silent semantic changes.
11
+ - Update relevant docs before or alongside implementation.
12
+
13
+ ## Development setup
14
+
15
+ ```bash
16
+ python -m venv .venv
17
+ source .venv/bin/activate
18
+ pip install -e ".[dev]"
19
+ pre-commit install
20
+ ```
21
+
22
+ ## Checks
23
+
24
+ ```bash
25
+ ruff check .
26
+ ruff format .
27
+ mypy src/sqlrules
28
+ pytest
29
+ ```
30
+
31
+ ## Pull requests
32
+
33
+ - Keep changes focused.
34
+ - Add or update tests for every constraint or error path you touch.
35
+ - Match existing code style and documentation tone.
36
+
37
+ ## Releasing
38
+
39
+ 0.1.x releases are published to PyPI by pushing a version tag. Before tagging:
40
+
41
+ 1. Confirm `pyproject.toml` and `sqlrules.__version__` match the changelog.
42
+ 2. Run the full check suite (`ruff`, `mypy`, `pytest`).
43
+ 3. Ensure CI is green on `main`.
44
+
45
+ Then create and push the tag (example for 0.1.0):
46
+
47
+ ```bash
48
+ git tag -a v0.1.0 -m "sqlrules 0.1.0"
49
+ git push origin v0.1.0
50
+ ```
51
+
52
+ The [release workflow](.github/workflows/release.yml) runs CI, builds the
53
+ sdist/wheel, and publishes with `PYPI_API_TOKEN`.
sqlrules-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 SQLRules Contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,127 @@
1
+ Metadata-Version: 2.4
2
+ Name: sqlrules
3
+ Version: 0.1.0
4
+ Summary: Compile constrained Pydantic models into SQLAlchemy WHERE-rule dictionaries.
5
+ Project-URL: Homepage, https://github.com/eddiethedean/sqlrules
6
+ Project-URL: Documentation, https://github.com/eddiethedean/sqlrules#readme
7
+ Project-URL: Repository, https://github.com/eddiethedean/sqlrules
8
+ Project-URL: Changelog, https://github.com/eddiethedean/sqlrules/blob/main/CHANGELOG.md
9
+ Project-URL: Issues, https://github.com/eddiethedean/sqlrules/issues
10
+ Author: SQLRules Contributors
11
+ License-Expression: MIT
12
+ License-File: LICENSE
13
+ Keywords: compiler,constraints,filters,pydantic,sqlalchemy,where
14
+ Classifier: Development Status :: 4 - Beta
15
+ Classifier: Intended Audience :: Developers
16
+ Classifier: License :: OSI Approved :: MIT License
17
+ Classifier: Operating System :: OS Independent
18
+ Classifier: Programming Language :: Python
19
+ Classifier: Programming Language :: Python :: 3
20
+ Classifier: Programming Language :: Python :: 3.10
21
+ Classifier: Programming Language :: Python :: 3.11
22
+ Classifier: Programming Language :: Python :: 3.12
23
+ Classifier: Programming Language :: Python :: 3.13
24
+ Classifier: Topic :: Database
25
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
26
+ Classifier: Typing :: Typed
27
+ Requires-Python: >=3.10
28
+ Requires-Dist: annotated-types>=0.6
29
+ Requires-Dist: pydantic>=2.0
30
+ Requires-Dist: sqlalchemy>=2.0
31
+ Provides-Extra: dev
32
+ Requires-Dist: mypy>=1.10; extra == 'dev'
33
+ Requires-Dist: pre-commit>=3.7; extra == 'dev'
34
+ Requires-Dist: pytest-cov>=5.0; extra == 'dev'
35
+ Requires-Dist: pytest>=8.0; extra == 'dev'
36
+ Requires-Dist: ruff>=0.5; extra == 'dev'
37
+ Description-Content-Type: text/markdown
38
+
39
+ # SQLRules
40
+
41
+ **Compile constrained Pydantic models into SQLAlchemy WHERE-rule dictionaries.**
42
+
43
+ One package. One job. Deterministic output. Zero database dependency.
44
+
45
+ ```python
46
+ from typing import Annotated
47
+ from pydantic import BaseModel, Field
48
+ from sqlalchemy import Table, Column, Integer, String, MetaData
49
+
50
+ import sqlrules
51
+
52
+ metadata = MetaData()
53
+
54
+ users = Table(
55
+ "users",
56
+ metadata,
57
+ Column("age", Integer),
58
+ Column("name", String),
59
+ )
60
+
61
+ class UserFilter(BaseModel):
62
+ age: Annotated[int, Field(ge=18, le=65)]
63
+ name: Annotated[str, Field(min_length=2)]
64
+
65
+ rules = sqlrules.compile(UserFilter, users)
66
+ # {
67
+ # "age": [users.c.age >= 18, users.c.age <= 65],
68
+ # "name": [func.length(users.c.name) >= 2],
69
+ # }
70
+
71
+ stmt = users.select().where(*sqlrules.where(rules))
72
+ ```
73
+
74
+ ## Install
75
+
76
+ ```bash
77
+ pip install sqlrules
78
+ ```
79
+
80
+ Requires Python 3.10+, Pydantic v2, and SQLAlchemy 2.x.
81
+
82
+ ## Supported constraints (0.1)
83
+
84
+ | Constraint | SQLAlchemy expression |
85
+ |---|---|
86
+ | `gt` / `ge` / `lt` / `le` | `column > / >= / < / <= value` |
87
+ | `multiple_of` | `column % value == 0` |
88
+ | `min_length` / `max_length` | `func.length(column) >= / <= value` |
89
+ | `Literal[...]` | `column.in_(...)` |
90
+ | `Enum` | `column.in_(...)` |
91
+
92
+ Unsupported constraints raise `UnsupportedConstraintError` by default.
93
+ Use `on_unsupported="warn"` or `"ignore"` to change that policy for unknown
94
+ constraint operators (unsupported types always raise).
95
+
96
+ ## Public API
97
+
98
+ ```python
99
+ sqlrules.compile(model, table, *, column_map=None, on_unsupported="raise")
100
+ sqlrules.where(rules) # flatten all expressions
101
+ sqlrules.flatten(rules) # alias of where()
102
+ ```
103
+
104
+ ## Non-goals
105
+
106
+ SQLRules is not an ORM, validator, query builder, SQL string generator,
107
+ migration tool, or database client. It only compiles supported Pydantic
108
+ constraints into SQLAlchemy expressions.
109
+
110
+ ## Documentation
111
+
112
+ See [`docs/index.md`](docs/index.md) for the full documentation set,
113
+ including the [spec](docs/SPEC.md), [API](docs/API.md),
114
+ [architecture](docs/ARCHITECTURE.md), and [roadmap](docs/ROADMAP.md).
115
+
116
+ ## Development
117
+
118
+ ```bash
119
+ pip install -e ".[dev]"
120
+ pytest
121
+ ruff check .
122
+ mypy src/sqlrules
123
+ ```
124
+
125
+ ## License
126
+
127
+ MIT
@@ -0,0 +1,89 @@
1
+ # SQLRules
2
+
3
+ **Compile constrained Pydantic models into SQLAlchemy WHERE-rule dictionaries.**
4
+
5
+ One package. One job. Deterministic output. Zero database dependency.
6
+
7
+ ```python
8
+ from typing import Annotated
9
+ from pydantic import BaseModel, Field
10
+ from sqlalchemy import Table, Column, Integer, String, MetaData
11
+
12
+ import sqlrules
13
+
14
+ metadata = MetaData()
15
+
16
+ users = Table(
17
+ "users",
18
+ metadata,
19
+ Column("age", Integer),
20
+ Column("name", String),
21
+ )
22
+
23
+ class UserFilter(BaseModel):
24
+ age: Annotated[int, Field(ge=18, le=65)]
25
+ name: Annotated[str, Field(min_length=2)]
26
+
27
+ rules = sqlrules.compile(UserFilter, users)
28
+ # {
29
+ # "age": [users.c.age >= 18, users.c.age <= 65],
30
+ # "name": [func.length(users.c.name) >= 2],
31
+ # }
32
+
33
+ stmt = users.select().where(*sqlrules.where(rules))
34
+ ```
35
+
36
+ ## Install
37
+
38
+ ```bash
39
+ pip install sqlrules
40
+ ```
41
+
42
+ Requires Python 3.10+, Pydantic v2, and SQLAlchemy 2.x.
43
+
44
+ ## Supported constraints (0.1)
45
+
46
+ | Constraint | SQLAlchemy expression |
47
+ |---|---|
48
+ | `gt` / `ge` / `lt` / `le` | `column > / >= / < / <= value` |
49
+ | `multiple_of` | `column % value == 0` |
50
+ | `min_length` / `max_length` | `func.length(column) >= / <= value` |
51
+ | `Literal[...]` | `column.in_(...)` |
52
+ | `Enum` | `column.in_(...)` |
53
+
54
+ Unsupported constraints raise `UnsupportedConstraintError` by default.
55
+ Use `on_unsupported="warn"` or `"ignore"` to change that policy for unknown
56
+ constraint operators (unsupported types always raise).
57
+
58
+ ## Public API
59
+
60
+ ```python
61
+ sqlrules.compile(model, table, *, column_map=None, on_unsupported="raise")
62
+ sqlrules.where(rules) # flatten all expressions
63
+ sqlrules.flatten(rules) # alias of where()
64
+ ```
65
+
66
+ ## Non-goals
67
+
68
+ SQLRules is not an ORM, validator, query builder, SQL string generator,
69
+ migration tool, or database client. It only compiles supported Pydantic
70
+ constraints into SQLAlchemy expressions.
71
+
72
+ ## Documentation
73
+
74
+ See [`docs/index.md`](docs/index.md) for the full documentation set,
75
+ including the [spec](docs/SPEC.md), [API](docs/API.md),
76
+ [architecture](docs/ARCHITECTURE.md), and [roadmap](docs/ROADMAP.md).
77
+
78
+ ## Development
79
+
80
+ ```bash
81
+ pip install -e ".[dev]"
82
+ pytest
83
+ ruff check .
84
+ mypy src/sqlrules
85
+ ```
86
+
87
+ ## License
88
+
89
+ MIT
@@ -0,0 +1,75 @@
1
+ # Public API
2
+
3
+ SQLRules exposes a deliberately small public surface.
4
+
5
+ ## `compile`
6
+
7
+ ```python
8
+ sqlrules.compile(
9
+ model,
10
+ table,
11
+ *,
12
+ column_map=None,
13
+ on_unsupported="raise",
14
+ ) -> dict[str, list[ColumnElement[bool]]]
15
+ ```
16
+
17
+ Compile a constrained Pydantic model into a field-keyed rule dictionary.
18
+
19
+ | Parameter | Description |
20
+ |---|---|
21
+ | `model` | Pydantic `BaseModel` subclass |
22
+ | `table` | SQLAlchemy `Table`, alias, ORM class, or object with `.c` |
23
+ | `column_map` | Optional explicit `field_name` or alias → column mapping |
24
+ | `on_unsupported` | `"raise"` (default), `"warn"`, or `"ignore"` for unknown **operators** only |
25
+
26
+ Rule dictionary keys are always the Python field names. String field aliases
27
+ (`alias`, `validation_alias`, `serialization_alias`) are used only for column
28
+ binding. Unconstrained fields are omitted and do not require a column.
29
+
30
+ Unsupported types always raise, regardless of `on_unsupported`.
31
+
32
+ ## `where` / `flatten`
33
+
34
+ ```python
35
+ sqlrules.where(rules) -> list[ColumnElement[bool]]
36
+ sqlrules.flatten(rules) -> list[ColumnElement[bool]]
37
+ ```
38
+
39
+ Flatten a rule dictionary into a single list of expressions suitable for
40
+ `Query.where(*expressions)` or `select(...).where(*expressions)`.
41
+
42
+ `where` and `flatten` are identical aliases.
43
+
44
+ ## `Compiler`
45
+
46
+ ```python
47
+ compiler = sqlrules.Compiler(on_unsupported="raise", registry=None)
48
+ rules = compiler.compile(model, table, column_map=None)
49
+ ```
50
+
51
+ Reusable compiler instance with a fixed unsupported-constraint policy and
52
+ optional custom translator registry.
53
+
54
+ ## Other exports
55
+
56
+ Also exported for advanced use and typing:
57
+
58
+ - `__version__`
59
+ - `SQLRulesWarning`
60
+ - `CompilationContext`, `Constraint`, `FieldDescriptor` (IR helpers)
61
+
62
+ ## Exceptions
63
+
64
+ All public exceptions inherit from `SQLRulesError`:
65
+
66
+ - `InvalidModelError`
67
+ - `MissingColumnError`
68
+ - `UnsupportedConstraintError`
69
+ - `TranslatorError`
70
+ - `InvalidTranslatorError` (reserved; not raised in 0.1)
71
+ - `RegistryError`
72
+ - `ConfigurationError`
73
+ - `InternalCompilerError` (reserved; not raised in 0.1)
74
+
75
+ See [ERRORS.md](ERRORS.md) for details.
@@ -0,0 +1,25 @@
1
+ # Architecture
2
+
3
+ ```text
4
+ Pydantic Model
5
+
6
+ Metadata Reader
7
+
8
+ Constraint IR
9
+
10
+ SQLAlchemy Compiler
11
+
12
+ Rule Dictionary
13
+ ```
14
+
15
+ SQLRules is a pure compiler pipeline:
16
+
17
+ 1. **Inspect** the Pydantic model and preserve field declaration order.
18
+ 2. **Resolve** each field to a SQLAlchemy column.
19
+ 3. **Extract** supported constraints into a dialect-neutral IR.
20
+ 4. **Translate** each IR constraint into one SQLAlchemy expression.
21
+ 5. **Assemble** expressions into `dict[str, list[ColumnElement[bool]]]`.
22
+
23
+ The compiler never connects to a database, executes SQL, or renders SQL
24
+ strings. See [COMPILER.md](COMPILER.md) and [INTERNAL_API.md](INTERNAL_API.md)
25
+ for stage-level detail.
@@ -0,0 +1,168 @@
1
+ # SQLRules Compiler Architecture
2
+
3
+ ## Purpose
4
+
5
+ The SQLRules compiler transforms a constrained Pydantic model into a
6
+ dictionary of SQLAlchemy WHERE expressions.
7
+
8
+ The compiler never connects to a database, executes SQL, or generates
9
+ SQL strings. It only produces SQLAlchemy expression objects.
10
+
11
+ ## Pipeline
12
+
13
+ ``` text
14
+ Pydantic Model
15
+
16
+
17
+ Model Introspection
18
+
19
+
20
+ Field Extraction
21
+
22
+
23
+ Constraint Extraction
24
+
25
+
26
+ Intermediate Representation (IR)
27
+
28
+
29
+ Constraint Translators
30
+
31
+
32
+ SQLAlchemy Expressions
33
+
34
+
35
+ Rule Dictionary
36
+ ```
37
+
38
+ ## Stage 1 -- Model Introspection
39
+
40
+ Inputs: - Pydantic BaseModel subclass - SQLAlchemy Table, Alias, ORM
41
+ class, or column mapping
42
+
43
+ Responsibilities: - Validate the input model. - Enumerate model
44
+ fields. - Preserve declaration order.
45
+
46
+ Output: - Iterable of field definitions.
47
+
48
+ ## Stage 2 -- Field Extraction
49
+
50
+ For each field:
51
+
52
+ - Python type
53
+ - Optionality
54
+ - Metadata
55
+ - Field name
56
+ - Alias (optional)
57
+
58
+ Unsupported field definitions fail fast.
59
+
60
+ ## Stage 3 -- Constraint Extraction
61
+
62
+ Read only constraints that have deterministic SQL equivalents.
63
+
64
+ Examples: - gt - ge - lt - le - multiple_of - min_length - max_length -
65
+ Literal - Enum
66
+
67
+ Constraints without SQL equivalents are delegated to the
68
+ unsupported-constraint policy.
69
+
70
+ ## Stage 4 -- Intermediate Representation
71
+
72
+ Each constraint becomes a normalized object.
73
+
74
+ Example:
75
+
76
+ ``` text
77
+ Constraint(
78
+ field="age",
79
+ operator="ge",
80
+ value=18,
81
+ )
82
+ ```
83
+
84
+ The IR isolates compiler logic from both Pydantic and SQLAlchemy APIs.
85
+
86
+ ## Stage 5 -- Translators
87
+
88
+ Each constraint is translated independently.
89
+
90
+ Examples:
91
+
92
+ - ge → column \>= value
93
+ - gt → column \> value
94
+ - min_length → func.length(column) \>= value
95
+ - Literal → column.in\_(...)
96
+
97
+ Every translator returns one SQLAlchemy expression.
98
+
99
+ ## Stage 6 -- Rule Assembly
100
+
101
+ Expressions are grouped by field.
102
+
103
+ Example:
104
+
105
+ ``` python
106
+ {
107
+ "age": [
108
+ users.c.age >= 18,
109
+ users.c.age <= 65,
110
+ ]
111
+ }
112
+ ```
113
+
114
+ Ordering is deterministic and follows the source model.
115
+
116
+ ## Error Handling
117
+
118
+ Modes:
119
+
120
+ - raise (default)
121
+ - warn
122
+ - ignore
123
+
124
+ Errors include:
125
+
126
+ - UnsupportedConstraintError
127
+ - MissingColumnError
128
+ - InvalidModelError
129
+ - TranslatorError
130
+
131
+ ## Caching
132
+
133
+ Future versions may cache compiled metadata using the model type as the
134
+ cache key. Translation remains deterministic.
135
+
136
+ ## Extension Points
137
+
138
+ Future plugin hooks:
139
+
140
+ - Register custom translators.
141
+ - Register dialect-specific translators.
142
+ - Override built-in mappings.
143
+ - Add new IR transforms.
144
+
145
+ ## Design Principles
146
+
147
+ - Pure function compiler
148
+ - No database dependency
149
+ - Deterministic output
150
+ - SQLAlchemy-first
151
+ - Easy to test
152
+ - Easy to extend
153
+ - Fail fast on unsupported semantics
154
+
155
+ ## Public Contract
156
+
157
+ ``` python
158
+ rules = sqlrules.compile(UserFilter, users)
159
+ ```
160
+
161
+ Returns:
162
+
163
+ ``` python
164
+ dict[str, list]
165
+ ```
166
+
167
+ where each value is a list of SQLAlchemy boolean expressions suitable
168
+ for passing directly to `.where(*expressions)`.
@@ -0,0 +1,20 @@
1
+ # Supported Constraint Mapping
2
+
3
+ | Constraint | SQLAlchemy expression |
4
+ |---|---|
5
+ | `gt` | `column > value` |
6
+ | `ge` | `column >= value` |
7
+ | `lt` | `column < value` |
8
+ | `le` | `column <= value` |
9
+ | `min_length` | `func.length(column) >= value` |
10
+ | `max_length` | `func.length(column) <= value` |
11
+ | `multiple_of` | `column % value == 0` |
12
+ | `Literal[...]` | `column.in_(...)` |
13
+ | `Enum` | `column.in_(member values)` |
14
+
15
+ Accepted input forms for the same semantics include `Field(...)`,
16
+ `annotated_types` primitives, `Interval`, `Len`, `conint`/`constr`, and
17
+ `StringConstraints` (length attributes only).
18
+
19
+ Constraints without a deterministic SQL equivalent are rejected by default.
20
+ See [TYPE_SUPPORT.md](TYPE_SUPPORT.md) and [ERRORS.md](ERRORS.md).
@@ -0,0 +1,10 @@
1
+ # Contributing
2
+
3
+ See the root [CONTRIBUTING.md](../CONTRIBUTING.md) for development setup,
4
+ checks, and pull-request guidelines.
5
+
6
+ Key rules:
7
+
8
+ - Keep the public API minimal.
9
+ - Every feature must map directly to SQLAlchemy expressions.
10
+ - Unsupported Pydantic features should not be approximated.