Skip to main content

A comprehensive projection system for defining how data should be shaped, aggregated, grouped, ordered, and limited in database queries

Project description

Fractal Projections

A comprehensive projection system for defining how data should be shaped, aggregated, grouped, ordered, and limited in database queries.

PyPI Version Build Status

This library complements fractal-specifications (which handles filtering) by providing database-agnostic data shaping capabilities.

Features

  • Database-Agnostic: Write projections once, use them across different databases
  • Type-Safe: Fully typed Python API for better IDE support and fewer errors
  • Flexible: Support for field selection, aggregations, grouping, ordering, and limiting
  • Multi-Database Support: Built-in builders for:
    • PostgreSQL
    • Django ORM
    • DuckDB
    • MongoDB
    • Firestore
    • Elasticsearch
  • Repository Integration: Ready-to-use mixins for fractal-repositories

Installation

pip install fractal-projections

For specific database support:

# PostgreSQL
pip install fractal-projections[postgres]

# Django ORM
pip install fractal-projections[django]

# DuckDB
pip install fractal-projections[duckdb]

# MongoDB
pip install fractal-projections[mongo]

# Firestore
pip install fractal-projections[firestore]

# Elasticsearch
pip install fractal-projections[elasticsearch]

# All databases
pip install fractal-projections[all]

Quick Start

from fractal_projections import (
    QueryProjection,
    FieldProjection,
    ProjectionList,
    OrderingProjection,
    OrderingList,
    LimitProjection,
)
from fractal_projections.builders import PostgresProjectionBuilder
from fractal_specifications.generic.operators import EqualsSpecification

# Define a database-agnostic projection
query = QueryProjection(
    filter=EqualsSpecification("status", "active"),
    projection=ProjectionList([
        FieldProjection("id"),
        FieldProjection("name"),
        FieldProjection("created_at"),
    ]),
    ordering=OrderingList([OrderingProjection("created_at", ascending=False)]),
    limiting=LimitProjection(10),
)

# Convert to database-specific query
builder = PostgresProjectionBuilder("users")
sql, params = builder.build(query)
print(sql)
# SELECT id, name, created_at FROM users WHERE status = %s ORDER BY created_at DESC LIMIT 10
# params = ['active']

Core Concepts

Field Projection

Select specific fields from your data:

from fractal_projections import FieldProjection, ProjectionList

projection = ProjectionList([
    FieldProjection("user_id"),
    FieldProjection("email"),
])

Distinct Selection

Select unique values using the distinct parameter:

from fractal_projections import FieldProjection, ProjectionList

# SELECT DISTINCT department FROM users
projection = ProjectionList(
    [FieldProjection("department")],
    distinct=True
)

Aggregation

Perform aggregations using available aggregate functions: COUNT, SUM, AVG, MIN, MAX, COUNT_DISTINCT:

from fractal_projections import AggregateProjection, AggregateFunction, ProjectionList

# Single aggregate
projection = ProjectionList([
    AggregateProjection(AggregateFunction.SUM, "revenue", "total_revenue")
])

# Multiple aggregates
projection = ProjectionList([
    AggregateProjection(AggregateFunction.COUNT, alias="total_count"),
    AggregateProjection(AggregateFunction.AVG, "salary", "avg_salary"),
    AggregateProjection(AggregateFunction.MIN, "created_at", "earliest"),
    AggregateProjection(AggregateFunction.MAX, "updated_at", "latest"),
    AggregateProjection(AggregateFunction.COUNT_DISTINCT, "user_id", "unique_users"),
])

Grouping

Group results by one or more fields:

from fractal_projections import GroupingProjection

grouping = GroupingProjection(["organization_id", "status"])

Ordering

Sort results by fields:

from fractal_projections import OrderingProjection, OrderingList

ordering = OrderingList([
    OrderingProjection("created_at", ascending=False),  # descending
    OrderingProjection("name", ascending=True),  # ascending
])

Limiting

Limit and offset results:

from fractal_projections import LimitProjection

limit = LimitProjection(limit=20, offset=10)

Architecture

The library follows a builder pattern:

  1. Projections: Database-agnostic definitions of how data should be shaped
  2. Builders: Database-specific converters that translate projections into native queries
  3. Mixins: Repository mixins for seamless integration with fractal-repositories
QueryProjection (agnostic)
    ↓
PostgresProjectionBuilder → SQL
DjangoProjectionBuilder → Django QuerySet
DuckDBProjectionBuilder → SQL
MongoProjectionBuilder → MongoDB Pipeline
FirestoreProjectionBuilder → Firestore Query
ElasticsearchProjectionBuilder → ES Query DSL

This separation allows you to:

  • Write business logic once
  • Switch databases without changing application code
  • Get optimized native queries for each backend

Repository Integration

Fractal Projections provides ready-to-use mixins for seamless integration with fractal-repositories. These mixins add projection capabilities to your repositories.

Available Mixins

  • PostgresProjectionsMixin - For PostgreSQL databases
  • DjangoProjectionsMixin - For Django ORM
  • DuckDBProjectionsMixin - For DuckDB databases
  • MongoProjectionsMixin - For MongoDB
  • FirestoreProjectionsMixin - For Firestore

Django Example

from fractal_repositories.contrib.django import DjangoModelRepositoryMixin
from fractal_projections import DjangoProjectionsMixin, QueryProjection, FieldProjection, ProjectionList
from fractal_specifications.generic.operators import EqualsSpecification

class UserRepository(DjangoModelRepositoryMixin, DjangoProjectionsMixin):
    entity = User
    django_model = DjangoUserModel

# Use the repository with projections
repo = UserRepository()

# Define a projection query
query = QueryProjection(
    filter=EqualsSpecification("is_active", True),
    projection=ProjectionList([
        FieldProjection("id"),
        FieldProjection("email"),
        FieldProjection("username"),
    ]),
)

# Execute the query using the mixin
results = list(repo.find_with_projection(query))
# Returns: [{'id': 1, 'email': 'user@example.com', 'username': 'user1'}, ...]

# Count results
count = repo.count_with_projection(query)

# Get query explanation
explanation = repo.explain_query(query)

PostgreSQL Example

from fractal_repositories.contrib.postgres import PostgresRepositoryMixin
from fractal_projections import PostgresProjectionsMixin, QueryProjection

class ProductRepository(PostgresRepositoryMixin, PostgresProjectionsMixin):
    entity = Product
    table_name = "products"

repo = ProductRepository(connection)
results = list(repo.find_with_projection(query))

Mixin Methods

All projection mixins provide these methods:

  • find_with_projection(query_projection) - Execute query and return results
  • count_with_projection(query_projection) - Count matching records
  • explain_query(query_projection) - Get query execution plan (for debugging/optimization)

Advanced Usage

See the examples.py file for comprehensive examples including:

  • Complex aggregations with grouping
  • Multi-field ordering
  • Combining filters with projections
  • Database-specific optimizations

Development

# Clone the repository
git clone https://github.com/Fractal-Forge/fractal-projections.git
cd fractal-projections

# Install development dependencies
pip install -e ".[dev]"

# Run tests
pytest

# Format code
black .
isort .
ruff check --fix .

# Lint code
ruff check .
mypy fractal_projections

License

MIT License - see LICENSE file for details

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

Related Projects

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

fractal_projections-0.3.1.tar.gz (51.9 kB view details)

Uploaded Source

Built Distribution

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

fractal_projections-0.3.1-py3-none-any.whl (36.2 kB view details)

Uploaded Python 3

File details

Details for the file fractal_projections-0.3.1.tar.gz.

File metadata

  • Download URL: fractal_projections-0.3.1.tar.gz
  • Upload date:
  • Size: 51.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: python-requests/2.32.5

File hashes

Hashes for fractal_projections-0.3.1.tar.gz
Algorithm Hash digest
SHA256 27d880a52590f2a3d3a1e770e3700081a1dac2ecf6901d0b2da2eed25a714e16
MD5 624448633315c2d2259b4b23c75eae68
BLAKE2b-256 fd00cc5a9e8a90c87097748e73acd33223bb5c59577b88097196568ca12a3c9a

See more details on using hashes here.

File details

Details for the file fractal_projections-0.3.1-py3-none-any.whl.

File metadata

File hashes

Hashes for fractal_projections-0.3.1-py3-none-any.whl
Algorithm Hash digest
SHA256 a2f8665e327d8143529c8f35a5f3c00d412a30eae89c2082a355888aa42361cb
MD5 9587cd660e5db0eebd86970eb3576c88
BLAKE2b-256 a186d567ec84fd4a7d123bee5a57242bb39ee3572c2000e3e00e344d4a751597

See more details on using hashes here.

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