F
FasORM
v0.1.0

Fluent Query Builder

FasORM features a chainable, lazy query builder. Queries are constructed fluently and hit the database only when executor methods (like get, first, count, or paginate) are awaited.

Constructing Queries

Start queries via Model.where(...) or Model.query():

Python
# Start query with where
query = User.where(is_active=True)

# Or start with query builder instance
query = User.query().where("age", ">=", 18)

Filtering Clause Methods

Where Clauses

Multiple signature options are supported for flexibility:

Python
# Keyword equality shorthand
users = await User.where(role="admin", is_active=True).get()

# Field, operator, value format
users = await User.where("age", ">=", 21).get()
users = await User.where("name", "like", "%Alice%").get()

# Two-argument implied equality format
users = await User.where("status", "approved").get()

Additional Filter Helpers

Method Description & Usage
.or_where(**kwargs) Adds an OR WHERE condition to the query.
.where_in(field, values) Matches values in list: .where_in("status", ["a", "b"])
.where_not_in(field, values) Excludes values in list: .where_not_in("role", ["banned"])
.where_null(field) Matches NULL columns: .where_null("deleted_at")
.where_not_null(field) Matches non-NULL columns: .where_not_null("verified_at")
.where_between(field, low, high) Range condition: .where_between("age", 18, 30)

Ordering, Limiting & Offsetting

Python
# Order by ascending or descending
users = await User.order_by("name", "asc").get()

# Latest / Oldest helpers
newest = await User.latest().get()        # Orders by created_at desc
oldest = await User.oldest("id").get()  # Orders by custom field asc

# Limit and offset
users = await User.limit(10).offset(20).get()
users = await User.take(5).skip(10).get()  # Aliases for limit/offset

Eager Loading & with_count

Eager Loading Relationships with with_()

Load related models efficiently in a single query using selectinload under the hood to prevent N+1 issues:

Python
users = await User.with_("posts", "roles").get()
# Access pre-loaded relations instantly without extra DB trips
print(users[0].posts)

Counting Related Records with with_count()

Compute related record counts efficiently via scalar subqueries. Attaches a <relation>_count attribute to result instances and serialization dictionaries:

Python
users = await User.with_count("posts").get()
print(users[0].posts_count)  # e.g. 5

# Serializes directly into dict/JSON
user_dicts = await User.with_count("posts").to_dict()
# -> [{"id": 1, "name": "Alice", "posts_count": 5}]

Aggregates & Pagination

Aggregates

Python
total = await User.with_("posts").where(is_active=True).count()
exists = await User.where(email="[email protected]").exists()
sum_val = await User.sum("age")
avg_val = await User.avg("age")
min_val = await User.min("created_at")
max_val = await User.max("age")

Pagination

Python
page = await User.where(is_active=True).paginate(per_page=15, page=1)

print(page.total)         # Total matching rows
print(page.last_page)     # Total number of pages
print(page.items)         # Model instances for page 1

# Serialize paginated response
page_dict = page.to_dict()
# -> {"data": [...], "meta": {"total": 100, "per_page": 15, "current_page": 1, "last_page": 7}}

Pluck & Chunk

Python
# Extract single column values as a list
emails = await User.pluck("email")
# -> ["[email protected]", "[email protected]"]

# Process large datasets in chunks
async for chunk in User.chunk(size=1000):
    for user in chunk:
        print(user.name)