sqlrules 0.4.0__tar.gz → 1.0.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 (129) hide show
  1. {sqlrules-0.4.0 → sqlrules-1.0.0}/.gitignore +1 -0
  2. {sqlrules-0.4.0 → sqlrules-1.0.0}/CHANGELOG.md +48 -0
  3. sqlrules-1.0.0/CODE_OF_CONDUCT.md +70 -0
  4. sqlrules-1.0.0/CONTRIBUTING.md +74 -0
  5. sqlrules-1.0.0/PKG-INFO +358 -0
  6. sqlrules-1.0.0/README.md +298 -0
  7. sqlrules-1.0.0/RELEASING.md +72 -0
  8. {sqlrules-0.4.0/docs → sqlrules-1.0.0}/ROADMAP.md +15 -4
  9. sqlrules-1.0.0/SECURITY.md +34 -0
  10. sqlrules-1.0.0/docs/API.md +209 -0
  11. {sqlrules-0.4.0 → sqlrules-1.0.0}/docs/ARCHITECTURE.md +8 -6
  12. {sqlrules-0.4.0 → sqlrules-1.0.0}/docs/CONSTRAINTS.md +7 -2
  13. {sqlrules-0.4.0 → sqlrules-1.0.0}/docs/DESIGN_DECISIONS.md +17 -17
  14. {sqlrules-0.4.0 → sqlrules-1.0.0}/docs/DIALECT_SUPPORT.md +16 -16
  15. {sqlrules-0.4.0 → sqlrules-1.0.0}/docs/ERRORS.md +22 -20
  16. sqlrules-1.0.0/docs/INTERNAL_API.md +91 -0
  17. sqlrules-1.0.0/docs/IR_CONTRACT.md +61 -0
  18. {sqlrules-0.4.0 → sqlrules-1.0.0}/docs/MILESTONES.md +34 -45
  19. {sqlrules-0.4.0 → sqlrules-1.0.0}/docs/PERFORMANCE.md +28 -24
  20. {sqlrules-0.4.0 → sqlrules-1.0.0}/docs/PLUGIN_SYSTEM.md +37 -18
  21. sqlrules-1.0.0/docs/README.md +19 -0
  22. sqlrules-1.0.0/docs/SECURITY.md +43 -0
  23. {sqlrules-0.4.0 → sqlrules-1.0.0}/docs/SPEC.md +18 -4
  24. {sqlrules-0.4.0 → sqlrules-1.0.0}/docs/TESTING.md +24 -4
  25. {sqlrules-0.4.0 → sqlrules-1.0.0}/docs/TRANSLATORS.md +15 -15
  26. {sqlrules-0.4.0 → sqlrules-1.0.0}/docs/TYPE_SUPPORT.md +59 -28
  27. sqlrules-1.0.0/docs/_static/custom.css +225 -0
  28. sqlrules-1.0.0/docs/_static/favicon.svg +4 -0
  29. sqlrules-1.0.0/docs/_static/logo-dark.svg +5 -0
  30. sqlrules-1.0.0/docs/_static/logo.svg +5 -0
  31. sqlrules-1.0.0/docs/_templates/.gitkeep +0 -0
  32. sqlrules-1.0.0/docs/conf.py +190 -0
  33. sqlrules-1.0.0/docs/guides/design-philosophy.md +53 -0
  34. sqlrules-1.0.0/docs/guides/faq.md +75 -0
  35. sqlrules-1.0.0/docs/guides/getting-started.md +149 -0
  36. sqlrules-1.0.0/docs/guides/markers.md +66 -0
  37. sqlrules-1.0.0/docs/guides/orm-column-map.md +78 -0
  38. sqlrules-1.0.0/docs/guides/start-here.md +50 -0
  39. sqlrules-1.0.0/docs/guides/troubleshooting.md +74 -0
  40. sqlrules-1.0.0/docs/index.md +163 -0
  41. sqlrules-1.0.0/docs/internals/index.md +20 -0
  42. sqlrules-1.0.0/docs/project/changelog.md +2 -0
  43. sqlrules-1.0.0/docs/project/contributing.md +2 -0
  44. sqlrules-1.0.0/docs/project/roadmap.md +2 -0
  45. sqlrules-1.0.0/docs/project/support.md +55 -0
  46. sqlrules-1.0.0/docs/reference/application.md +16 -0
  47. sqlrules-1.0.0/docs/reference/glossary.md +22 -0
  48. sqlrules-1.0.0/docs/reference/index.md +46 -0
  49. sqlrules-1.0.0/docs/reference/plugin-api.md +17 -0
  50. sqlrules-1.0.0/docs/requirements.txt +7 -0
  51. sqlrules-1.0.0/examples/README.md +37 -0
  52. sqlrules-1.0.0/examples/basic_compile.py +38 -0
  53. sqlrules-1.0.0/examples/postgresql_pattern.py +53 -0
  54. sqlrules-1.0.0/examples/select_usage.py +38 -0
  55. {sqlrules-0.4.0 → sqlrules-1.0.0}/pyproject.toml +30 -7
  56. sqlrules-1.0.0/scripts/check_versions.py +74 -0
  57. {sqlrules-0.4.0 → sqlrules-1.0.0}/src/sqlrules/__init__.py +11 -3
  58. sqlrules-1.0.0/src/sqlrules/cache.py +51 -0
  59. sqlrules-1.0.0/src/sqlrules/compiler.py +361 -0
  60. {sqlrules-0.4.0 → sqlrules-1.0.0}/src/sqlrules/constraints.py +153 -6
  61. {sqlrules-0.4.0 → sqlrules-1.0.0}/src/sqlrules/ir.py +9 -0
  62. {sqlrules-0.4.0 → sqlrules-1.0.0}/src/sqlrules/plugins.py +25 -0
  63. sqlrules-1.0.0/src/sqlrules/py.typed +0 -0
  64. {sqlrules-0.4.0 → sqlrules-1.0.0}/src/sqlrules/translators.py +90 -42
  65. {sqlrules-0.4.0 → sqlrules-1.0.0}/tests/test_correctness.py +82 -11
  66. {sqlrules-0.4.0 → sqlrules-1.0.0}/tests/test_coverage_edges.py +43 -10
  67. {sqlrules-0.4.0 → sqlrules-1.0.0}/tests/test_errors.py +47 -1
  68. {sqlrules-0.4.0 → sqlrules-1.0.0}/tests/test_literal_enum.py +18 -0
  69. sqlrules-1.0.0/tests/test_numeric_constraints.py +37 -0
  70. {sqlrules-0.4.0 → sqlrules-1.0.0}/tests/test_plugins.py +24 -0
  71. sqlrules-1.0.0/tests/test_string_constraints.py +31 -0
  72. sqlrules-1.0.0/tests/test_type_checks.py +297 -0
  73. {sqlrules-0.4.0 → sqlrules-1.0.0}/tests/test_v01_features.py +8 -0
  74. {sqlrules-0.4.0 → sqlrules-1.0.0}/tests/test_v02_features.py +2 -8
  75. {sqlrules-0.4.0 → sqlrules-1.0.0}/tests/test_v04_markers.py +20 -9
  76. sqlrules-0.4.0/CONTRIBUTING.md +0 -86
  77. sqlrules-0.4.0/PKG-INFO +0 -171
  78. sqlrules-0.4.0/README.md +0 -131
  79. sqlrules-0.4.0/docs/API.md +0 -142
  80. sqlrules-0.4.0/docs/CONTRIBUTING.md +0 -10
  81. sqlrules-0.4.0/docs/INTERNAL_API.md +0 -251
  82. sqlrules-0.4.0/docs/index.md +0 -43
  83. sqlrules-0.4.0/packages/sqlrules-mssql/README.md +0 -37
  84. sqlrules-0.4.0/packages/sqlrules-mssql/pyproject.toml +0 -28
  85. sqlrules-0.4.0/packages/sqlrules-mssql/src/sqlrules_mssql/__init__.py +0 -52
  86. sqlrules-0.4.0/packages/sqlrules-mssql/src/sqlrules_mssql/json.py +0 -70
  87. sqlrules-0.4.0/packages/sqlrules-mssql/src/sqlrules_mssql/length.py +0 -26
  88. sqlrules-0.4.0/packages/sqlrules-mssql/tests/test_mssql_plugin.py +0 -52
  89. sqlrules-0.4.0/packages/sqlrules-mysql/README.md +0 -36
  90. sqlrules-0.4.0/packages/sqlrules-mysql/pyproject.toml +0 -28
  91. sqlrules-0.4.0/packages/sqlrules-mysql/src/sqlrules_mysql/__init__.py +0 -39
  92. sqlrules-0.4.0/packages/sqlrules-mysql/src/sqlrules_mysql/fulltext.py +0 -20
  93. sqlrules-0.4.0/packages/sqlrules-mysql/src/sqlrules_mysql/json.py +0 -35
  94. sqlrules-0.4.0/packages/sqlrules-mysql/src/sqlrules_mysql/pattern.py +0 -22
  95. sqlrules-0.4.0/packages/sqlrules-mysql/tests/test_mysql_plugin.py +0 -45
  96. sqlrules-0.4.0/packages/sqlrules-postgresql/README.md +0 -53
  97. sqlrules-0.4.0/packages/sqlrules-postgresql/pyproject.toml +0 -28
  98. sqlrules-0.4.0/packages/sqlrules-postgresql/src/sqlrules_postgresql/__init__.py +0 -46
  99. sqlrules-0.4.0/packages/sqlrules-postgresql/src/sqlrules_postgresql/array.py +0 -25
  100. sqlrules-0.4.0/packages/sqlrules-postgresql/src/sqlrules_postgresql/jsonb.py +0 -25
  101. sqlrules-0.4.0/packages/sqlrules-postgresql/src/sqlrules_postgresql/pattern.py +0 -19
  102. sqlrules-0.4.0/packages/sqlrules-postgresql/src/sqlrules_postgresql/range.py +0 -25
  103. sqlrules-0.4.0/packages/sqlrules-postgresql/tests/test_postgres_plugin.py +0 -88
  104. sqlrules-0.4.0/packages/sqlrules-sqlite/README.md +0 -53
  105. sqlrules-0.4.0/packages/sqlrules-sqlite/pyproject.toml +0 -28
  106. sqlrules-0.4.0/packages/sqlrules-sqlite/src/sqlrules_sqlite/__init__.py +0 -48
  107. sqlrules-0.4.0/packages/sqlrules-sqlite/src/sqlrules_sqlite/json.py +0 -58
  108. sqlrules-0.4.0/packages/sqlrules-sqlite/src/sqlrules_sqlite/pattern.py +0 -25
  109. sqlrules-0.4.0/packages/sqlrules-sqlite/src/sqlrules_sqlite/regexp.py +0 -30
  110. sqlrules-0.4.0/packages/sqlrules-sqlite/tests/test_sqlite_plugin.py +0 -72
  111. sqlrules-0.4.0/src/sqlrules/cache.py +0 -40
  112. sqlrules-0.4.0/src/sqlrules/compiler.py +0 -206
  113. sqlrules-0.4.0/tests/test_numeric_constraints.py +0 -23
  114. sqlrules-0.4.0/tests/test_string_constraints.py +0 -17
  115. {sqlrules-0.4.0 → sqlrules-1.0.0}/LICENSE +0 -0
  116. {sqlrules-0.4.0 → sqlrules-1.0.0}/benchmarks/__init__.py +0 -0
  117. {sqlrules-0.4.0 → sqlrules-1.0.0}/benchmarks/bench_compile.py +0 -0
  118. {sqlrules-0.4.0 → sqlrules-1.0.0}/docs/COMPILER.md +0 -0
  119. {sqlrules-0.4.0 → sqlrules-1.0.0}/docs/NON_GOALS.md +0 -0
  120. {sqlrules-0.4.0 → sqlrules-1.0.0}/docs/PHILOSOPHY.md +0 -0
  121. {sqlrules-0.4.0 → sqlrules-1.0.0}/docs/VISION.md +0 -0
  122. /sqlrules-0.4.0/src/sqlrules/py.typed → /sqlrules-1.0.0/docs/_static/.gitkeep +0 -0
  123. {sqlrules-0.4.0 → sqlrules-1.0.0}/src/sqlrules/columns.py +0 -0
  124. {sqlrules-0.4.0 → sqlrules-1.0.0}/src/sqlrules/conformance.py +0 -0
  125. {sqlrules-0.4.0 → sqlrules-1.0.0}/src/sqlrules/errors.py +0 -0
  126. {sqlrules-0.4.0 → sqlrules-1.0.0}/src/sqlrules/inspectors.py +0 -0
  127. {sqlrules-0.4.0 → sqlrules-1.0.0}/src/sqlrules/markers.py +0 -0
  128. {sqlrules-0.4.0 → sqlrules-1.0.0}/tests/conftest.py +0 -0
  129. {sqlrules-0.4.0 → sqlrules-1.0.0}/tests/test_helpers.py +0 -0
@@ -18,3 +18,4 @@ build/
18
18
  .vscode/
19
19
  *.swp
20
20
  *.swo
21
+ docs/_build/
@@ -5,6 +5,53 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0/).
7
7
 
8
+ ## [Unreleased]
9
+
10
+ ## [1.0.0] - 2026-07-10
11
+
12
+ ### Added
13
+
14
+ - **Stable 1.0** Application + Plugin APIs frozen; classifiers
15
+ `Production/Stable`
16
+ - Opt-in `emit_type_checks` on `Compiler` / `compile()`: extracts `type_check`
17
+ IR (`TypeSpec`) from supported scalar annotations, honoring Field /
18
+ `Strict()` / `model_config` strictness and `Optional` → `allow_none`
19
+ - `TypeSpec` / `type_spec()` helper; dialect plugins translate `type_check`
20
+ (PostgreSQL reference matrix; SQLite / MySQL / MSSQL partial support)
21
+ - Application API `clear_model_cache()` for the process-wide Phase-1 IR cache
22
+ - `docs/IR_CONTRACT.md` — frozen Plugin API v1 IR schema
23
+ - `scripts/check_versions.py` — core/plugin lockstep + extras pin checks
24
+ - All-or-nothing PyPI publish via Trusted Publishing (OIDC)
25
+ - Plugin wheel install + conformance smoke in CI; mypy on dialect packages
26
+ - `examples/` runnable scripts; Makefile (`install` / `test` / `docs` / `dist`)
27
+ - Root `SECURITY.md`, `CODE_OF_CONDUCT.md`, `RELEASING.md`; GitHub issue templates
28
+ - Docs: Application vs Plugin autodoc pages; pattern footgun in getting started;
29
+ how-to guides (ORM/`column_map`, markers); Support & compatibility page
30
+
31
+ ### Changed
32
+
33
+ - Core and dialect packages versioned `1.0.0` in lockstep; pins
34
+ `sqlrules>=1,<2` / extras `sqlrules-*>=1,<2`
35
+ - Phase-1 IR cache keyed by `(model, emit_type_checks)` so type-check IR
36
+ does not collide with default compiles
37
+ - `Strict()` metadata is no longer turned into a fake IR operator
38
+ - Builtin translator registry built once per process; module `compile()`
39
+ reuses shared default `Compiler` instances
40
+ - `max_digits` / `decimal_places` and unknown Field metadata keys rejected at
41
+ extract (no invented operators)
42
+ - Elevated pattern/ReDoS guidance in SECURITY and dialect READMEs
43
+ - Core sdist no longer bundles `/packages`
44
+ - `annotated-types` upper-bounded (`>=0.6,<1`)
45
+ - README mental-model anti-example, install honesty (PyPI vs source), prefer
46
+ `where`; CONTRIBUTING focused on contributors; release steps in RELEASING.md
47
+
48
+ ### Docs
49
+
50
+ - Whole-model type matrix documented as intentional 1.0 contract
51
+ - Registry mutation after `Compiler` init documented as unsupported
52
+ - Prefer `register_constraint` in Plugin docs
53
+ - Diátaxis-oriented navigation; one H1 per page for sidebar hygiene
54
+
8
55
  ## [0.4.0] - 2026-07-10
9
56
 
10
57
  ### Added
@@ -132,6 +179,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
132
179
  - Docs clarify that `on_unsupported` does not soften unsupported types;
133
180
  plugin / two-phase compile designs are marked as future
134
181
 
182
+ [1.0.0]: https://github.com/eddiethedean/sqlrules/releases/tag/v1.0.0
135
183
  [0.4.0]: https://github.com/eddiethedean/sqlrules/releases/tag/v0.4.0
136
184
  [0.3.0]: https://github.com/eddiethedean/sqlrules/releases/tag/v0.3.0
137
185
  [0.2.0]: https://github.com/eddiethedean/sqlrules/releases/tag/v0.2.0
@@ -0,0 +1,70 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ We as members, contributors, and leaders pledge to make participation in our
6
+ community a harassment-free experience for everyone, regardless of age, body
7
+ size, visible or invisible disability, ethnicity, sex characteristics, gender
8
+ identity and expression, level of experience, education, socio-economic status,
9
+ nationality, personal appearance, race, caste, color, religion, or sexual
10
+ identity and orientation.
11
+
12
+ We pledge to act and interact in ways that contribute to an open, welcoming,
13
+ diverse, inclusive, and healthy community.
14
+
15
+ ## Our Standards
16
+
17
+ Examples of behavior that contributes to a positive environment:
18
+
19
+ - Demonstrating empathy and kindness toward other people
20
+ - Being respectful of differing opinions, viewpoints, and experiences
21
+ - Giving and gracefully accepting constructive feedback
22
+ - Accepting responsibility and apologizing to those affected by our mistakes
23
+ - Focusing on what is best for the community
24
+
25
+ Examples of unacceptable behavior:
26
+
27
+ - The use of sexualized language or imagery, and sexual attention or advances
28
+ - Trolling, insulting or derogatory comments, and personal or political attacks
29
+ - Public or private harassment
30
+ - Publishing others' private information without explicit permission
31
+ - Other conduct which could reasonably be considered inappropriate in a
32
+ professional setting
33
+
34
+ ## Enforcement Responsibilities
35
+
36
+ Project maintainers are responsible for clarifying and enforcing our standards
37
+ of acceptable behavior and will take appropriate and fair corrective action in
38
+ response to any behavior that they deem inappropriate, threatening, offensive,
39
+ or harmful.
40
+
41
+ ## Scope
42
+
43
+ This Code of Conduct applies within all community spaces and also applies when
44
+ an individual is officially representing the community in public spaces.
45
+
46
+ ## Enforcement
47
+
48
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
49
+ reported by contacting the repository owner privately (do **not** use public
50
+ GitHub Issues for sensitive reports). Maintainers may also be reached through
51
+ a private GitHub security advisory when appropriate.
52
+
53
+ All complaints will be reviewed and investigated promptly and fairly.
54
+
55
+ ### Enforcement guidelines
56
+
57
+ | Impact | Consequence |
58
+ |---|---|
59
+ | Minor / first offense | Private warning; clarification of standards |
60
+ | Repeated or serious | Temporary restriction from community spaces |
61
+ | Severe or patterned abuse | Permanent ban from community spaces |
62
+
63
+ Project maintainers who do not follow or enforce this Code of Conduct in good
64
+ faith may face temporary or permanent repercussions as determined by other
65
+ maintainers.
66
+
67
+ ## Attribution
68
+
69
+ This Code of Conduct is adapted from the
70
+ [Contributor Covenant](https://www.contributor-covenant.org), version 2.1.
@@ -0,0 +1,74 @@
1
+ # Contributing
2
+
3
+ Thanks for helping improve SQLRules.
4
+
5
+ **Requires** Python 3.10+.
6
+
7
+ ## Principles
8
+
9
+ - Keep the Application API minimal.
10
+ - Every feature must map directly to SQLAlchemy expressions.
11
+ - Unsupported Pydantic features should not be approximated.
12
+ - Prefer fail-fast behavior over silent semantic changes.
13
+ - Update relevant docs before or alongside implementation.
14
+
15
+ ## Development setup
16
+
17
+ ```bash
18
+ python -m venv .venv
19
+ source .venv/bin/activate
20
+ make install
21
+ pre-commit install
22
+ ```
23
+
24
+ `make install` editable-installs core (`dev` + `docs` extras) and the four
25
+ dialect packages under `packages/`.
26
+
27
+ `pre-commit` runs **Ruff** only (format/lint). It does **not** replace CI —
28
+ still run the checks below before opening a PR.
29
+
30
+ ## Day-to-day checks (match CI)
31
+
32
+ ```bash
33
+ make check # ruff, mypy, version sync, pytest, sphinx -W
34
+ make dist # build + twine check core and dialect plugins (CI package job)
35
+ ```
36
+
37
+ Equivalents:
38
+
39
+ ```bash
40
+ make test # lint + types + version sync + pytest (no docs)
41
+ make docs # sphinx-build -W
42
+ ```
43
+
44
+ **Coverage:** core `sqlrules` is gated at ≥95% (`--cov-fail-under=95`).
45
+ Dialect packages are tested but not included in that fail-under.
46
+
47
+ ## Pull requests
48
+
49
+ - Keep changes focused.
50
+ - Add or update tests for every constraint or error path you touch.
51
+ - Update docs (and CHANGELOG under `[Unreleased]` for user-visible changes).
52
+ - Run `make check` and `make dist` so local gates match CI
53
+ (lint / test / docs / package).
54
+ - Issue templates label `bug` / `enhancement` / `question`; starter tasks may
55
+ also use `good first issue` when maintainers apply that label.
56
+
57
+ ## Plugins
58
+
59
+ - Declare `name`, `api_version` (`PLUGIN_API_VERSION`), and `register(registry)`.
60
+ - Prefer `register_constraint(..., on_conflict=...)`.
61
+ - Use `pattern_text()` for `pattern` values (`PatternSpec` is part of API v1).
62
+ - Use `type_spec()` / `TypeSpec` when implementing `type_check` translators.
63
+ - Run `sqlrules.conformance.run_basic_conformance(plugin)` for API shape;
64
+ add golden SQL asserts for dialect correctness.
65
+ - Official dialect packages live under `packages/`. They pin
66
+ `sqlrules>=1,<2` and must share the same release tag version as core.
67
+ - Develop from the monorepo with `make install`; see each package README for
68
+ operators, and [PLUGIN_SYSTEM](https://sqlrules.readthedocs.io/en/latest/PLUGIN_SYSTEM.html)
69
+ for the full contract.
70
+
71
+ ## Maintainers
72
+
73
+ Release process (CHANGELOG cut, Trusted Publishing, tags, lockstep bumps):
74
+ see [RELEASING.md](https://github.com/eddiethedean/sqlrules/blob/main/RELEASING.md).
@@ -0,0 +1,358 @@
1
+ Metadata-Version: 2.4
2
+ Name: sqlrules
3
+ Version: 1.0.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://sqlrules.readthedocs.io
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 :: 5 - Production/Stable
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<1,>=0.6
29
+ Requires-Dist: pydantic<3,>=2.0
30
+ Requires-Dist: sqlalchemy<3,>=2.0
31
+ Provides-Extra: dev
32
+ Requires-Dist: build>=1.2; extra == 'dev'
33
+ Requires-Dist: mypy>=1.10; extra == 'dev'
34
+ Requires-Dist: pre-commit>=3.7; extra == 'dev'
35
+ Requires-Dist: pytest-cov>=5.0; extra == 'dev'
36
+ Requires-Dist: pytest>=8.0; extra == 'dev'
37
+ Requires-Dist: ruff>=0.5; extra == 'dev'
38
+ Requires-Dist: twine>=5.0; extra == 'dev'
39
+ Provides-Extra: dialects
40
+ Requires-Dist: sqlrules-mssql<2,>=1; extra == 'dialects'
41
+ Requires-Dist: sqlrules-mysql<2,>=1; extra == 'dialects'
42
+ Requires-Dist: sqlrules-postgresql<2,>=1; extra == 'dialects'
43
+ Requires-Dist: sqlrules-sqlite<2,>=1; extra == 'dialects'
44
+ Provides-Extra: docs
45
+ Requires-Dist: furo>=2024.8.6; extra == 'docs'
46
+ Requires-Dist: linkify-it-py>=2.0; extra == 'docs'
47
+ Requires-Dist: myst-parser<5,>=4.0; extra == 'docs'
48
+ Requires-Dist: sphinx-copybutton>=0.5.2; extra == 'docs'
49
+ Requires-Dist: sphinx-design<1,>=0.5; extra == 'docs'
50
+ Requires-Dist: sphinx<9,>=8.0; extra == 'docs'
51
+ Provides-Extra: mssql
52
+ Requires-Dist: sqlrules-mssql<2,>=1; extra == 'mssql'
53
+ Provides-Extra: mysql
54
+ Requires-Dist: sqlrules-mysql<2,>=1; extra == 'mysql'
55
+ Provides-Extra: postgresql
56
+ Requires-Dist: sqlrules-postgresql<2,>=1; extra == 'postgresql'
57
+ Provides-Extra: sqlite
58
+ Requires-Dist: sqlrules-sqlite<2,>=1; extra == 'sqlite'
59
+ Description-Content-Type: text/markdown
60
+
61
+ # SQLRules
62
+
63
+ [![CI](https://github.com/eddiethedean/sqlrules/actions/workflows/ci.yml/badge.svg)](https://github.com/eddiethedean/sqlrules/actions/workflows/ci.yml)
64
+ [![PyPI](https://img.shields.io/pypi/v/sqlrules.svg)](https://pypi.org/project/sqlrules/)
65
+ [![Documentation](https://readthedocs.org/projects/sqlrules/badge/?version=latest)](https://sqlrules.readthedocs.io/en/latest/)
66
+ [![License](https://img.shields.io/pypi/l/sqlrules.svg)](https://github.com/eddiethedean/sqlrules/blob/main/LICENSE)
67
+
68
+ **Compile Pydantic Field constraint metadata into SQLAlchemy WHERE expressions.**
69
+
70
+ SQLRules reads constraints declared on a model (`Field(ge=18)`, `min_length`,
71
+ `Literal`, …) and turns them into SQLAlchemy boolean expressions. It depends on
72
+ Pydantic v2 and SQLAlchemy 2.x, performs **no database I/O**, and needs a
73
+ dialect plugin only for non-portable operators (regex, JSON, arrays, …).
74
+
75
+ ```text
76
+ SQLRules does THIS (constraint metadata → expressions):
77
+ Field(ge=18) → column >= 18
78
+
79
+ It does NOT do this (instance values → predicates):
80
+ UserFilter(age=25) → column == 25 # not what sqlrules.compile does
81
+ ```
82
+
83
+ Not an ORM, validator, or query builder: **constraint metadata → expressions**,
84
+ nothing else.
85
+
86
+ **In 30 seconds:**
87
+
88
+ ```bash
89
+ pip install "sqlrules>=1,<2"
90
+ ```
91
+
92
+ ```python
93
+ from typing import Annotated
94
+
95
+ from pydantic import BaseModel, Field
96
+ from sqlalchemy import Column, Integer, MetaData, String, Table
97
+
98
+ import sqlrules
99
+
100
+ users = Table(
101
+ "users",
102
+ MetaData(),
103
+ Column("age", Integer),
104
+ Column("name", String),
105
+ )
106
+
107
+ class UserFilter(BaseModel):
108
+ age: Annotated[int, Field(ge=18, le=65)]
109
+ name: Annotated[str, Field(min_length=2)]
110
+
111
+ rules = sqlrules.compile(UserFilter, users)
112
+ # {
113
+ # "age": [users.c.age >= 18, users.c.age <= 65],
114
+ # "name": [length(users.c.name) >= 2],
115
+ # }
116
+
117
+ stmt = users.select().where(*sqlrules.where(rules))
118
+ ```
119
+
120
+ > **`pattern` needs a plugin.** Core compiles comparisons, lengths, `Literal`,
121
+ > and `Enum`. Regex / JSON / arrays require a dialect package (see below).
122
+ > Prefer static patterns; untrusted regex can be expensive (see
123
+ > [SECURITY](https://sqlrules.readthedocs.io/en/latest/SECURITY.html)).
124
+
125
+ Full walkthrough: [Getting started](https://sqlrules.readthedocs.io/en/latest/guides/getting-started.html) · Runnable scripts: [`examples/`](examples/).
126
+
127
+ | | |
128
+ |---|---|
129
+ | **Latest** | [sqlrules on PyPI](https://pypi.org/project/sqlrules/) · [Changelog](https://sqlrules.readthedocs.io/en/latest/project/changelog.html) |
130
+ | **Docs** | [sqlrules.readthedocs.io](https://sqlrules.readthedocs.io/en/latest/) |
131
+ | **Python** | 3.10+ (Pydantic v2, SQLAlchemy 2.x) |
132
+
133
+ ---
134
+
135
+ ## Choose your path
136
+
137
+ | Path | Start here |
138
+ |---|---|
139
+ | **Not sure?** | [Start here](https://sqlrules.readthedocs.io/en/latest/guides/start-here.html) |
140
+ | **Compile constraints** | [Getting started](https://sqlrules.readthedocs.io/en/latest/guides/getting-started.html) |
141
+ | **Dialect plugins** | [Plugin system](https://sqlrules.readthedocs.io/en/latest/PLUGIN_SYSTEM.html) |
142
+ | **Evaluate fit** | [Design philosophy](https://sqlrules.readthedocs.io/en/latest/guides/design-philosophy.html) |
143
+ | **Contribute** | [Contributing](https://sqlrules.readthedocs.io/en/latest/project/contributing.html) |
144
+
145
+ ---
146
+
147
+ ## Install
148
+
149
+ **Requires** Python 3.10+, Pydantic v2, and SQLAlchemy 2.x (pulled in
150
+ transitively).
151
+
152
+ ### From PyPI (1.0+)
153
+
154
+ ```bash
155
+ pip install "sqlrules>=1,<2"
156
+ # or: uv add "sqlrules>=1,<2"
157
+ ```
158
+
159
+ Confirm the installed version is **1.0.0 or newer** (`pip show sqlrules`).
160
+ If PyPI still serves an older release, or dialect packages are missing, use
161
+ **from source** below.
162
+
163
+ Optional dialect plugins (same major line as core):
164
+
165
+ ```bash
166
+ pip install "sqlrules-postgresql>=1,<2" # ~ / ~*, JSONB, ARRAY, range
167
+ pip install "sqlrules-sqlite>=1,<2" # REGEXP helper + JSON
168
+ pip install "sqlrules-mysql>=1,<2" # REGEXP, JSON, full-text
169
+ pip install "sqlrules-mssql>=1,<2" # JSON + LEN string ops
170
+ ```
171
+
172
+ Extras are equivalent shortcuts (pull the matching plugin package):
173
+
174
+ ```bash
175
+ pip install "sqlrules[postgresql]"
176
+ pip install "sqlrules[dialects]" # all four
177
+ ```
178
+
179
+ SQLite `pattern` emits `REGEXP` — call `sqlrules_sqlite.register_regexp(connection)`
180
+ on each connection before executing queries.
181
+
182
+ ### From source (repo / pre-PyPI)
183
+
184
+ ```bash
185
+ git clone https://github.com/eddiethedean/sqlrules.git
186
+ cd sqlrules
187
+ python -m venv .venv && source .venv/bin/activate
188
+ make install # editable core + all four dialect plugins
189
+ ```
190
+
191
+ Or install built wheels from a checkout that already ran `make dist`:
192
+
193
+ ```bash
194
+ pip install dist/sqlrules-*.whl dist-plugins/sqlrules_*.whl
195
+ ```
196
+
197
+ **End users** should prefer PyPI once 1.0+ is published. You do not need to
198
+ clone this repo or install from `packages/` for normal application use.
199
+
200
+ ### Plugin example
201
+
202
+ ```python
203
+ from typing import Annotated, Any
204
+
205
+ from pydantic import BaseModel, Field
206
+ from sqlalchemy import Column, MetaData, String, Table
207
+ from sqlalchemy.dialects.postgresql import JSONB
208
+
209
+ import sqlrules
210
+ from sqlrules import Compiler, JsonContains
211
+ from sqlrules_postgresql import PostgresPlugin
212
+
213
+ table = Table(
214
+ "rows",
215
+ MetaData(),
216
+ Column("name", String),
217
+ Column("meta", JSONB),
218
+ )
219
+
220
+ class RowFilter(BaseModel):
221
+ name: Annotated[str, Field(pattern=r"^A")]
222
+ meta: Annotated[dict[str, Any], JsonContains({"active": True})]
223
+
224
+ # dialect= is a hint for custom translators only — it does not load plugins.
225
+ compiler = Compiler(plugins=[PostgresPlugin()], dialect="postgresql")
226
+ rules = compiler.compile(RowFilter, table)
227
+ stmt = table.select().where(*sqlrules.where(rules))
228
+ ```
229
+
230
+ See [`examples/postgresql_pattern.py`](examples/postgresql_pattern.py).
231
+
232
+ ### Common failures
233
+
234
+ | Symptom | Fix |
235
+ |---|---|
236
+ | `UnsupportedConstraintError` on `pattern` | Install a dialect plugin and pass it to `Compiler(plugins=[...])` |
237
+ | `NameError: sqlrules` after `from sqlrules import Compiler` | Also `import sqlrules` (or import `where`) |
238
+ | `pip` installs &lt; 1.0 / dialect package 404 | Install [from source](#from-source-repo--pre-pypi) until PyPI has 1.0+ |
239
+ | SQLite `REGEXP` errors at execute time | Call `register_regexp(connection)` |
240
+
241
+ More: [Troubleshooting](https://sqlrules.readthedocs.io/en/latest/guides/troubleshooting.html).
242
+
243
+ ## Supported constraints (1.0)
244
+
245
+ | Constraint | SQLAlchemy expression |
246
+ |---|---|
247
+ | `gt` / `ge` / `lt` / `le` | `column > / >= / < / <= value` |
248
+ | `multiple_of` | `column % value == 0` |
249
+ | `min_length` / `max_length` | `func.length(column) >= / <= value` |
250
+ | `Literal[...]` | `column.in_(...)` |
251
+ | `Enum` | `column.in_(...)` |
252
+
253
+ `pattern` is extracted into IR (`PatternSpec`) but has **no portable core
254
+ translator**. Install a dialect plugin or register a custom translator.
255
+
256
+ With `emit_type_checks=True`, supported scalar annotations also emit
257
+ `type_check` (`TypeSpec`) IR — likewise plugin-translated only.
258
+
259
+ Dialect markers (`JsonContains`, `ArrayContains`, `RangeContains`,
260
+ `FullTextMatch`, …) are re-exported from `sqlrules` (and live in
261
+ `sqlrules.markers`); they require a dialect plugin.
262
+
263
+ Unsupported constraints raise `UnsupportedConstraintError` by default.
264
+ Use `on_unsupported="warn"` or `"ignore"` for unknown **operators**.
265
+ Unconstrained fields with **supported** types are omitted from the rules
266
+ dict. Fields with **unsupported** type annotations always raise — even if
267
+ unconstrained.
268
+
269
+ ## When *not* to use SQLRules
270
+
271
+ Skip SQLRules when:
272
+
273
+ - You need **request/instance values** as WHERE predicates
274
+ (`UserFilter(age=25)` → `age = 25`). That is a query/filter library, not
275
+ this compiler.
276
+ - You have a few static expressions and will never share constraint metadata
277
+ with a Pydantic model — write SQLAlchemy clauses directly.
278
+ - You need **portable regex** with core alone — `pattern` requires a dialect
279
+ plugin or custom translator.
280
+ - You expect `dialect="postgresql"` to **load plugins** — it is a hint only;
281
+ pass `plugins=[...]` explicitly.
282
+ - You want a general-purpose **query builder**, ORM, or SQL string generator.
283
+
284
+ SQLRules pays off when the Pydantic model *is* the shared source of truth for
285
+ constraint metadata across many fields or dialects.
286
+
287
+ ## Public API
288
+
289
+ ```python
290
+ sqlrules.compile(model, table, *, column_map=None, on_unsupported="raise", cache=True, emit_type_checks=False)
291
+ sqlrules.where(rules) # prefer this to flatten expressions
292
+ sqlrules.flatten(rules) # alias of where()
293
+ sqlrules.clear_model_cache() # drop process-wide Phase-1 IR cache
294
+
295
+ compiler = sqlrules.Compiler(
296
+ plugins=[...], # optional SQLRulesPlugin instances
297
+ on_conflict="raise", # raise | replace | ignore
298
+ dialect=None, # hint only — does not load plugins
299
+ on_unsupported="raise",
300
+ cache=True,
301
+ emit_type_checks=False, # opt-in type_check IR (needs plugin translator)
302
+ )
303
+ ```
304
+
305
+ ## Non-goals
306
+
307
+ SQLRules is not an ORM, validator, query builder, SQL string generator,
308
+ migration tool, or database client. It only compiles supported Pydantic
309
+ constraints into SQLAlchemy expressions. See
310
+ [design philosophy](https://sqlrules.readthedocs.io/en/latest/guides/design-philosophy.html)
311
+ and [non-goals](https://sqlrules.readthedocs.io/en/latest/NON_GOALS.html).
312
+
313
+ ## Documentation
314
+
315
+ Full site: **[sqlrules.readthedocs.io](https://sqlrules.readthedocs.io/en/latest/)**
316
+
317
+ | Topic | Link |
318
+ |---|---|
319
+ | Getting started | [Guide](https://sqlrules.readthedocs.io/en/latest/guides/getting-started.html) |
320
+ | How-to guides | [ORM binding](https://sqlrules.readthedocs.io/en/latest/guides/orm-column-map.html) · [Markers](https://sqlrules.readthedocs.io/en/latest/guides/markers.html) |
321
+ | Examples | [`examples/`](examples/) |
322
+ | Spec & constraints | [SPEC](https://sqlrules.readthedocs.io/en/latest/SPEC.html) · [CONSTRAINTS](https://sqlrules.readthedocs.io/en/latest/CONSTRAINTS.html) |
323
+ | Plugins | [Plugin system](https://sqlrules.readthedocs.io/en/latest/PLUGIN_SYSTEM.html) |
324
+ | API reference | [Reference hub](https://sqlrules.readthedocs.io/en/latest/reference/index.html) |
325
+ | FAQ | [FAQ](https://sqlrules.readthedocs.io/en/latest/guides/faq.html) |
326
+ | Support | [Support & compatibility](https://sqlrules.readthedocs.io/en/latest/project/support.html) |
327
+ | Roadmap | [Roadmap](https://sqlrules.readthedocs.io/en/latest/project/roadmap.html) |
328
+ | Changelog | [Changelog](https://sqlrules.readthedocs.io/en/latest/project/changelog.html) |
329
+
330
+ ```bash
331
+ pip install -e ".[docs]"
332
+ make docs
333
+ ```
334
+
335
+ ## Repo map
336
+
337
+ | Path | Who cares |
338
+ |---|---|
339
+ | PyPI `sqlrules` / `sqlrules-*` | **Application users** — install these |
340
+ | [`examples/`](examples/) | Copy-paste runnable scripts |
341
+ | [`docs/`](docs/) | Spec, guides, architecture (also on Read the Docs) |
342
+ | [`packages/`](packages/) | **Contributors** — official dialect plugin sources |
343
+ | [`src/sqlrules/`](src/sqlrules/) | Core library source |
344
+ | [`benchmarks/`](benchmarks/) | Optional local compile benchmarks |
345
+
346
+ ## Development (contributors)
347
+
348
+ ```bash
349
+ make install
350
+ make check # lint, types, tests, docs (matches most of CI)
351
+ make dist # packaging smoke — required before release / to match full CI
352
+ ```
353
+
354
+ See [CONTRIBUTING.md](CONTRIBUTING.md). Maintainers: [RELEASING.md](RELEASING.md).
355
+
356
+ ## License
357
+
358
+ MIT