Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,27 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).

---

## v26.06.74 (2026-06-07)

### Docs (data — query-mechanism decision guide + Spring-Data parity matrix)

Following a full Spring-Data parity audit (CrudRepository / Pageable / derived queries / @query /
Specifications / Query-by-Example, relational **and** document — all present and behavior-tested),
`docs/modules/data.md` gains two teaching sections so users know **when** to use each tool and
where the boundaries are:

- **Choosing a Query Mechanism** — a decision table for derived methods vs `@query` vs
Specifications vs Query-by-Example (and when *not* to use each), plus how `Pageable`/`Sort`
layer on top.
- **Spring Data Parity & Current Limitations** — a relational-vs-document capability matrix
(soft-delete, optimistic locking, auditing, transactions differ by backend) and an explicit list
of Spring features **not yet** implemented (`@Modifying` bulk writes, `Slice`, DTO/open
projections, the `StartingWith`/`IgnoreCase`/`Top<N>` derived keywords, etc.) — so the docs set
accurate expectations rather than implying parity that isn't there.

The companion plugin's `implement-data-repository` skill gains the same decision table + capability
matrix + limitations (verified against the source: every cited symbol and operator exists).

## v26.06.73 (2026-06-07)

### Changed (benchmarks — rigor overhaul)
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
<a href="https://github.com/fireflyframework"><img src="https://img.shields.io/badge/Firefly_Framework-official-ff6600?logo=data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCI+PHBhdGggZmlsbD0id2hpdGUiIGQ9Ik0xMiAyQzYuNDggMiAyIDYuNDggMiAxMnM0LjQ4IDEwIDEwIDEwIDEwLTQuNDggMTAtMTBTMTcuNTIgMiAxMiAyeiIvPjwvc3ZnPg==" alt="Firefly Framework"></a>
<a href="https://www.python.org/"><img src="https://img.shields.io/badge/python-3.12%2B-blue?logo=python&logoColor=white" alt="Python 3.12+"></a>
<a href="LICENSE"><img src="https://img.shields.io/badge/license-Apache%202.0-green" alt="License: Apache 2.0"></a>
<a href="#"><img src="https://img.shields.io/badge/version-26.06.73-brightgreen" alt="Version: 26.06.73"></a>
<a href="#"><img src="https://img.shields.io/badge/version-26.06.74-brightgreen" alt="Version: 26.06.74"></a>
<a href="#"><img src="https://img.shields.io/badge/type--checked-mypy%20strict-blue?logo=python&logoColor=white" alt="Type Checked: mypy strict"></a>
<a href="#"><img src="https://img.shields.io/badge/code%20style-ruff-purple?logo=ruff&logoColor=white" alt="Code Style: Ruff"></a>
<a href="#"><img src="https://img.shields.io/badge/async-first-brightgreen" alt="Async First"></a>
Expand Down
43 changes: 43 additions & 0 deletions docs/modules/data.md
Original file line number Diff line number Diff line change
Expand Up @@ -1045,6 +1045,49 @@ Source files:

---

## Choosing a Query Mechanism

PyFly offers four ways to express a read, plus pagination that layers on top of any of them.
Reach for the simplest one that fits, and escalate only when it can't express the query:

| Mechanism | Use it when | Avoid it when | Example |
|-----------|-------------|---------------|---------|
| **Derived query methods** (`find_by_…`) | The predicate is a fixed combination of fields and the [supported operators](#operators), joined by AND/OR, optionally ordered. Type-safe, no SQL. **Start here.** | The query needs joins, aggregation, `OR` across more than a couple of fields, or an operator PyFly doesn't derive (see limitations). | `find_by_status_and_total_greater_than(...)` |
| **`@query`** (JPQL-like or `native=True`) | The query is too complex to name — joins, aggregates, hand-tuned SQL, or a MongoDB filter document. | A derived method would read clearly — don't write SQL for `find_by_id`. | `@query("SELECT o FROM Order o WHERE o.total > :min")` |
| **Specification** | The predicate is **dynamic** — built at runtime from optional filters and composed with `&` / `\|` / `~`. | The predicate is fixed (use a derived method) or static (use `@query`). | `active & (admin \| owner)` |
| **Query-by-Example** (`FilterUtils.from_example` / `from_dict`) | You have a populated example object or a dict of equality filters (e.g. straight from API query params). | You need ranges, `OR`, or anything beyond field-equality `AND`. | `FilterUtils.from_dict({"status": "ACTIVE"})` |

Then wrap any of the above with **`Pageable` + `Sort`** for paginated, ordered results
(`find_paginated`, `find_all_by_spec_paged`). Use `Pageable.unpaged()` to fetch everything.

## Spring Data Parity & Current Limitations

PyFly's repositories are Spring-Data-equivalent for the everyday feature set — across **both**
backends: CRUD + batch ops, `Pageable`/`Sort`/`Page`, derived queries, `@query`, Specifications,
Query-by-Example, projections, repository auto-implementation, and generic-type extraction are all
implemented and behavior-tested on relational **and** document.

Some capabilities are **backend-specific** today:

| Capability | Relational (SQLAlchemy) | Document (MongoDB) |
|------------|:-----------------------:|:------------------:|
| CRUD + batch, Pageable/Sort/Page, derived queries, `@query`, Specifications, QBE | ✅ | ✅ |
| Projections | ✅ | ✅ (closed/field-subset) |
| Soft delete (`SoftDeleteRepository`) | ✅ | ❌ not yet |
| Optimistic locking (`VersionedMixin` / `@Version`) | ✅ | ❌ not yet |
| Auditing auto-population | ✅ `created/updated_at` **and** `created/updated_by` | ⚠️ timestamps at insert only |
| `@transactional` (propagation, isolation, read-only, `rollback_for`) | ✅ | ⚠️ basic commit/abort (`@mongo_transactional`, replica set required) |

**Not yet implemented on either backend** (so you don't reach for them): `@Modifying`-style
declarative bulk `UPDATE`/`DELETE`; `Slice` (count-less paging) and streaming/reactive result
types; DTO / open (SpEL) / dynamic / association-traversing projections; the derived-query keywords
`StartingWith` / `EndingWith` / `IgnoreCase` / `True` / `False` / `Distinct` / `Top<N>` /
`After` / `Before` (use `_like`/`_containing`/`@query` instead); `ExampleMatcher` string-match
modes; named queries and `Pageable`/SpEL injection into `@query`. For these, fall back to `@query`
(or `native=True`) — it covers every case the derived parser doesn't.

---

## Available Adapters

| Adapter | Package | Backend | Guide |
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ name = "pyfly"
# CalVer YY.MM.PATCH — package metadata uses PEP 440 normalized form (26.5.4);
# git tag, GitHub release and human-readable display use leading-zero form
# (v26.05.04) to match the Java/.NET/Go siblings.
version = "26.6.73"
version = "26.6.74"
description = "The official Python implementation of the Firefly Framework — DI, CQRS, EDA, hexagonal architecture, and more."
readme = "README.md"
license = "Apache-2.0"
Expand Down
2 changes: 1 addition & 1 deletion src/pyfly/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,4 @@
# limitations under the License.
"""PyFly — Enterprise Python Framework."""

__version__ = "26.06.73"
__version__ = "26.06.74"
2 changes: 1 addition & 1 deletion uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading