FireProx Phase 2.5 Feature Demo: Query Builder¶
This notebook demonstrates the Phase 2.5 query builder features:
- Chainable Queries -
.where().order_by().limit()interface - Multiple Execution Methods -
.get()for lists,.stream()for iterators - Collection-Level Methods - Start queries directly from collections
- Immutable Pattern - Safe query reuse and composition
The demo is split into two sections:
- Synchronous API examples
- Asynchronous API examples
Setup¶
Import the necessary modules for both sync and async APIs.
from fire_prox import AsyncFireProx, FireProx
from fire_prox.testing import async_demo_client, demo_client
Initialize Sync Client and Create Sample Data¶
# Create sync client and collection
client = demo_client()
db = FireProx(client)
users = db.collection('phase2_5_demo_users')
# Create sample data
sample_users = [
{'name': 'Ada Lovelace', 'birth_year': 1815, 'country': 'England', 'field': 'Mathematics', 'score': 95},
{'name': 'Charles Babbage', 'birth_year': 1791, 'country': 'England', 'field': 'Engineering', 'score': 90},
{'name': 'Alan Turing', 'birth_year': 1912, 'country': 'England', 'field': 'Computer Science', 'score': 98},
{'name': 'Grace Hopper', 'birth_year': 1906, 'country': 'USA', 'field': 'Computer Science', 'score': 92},
{'name': 'John von Neumann', 'birth_year': 1903, 'country': 'Hungary', 'field': 'Mathematics', 'score': 97},
]
for user_data in sample_users:
user = users.new()
for key, value in user_data.items():
setattr(user, key, value)
user.save()
print(f"Created {len(sample_users)} sample users")
Created 5 sample users
Feature 1: Simple where() Queries¶
Filter documents with a single condition.
# Find users born after 1900
query = users.where('birth_year', '>', 1900)
results = query.get()
print(f"\nUsers born after 1900: {len(results)} found")
for user in results:
print(f" - {user.name} ({user.birth_year})")
Users born after 1900: 3 found - John von Neumann (1903) - Grace Hopper (1906) - Alan Turing (1912)
# Find users from England
query = users.where('country', '==', 'England')
results = query.get()
print(f"\nUsers from England: {len(results)} found")
for user in results:
print(f" - {user.name}")
Users from England: 3 found - Charles Babbage - Ada Lovelace - Alan Turing
Feature 2: Chained Queries¶
Combine multiple conditions by chaining where() calls.
# Find English users in Computer Science
query = (users
.where('country', '==', 'England')
.where('field', '==', 'Computer Science'))
results = query.get()
print(f"\nEnglish Computer Scientists: {len(results)} found")
for user in results:
print(f" - {user.name} ({user.birth_year})")
English Computer Scientists: 1 found - Alan Turing (1912)
Feature 3: Ordering Results¶
Sort query results with order_by().
# Get all users ordered by birth year (ascending)
query = users.order_by('birth_year')
results = query.get()
print("\nUsers ordered by birth year (oldest first):")
for user in results:
print(f" {user.birth_year}: {user.name}")
Users ordered by birth year (oldest first): 1791: Charles Babbage 1815: Ada Lovelace 1903: John von Neumann 1906: Grace Hopper 1912: Alan Turing
# Get users ordered by score (descending)
query = users.order_by('score', direction='DESCENDING')
results = query.get()
print("\nUsers ordered by score (highest first):")
for user in results:
print(f" {user.score}: {user.name}")
Users ordered by score (highest first): 98: Alan Turing 97: John von Neumann 95: Ada Lovelace 92: Grace Hopper 90: Charles Babbage
Feature 4: Limiting Results¶
Paginate or get top N results with limit().
# Get top 3 scorers
query = users.order_by('score', direction='DESCENDING').limit(3)
results = query.get()
print("\nTop 3 scorers:")
for i, user in enumerate(results, 1):
print(f" {i}. {user.name} - Score: {user.score}")
Top 3 scorers: 1. Alan Turing - Score: 98 2. John von Neumann - Score: 97 3. Ada Lovelace - Score: 95
Feature 5: Complex Chained Queries¶
Combine where(), order_by(), and limit() for powerful queries.
# Get top 2 English users by score
query = (users
.where('country', '==', 'England')
.order_by('score', direction='DESCENDING')
.limit(2))
results = query.get()
print("\nTop 2 English users by score:")
for user in results:
print(f" - {user.name}: {user.score}")
Top 2 English users by score: - Alan Turing: 98 - Ada Lovelace: 95
Feature 6: Stream vs Get¶
Compare .get() (returns list) vs .stream() (returns iterator).
# Using .get() - returns a list
query = users.where('field', '==', 'Computer Science')
results = query.get()
print(f"\n.get() returned a {type(results).__name__} with {len(results)} items:")
for user in results:
print(f" - {user.name}")
.get() returned a list with 2 items: - Grace Hopper - Alan Turing
# Using .stream() - returns an iterator (more memory efficient)
query = users.where('field', '==', 'Computer Science')
stream = query.stream()
print(f"\n.stream() returned a {type(stream).__name__}:")
for user in stream:
print(f" - {user.name}")
print("\nNote: Stream is memory-efficient for large result sets!")
.stream() returned a generator: - Grace Hopper - Alan Turing Note: Stream is memory-efficient for large result sets!
Feature 7: Immutable Query Pattern¶
Queries can be safely reused and extended.
# Create a base query
base_query = users.where('country', '==', 'England')
# Extend it in different ways
top_3 = base_query.order_by('score', direction='DESCENDING').limit(3)
oldest = base_query.order_by('birth_year').limit(1)
# Base query is unchanged
print(f"\nAll English users: {len(base_query.get())} found")
print(f"Top 3 English users: {len(top_3.get())} found")
print(f"Oldest English user: {len(oldest.get())} found")
oldest_user = oldest.get()[0]
print(f"\nOldest English user: {oldest_user.name} ({oldest_user.birth_year})")
All English users: 3 found Top 3 English users: 3 found Oldest English user: 1 found Oldest English user: Charles Babbage (1791)
Feature 8: get_all() Method¶
Retrieve all documents in a collection.
# Get all users (no filtering)
print("\nAll users in collection:")
for user in users.get_all():
print(f" - {user.name} ({user.country}, {user.birth_year})")
All users in collection: - Grace Hopper (USA, 1906) - Charles Babbage (England, 1791) - John von Neumann (Hungary, 1903) - Ada Lovelace (England, 1815) - Alan Turing (England, 1912)
Part 2: Asynchronous API Examples¶
The following examples use the asynchronous AsyncFireProx API with async/await.
Initialize Async Client and Create Sample Data¶
# Create async client and collection
async_client = async_demo_client()
async_db = AsyncFireProx(async_client)
async_users = async_db.collection('phase2_5_demo_users_async')
# Create sample data
for user_data in sample_users:
user = async_users.new()
for key, value in user_data.items():
setattr(user, key, value)
await user.save()
print(f"Created {len(sample_users)} sample users (async)")
Created 5 sample users (async)
Feature 1: Simple where() Queries (Async)¶
# Find users born after 1900
query = async_users.where('birth_year', '>', 1900)
results = await query.get()
print(f"\nUsers born after 1900: {len(results)} found")
for user in results:
print(f" - {user.name} ({user.birth_year})")
Users born after 1900: 3 found - John von Neumann (1903) - Grace Hopper (1906) - Alan Turing (1912)
# Find users from England
query = async_users.where('country', '==', 'England')
results = await query.get()
print(f"\nUsers from England: {len(results)} found")
for user in results:
print(f" - {user.name}")
Users from England: 3 found - Ada Lovelace - Alan Turing - Charles Babbage
Feature 2: Chained Queries (Async)¶
# Find English users in Computer Science
query = (async_users
.where('country', '==', 'England')
.where('field', '==', 'Computer Science'))
results = await query.get()
print(f"\nEnglish Computer Scientists: {len(results)} found")
for user in results:
print(f" - {user.name} ({user.birth_year})")
English Computer Scientists: 1 found - Alan Turing (1912)
Feature 3: Ordering Results (Async)¶
# Get all users ordered by birth year (ascending)
query = async_users.order_by('birth_year')
results = await query.get()
print("\nUsers ordered by birth year (oldest first):")
for user in results:
print(f" {user.birth_year}: {user.name}")
Users ordered by birth year (oldest first): 1791: Charles Babbage 1815: Ada Lovelace 1903: John von Neumann 1906: Grace Hopper 1912: Alan Turing
# Get users ordered by score (descending)
query = async_users.order_by('score', direction='DESCENDING')
results = await query.get()
print("\nUsers ordered by score (highest first):")
for user in results:
print(f" {user.score}: {user.name}")
Users ordered by score (highest first): 98: Alan Turing 97: John von Neumann 95: Ada Lovelace 92: Grace Hopper 90: Charles Babbage
Feature 4: Limiting Results (Async)¶
# Get top 3 scorers
query = async_users.order_by('score', direction='DESCENDING').limit(3)
results = await query.get()
print("\nTop 3 scorers:")
for i, user in enumerate(results, 1):
print(f" {i}. {user.name} - Score: {user.score}")
Top 3 scorers: 1. Alan Turing - Score: 98 2. John von Neumann - Score: 97 3. Ada Lovelace - Score: 95
Feature 5: Complex Chained Queries (Async)¶
# Get top 2 English users by score
query = (async_users
.where('country', '==', 'England')
.order_by('score', direction='DESCENDING')
.limit(2))
results = await query.get()
print("\nTop 2 English users by score:")
for user in results:
print(f" - {user.name}: {user.score}")
Top 2 English users by score: - Alan Turing: 98 - Ada Lovelace: 95
Feature 6: Async Stream¶
Using async for with .stream() for memory efficiency.
# Using .get() - returns a list
query = async_users.where('field', '==', 'Computer Science')
results = await query.get()
print(f"\n.get() returned a {type(results).__name__} with {len(results)} items:")
for user in results:
print(f" - {user.name}")
.get() returned a list with 2 items: - Alan Turing - Grace Hopper
# Using .stream() - returns an async iterator
query = async_users.where('field', '==', 'Computer Science')
print("\n.stream() returns an async iterator:")
async for user in query.stream():
print(f" - {user.name}")
print("\nNote: Async stream is memory-efficient for large result sets!")
.stream() returns an async iterator: - Alan Turing - Grace Hopper Note: Async stream is memory-efficient for large result sets!
Feature 7: Immutable Query Pattern (Async)¶
# Create a base query
base_query = async_users.where('country', '==', 'England')
# Extend it in different ways
top_3 = base_query.order_by('score', direction='DESCENDING').limit(3)
oldest = base_query.order_by('birth_year').limit(1)
# Base query is unchanged
print(f"\nAll English users: {len(await base_query.get())} found")
print(f"Top 3 English users: {len(await top_3.get())} found")
print(f"Oldest English user: {len(await oldest.get())} found")
oldest_user = (await oldest.get())[0]
print(f"\nOldest English user: {oldest_user.name} ({oldest_user.birth_year})")
All English users: 3 found Top 3 English users: 3 found Oldest English user: 1 found Oldest English user: Charles Babbage (1791)
Feature 8: get_all() Method (Async)¶
# Get all users (no filtering)
print("\nAll users in collection:")
async for user in async_users.get_all():
print(f" - {user.name} ({user.country}, {user.birth_year})")
All users in collection:
- John von Neumann (Hungary, 1903) - Ada Lovelace (England, 1815) - Alan Turing (England, 1912) - Charles Babbage (England, 1791) - Grace Hopper (USA, 1906)
Summary¶
This demo showcased all Phase 2.5 query builder features:
✅ where(field, op, value) - Filter documents with conditions
✅ order_by(field, direction) - Sort results ascending or descending
✅ limit(count) - Paginate or get top N results
✅ Chainable Interface - Combine where(), order_by(), and limit()
✅ .get() - Execute query and get results as a list
✅ .stream() - Execute query and get memory-efficient iterator
✅ .get_all() - Retrieve all documents in a collection
✅ Immutable Pattern - Safely reuse and extend queries
All features work identically in both sync and async APIs!
Performance Benefits¶
- Code Reduction: 70% less boilerplate vs native API
- Readability: Natural, chainable interface
- Memory Efficiency: Stream large result sets
- Safety: Immutable pattern prevents bugs
Supported Operators¶
- Comparison:
==,!=,<,<=,>,>= - Set Operations:
in,not-in - Array Operations:
array-contains,array-contains-any
Learn More¶
See docs/PHASE2_5_IMPLEMENTATION_REPORT.md for complete documentation.