ferrum-orm 0.1.2__tar.gz → 0.1.4__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.
- {ferrum_orm-0.1.2 → ferrum_orm-0.1.4}/Cargo.lock +26 -4
- {ferrum_orm-0.1.2 → ferrum_orm-0.1.4}/Cargo.toml +4 -1
- {ferrum_orm-0.1.2 → ferrum_orm-0.1.4}/PKG-INFO +116 -33
- {ferrum_orm-0.1.2 → ferrum_orm-0.1.4}/README.md +97 -27
- {ferrum_orm-0.1.2 → ferrum_orm-0.1.4}/crates/ferrum-core/benches/hydrate.rs +10 -0
- {ferrum_orm-0.1.2 → ferrum_orm-0.1.4}/crates/ferrum-core/src/compile/mod.rs +443 -29
- ferrum_orm-0.1.4/crates/ferrum-core/src/error.rs +111 -0
- {ferrum_orm-0.1.2 → ferrum_orm-0.1.4}/crates/ferrum-core/src/hydrate/mod.rs +8 -0
- {ferrum_orm-0.1.2 → ferrum_orm-0.1.4}/crates/ferrum-core/src/ir/metadata.rs +55 -1
- ferrum_orm-0.1.4/crates/ferrum-core/src/ir/mod.rs +302 -0
- ferrum_orm-0.1.4/crates/ferrum-core/src/migrate/mod.rs +91 -0
- {ferrum_orm-0.1.2 → ferrum_orm-0.1.4}/crates/ferrum-pyo3/Cargo.toml +1 -0
- {ferrum_orm-0.1.2 → ferrum_orm-0.1.4}/crates/ferrum-pyo3/src/lib.rs +168 -30
- {ferrum_orm-0.1.2 → ferrum_orm-0.1.4}/crates/ferrum-sql/Cargo.toml +3 -0
- {ferrum_orm-0.1.2 → ferrum_orm-0.1.4}/crates/ferrum-sql/benches/compile.rs +15 -0
- ferrum_orm-0.1.4/crates/ferrum-sql/src/dialect.rs +143 -0
- ferrum_orm-0.1.4/crates/ferrum-sql/src/emit.rs +1801 -0
- ferrum_orm-0.1.4/crates/ferrum-sql/src/fts/mod.rs +318 -0
- ferrum_orm-0.1.4/crates/ferrum-sql/src/fts/mssql.rs +60 -0
- ferrum_orm-0.1.4/crates/ferrum-sql/src/fts/mysql.rs +62 -0
- ferrum_orm-0.1.4/crates/ferrum-sql/src/fts/postgres.rs +58 -0
- ferrum_orm-0.1.4/crates/ferrum-sql/src/fts/sqlite.rs +51 -0
- {ferrum_orm-0.1.2 → ferrum_orm-0.1.4}/crates/ferrum-sql/src/lib.rs +1 -0
- {ferrum_orm-0.1.2 → ferrum_orm-0.1.4}/pyproject.toml +34 -8
- {ferrum_orm-0.1.2 → ferrum_orm-0.1.4}/python/ferrum/__init__.py +51 -3
- {ferrum_orm-0.1.2 → ferrum_orm-0.1.4}/python/ferrum/_native.pyi +34 -1
- {ferrum_orm-0.1.2 → ferrum_orm-0.1.4}/python/ferrum/cli/app.py +20 -0
- {ferrum_orm-0.1.2 → ferrum_orm-0.1.4}/python/ferrum/cli/bootstrap.py +3 -2
- {ferrum_orm-0.1.2 → ferrum_orm-0.1.4}/python/ferrum/cli/init.py +3 -0
- {ferrum_orm-0.1.2 → ferrum_orm-0.1.4}/python/ferrum/cli/makemigrations_cmd.py +13 -0
- {ferrum_orm-0.1.2 → ferrum_orm-0.1.4}/python/ferrum/cli/migrate_cmd.py +24 -0
- {ferrum_orm-0.1.2 → ferrum_orm-0.1.4}/python/ferrum/cli/migrations_cmd.py +14 -4
- {ferrum_orm-0.1.2 → ferrum_orm-0.1.4}/python/ferrum/cli/revert_cmd.py +5 -0
- {ferrum_orm-0.1.2 → ferrum_orm-0.1.4}/python/ferrum/cli/showmigrations_cmd.py +6 -3
- ferrum_orm-0.1.4/python/ferrum/cli/sqlmigrate_cmd.py +53 -0
- ferrum_orm-0.1.4/python/ferrum/config.py +243 -0
- ferrum_orm-0.1.4/python/ferrum/connection.py +567 -0
- ferrum_orm-0.1.4/python/ferrum/contrib/fastapi.py +75 -0
- {ferrum_orm-0.1.2 → ferrum_orm-0.1.4}/python/ferrum/drivers/__init__.py +10 -1
- ferrum_orm-0.1.4/python/ferrum/drivers/mssql.py +200 -0
- {ferrum_orm-0.1.2 → ferrum_orm-0.1.4}/python/ferrum/drivers/mysql.py +11 -1
- {ferrum_orm-0.1.2 → ferrum_orm-0.1.4}/python/ferrum/drivers/postgres.py +33 -8
- {ferrum_orm-0.1.2 → ferrum_orm-0.1.4}/python/ferrum/drivers/protocol.py +17 -3
- {ferrum_orm-0.1.2 → ferrum_orm-0.1.4}/python/ferrum/drivers/sqlite.py +14 -3
- {ferrum_orm-0.1.2 → ferrum_orm-0.1.4}/python/ferrum/errors.py +43 -0
- ferrum_orm-0.1.4/python/ferrum/expressions.py +82 -0
- ferrum_orm-0.1.4/python/ferrum/ext/fts.py +95 -0
- ferrum_orm-0.1.4/python/ferrum/ext/pgvector.py +238 -0
- {ferrum_orm-0.1.2 → ferrum_orm-0.1.4}/python/ferrum/migrations/__init__.py +24 -0
- ferrum_orm-0.1.4/python/ferrum/migrations/fts/__init__.py +57 -0
- ferrum_orm-0.1.4/python/ferrum/migrations/fts/mssql.py +31 -0
- ferrum_orm-0.1.4/python/ferrum/migrations/fts/mysql.py +22 -0
- ferrum_orm-0.1.4/python/ferrum/migrations/fts/postgres.py +27 -0
- ferrum_orm-0.1.4/python/ferrum/migrations/fts/sqlite.py +54 -0
- {ferrum_orm-0.1.2 → ferrum_orm-0.1.4}/python/ferrum/migrations/introspect.py +81 -1
- {ferrum_orm-0.1.2 → ferrum_orm-0.1.4}/python/ferrum/migrations/ledger.py +48 -3
- {ferrum_orm-0.1.2 → ferrum_orm-0.1.4}/python/ferrum/migrations/loader.py +7 -0
- ferrum_orm-0.1.4/python/ferrum/migrations/operations.py +739 -0
- {ferrum_orm-0.1.2 → ferrum_orm-0.1.4}/python/ferrum/migrations/orchestrator.py +331 -15
- {ferrum_orm-0.1.2 → ferrum_orm-0.1.4}/python/ferrum/models.py +278 -30
- ferrum_orm-0.1.4/python/ferrum/observability.py +159 -0
- ferrum_orm-0.1.4/python/ferrum/queryset.py +2369 -0
- ferrum_orm-0.1.4/python/ferrum/registry.py +55 -0
- ferrum_orm-0.1.4/python/ferrum/relations.py +359 -0
- ferrum_orm-0.1.4/python/ferrum/runtime.py +188 -0
- ferrum_orm-0.1.4/python/ferrum/session.py +171 -0
- ferrum_orm-0.1.2/crates/ferrum-core/src/error.rs +0 -73
- ferrum_orm-0.1.2/crates/ferrum-core/src/ir/mod.rs +0 -152
- ferrum_orm-0.1.2/crates/ferrum-core/src/migrate/mod.rs +0 -72
- ferrum_orm-0.1.2/crates/ferrum-sql/src/dialect.rs +0 -94
- ferrum_orm-0.1.2/crates/ferrum-sql/src/emit.rs +0 -864
- ferrum_orm-0.1.2/python/ferrum/config.py +0 -104
- ferrum_orm-0.1.2/python/ferrum/connection.py +0 -292
- ferrum_orm-0.1.2/python/ferrum/contrib/fastapi.py +0 -40
- ferrum_orm-0.1.2/python/ferrum/ext/pgvector.py +0 -49
- ferrum_orm-0.1.2/python/ferrum/migrations/operations.py +0 -334
- ferrum_orm-0.1.2/python/ferrum/queryset.py +0 -1078
- {ferrum_orm-0.1.2 → ferrum_orm-0.1.4}/LICENSE +0 -0
- {ferrum_orm-0.1.2 → ferrum_orm-0.1.4}/crates/ferrum-core/Cargo.toml +0 -0
- {ferrum_orm-0.1.2 → ferrum_orm-0.1.4}/crates/ferrum-core/src/lib.rs +0 -0
- {ferrum_orm-0.1.2 → ferrum_orm-0.1.4}/python/ferrum/cli/__init__.py +0 -0
- {ferrum_orm-0.1.2 → ferrum_orm-0.1.4}/python/ferrum/cli/inspectdb_cmd.py +0 -0
- {ferrum_orm-0.1.2 → ferrum_orm-0.1.4}/python/ferrum/cli/resetdb_cmd.py +0 -0
- {ferrum_orm-0.1.2 → ferrum_orm-0.1.4}/python/ferrum/contrib/__init__.py +0 -0
- {ferrum_orm-0.1.2 → ferrum_orm-0.1.4}/python/ferrum/ext/__init__.py +0 -0
- {ferrum_orm-0.1.2 → ferrum_orm-0.1.4}/python/ferrum/hooks.py +0 -0
- {ferrum_orm-0.1.2 → ferrum_orm-0.1.4}/python/ferrum/migrations/base.py +0 -0
- {ferrum_orm-0.1.2 → ferrum_orm-0.1.4}/python/ferrum/migrations/drift.py +0 -0
- {ferrum_orm-0.1.2 → ferrum_orm-0.1.4}/python/ferrum/migrations/gates.py +0 -0
- {ferrum_orm-0.1.2 → ferrum_orm-0.1.4}/python/ferrum/migrations/tokens.py +0 -0
- {ferrum_orm-0.1.2 → ferrum_orm-0.1.4}/python/ferrum/py.typed +0 -0
|
@@ -223,7 +223,7 @@ checksum = "9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6"
|
|
|
223
223
|
|
|
224
224
|
[[package]]
|
|
225
225
|
name = "ferrum-core"
|
|
226
|
-
version = "0.1.
|
|
226
|
+
version = "0.1.4"
|
|
227
227
|
dependencies = [
|
|
228
228
|
"criterion",
|
|
229
229
|
"proptest",
|
|
@@ -234,7 +234,7 @@ dependencies = [
|
|
|
234
234
|
|
|
235
235
|
[[package]]
|
|
236
236
|
name = "ferrum-migrate"
|
|
237
|
-
version = "0.1.
|
|
237
|
+
version = "0.1.4"
|
|
238
238
|
dependencies = [
|
|
239
239
|
"ferrum-core",
|
|
240
240
|
"serde",
|
|
@@ -243,23 +243,26 @@ dependencies = [
|
|
|
243
243
|
|
|
244
244
|
[[package]]
|
|
245
245
|
name = "ferrum-pyo3"
|
|
246
|
-
version = "0.1.
|
|
246
|
+
version = "0.1.4"
|
|
247
247
|
dependencies = [
|
|
248
248
|
"ferrum-core",
|
|
249
249
|
"ferrum-sql",
|
|
250
250
|
"pyo3",
|
|
251
|
+
"rmp-serde",
|
|
251
252
|
"serde_json",
|
|
252
253
|
"thiserror",
|
|
253
254
|
]
|
|
254
255
|
|
|
255
256
|
[[package]]
|
|
256
257
|
name = "ferrum-sql"
|
|
257
|
-
version = "0.1.
|
|
258
|
+
version = "0.1.4"
|
|
258
259
|
dependencies = [
|
|
259
260
|
"criterion",
|
|
260
261
|
"ferrum-core",
|
|
261
262
|
"proptest",
|
|
263
|
+
"rmp-serde",
|
|
262
264
|
"serde",
|
|
265
|
+
"serde_json",
|
|
263
266
|
"thiserror",
|
|
264
267
|
]
|
|
265
268
|
|
|
@@ -726,6 +729,25 @@ version = "0.8.11"
|
|
|
726
729
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
727
730
|
checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4"
|
|
728
731
|
|
|
732
|
+
[[package]]
|
|
733
|
+
name = "rmp"
|
|
734
|
+
version = "0.8.15"
|
|
735
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
736
|
+
checksum = "4ba8be72d372b2c9b35542551678538b562e7cf86c3315773cae48dfbfe7790c"
|
|
737
|
+
dependencies = [
|
|
738
|
+
"num-traits",
|
|
739
|
+
]
|
|
740
|
+
|
|
741
|
+
[[package]]
|
|
742
|
+
name = "rmp-serde"
|
|
743
|
+
version = "1.3.1"
|
|
744
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
745
|
+
checksum = "72f81bee8c8ef9b577d1681a70ebbc962c232461e397b22c208c43c04b67a155"
|
|
746
|
+
dependencies = [
|
|
747
|
+
"rmp",
|
|
748
|
+
"serde",
|
|
749
|
+
]
|
|
750
|
+
|
|
729
751
|
[[package]]
|
|
730
752
|
name = "rustix"
|
|
731
753
|
version = "1.1.4"
|
|
@@ -3,7 +3,7 @@ members = ["crates/ferrum-core", "crates/ferrum-sql", "crates/ferrum-pyo3"]
|
|
|
3
3
|
resolver = "2"
|
|
4
4
|
|
|
5
5
|
[workspace.package]
|
|
6
|
-
version = "0.1.
|
|
6
|
+
version = "0.1.4"
|
|
7
7
|
edition = "2021"
|
|
8
8
|
authors = ["Ferrum Contributors"]
|
|
9
9
|
license = "Apache-2.0"
|
|
@@ -17,6 +17,9 @@ pyo3 = { version = "0.29", features = ["abi3-py311"] }
|
|
|
17
17
|
# Serialization
|
|
18
18
|
serde = { version = "1", features = ["derive"] }
|
|
19
19
|
serde_json = "1"
|
|
20
|
+
# MessagePack wire format for the PyO3 boundary (always compiled; the Python
|
|
21
|
+
# `[msgpack]` extra gates only the runtime `msgpack` package + selection).
|
|
22
|
+
rmp-serde = "1"
|
|
20
23
|
|
|
21
24
|
# Error handling
|
|
22
25
|
thiserror = "2"
|
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ferrum-orm
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.4
|
|
4
4
|
Classifier: Development Status :: 3 - Alpha
|
|
5
5
|
Classifier: Framework :: AsyncIO
|
|
6
6
|
Classifier: Intended Audience :: Developers
|
|
7
7
|
Classifier: License :: OSI Approved :: Apache Software License
|
|
8
|
+
Classifier: Operating System :: OS Independent
|
|
8
9
|
Classifier: Programming Language :: Python :: 3
|
|
9
10
|
Classifier: Programming Language :: Python :: 3.11
|
|
10
11
|
Classifier: Programming Language :: Python :: 3.12
|
|
11
12
|
Classifier: Programming Language :: Python :: 3.13
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
12
14
|
Classifier: Programming Language :: Rust
|
|
13
15
|
Classifier: Topic :: Database
|
|
14
16
|
Classifier: Topic :: Software Development :: Libraries
|
|
@@ -17,6 +19,8 @@ Requires-Dist: pydantic>=2.0
|
|
|
17
19
|
Requires-Dist: ferrum-orm[pg] ; extra == 'all'
|
|
18
20
|
Requires-Dist: ferrum-orm[mysql] ; extra == 'all'
|
|
19
21
|
Requires-Dist: ferrum-orm[sqlite] ; extra == 'all'
|
|
22
|
+
Requires-Dist: ferrum-orm[mssql] ; extra == 'all'
|
|
23
|
+
Requires-Dist: ferrum-orm[msgpack] ; extra == 'all'
|
|
20
24
|
Requires-Dist: ferrum-orm[cli] ; extra == 'all'
|
|
21
25
|
Requires-Dist: ferrum-orm[dotenv] ; extra == 'all'
|
|
22
26
|
Requires-Dist: typer>=0.12 ; extra == 'cli'
|
|
@@ -32,8 +36,12 @@ Requires-Dist: ty>=0.0.49 ; extra == 'dev'
|
|
|
32
36
|
Requires-Dist: import-linter>=2 ; extra == 'dev'
|
|
33
37
|
Requires-Dist: testcontainers[postgres]>=4 ; extra == 'dev'
|
|
34
38
|
Requires-Dist: pip-audit>=2 ; extra == 'dev'
|
|
39
|
+
Requires-Dist: fastapi>=0.110 ; extra == 'dev'
|
|
35
40
|
Requires-Dist: python-dotenv>=1.0 ; extra == 'dotenv'
|
|
41
|
+
Requires-Dist: msgpack>=1.0 ; extra == 'msgpack'
|
|
42
|
+
Requires-Dist: aioodbc>=0.5 ; extra == 'mssql'
|
|
36
43
|
Requires-Dist: asyncmy>=0.2 ; extra == 'mysql'
|
|
44
|
+
Requires-Dist: opentelemetry-api>=1.20 ; extra == 'otel'
|
|
37
45
|
Requires-Dist: asyncpg>=0.29 ; extra == 'pg'
|
|
38
46
|
Requires-Dist: aiosqlite>=0.19 ; extra == 'sqlite'
|
|
39
47
|
Requires-Dist: uuid6>=2024.1 ; extra == 'uuid7'
|
|
@@ -42,20 +50,25 @@ Provides-Extra: cli
|
|
|
42
50
|
Provides-Extra: dev
|
|
43
51
|
Provides-Extra: dotenv
|
|
44
52
|
Provides-Extra: fastapi
|
|
53
|
+
Provides-Extra: msgpack
|
|
54
|
+
Provides-Extra: mssql
|
|
45
55
|
Provides-Extra: mysql
|
|
56
|
+
Provides-Extra: otel
|
|
46
57
|
Provides-Extra: pg
|
|
47
58
|
Provides-Extra: sqlite
|
|
48
59
|
Provides-Extra: uuid7
|
|
49
60
|
License-File: LICENSE
|
|
50
61
|
Summary: Next-generation async ORM for Python with a Rust-powered core
|
|
51
|
-
Keywords: orm,async,postgresql,mysql,sqlite,pydantic,rust
|
|
62
|
+
Keywords: orm,async,postgresql,mysql,sqlite,mssql,pydantic,rust,asyncpg,query-builder
|
|
63
|
+
Author: Ferrum Contributors
|
|
52
64
|
License: Apache-2.0
|
|
53
65
|
Requires-Python: >=3.11
|
|
54
66
|
Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
|
|
55
|
-
Project-URL:
|
|
56
|
-
Project-URL: Documentation, https://
|
|
57
|
-
Project-URL: Homepage, https://github.com/
|
|
58
|
-
Project-URL:
|
|
67
|
+
Project-URL: Changelog, https://github.com/ferrum-orm/ferrum/blob/main/CHANGELOG.md
|
|
68
|
+
Project-URL: Documentation, https://github.com/ferrum-orm/ferrum/tree/main/docs
|
|
69
|
+
Project-URL: Homepage, https://github.com/ferrum-orm/ferrum
|
|
70
|
+
Project-URL: Issues, https://github.com/ferrum-orm/ferrum/issues
|
|
71
|
+
Project-URL: Repository, https://github.com/ferrum-orm/ferrum
|
|
59
72
|
|
|
60
73
|
# Ferrum
|
|
61
74
|
|
|
@@ -83,7 +96,7 @@ Ferrum aims to provide all four.
|
|
|
83
96
|
- Pydantic-first models
|
|
84
97
|
- Django-inspired ORM experience
|
|
85
98
|
- Rust-powered query engine
|
|
86
|
-
- PostgreSQL-first architecture (MySQL and
|
|
99
|
+
- PostgreSQL-first architecture (MySQL, SQLite, and SQL Server via optional extras)
|
|
87
100
|
- Type-safe query construction
|
|
88
101
|
- Automatic migrations
|
|
89
102
|
- High-performance result hydration
|
|
@@ -172,6 +185,50 @@ Performance-critical components are implemented in Rust:
|
|
|
172
185
|
|
|
173
186
|
This allows Ferrum to maintain a Pythonic API without sacrificing performance.
|
|
174
187
|
|
|
188
|
+
### Cross-Driver Full-Text Search
|
|
189
|
+
|
|
190
|
+
Native full-text search across PostgreSQL, MySQL, SQLite FTS5, and SQL Server — one
|
|
191
|
+
QuerySet API, dialect-specific SQL emit and migration DDL.
|
|
192
|
+
|
|
193
|
+
**Query modes** (filter lookups and ranking):
|
|
194
|
+
|
|
195
|
+
| Mode | Lookup operator | Typical use |
|
|
196
|
+
| ----------- | ----------------- | ------------------------------------ |
|
|
197
|
+
| `plain` | `__match` | Natural-language terms |
|
|
198
|
+
| `phrase` | `__match_phrase` | Exact phrase |
|
|
199
|
+
| `websearch` | `__match_websearch` | Web-style quotes, `-` negation |
|
|
200
|
+
| `boolean` | `__match_boolean` | Boolean operators (`&`, `\|`, `!`) |
|
|
201
|
+
|
|
202
|
+
**Convenience methods:**
|
|
203
|
+
|
|
204
|
+
```python
|
|
205
|
+
# Filter + relevance ranking in one call
|
|
206
|
+
hits = await Article.objects.search(
|
|
207
|
+
"python async orm", field="body", mode="websearch"
|
|
208
|
+
).limit(10).all(conn)
|
|
209
|
+
|
|
210
|
+
# Rank without an implicit filter
|
|
211
|
+
ranked = await Article.objects.rank_by("body", "rust", mode="plain").all(conn)
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
**Index declaration** — PostgreSQL uses `TSVector` columns; other drivers index base
|
|
215
|
+
`text` columns via `Meta.full_text_indexes`:
|
|
216
|
+
|
|
217
|
+
```python
|
|
218
|
+
from ferrum.models import Field, FullTextIndex
|
|
219
|
+
|
|
220
|
+
class Article(Model):
|
|
221
|
+
search_vector: Annotated[TSVector, Field(fts_config="english")] | None = None
|
|
222
|
+
body: str = ""
|
|
223
|
+
|
|
224
|
+
class Meta:
|
|
225
|
+
full_text_indexes = [FullTextIndex(fields=("body",), config="english")]
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
Query strings are always bound parameters; `fts_config` and index names come from
|
|
229
|
+
model-metadata allowlists only. See [Getting Started → Vector and full-text columns](docs/getting-started.md)
|
|
230
|
+
and [API Reference](docs/api-reference.md) for per-dialect DDL and operator mapping.
|
|
231
|
+
|
|
175
232
|
## Architecture
|
|
176
233
|
|
|
177
234
|
```text
|
|
@@ -199,34 +256,41 @@ This allows Ferrum to maintain a Pythonic API without sacrificing performance.
|
|
|
199
256
|
|
|
200
257
|
## Roadmap
|
|
201
258
|
|
|
202
|
-
### v0.1
|
|
203
|
-
|
|
204
|
-
- [
|
|
205
|
-
- [
|
|
206
|
-
- [
|
|
207
|
-
- [
|
|
208
|
-
- [
|
|
209
|
-
- [
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
- [
|
|
214
|
-
- [x]
|
|
215
|
-
- [
|
|
216
|
-
- [
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
- [
|
|
222
|
-
- [
|
|
259
|
+
### v0.1 (complete)
|
|
260
|
+
|
|
261
|
+
- [x] PostgreSQL support
|
|
262
|
+
- [x] Basic CRUD operations
|
|
263
|
+
- [x] Async query execution
|
|
264
|
+
- [x] Pydantic models
|
|
265
|
+
- [x] Query builder
|
|
266
|
+
- [x] Type-safe filters
|
|
267
|
+
- [x] Transactions and savepoints
|
|
268
|
+
- [x] Bulk operations (`bulk_create`, `bulk_update`, `bulk_delete`)
|
|
269
|
+
- [x] Migrations (schema diff, apply, revert, CLI)
|
|
270
|
+
- [x] Relationships (ForeignKey, OneToOne, ManyToMany)
|
|
271
|
+
- [x] pgvector KNN search and HNSW/IVFFLAT index DDL
|
|
272
|
+
- [x] Full-text search (cross-dialect: PostgreSQL, MySQL, SQLite FTS5, SQL Server)
|
|
273
|
+
- [x] Observability hooks (Tier A/B/C)
|
|
274
|
+
- [x] CLI (`makemigrations`, `migrate`, `revert`, `showmigrations`, `inspectdb`, `resetdb`)
|
|
275
|
+
|
|
276
|
+
### v0.2 (in progress)
|
|
277
|
+
|
|
278
|
+
- [x] Upsert API (`upsert`, `bulk_upsert` with conflict targets and `RETURNING`)
|
|
279
|
+
- [x] Composite primary keys
|
|
280
|
+
- [x] Array field types (`uuid[]`, `text[]`, scalar arrays)
|
|
281
|
+
- [x] JSONB operators (`__contains`, `__has_key`)
|
|
282
|
+
- [x] RLS / tenant session helpers (`set_config`, `tenant_session`)
|
|
283
|
+
- [x] `call_function` for allowlisted stored-procedure calls
|
|
284
|
+
- [x] Migration ops for extensions, RLS policies, and function DDL
|
|
285
|
+
- [x] pgvector similarity score projection (`vector_search` helper)
|
|
286
|
+
- [ ] Query optimization (deferred fields, prefetch tuning)
|
|
287
|
+
- [ ] Advanced relationship loading
|
|
223
288
|
|
|
224
289
|
### v1.0
|
|
225
290
|
|
|
226
291
|
- [ ] Production-ready stability
|
|
227
|
-
- [ ]
|
|
228
|
-
- [ ]
|
|
229
|
-
- [ ] Full documentation
|
|
292
|
+
- [ ] Performance benchmarking suite
|
|
293
|
+
- [ ] Full documentation site
|
|
230
294
|
|
|
231
295
|
## Project Status
|
|
232
296
|
|
|
@@ -249,6 +313,12 @@ pip install 'ferrum-orm[mysql]'
|
|
|
249
313
|
# SQLite + migrations CLI (testing / local dev)
|
|
250
314
|
pip install 'ferrum-orm[sqlite,cli]'
|
|
251
315
|
|
|
316
|
+
# SQL Server (also needs a system ODBC driver, e.g. msodbcsql18)
|
|
317
|
+
pip install 'ferrum-orm[mssql]'
|
|
318
|
+
|
|
319
|
+
# Optional MessagePack wire format for the Python<->Rust boundary
|
|
320
|
+
pip install 'ferrum-orm[msgpack]'
|
|
321
|
+
|
|
252
322
|
# Everything (all drivers + CLI + dotenv)
|
|
253
323
|
pip install 'ferrum-orm[all]'
|
|
254
324
|
|
|
@@ -257,7 +327,19 @@ pip install ferrum-orm
|
|
|
257
327
|
```
|
|
258
328
|
|
|
259
329
|
Bare `ferrum-orm` installs Pydantic and the Rust core only. Choose a driver extra
|
|
260
|
-
(`pg`, `mysql`, or `
|
|
330
|
+
(`pg`, `mysql`, `sqlite`, or `mssql`) before calling `ferrum.connect()`.
|
|
331
|
+
|
|
332
|
+
MySQL, SQLite, and SQL Server are **thin-parity** backends: they support core CRUD
|
|
333
|
+
and migrations but not transactions, upsert, `bulk_update`, RLS, or pgvector
|
|
334
|
+
(PostgreSQL only). SQL Server connects via `aioodbc`/`pyodbc` and requires a system
|
|
335
|
+
ODBC driver such as `msodbcsql18`; DSNs use the `mssql://` or `sqlserver://` scheme.
|
|
336
|
+
|
|
337
|
+
### Wire format (advanced)
|
|
338
|
+
|
|
339
|
+
The Python↔Rust IR/hydration boundary defaults to JSON. Installing the `msgpack`
|
|
340
|
+
extra lets you switch it to MessagePack, selected via the `FERRUM_WIRE_FORMAT`
|
|
341
|
+
environment variable (`json` | `msgpack`) or the `[ferrum] wire_format` key in
|
|
342
|
+
`ferrum.toml` / `pyproject.toml`. JSON remains the default; MessagePack is opt-in.
|
|
261
343
|
|
|
262
344
|
From source, build the native extension with `maturin develop` (or `mise run dev`).
|
|
263
345
|
|
|
@@ -271,7 +353,8 @@ Runnable samples live under [`examples/`](examples/):
|
|
|
271
353
|
|
|
272
354
|
## Contributing
|
|
273
355
|
|
|
274
|
-
Contributions are welcome.
|
|
356
|
+
Contributions are welcome. Start with [`CONTRIBUTING.md`](CONTRIBUTING.md) for local setup,
|
|
357
|
+
scoped verification, architecture rules, and pull request expectations.
|
|
275
358
|
|
|
276
359
|
## License
|
|
277
360
|
|
|
@@ -24,7 +24,7 @@ Ferrum aims to provide all four.
|
|
|
24
24
|
- Pydantic-first models
|
|
25
25
|
- Django-inspired ORM experience
|
|
26
26
|
- Rust-powered query engine
|
|
27
|
-
- PostgreSQL-first architecture (MySQL and
|
|
27
|
+
- PostgreSQL-first architecture (MySQL, SQLite, and SQL Server via optional extras)
|
|
28
28
|
- Type-safe query construction
|
|
29
29
|
- Automatic migrations
|
|
30
30
|
- High-performance result hydration
|
|
@@ -113,6 +113,50 @@ Performance-critical components are implemented in Rust:
|
|
|
113
113
|
|
|
114
114
|
This allows Ferrum to maintain a Pythonic API without sacrificing performance.
|
|
115
115
|
|
|
116
|
+
### Cross-Driver Full-Text Search
|
|
117
|
+
|
|
118
|
+
Native full-text search across PostgreSQL, MySQL, SQLite FTS5, and SQL Server — one
|
|
119
|
+
QuerySet API, dialect-specific SQL emit and migration DDL.
|
|
120
|
+
|
|
121
|
+
**Query modes** (filter lookups and ranking):
|
|
122
|
+
|
|
123
|
+
| Mode | Lookup operator | Typical use |
|
|
124
|
+
| ----------- | ----------------- | ------------------------------------ |
|
|
125
|
+
| `plain` | `__match` | Natural-language terms |
|
|
126
|
+
| `phrase` | `__match_phrase` | Exact phrase |
|
|
127
|
+
| `websearch` | `__match_websearch` | Web-style quotes, `-` negation |
|
|
128
|
+
| `boolean` | `__match_boolean` | Boolean operators (`&`, `\|`, `!`) |
|
|
129
|
+
|
|
130
|
+
**Convenience methods:**
|
|
131
|
+
|
|
132
|
+
```python
|
|
133
|
+
# Filter + relevance ranking in one call
|
|
134
|
+
hits = await Article.objects.search(
|
|
135
|
+
"python async orm", field="body", mode="websearch"
|
|
136
|
+
).limit(10).all(conn)
|
|
137
|
+
|
|
138
|
+
# Rank without an implicit filter
|
|
139
|
+
ranked = await Article.objects.rank_by("body", "rust", mode="plain").all(conn)
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
**Index declaration** — PostgreSQL uses `TSVector` columns; other drivers index base
|
|
143
|
+
`text` columns via `Meta.full_text_indexes`:
|
|
144
|
+
|
|
145
|
+
```python
|
|
146
|
+
from ferrum.models import Field, FullTextIndex
|
|
147
|
+
|
|
148
|
+
class Article(Model):
|
|
149
|
+
search_vector: Annotated[TSVector, Field(fts_config="english")] | None = None
|
|
150
|
+
body: str = ""
|
|
151
|
+
|
|
152
|
+
class Meta:
|
|
153
|
+
full_text_indexes = [FullTextIndex(fields=("body",), config="english")]
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
Query strings are always bound parameters; `fts_config` and index names come from
|
|
157
|
+
model-metadata allowlists only. See [Getting Started → Vector and full-text columns](docs/getting-started.md)
|
|
158
|
+
and [API Reference](docs/api-reference.md) for per-dialect DDL and operator mapping.
|
|
159
|
+
|
|
116
160
|
## Architecture
|
|
117
161
|
|
|
118
162
|
```text
|
|
@@ -140,34 +184,41 @@ This allows Ferrum to maintain a Pythonic API without sacrificing performance.
|
|
|
140
184
|
|
|
141
185
|
## Roadmap
|
|
142
186
|
|
|
143
|
-
### v0.1
|
|
144
|
-
|
|
145
|
-
- [
|
|
146
|
-
- [
|
|
147
|
-
- [
|
|
148
|
-
- [
|
|
149
|
-
- [
|
|
150
|
-
- [
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
- [
|
|
155
|
-
- [x]
|
|
156
|
-
- [
|
|
157
|
-
- [
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
- [
|
|
163
|
-
- [
|
|
187
|
+
### v0.1 (complete)
|
|
188
|
+
|
|
189
|
+
- [x] PostgreSQL support
|
|
190
|
+
- [x] Basic CRUD operations
|
|
191
|
+
- [x] Async query execution
|
|
192
|
+
- [x] Pydantic models
|
|
193
|
+
- [x] Query builder
|
|
194
|
+
- [x] Type-safe filters
|
|
195
|
+
- [x] Transactions and savepoints
|
|
196
|
+
- [x] Bulk operations (`bulk_create`, `bulk_update`, `bulk_delete`)
|
|
197
|
+
- [x] Migrations (schema diff, apply, revert, CLI)
|
|
198
|
+
- [x] Relationships (ForeignKey, OneToOne, ManyToMany)
|
|
199
|
+
- [x] pgvector KNN search and HNSW/IVFFLAT index DDL
|
|
200
|
+
- [x] Full-text search (cross-dialect: PostgreSQL, MySQL, SQLite FTS5, SQL Server)
|
|
201
|
+
- [x] Observability hooks (Tier A/B/C)
|
|
202
|
+
- [x] CLI (`makemigrations`, `migrate`, `revert`, `showmigrations`, `inspectdb`, `resetdb`)
|
|
203
|
+
|
|
204
|
+
### v0.2 (in progress)
|
|
205
|
+
|
|
206
|
+
- [x] Upsert API (`upsert`, `bulk_upsert` with conflict targets and `RETURNING`)
|
|
207
|
+
- [x] Composite primary keys
|
|
208
|
+
- [x] Array field types (`uuid[]`, `text[]`, scalar arrays)
|
|
209
|
+
- [x] JSONB operators (`__contains`, `__has_key`)
|
|
210
|
+
- [x] RLS / tenant session helpers (`set_config`, `tenant_session`)
|
|
211
|
+
- [x] `call_function` for allowlisted stored-procedure calls
|
|
212
|
+
- [x] Migration ops for extensions, RLS policies, and function DDL
|
|
213
|
+
- [x] pgvector similarity score projection (`vector_search` helper)
|
|
214
|
+
- [ ] Query optimization (deferred fields, prefetch tuning)
|
|
215
|
+
- [ ] Advanced relationship loading
|
|
164
216
|
|
|
165
217
|
### v1.0
|
|
166
218
|
|
|
167
219
|
- [ ] Production-ready stability
|
|
168
|
-
- [ ]
|
|
169
|
-
- [ ]
|
|
170
|
-
- [ ] Full documentation
|
|
220
|
+
- [ ] Performance benchmarking suite
|
|
221
|
+
- [ ] Full documentation site
|
|
171
222
|
|
|
172
223
|
## Project Status
|
|
173
224
|
|
|
@@ -190,6 +241,12 @@ pip install 'ferrum-orm[mysql]'
|
|
|
190
241
|
# SQLite + migrations CLI (testing / local dev)
|
|
191
242
|
pip install 'ferrum-orm[sqlite,cli]'
|
|
192
243
|
|
|
244
|
+
# SQL Server (also needs a system ODBC driver, e.g. msodbcsql18)
|
|
245
|
+
pip install 'ferrum-orm[mssql]'
|
|
246
|
+
|
|
247
|
+
# Optional MessagePack wire format for the Python<->Rust boundary
|
|
248
|
+
pip install 'ferrum-orm[msgpack]'
|
|
249
|
+
|
|
193
250
|
# Everything (all drivers + CLI + dotenv)
|
|
194
251
|
pip install 'ferrum-orm[all]'
|
|
195
252
|
|
|
@@ -198,7 +255,19 @@ pip install ferrum-orm
|
|
|
198
255
|
```
|
|
199
256
|
|
|
200
257
|
Bare `ferrum-orm` installs Pydantic and the Rust core only. Choose a driver extra
|
|
201
|
-
(`pg`, `mysql`, or `
|
|
258
|
+
(`pg`, `mysql`, `sqlite`, or `mssql`) before calling `ferrum.connect()`.
|
|
259
|
+
|
|
260
|
+
MySQL, SQLite, and SQL Server are **thin-parity** backends: they support core CRUD
|
|
261
|
+
and migrations but not transactions, upsert, `bulk_update`, RLS, or pgvector
|
|
262
|
+
(PostgreSQL only). SQL Server connects via `aioodbc`/`pyodbc` and requires a system
|
|
263
|
+
ODBC driver such as `msodbcsql18`; DSNs use the `mssql://` or `sqlserver://` scheme.
|
|
264
|
+
|
|
265
|
+
### Wire format (advanced)
|
|
266
|
+
|
|
267
|
+
The Python↔Rust IR/hydration boundary defaults to JSON. Installing the `msgpack`
|
|
268
|
+
extra lets you switch it to MessagePack, selected via the `FERRUM_WIRE_FORMAT`
|
|
269
|
+
environment variable (`json` | `msgpack`) or the `[ferrum] wire_format` key in
|
|
270
|
+
`ferrum.toml` / `pyproject.toml`. JSON remains the default; MessagePack is opt-in.
|
|
202
271
|
|
|
203
272
|
From source, build the native extension with `maturin develop` (or `mise run dev`).
|
|
204
273
|
|
|
@@ -212,7 +281,8 @@ Runnable samples live under [`examples/`](examples/):
|
|
|
212
281
|
|
|
213
282
|
## Contributing
|
|
214
283
|
|
|
215
|
-
Contributions are welcome.
|
|
284
|
+
Contributions are welcome. Start with [`CONTRIBUTING.md`](CONTRIBUTING.md) for local setup,
|
|
285
|
+
scoped verification, architecture rules, and pull request expectations.
|
|
216
286
|
|
|
217
287
|
## License
|
|
218
288
|
|
|
@@ -20,6 +20,8 @@ fn bench_metadata() -> ModelMetadata {
|
|
|
20
20
|
allowed_operators: vec!["eq".into()],
|
|
21
21
|
nullable: false,
|
|
22
22
|
vector_dimensions: None,
|
|
23
|
+
fts_config: None,
|
|
24
|
+
fts_source_columns: None,
|
|
23
25
|
},
|
|
24
26
|
FieldMeta {
|
|
25
27
|
name: "title".into(),
|
|
@@ -28,6 +30,8 @@ fn bench_metadata() -> ModelMetadata {
|
|
|
28
30
|
allowed_operators: vec!["eq".into(), "icontains".into()],
|
|
29
31
|
nullable: false,
|
|
30
32
|
vector_dimensions: None,
|
|
33
|
+
fts_config: None,
|
|
34
|
+
fts_source_columns: None,
|
|
31
35
|
},
|
|
32
36
|
FieldMeta {
|
|
33
37
|
name: "body".into(),
|
|
@@ -36,6 +40,8 @@ fn bench_metadata() -> ModelMetadata {
|
|
|
36
40
|
allowed_operators: vec!["eq".into()],
|
|
37
41
|
nullable: true,
|
|
38
42
|
vector_dimensions: None,
|
|
43
|
+
fts_config: None,
|
|
44
|
+
fts_source_columns: None,
|
|
39
45
|
},
|
|
40
46
|
FieldMeta {
|
|
41
47
|
name: "published".into(),
|
|
@@ -44,9 +50,13 @@ fn bench_metadata() -> ModelMetadata {
|
|
|
44
50
|
allowed_operators: vec!["eq".into()],
|
|
45
51
|
nullable: false,
|
|
46
52
|
vector_dimensions: None,
|
|
53
|
+
fts_config: None,
|
|
54
|
+
fts_source_columns: None,
|
|
47
55
|
},
|
|
48
56
|
],
|
|
49
57
|
pk_index: 0,
|
|
58
|
+
pk_fields: vec![0],
|
|
59
|
+
full_text_indexes: vec![],
|
|
50
60
|
}
|
|
51
61
|
}
|
|
52
62
|
|