sqlrules 0.3.0__tar.gz → 0.4.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 (89) hide show
  1. {sqlrules-0.3.0 → sqlrules-0.4.0}/CHANGELOG.md +25 -0
  2. {sqlrules-0.3.0 → sqlrules-0.4.0}/CONTRIBUTING.md +16 -10
  3. {sqlrules-0.3.0 → sqlrules-0.4.0}/PKG-INFO +23 -11
  4. {sqlrules-0.3.0 → sqlrules-0.4.0}/README.md +22 -10
  5. {sqlrules-0.3.0 → sqlrules-0.4.0}/docs/API.md +8 -4
  6. sqlrules-0.4.0/docs/CONSTRAINTS.md +55 -0
  7. {sqlrules-0.3.0 → sqlrules-0.4.0}/docs/DIALECT_SUPPORT.md +41 -57
  8. {sqlrules-0.3.0 → sqlrules-0.4.0}/docs/MILESTONES.md +10 -4
  9. {sqlrules-0.3.0 → sqlrules-0.4.0}/docs/PLUGIN_SYSTEM.md +21 -12
  10. {sqlrules-0.3.0 → sqlrules-0.4.0}/docs/ROADMAP.md +2 -1
  11. {sqlrules-0.3.0 → sqlrules-0.4.0}/docs/SPEC.md +9 -6
  12. {sqlrules-0.3.0 → sqlrules-0.4.0}/docs/TRANSLATORS.md +9 -4
  13. {sqlrules-0.3.0 → sqlrules-0.4.0}/docs/TYPE_SUPPORT.md +9 -7
  14. {sqlrules-0.3.0 → sqlrules-0.4.0}/docs/index.md +1 -1
  15. sqlrules-0.4.0/packages/sqlrules-mssql/README.md +37 -0
  16. sqlrules-0.4.0/packages/sqlrules-mssql/pyproject.toml +28 -0
  17. sqlrules-0.4.0/packages/sqlrules-mssql/src/sqlrules_mssql/__init__.py +52 -0
  18. sqlrules-0.4.0/packages/sqlrules-mssql/src/sqlrules_mssql/json.py +70 -0
  19. sqlrules-0.4.0/packages/sqlrules-mssql/src/sqlrules_mssql/length.py +26 -0
  20. sqlrules-0.4.0/packages/sqlrules-mssql/tests/test_mssql_plugin.py +52 -0
  21. sqlrules-0.4.0/packages/sqlrules-mysql/README.md +36 -0
  22. sqlrules-0.4.0/packages/sqlrules-mysql/pyproject.toml +28 -0
  23. sqlrules-0.4.0/packages/sqlrules-mysql/src/sqlrules_mysql/__init__.py +39 -0
  24. sqlrules-0.4.0/packages/sqlrules-mysql/src/sqlrules_mysql/fulltext.py +20 -0
  25. sqlrules-0.4.0/packages/sqlrules-mysql/src/sqlrules_mysql/json.py +35 -0
  26. sqlrules-0.4.0/packages/sqlrules-mysql/src/sqlrules_mysql/pattern.py +22 -0
  27. sqlrules-0.4.0/packages/sqlrules-mysql/tests/test_mysql_plugin.py +45 -0
  28. sqlrules-0.4.0/packages/sqlrules-postgresql/README.md +53 -0
  29. {sqlrules-0.3.0 → sqlrules-0.4.0}/packages/sqlrules-postgresql/pyproject.toml +3 -3
  30. sqlrules-0.4.0/packages/sqlrules-postgresql/src/sqlrules_postgresql/__init__.py +46 -0
  31. sqlrules-0.4.0/packages/sqlrules-postgresql/src/sqlrules_postgresql/array.py +25 -0
  32. sqlrules-0.4.0/packages/sqlrules-postgresql/src/sqlrules_postgresql/jsonb.py +25 -0
  33. {sqlrules-0.3.0 → sqlrules-0.4.0}/packages/sqlrules-postgresql/src/sqlrules_postgresql/pattern.py +5 -2
  34. sqlrules-0.4.0/packages/sqlrules-postgresql/src/sqlrules_postgresql/range.py +25 -0
  35. sqlrules-0.4.0/packages/sqlrules-postgresql/tests/test_postgres_plugin.py +88 -0
  36. sqlrules-0.4.0/packages/sqlrules-sqlite/README.md +53 -0
  37. {sqlrules-0.3.0 → sqlrules-0.4.0}/packages/sqlrules-sqlite/pyproject.toml +3 -3
  38. {sqlrules-0.3.0 → sqlrules-0.4.0}/packages/sqlrules-sqlite/src/sqlrules_sqlite/__init__.py +19 -4
  39. sqlrules-0.4.0/packages/sqlrules-sqlite/src/sqlrules_sqlite/json.py +58 -0
  40. {sqlrules-0.3.0 → sqlrules-0.4.0}/packages/sqlrules-sqlite/src/sqlrules_sqlite/pattern.py +7 -1
  41. sqlrules-0.4.0/packages/sqlrules-sqlite/src/sqlrules_sqlite/regexp.py +30 -0
  42. sqlrules-0.4.0/packages/sqlrules-sqlite/tests/test_sqlite_plugin.py +72 -0
  43. {sqlrules-0.3.0 → sqlrules-0.4.0}/pyproject.toml +1 -1
  44. {sqlrules-0.3.0 → sqlrules-0.4.0}/src/sqlrules/__init__.py +21 -1
  45. {sqlrules-0.3.0 → sqlrules-0.4.0}/src/sqlrules/conformance.py +19 -5
  46. {sqlrules-0.3.0 → sqlrules-0.4.0}/src/sqlrules/constraints.py +61 -11
  47. {sqlrules-0.3.0 → sqlrules-0.4.0}/src/sqlrules/ir.py +8 -0
  48. sqlrules-0.4.0/src/sqlrules/markers.py +86 -0
  49. {sqlrules-0.3.0 → sqlrules-0.4.0}/tests/test_correctness.py +12 -3
  50. {sqlrules-0.3.0 → sqlrules-0.4.0}/tests/test_errors.py +1 -1
  51. {sqlrules-0.3.0 → sqlrules-0.4.0}/tests/test_plugins.py +7 -6
  52. {sqlrules-0.3.0 → sqlrules-0.4.0}/tests/test_v01_features.py +2 -2
  53. {sqlrules-0.3.0 → sqlrules-0.4.0}/tests/test_v02_features.py +24 -6
  54. sqlrules-0.4.0/tests/test_v04_markers.py +101 -0
  55. sqlrules-0.3.0/docs/CONSTRAINTS.md +0 -42
  56. sqlrules-0.3.0/packages/sqlrules-postgresql/README.md +0 -16
  57. sqlrules-0.3.0/packages/sqlrules-postgresql/src/sqlrules_postgresql/__init__.py +0 -28
  58. sqlrules-0.3.0/packages/sqlrules-postgresql/tests/test_postgres_plugin.py +0 -33
  59. sqlrules-0.3.0/packages/sqlrules-sqlite/README.md +0 -19
  60. sqlrules-0.3.0/packages/sqlrules-sqlite/tests/test_sqlite_plugin.py +0 -33
  61. {sqlrules-0.3.0 → sqlrules-0.4.0}/.gitignore +0 -0
  62. {sqlrules-0.3.0 → sqlrules-0.4.0}/LICENSE +0 -0
  63. {sqlrules-0.3.0 → sqlrules-0.4.0}/benchmarks/__init__.py +0 -0
  64. {sqlrules-0.3.0 → sqlrules-0.4.0}/benchmarks/bench_compile.py +0 -0
  65. {sqlrules-0.3.0 → sqlrules-0.4.0}/docs/ARCHITECTURE.md +0 -0
  66. {sqlrules-0.3.0 → sqlrules-0.4.0}/docs/COMPILER.md +0 -0
  67. {sqlrules-0.3.0 → sqlrules-0.4.0}/docs/CONTRIBUTING.md +0 -0
  68. {sqlrules-0.3.0 → sqlrules-0.4.0}/docs/DESIGN_DECISIONS.md +0 -0
  69. {sqlrules-0.3.0 → sqlrules-0.4.0}/docs/ERRORS.md +0 -0
  70. {sqlrules-0.3.0 → sqlrules-0.4.0}/docs/INTERNAL_API.md +0 -0
  71. {sqlrules-0.3.0 → sqlrules-0.4.0}/docs/NON_GOALS.md +0 -0
  72. {sqlrules-0.3.0 → sqlrules-0.4.0}/docs/PERFORMANCE.md +0 -0
  73. {sqlrules-0.3.0 → sqlrules-0.4.0}/docs/PHILOSOPHY.md +0 -0
  74. {sqlrules-0.3.0 → sqlrules-0.4.0}/docs/TESTING.md +0 -0
  75. {sqlrules-0.3.0 → sqlrules-0.4.0}/docs/VISION.md +0 -0
  76. {sqlrules-0.3.0 → sqlrules-0.4.0}/src/sqlrules/cache.py +0 -0
  77. {sqlrules-0.3.0 → sqlrules-0.4.0}/src/sqlrules/columns.py +0 -0
  78. {sqlrules-0.3.0 → sqlrules-0.4.0}/src/sqlrules/compiler.py +0 -0
  79. {sqlrules-0.3.0 → sqlrules-0.4.0}/src/sqlrules/errors.py +0 -0
  80. {sqlrules-0.3.0 → sqlrules-0.4.0}/src/sqlrules/inspectors.py +0 -0
  81. {sqlrules-0.3.0 → sqlrules-0.4.0}/src/sqlrules/plugins.py +0 -0
  82. {sqlrules-0.3.0 → sqlrules-0.4.0}/src/sqlrules/py.typed +0 -0
  83. {sqlrules-0.3.0 → sqlrules-0.4.0}/src/sqlrules/translators.py +0 -0
  84. {sqlrules-0.3.0 → sqlrules-0.4.0}/tests/conftest.py +0 -0
  85. {sqlrules-0.3.0 → sqlrules-0.4.0}/tests/test_coverage_edges.py +0 -0
  86. {sqlrules-0.3.0 → sqlrules-0.4.0}/tests/test_helpers.py +0 -0
  87. {sqlrules-0.3.0 → sqlrules-0.4.0}/tests/test_literal_enum.py +0 -0
  88. {sqlrules-0.3.0 → sqlrules-0.4.0}/tests/test_numeric_constraints.py +0 -0
  89. {sqlrules-0.3.0 → sqlrules-0.4.0}/tests/test_string_constraints.py +0 -0
@@ -5,6 +5,30 @@ 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
+ ## [0.4.0] - 2026-07-10
9
+
10
+ ### Added
11
+
12
+ - `ConstraintMarker` protocol and shared markers in `sqlrules.markers`:
13
+ `JsonContains`, `JsonHasKey`, `ArrayContains`, `ArrayOverlap`,
14
+ `RangeContains`, `RangeOverlap`, `FullTextMatch`
15
+ - `PatternSpec` IR value for `pattern` (preserves `ignore_case` from
16
+ `re.Pattern` flags); `pattern_text()` helper for plugins
17
+ - `list` / `dict` annotations for marker-driven fields (portable
18
+ constraints on containers still raise)
19
+ - Expanded dialect plugins:
20
+ - `sqlrules-postgresql` — `~` / `~*`, JSONB, ARRAY, range operators
21
+ - `sqlrules-sqlite` — `register_regexp()`, flag-aware REGEXP, JSON helpers
22
+ - `sqlrules-mysql` — REGEXP, JSON, `fulltext_match`
23
+ - `sqlrules-mssql` — JSON helpers, `LEN` overrides for length constraints
24
+ - Conformance helpers accept optional `model` / `table` / `field` for
25
+ non-`pattern` operators
26
+
27
+ ### Changed
28
+
29
+ - Package version bumped to 0.4.0
30
+ - Official plugin packages depend on `sqlrules>=0.4,<0.5`
31
+
8
32
  ## [0.3.0] - 2026-07-10
9
33
 
10
34
  ### Added
@@ -108,6 +132,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
108
132
  - Docs clarify that `on_unsupported` does not soften unsupported types;
109
133
  plugin / two-phase compile designs are marked as future
110
134
 
135
+ [0.4.0]: https://github.com/eddiethedean/sqlrules/releases/tag/v0.4.0
111
136
  [0.3.0]: https://github.com/eddiethedean/sqlrules/releases/tag/v0.3.0
112
137
  [0.2.0]: https://github.com/eddiethedean/sqlrules/releases/tag/v0.2.0
113
138
  [0.1.0]: https://github.com/eddiethedean/sqlrules/releases/tag/v0.1.0
@@ -16,7 +16,8 @@ Thanks for helping improve SQLRules.
16
16
  python -m venv .venv
17
17
  source .venv/bin/activate
18
18
  pip install -e ".[dev]"
19
- pip install -e packages/sqlrules-postgresql -e packages/sqlrules-sqlite
19
+ pip install -e packages/sqlrules-postgresql -e packages/sqlrules-sqlite \
20
+ -e packages/sqlrules-mysql -e packages/sqlrules-mssql
20
21
  pre-commit install
21
22
  ```
22
23
 
@@ -26,10 +27,13 @@ pre-commit install
26
27
  ruff check .
27
28
  ruff format --check .
28
29
  mypy src/sqlrules
29
- pytest tests packages/sqlrules-postgresql/tests packages/sqlrules-sqlite/tests
30
+ pytest tests packages/sqlrules-postgresql/tests packages/sqlrules-sqlite/tests \
31
+ packages/sqlrules-mysql/tests packages/sqlrules-mssql/tests
30
32
  python -m build && twine check dist/*
31
33
  python -m build packages/sqlrules-postgresql --outdir dist-plugins
32
34
  python -m build packages/sqlrules-sqlite --outdir dist-plugins
35
+ python -m build packages/sqlrules-mysql --outdir dist-plugins
36
+ python -m build packages/sqlrules-mssql --outdir dist-plugins
33
37
  twine check dist-plugins/*
34
38
  ```
35
39
 
@@ -42,7 +46,7 @@ wheel imports cleanly.
42
46
  - Prefer `register_constraint(..., on_conflict=...)`.
43
47
  - Run `sqlrules.conformance.run_basic_conformance(plugin)`.
44
48
  - Official dialect packages live under `packages/` and should track the
45
- plugin API major (`sqlrules>=0.3,<0.4` while `PLUGIN_API_VERSION == "1"`).
49
+ core minor (`sqlrules>=0.4,<0.5` while `PLUGIN_API_VERSION == "1"`).
46
50
 
47
51
  ## Pull requests
48
52
 
@@ -58,11 +62,11 @@ Releases are published to PyPI by pushing a version tag. Before tagging:
58
62
  2. Run the full check suite (`ruff`, `mypy`, `pytest`).
59
63
  3. Ensure CI is green on `main`.
60
64
 
61
- Then create and push the tag (example for 0.3.0):
65
+ Then create and push the tag (example for 0.4.0):
62
66
 
63
67
  ```bash
64
- git tag -a v0.3.0 -m "sqlrules 0.3.0"
65
- git push origin v0.3.0
68
+ git tag -a v0.4.0 -m "sqlrules 0.4.0"
69
+ git push origin v0.4.0
66
70
  ```
67
71
 
68
72
  The [release workflow](.github/workflows/release.yml) runs CI, verifies the
@@ -71,10 +75,12 @@ publishes **core** `sqlrules` with `PYPI_API_TOKEN`.
71
75
 
72
76
  Dialect plugin packages under `packages/` are versioned independently and
73
77
  are **not** published by the core release workflow. Publish them separately
74
- after core `0.3.0` is on PyPI (they depend on `sqlrules>=0.3,<0.4`):
78
+ after core `0.4.0` is on PyPI (they depend on `sqlrules>=0.4,<0.5`):
75
79
 
76
80
  ```bash
77
- python -m build packages/sqlrules-postgresql
78
- python -m build packages/sqlrules-sqlite
79
- twine upload dist-plugins/* # after building with --outdir dist-plugins
81
+ python -m build packages/sqlrules-postgresql --outdir dist-plugins
82
+ python -m build packages/sqlrules-sqlite --outdir dist-plugins
83
+ python -m build packages/sqlrules-mysql --outdir dist-plugins
84
+ python -m build packages/sqlrules-mssql --outdir dist-plugins
85
+ twine upload dist-plugins/*
80
86
  ```
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sqlrules
3
- Version: 0.3.0
3
+ Version: 0.4.0
4
4
  Summary: Compile constrained Pydantic models into SQLAlchemy WHERE-rule dictionaries.
5
5
  Project-URL: Homepage, https://github.com/eddiethedean/sqlrules
6
6
  Project-URL: Documentation, https://github.com/eddiethedean/sqlrules#readme
@@ -84,19 +84,27 @@ Requires Python 3.10+, Pydantic v2, and SQLAlchemy 2.x.
84
84
  Optional dialect plugins:
85
85
 
86
86
  ```bash
87
- pip install sqlrules-postgresql # pattern PostgreSQL ~
88
- pip install sqlrules-sqlite # pattern SQLite REGEXP
87
+ pip install sqlrules-postgresql # ~ / ~*, JSONB, ARRAY, range
88
+ pip install sqlrules-sqlite # REGEXP helper + JSON
89
+ pip install sqlrules-mysql # REGEXP, JSON, full-text
90
+ pip install sqlrules-mssql # JSON + LEN string ops
89
91
  ```
90
92
 
91
93
  ```python
92
- from sqlrules import Compiler
94
+ from typing import Annotated, Any
95
+ from pydantic import BaseModel, Field
96
+ from sqlrules import Compiler, JsonContains
93
97
  from sqlrules_postgresql import PostgresPlugin
94
98
 
99
+ class RowFilter(BaseModel):
100
+ name: Annotated[str, Field(pattern=r"^A")]
101
+ meta: Annotated[dict[str, Any], JsonContains({"active": True})]
102
+
95
103
  compiler = Compiler(plugins=[PostgresPlugin()], dialect="postgresql")
96
- rules = compiler.compile(UserFilter, users)
104
+ rules = compiler.compile(RowFilter, table)
97
105
  ```
98
106
 
99
- ## Supported constraints (0.3)
107
+ ## Supported constraints (0.4)
100
108
 
101
109
  | Constraint | SQLAlchemy expression |
102
110
  |---|---|
@@ -106,9 +114,11 @@ rules = compiler.compile(UserFilter, users)
106
114
  | `Literal[...]` | `column.in_(...)` |
107
115
  | `Enum` | `column.in_(...)` |
108
116
 
109
- `pattern` is extracted into IR but has no portable core translator.
110
- Use a custom registry translator or a dialect plugin
111
- (`sqlrules-postgresql`, `sqlrules-sqlite`).
117
+ `pattern` is extracted into IR (`PatternSpec`) but has no portable core
118
+ translator. Use a dialect plugin or a custom registry translator.
119
+
120
+ Dialect markers (`JsonContains`, `ArrayContains`, `RangeContains`,
121
+ `FullTextMatch`, …) live in `sqlrules.markers` and require a dialect plugin.
112
122
 
113
123
  Unsupported constraints raise `UnsupportedConstraintError` by default.
114
124
  Use `on_unsupported="warn"` or `"ignore"` to change that policy for unknown
@@ -147,8 +157,10 @@ and [roadmap](docs/ROADMAP.md).
147
157
 
148
158
  ```bash
149
159
  pip install -e ".[dev]"
150
- pip install -e packages/sqlrules-postgresql -e packages/sqlrules-sqlite
151
- pytest tests packages/sqlrules-postgresql/tests packages/sqlrules-sqlite/tests
160
+ pip install -e packages/sqlrules-postgresql -e packages/sqlrules-sqlite \
161
+ -e packages/sqlrules-mysql -e packages/sqlrules-mssql
162
+ pytest tests packages/sqlrules-postgresql/tests packages/sqlrules-sqlite/tests \
163
+ packages/sqlrules-mysql/tests packages/sqlrules-mssql/tests
152
164
  ruff check .
153
165
  mypy src/sqlrules
154
166
  python -m benchmarks.bench_compile
@@ -44,19 +44,27 @@ Requires Python 3.10+, Pydantic v2, and SQLAlchemy 2.x.
44
44
  Optional dialect plugins:
45
45
 
46
46
  ```bash
47
- pip install sqlrules-postgresql # pattern PostgreSQL ~
48
- pip install sqlrules-sqlite # pattern SQLite REGEXP
47
+ pip install sqlrules-postgresql # ~ / ~*, JSONB, ARRAY, range
48
+ pip install sqlrules-sqlite # REGEXP helper + JSON
49
+ pip install sqlrules-mysql # REGEXP, JSON, full-text
50
+ pip install sqlrules-mssql # JSON + LEN string ops
49
51
  ```
50
52
 
51
53
  ```python
52
- from sqlrules import Compiler
54
+ from typing import Annotated, Any
55
+ from pydantic import BaseModel, Field
56
+ from sqlrules import Compiler, JsonContains
53
57
  from sqlrules_postgresql import PostgresPlugin
54
58
 
59
+ class RowFilter(BaseModel):
60
+ name: Annotated[str, Field(pattern=r"^A")]
61
+ meta: Annotated[dict[str, Any], JsonContains({"active": True})]
62
+
55
63
  compiler = Compiler(plugins=[PostgresPlugin()], dialect="postgresql")
56
- rules = compiler.compile(UserFilter, users)
64
+ rules = compiler.compile(RowFilter, table)
57
65
  ```
58
66
 
59
- ## Supported constraints (0.3)
67
+ ## Supported constraints (0.4)
60
68
 
61
69
  | Constraint | SQLAlchemy expression |
62
70
  |---|---|
@@ -66,9 +74,11 @@ rules = compiler.compile(UserFilter, users)
66
74
  | `Literal[...]` | `column.in_(...)` |
67
75
  | `Enum` | `column.in_(...)` |
68
76
 
69
- `pattern` is extracted into IR but has no portable core translator.
70
- Use a custom registry translator or a dialect plugin
71
- (`sqlrules-postgresql`, `sqlrules-sqlite`).
77
+ `pattern` is extracted into IR (`PatternSpec`) but has no portable core
78
+ translator. Use a dialect plugin or a custom registry translator.
79
+
80
+ Dialect markers (`JsonContains`, `ArrayContains`, `RangeContains`,
81
+ `FullTextMatch`, …) live in `sqlrules.markers` and require a dialect plugin.
72
82
 
73
83
  Unsupported constraints raise `UnsupportedConstraintError` by default.
74
84
  Use `on_unsupported="warn"` or `"ignore"` to change that policy for unknown
@@ -107,8 +117,10 @@ and [roadmap](docs/ROADMAP.md).
107
117
 
108
118
  ```bash
109
119
  pip install -e ".[dev]"
110
- pip install -e packages/sqlrules-postgresql -e packages/sqlrules-sqlite
111
- pytest tests packages/sqlrules-postgresql/tests packages/sqlrules-sqlite/tests
120
+ pip install -e packages/sqlrules-postgresql -e packages/sqlrules-sqlite \
121
+ -e packages/sqlrules-mysql -e packages/sqlrules-mssql
122
+ pytest tests packages/sqlrules-postgresql/tests packages/sqlrules-sqlite/tests \
123
+ packages/sqlrules-mysql/tests packages/sqlrules-mssql/tests
112
124
  ruff check .
113
125
  mypy src/sqlrules
114
126
  python -m benchmarks.bench_compile
@@ -90,6 +90,7 @@ instances.
90
90
 
91
91
  ```python
92
92
  from sqlrules import PLUGIN_API_VERSION, Compiler
93
+ from sqlrules.constraints import pattern_text
93
94
 
94
95
  class MyPlugin:
95
96
  name = "my-plugin"
@@ -98,15 +99,16 @@ class MyPlugin:
98
99
  def register(self, registry):
99
100
  registry.register_constraint(
100
101
  "pattern",
101
- lambda c, col, ctx: col.op("~")(c.value),
102
+ lambda c, col, ctx: col.op("~")(pattern_text(c.value)[0]),
102
103
  on_conflict="replace",
103
104
  )
104
105
 
105
106
  compiler = Compiler(plugins=[MyPlugin()])
106
107
  ```
107
108
 
108
- See [PLUGIN_SYSTEM.md](PLUGIN_SYSTEM.md). Conformance helpers live in
109
- `sqlrules.conformance`.
109
+ Dialect markers (`JsonContains`, `ArrayContains`, …) are extracted into IR
110
+ and translated by official dialect plugins. See [PLUGIN_SYSTEM.md](PLUGIN_SYSTEM.md).
111
+ Conformance helpers live in `sqlrules.conformance`.
110
112
 
111
113
  ## Other exports
112
114
 
@@ -116,7 +118,9 @@ Also exported for advanced use and typing:
116
118
  - `PLUGIN_API_VERSION`, `SQLRulesPlugin`
117
119
  - `SQLRulesWarning`
118
120
  - `CompilationContext`, `Constraint`, `FieldDescriptor`, `FieldIR`, `ModelIR`,
119
- `Diagnostic` (IR helpers)
121
+ `Diagnostic`, `PatternSpec`
122
+ - Markers: `ConstraintMarker`, `JsonContains`, `JsonHasKey`, `ArrayContains`,
123
+ `ArrayOverlap`, `RangeContains`, `RangeOverlap`, `FullTextMatch`
120
124
 
121
125
  `DiagnosticsCollector` and `ModelIRCache` are internal (import from
122
126
  `sqlrules.ir` / `sqlrules.cache` only if you accept instability).
@@ -0,0 +1,55 @@
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
+ | `pattern` | IR (`PatternSpec`); translators via plugins / custom registry |
15
+
16
+ ## Dialect markers (`sqlrules.markers`)
17
+
18
+ | Marker | IR operator | Typical plugin translation |
19
+ |---|---|---|
20
+ | `JsonContains` | `json_contains` | JSONB / JSON containment |
21
+ | `JsonHasKey` | `json_has_key` | JSON key existence |
22
+ | `ArrayContains` | `array_contains` | PostgreSQL array containment |
23
+ | `ArrayOverlap` | `array_overlap` | PostgreSQL array overlap |
24
+ | `RangeContains` | `range_contains` | PostgreSQL range `@>` |
25
+ | `RangeOverlap` | `range_overlap` | PostgreSQL range `&&` |
26
+ | `FullTextMatch` | `fulltext_match` | MySQL `MATCH ... AGAINST` |
27
+
28
+ Accepted input forms for portable constraints include `Field(...)`,
29
+ `annotated_types` primitives, `Interval`, `Len`, `conint`/`constr`, and
30
+ `StringConstraints` (length attributes; `pattern` becomes `PatternSpec` IR).
31
+
32
+ Constraints without a deterministic SQL equivalent are rejected by default.
33
+ See [TYPE_SUPPORT.md](TYPE_SUPPORT.md) and [ERRORS.md](ERRORS.md).
34
+
35
+ To translate `pattern` or markers, use a dialect plugin:
36
+
37
+ ```python
38
+ from sqlrules import Compiler, JsonContains
39
+ from sqlrules_postgresql import PostgresPlugin
40
+
41
+ compiler = Compiler(plugins=[PostgresPlugin()], dialect="postgresql")
42
+ ```
43
+
44
+ ```python
45
+ from sqlrules.constraints import pattern_text
46
+ from sqlrules.translators import default_registry
47
+
48
+ registry = default_registry()
49
+ registry.register_constraint(
50
+ "pattern",
51
+ lambda c, col, ctx: col.op("~")(pattern_text(c.value)[0]),
52
+ on_conflict="replace",
53
+ )
54
+ compiler = sqlrules.Compiler(registry=registry)
55
+ ```
@@ -29,18 +29,18 @@ compiler deterministic.
29
29
 
30
30
  ------------------------------------------------------------------------
31
31
 
32
- # Planned Dialects
32
+ # Dialects
33
33
 
34
34
  Core emits portable SQLAlchemy Core expressions. The table below describes
35
35
  **intended** dialect posture, not a certified multi-backend test matrix.
36
36
 
37
37
  Dialect Status Notes
38
38
  ------------ -------------------- --------------------------------
39
- SQLite Core + plugin `sqlrules-sqlite` adds `pattern` (REGEXP)
40
- PostgreSQL Core + plugin `sqlrules-postgresql` adds `pattern` (`~`)
41
- MySQL Core (planned) Enhanced features via future plugin
42
- MariaDB Core (planned) Follows MySQL where practical
43
- SQL Server Core (planned) Enhanced features via future plugin
39
+ SQLite Core + plugin `sqlrules-sqlite` REGEXP + JSON
40
+ PostgreSQL Core + plugin `sqlrules-postgresql` regex, JSONB, ARRAY, range
41
+ MySQL Core + plugin `sqlrules-mysql` REGEXP, JSON, full-text
42
+ MariaDB Core + plugin Follows MySQL plugin where practical
43
+ SQL Server Core + plugin `sqlrules-mssql` JSON + `LEN`
44
44
  Oracle Planned Core support after 1.0
45
45
 
46
46
  ------------------------------------------------------------------------
@@ -61,20 +61,33 @@ These should compile identically across supported databases:
61
61
 
62
62
  ------------------------------------------------------------------------
63
63
 
64
- # PostgreSQL
64
+ # Shared dialect markers
65
65
 
66
- Package: `sqlrules-postgresql`
66
+ Dialect-oriented operators are expressed with `sqlrules.markers` and
67
+ extracted into IR. Core does not translate them; plugins register
68
+ translators for the stable operator names:
69
+
70
+ - `JsonContains` → `json_contains`
71
+ - `JsonHasKey` → `json_has_key`
72
+ - `ArrayContains` → `array_contains`
73
+ - `ArrayOverlap` → `array_overlap`
74
+ - `RangeContains` → `range_contains`
75
+ - `RangeOverlap` → `range_overlap`
76
+ - `FullTextMatch` → `fulltext_match`
67
77
 
68
- 0.3 enhancement:
78
+ `list` / `dict` field annotations are allowed for marker-driven fields.
79
+ Portable constraints on containers still raise.
80
+
81
+ ------------------------------------------------------------------------
69
82
 
70
- - Native regular expressions via `pattern` → `column ~ value`
83
+ # PostgreSQL
71
84
 
72
- Potential later enhancements (0.4+):
85
+ Package: `sqlrules-postgresql`
73
86
 
74
- - ARRAY operators
75
- - JSONB operators
76
- - Range types
77
- - Full-text search
87
+ - `pattern` → `~` or `~*` (`PatternSpec.ignore_case`)
88
+ - JSONB containment / key checks
89
+ - ARRAY contains / overlap
90
+ - range `@>` / `&&`
78
91
 
79
92
  ------------------------------------------------------------------------
80
93
 
@@ -82,37 +95,29 @@ Potential later enhancements (0.4+):
82
95
 
83
96
  Package: `sqlrules-sqlite`
84
97
 
85
- Goals:
86
-
87
- - Reliable test platform
88
- - Portable numeric comparisons
89
- - Portable string-length operations
90
- - `pattern` via `REGEXP` (application must enable REGEXP on the connection)
91
-
92
- Limitations:
93
-
94
- - REGEXP requires an extension / `create_function`
95
- - Limited advanced JSON functionality
98
+ - `pattern` via `REGEXP` — call `register_regexp(connection)`
99
+ - Case-insensitive patterns use a `(?i)` prefix understood by the helper
100
+ - JSON helpers via JSON1 `json_extract` / `json_type`
96
101
 
97
102
  ------------------------------------------------------------------------
98
103
 
99
104
  # MySQL / MariaDB
100
105
 
101
- Potential enhancements:
106
+ Package: `sqlrules-mysql`
102
107
 
103
- - Full-text search
104
- - JSON operators
105
- - Generated column optimizations
108
+ - `pattern` → `REGEXP`
109
+ - JSON operators (`JSON_CONTAINS`, `JSON_CONTAINS_PATH`)
110
+ - `fulltext_match` `MATCH ... AGAINST` (requires FULLTEXT index)
106
111
 
107
112
  ------------------------------------------------------------------------
108
113
 
109
114
  # SQL Server
110
115
 
111
- Potential enhancements:
116
+ Package: `sqlrules-mssql`
112
117
 
113
- - Specialized string functions
114
- - JSON functions
115
- - Spatial operators
118
+ - `min_length` / `max_length` → `LEN`
119
+ - JSON helpers via `JSON_VALUE` / `JSON_QUERY`
120
+ - `pattern` is not registered (no deterministic portable regex)
116
121
 
117
122
  ------------------------------------------------------------------------
118
123
 
@@ -145,36 +150,16 @@ If no override exists, the portable translator is used.
145
150
 
146
151
  ------------------------------------------------------------------------
147
152
 
148
- # Example
149
-
150
- Portable:
151
-
152
- ``` python
153
- func.length(users.c.name) >= 3
154
- ```
155
-
156
- PostgreSQL plugin:
157
-
158
- ``` python
159
- users.c.name.op("~")(pattern)
160
- ```
161
-
162
- Both originate from the same IR.
163
-
164
- ------------------------------------------------------------------------
165
-
166
153
  # Plugin Packages
167
154
 
168
- Recommended official plugins:
155
+ Official plugins:
169
156
 
170
157
  - sqlrules-postgresql
171
158
  - sqlrules-sqlite
172
159
  - sqlrules-mysql
173
160
  - sqlrules-mssql
174
- - sqlrules-oracle
175
161
 
176
- Each package should register only the translators relevant to its
177
- backend.
162
+ Each package registers only the translators relevant to its backend.
178
163
 
179
164
  ------------------------------------------------------------------------
180
165
 
@@ -184,7 +169,6 @@ Every supported dialect should include:
184
169
 
185
170
  - Unit tests
186
171
  - SQL compilation tests
187
- - Integration tests
188
172
  - Regression tests
189
173
 
190
174
  The same Pydantic model should produce equivalent logical behavior
@@ -114,7 +114,7 @@ Official plugin packages begin:
114
114
 
115
115
  ------------------------------------------------------------------------
116
116
 
117
- # 0.4.0 --- Dialect Enhancements
117
+ # 0.4.0 --- Dialect Enhancements
118
118
 
119
119
  ## Goals
120
120
 
@@ -122,14 +122,14 @@ Provide optimized translations for major databases.
122
122
 
123
123
  ### PostgreSQL
124
124
 
125
- - regex
125
+ - regex (`~` / `~*`)
126
126
  - JSONB
127
127
  - ARRAY
128
128
  - range operators
129
129
 
130
130
  ### SQLite
131
131
 
132
- - REGEXP integration
132
+ - REGEXP integration (`register_regexp`)
133
133
  - JSON helpers
134
134
 
135
135
  ### MySQL / MariaDB
@@ -140,7 +140,13 @@ Provide optimized translations for major databases.
140
140
  ### SQL Server
141
141
 
142
142
  - JSON support
143
- - string optimizations
143
+ - string optimizations (`LEN`)
144
+
145
+ ### Core
146
+
147
+ - `ConstraintMarker` + `sqlrules.markers`
148
+ - `PatternSpec` for pattern IR
149
+ - `list` / `dict` type support for marker fields
144
150
 
145
151
  ------------------------------------------------------------------------
146
152
 
@@ -51,6 +51,7 @@ A plugin is a Python object that exposes `name`, `api_version`, and
51
51
 
52
52
  ``` python
53
53
  from sqlrules import PLUGIN_API_VERSION
54
+ from sqlrules.constraints import pattern_text
54
55
  from sqlrules.translators import TranslatorRegistry
55
56
 
56
57
  class CompanyPlugin:
@@ -60,12 +61,21 @@ class CompanyPlugin:
60
61
  def register(self, registry: TranslatorRegistry) -> None:
61
62
  registry.register_constraint(
62
63
  "pattern",
63
- lambda c, col, ctx: col.op("~")(c.value),
64
+ lambda c, col, ctx: col.op("~")(pattern_text(c.value)[0]),
64
65
  on_conflict="replace",
65
66
  )
66
67
  ```
67
68
 
68
- `api_version` must equal `sqlrules.PLUGIN_API_VERSION` (`"1"` in 0.3).
69
+ `api_version` must equal `sqlrules.PLUGIN_API_VERSION` (`"1"` in 0.4).
70
+
71
+ ------------------------------------------------------------------------
72
+
73
+ # Markers
74
+
75
+ Dialect-oriented constraints use `sqlrules.markers` (for example
76
+ `JsonContains`, `ArrayContains`). Markers implement the
77
+ `ConstraintMarker` protocol (`operator`, `value`) and are extracted into
78
+ IR. Plugins register translators for those operator names.
69
79
 
70
80
  ------------------------------------------------------------------------
71
81
 
@@ -91,7 +101,7 @@ Invalid translators raise `InvalidTranslatorError`. Duplicate operators
91
101
  raise `RegistryError` unless `on_conflict` / `replace` allows otherwise.
92
102
 
93
103
  `register_type`, `register_dialect`, and `register_compiler_pass` are
94
- not implemented in 0.3 (reserved).
104
+ not implemented (reserved).
95
105
 
96
106
  ------------------------------------------------------------------------
97
107
 
@@ -121,14 +131,12 @@ caller-owned registries are never mutated.
121
131
 
122
132
  # Dialect Plugins
123
133
 
124
- Official starter packages (same monorepo under `packages/`):
125
-
126
- - `sqlrules-postgresql` — `pattern` → `column ~ value`
127
- - `sqlrules-sqlite` — `pattern` → `column REGEXP value` (app must enable REGEXP)
134
+ Official packages (monorepo under `packages/`):
128
135
 
129
- Dialect plugins override or supplement built-in translators while
130
- preserving the same IR. JSONB, ARRAY, and other enhancements are planned
131
- for 0.4.
136
+ - `sqlrules-postgresql` regex, JSONB, ARRAY, range
137
+ - `sqlrules-sqlite` REGEXP helper + JSON
138
+ - `sqlrules-mysql` — REGEXP, JSON, full-text
139
+ - `sqlrules-mssql` — JSON + `LEN` length overrides
132
140
 
133
141
  ------------------------------------------------------------------------
134
142
 
@@ -168,7 +176,8 @@ run_basic_conformance(PostgresPlugin(), operator="pattern")
168
176
  ```
169
177
 
170
178
  Helpers also cover API version checks, builtin preservation, and
171
- deterministic translation.
179
+ deterministic translation. Pass `model=` / `table=` / `field=` when
180
+ conformance-checking non-`pattern` operators.
172
181
 
173
182
  ------------------------------------------------------------------------
174
183
 
@@ -185,7 +194,7 @@ The plugin system does not support:
185
194
 
186
195
  - Runtime SQL execution
187
196
  - Database connections
188
- - Automatic package downloads / entry-point discovery (0.3)
197
+ - Automatic package downloads / entry-point discovery
189
198
  - Dynamic code generation
190
199
  - Compiler pass plugins (future)
191
200
 
@@ -28,11 +28,12 @@
28
28
  - Versioned plugin API (`PLUGIN_API_VERSION`)
29
29
  - Diagnostic codes
30
30
 
31
- ## 0.4 — Dialect Enhancements
31
+ ## 0.4 — Dialect Enhancements
32
32
 
33
33
  - PostgreSQL regex polish, JSONB, ARRAY, range operators
34
34
  - SQLite REGEXP integration helpers
35
35
  - MySQL / MariaDB / SQL Server enhancements
36
+ - Shared `ConstraintMarker` / `sqlrules.markers` API
36
37
 
37
38
  ## 1.0 — Stable
38
39
 
@@ -16,7 +16,7 @@ Ordering is deterministic and follows model field declaration order.
16
16
  Within a field, expressions follow constraint extraction order.
17
17
  Fields that produce no expressions are omitted from the dictionary.
18
18
 
19
- ## Supported constraints (v0.3)
19
+ ## Supported constraints (v0.4)
20
20
 
21
21
  - `gt`
22
22
  - `ge`
@@ -28,17 +28,20 @@ Fields that produce no expressions are omitted from the dictionary.
28
28
  - `Literal`
29
29
  - `Enum`
30
30
 
31
- `pattern` is extracted into IR but has no portable core translator. It raises
32
- by default; use `on_unsupported="warn"` / `"ignore"`, register a custom
33
- translator, or install a dialect plugin (`sqlrules-postgresql`,
34
- `sqlrules-sqlite`).
31
+ `pattern` is extracted into IR as `PatternSpec` but has no portable core
32
+ translator. It raises by default; use `on_unsupported="warn"` / `"ignore"`,
33
+ register a custom translator, or install a dialect plugin.
35
34
 
36
- ## Supported types (v0.2)
35
+ Dialect markers (`JsonContains`, `ArrayContains`, `RangeContains`,
36
+ `FullTextMatch`, …) are extracted into IR and require a dialect plugin.
37
+
38
+ ## Supported types (v0.4)
37
39
 
38
40
  - `bool`, `int`, `float`, `Decimal`, `str`
39
41
  - `date`, `datetime`, `time`
40
42
  - `UUID` (Literal / Enum only)
41
43
  - `Literal[...]`, `Enum`
44
+ - `list` / `dict` (marker-driven fields only)
42
45
 
43
46
  ## Unsupported constraints
44
47