Skip to main content

Small implementation of a filter criteria pattern in Python for Complex Heart SDK. Compose several filters using fluent interface.

Project description

Criteria (a.k.a Filter)

Test Quality Gate Status Coverage

Small implementation of a filter criteria pattern in Python for Complex Heart SDK. Query-system agnostic - works with SQL, NoSQL, APIs, or any data source.

Installation

pip install complex-heart-criteria

or using uv:

uv add complex-heart-criteria

Usage

from complexheart.domain.criteria import Criteria, Filter, FilterGroup, Order, Page

Building FilterGroups

Use + to compose filters into a FilterGroup (AND logic within group):

active_adults = Filter.equal("status", "active") + Filter.greater_or_equal_than("age", 18)

Or use the fluent API:

active_adults = (
    FilterGroup.empty()
    .add_filter_equal("status", "active")
    .add_filter_greater_or_equal_than("age", 18)
)

Building Criteria

Add FilterGroups to Criteria (OR logic between groups):

c = (
    Criteria()
    .with_filter_group(active_adults)
    .with_order(Order.desc(("created_at",)))
    .with_page_limit(10)
    .with_page_offset(20)
)

Merging Criteria

Use | for OR and & for AND between Criteria objects:

active_users = Criteria().with_filter_group(
    Filter.equal("status", "active") + Filter.greater_than("age", 18)
)
admin_users = Criteria().with_filter_group(
    FilterGroup.create(Filter.equal("role", "admin"))
)

# OR: concatenate groups
combined = active_users | admin_users
# Result: (status = 'active' AND age > 18) OR (role = 'admin')

# AND: merge into single group
merged = active_users & admin_users
# Result: (status = 'active' AND age > 18 AND role = 'admin')

Fluent API

criteria = (
    Criteria()
    .filter("status", "==", "active", group=0)
    .filter("age", ">=", 18, group=0)
    .filter("role", "==", "admin", group=1)
    .order_by(("created_at",), "DESC")
    .limit(10)
    .offset(20)
)
# Result: (status = 'active' AND age >= 18) OR (role = 'admin')

Filter Factories

Filter.equal("name", "Vincent")              # name == 'Vincent'
Filter.not_equal("name", "Vincent")          # name != 'Vincent'
Filter.greater_than("age", 18)               # age > 18
Filter.greater_or_equal_than("age", 18)      # age >= 18
Filter.less_than("age", 65)                  # age < 65
Filter.less_or_equal_than("age", 65)         # age <= 65
Filter.in_("status", ["a", "b"])             # status IN ('a', 'b')
Filter.not_in("status", ["x"])               # status NOT IN ('x')
Filter.like("name", "Vin%")                  # name LIKE 'Vin%'
Filter.not_like("name", "Vin%")              # name NOT LIKE 'Vin%'
Filter.contains("tags", "vip")               # tags contains 'vip'
Filter.not_contains("tags", "x")             # tags not contains 'x'

FilterGroup Methods

group = (
    FilterGroup.empty()
    .add_filter_equal("status", "active")
    .add_filter_greater_than("age", 18)
    .add_filter_in("role", ["admin", "moderator"])
)

Available methods: add_filter_equal, add_filter_not_equal, add_filter_greater_than, add_filter_greater_or_equal_than, add_filter_less_than, add_filter_less_or_equal_than, add_filter_in, add_filter_not_in, add_filter_like, add_filter_not_like, add_filter_contains, add_filter_not_contains.

Repository Integration

customers = customer_repository.match(criteria)

Immutability

All classes are immutable frozen dataclasses. Methods return new instances:

c1 = Criteria()
c2 = c1.filter("name", "==", "Vincent")

assert c1 is not c2
assert len(c1.filters) == 0
assert len(c2.filters) == 1

Migration from v0.x

v1.0 introduces breaking changes:

Immutability

# Old (v0.x) - mutation pattern
c = Criteria()
c.filter("name", "==", "Vincent")  # mutated c

# New (v1.x) - immutable, must reassign
c = Criteria()
c = c.filter("name", "==", "Vincent")  # returns new instance

Filter Factory Names

# Old
Filter.eq("name", "v")
Filter.neq("name", "v")
Filter.gt("age", 18)
Filter.gte("age", 18)
Filter.lt("age", 65)
Filter.lte("age", 65)

# New (aligned with PHP version)
Filter.equal("name", "v")
Filter.not_equal("name", "v")
Filter.greater_than("age", 18)
Filter.greater_or_equal_than("age", 18)
Filter.less_than("age", 65)
Filter.less_or_equal_than("age", 65)

Order.by is now tuple

# Old
Order.desc(["name", "age"])

# New
Order.desc(("name", "age"))

Criteria operators only accept Criteria

# Old - operators accepted Filter/FilterGroup
c = Criteria() | Filter.equal("a", 1)

# New - use with_filter_group instead
c = Criteria().with_filter_group(FilterGroup.create(Filter.equal("a", 1)))

# Operators only work between Criteria objects
c1 = Criteria().with_filter_group(group1)
c2 = Criteria().with_filter_group(group2)
combined = c1 | c2  # OK
merged = c1 & c2    # OK

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

complex_heart_criteria-1.0.0.tar.gz (10.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

complex_heart_criteria-1.0.0-py3-none-any.whl (7.2 kB view details)

Uploaded Python 3

File details

Details for the file complex_heart_criteria-1.0.0.tar.gz.

File metadata

  • Download URL: complex_heart_criteria-1.0.0.tar.gz
  • Upload date:
  • Size: 10.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for complex_heart_criteria-1.0.0.tar.gz
Algorithm Hash digest
SHA256 9e6726f467e6c4a0d7bffa2fd11d1a3a9964f9bfa9edae3ec6d3538b75efd4cf
MD5 8f25595a3c9ac07e63842034ca56b4e8
BLAKE2b-256 5ab4ba17f120e796ca39b44569974370c65183592fcaa83f5d5fdded9af58dc5

See more details on using hashes here.

Provenance

The following attestation bundles were made for complex_heart_criteria-1.0.0.tar.gz:

Publisher: release.yml on ComplexHeart/py-criteria

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file complex_heart_criteria-1.0.0-py3-none-any.whl.

File metadata

File hashes

Hashes for complex_heart_criteria-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 d84616db3e48a07f4683ceeba30389d03234ff655b9c148353131c550eedceaa
MD5 562e2e2f6caffaa51f06647337010262
BLAKE2b-256 f1ef184508e14c112ad98057745839675bdc0422daec9ca2b39b2837041c4c31

See more details on using hashes here.

Provenance

The following attestation bundles were made for complex_heart_criteria-1.0.0-py3-none-any.whl:

Publisher: release.yml on ComplexHeart/py-criteria

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page