A powerful, Supabase-inspired query builder for PostgreSQL with comprehensive analytics capabilities.
- Quick Start
- Basic CRUD Operations
- Filtering & Conditions
- Joins
- Analytics & Aggregations
- Date/Time Functions
- Window Functions
- Advanced Features
- Examples
- API Reference
from src.db.postgres.postgres import connection as db
# Basic query
result = db.table("users").select("*").execute()
users = result.data # List of dictionaries
count = result.count # Number of results# Select all columns
result = db.table("users").select("*").execute()
# Select specific columns
result = db.table("users").select("id", "name", "email").execute()
# Select with list
result = db.table("users").select(["id", "name"]).execute()
# Select distinct
result = db.table("users").select("email").distinct().execute()
# Select with limit and offset
result = db.table("users").select("*").limit(10).offset(20).execute()
# Select with range (Supabase-style)
result = db.table("users").select("*").range(0, 9).execute() # First 10 items# Insert single row
result = db.table("users").insert({
"name": "John Doe",
"email": "john@example.com",
"status": "active"
}).execute()
# Insert multiple rows
result = db.table("users").insert([
{"name": "John", "email": "john@example.com"},
{"name": "Jane", "email": "jane@example.com"}
]).execute()
# Insert and return data
result = db.table("users").insert({
"name": "John",
"email": "john@example.com"
}).returning("*").execute()
inserted_user = result.data[0]# Update single row (requires WHERE for safety)
result = db.table("users").update({
"status": "inactive",
"updated_at": "NOW()"
}).eq("id", user_id).execute()
# Update multiple rows
result = db.table("users").update({
"status": "active"
}).in_("id", [1, 2, 3]).execute()
# Update and return data
result = db.table("users").update({
"status": "active"
}).eq("id", user_id).returning("*").execute()
updated_user = result.data[0]# Delete single row (requires WHERE for safety)
result = db.table("users").delete().eq("id", user_id).execute()
# Delete multiple rows
result = db.table("users").delete().in_("id", [1, 2, 3]).execute()
# Delete and return data
result = db.table("users").delete().eq("id", user_id).returning("*").execute()
deleted_user = result.data[0]# Equals
result = db.table("users").select("*").eq("status", "active").execute()
# Not equals
result = db.table("users").select("*").neq("role", "admin").execute()
# Greater than
result = db.table("orders").select("*").gt("total", 100).execute()
# Greater than or equal
result = db.table("orders").select("*").gte("total", 100).execute()
# Less than
result = db.table("orders").select("*").lt("total", 1000).execute()
# Less than or equal
result = db.table("orders").select("*").lte("total", 1000).execute()# LIKE (case-sensitive)
result = db.table("users").select("*").like("name", "John%").execute()
# ILIKE (case-insensitive)
result = db.table("users").select("*").ilike("email", "%@gmail.com").execute()# IN
result = db.table("users").select("*").in_("id", [1, 2, 3, 4, 5]).execute()
# NOT IN
result = db.table("users").select("*").not_in("status", ["deleted", "banned"]).execute()# IS NULL
result = db.table("users").select("*").is_null("deleted_at").execute()
# IS NOT NULL
result = db.table("users").select("*").is_not_null("email").execute()# BETWEEN
result = db.table("orders").select("*").between("total", 100, 500).execute()
# Date range
from datetime import datetime
result = db.table("orders").select("*").between(
"created_at",
datetime(2024, 1, 1),
datetime(2024, 12, 31)
).execute()# Multiple conditions (AND by default)
result = db.table("users").select("*")\
.eq("status", "active")\
.neq("role", "admin")\
.is_not_null("email")\
.execute()
# Custom WHERE
result = db.table("orders").select("*")\
.where("total", ">", 100)\
.where("status", "=", "completed")\
.execute()# Search across multiple columns
result = db.table("users").select("*")\
.search("john", "first_name", "last_name", "email")\
.execute()result = db.table("posts").select("*")\
.inner_join("users", "posts.user_id = users.id")\
.execute()result = db.table("orders").select("*")\
.left_join("customers", "orders.customer_id = customers.id")\
.execute()result = db.table("orders").select("*")\
.right_join("customers", "orders.customer_id = customers.id")\
.execute()result = db.table("orders").select("*")\
.full_join("customers", "orders.customer_id = customers.id")\
.execute()result = db.table("orders").select("*")\
.left_join("customers", "orders.customer_id = customers.id")\
.left_join("products", "orders.product_id = products.id")\
.execute()# Count
result = db.table("users").count("*").execute()
total_count = result.data[0]['count']
# Count with condition
result = db.table("users").count("*").eq("status", "active").execute()
# Sum
result = db.table("orders").select("SUM(total) as total_revenue").execute()
# OR
result = db.table("orders").select("*").sum("total", "total_revenue").execute()
revenue = result.data[0]['total_revenue']
# Average
result = db.table("orders").select("*").avg("total", "avg_order_value").execute()
avg_value = result.data[0]['avg_order_value']
# Minimum
result = db.table("orders").select("*").min("total", "min_order").execute()
# Maximum
result = db.table("orders").select("*").max("total", "max_order").execute()
# Count distinct
result = db.table("orders").select("*").count_distinct("user_id", "unique_customers").execute()# Group by single column
result = db.table("orders").select("user_id", "SUM(total) as total_spent")\
.group_by("user_id")\
.execute()
# Group by multiple columns
result = db.table("orders").select("user_id", "status", "COUNT(*) as count")\
.group_by("user_id", "status")\
.execute()
# Group by with aggregations
result = db.table("orders").select("user_id")\
.sum("total", "total_spent")\
.count("*", "order_count")\
.avg("total", "avg_order")\
.group_by("user_id")\
.order_by("total_spent", ascending=False)\
.execute()# Having clause (filter aggregated results)
result = db.table("orders").select("user_id", "SUM(total) as total_spent")\
.group_by("user_id")\
.having("total_spent", ">", 1000)\
.execute()# Simple CASE WHEN
result = db.table("users").select("*")\
.case_when("status = 'active'", "'1'", "'0'", "is_active")\
.execute()
# Multiple CASE statements
result = db.table("orders").select("*")\
.case_when("total > 1000", "'high'", "'normal'", "order_category")\
.case_when("status = 'completed'", "1", "0", "is_completed")\
.execute()
# CASE with COUNT
result = db.table("orders").select(
"COUNT(CASE WHEN status = 'completed' THEN 1 END) as completed_count",
"COUNT(CASE WHEN status = 'pending' THEN 1 END) as pending_count"
).execute()# Group by day
result = db.table("orders").select("*")\
.date_trunc("day", "created_at", "order_date")\
.sum("total", "daily_revenue")\
.group_by("order_date")\
.order_by("order_date")\
.execute()
# Group by month
result = db.table("orders").select("*")\
.date_trunc("month", "created_at", "order_month")\
.sum("total", "monthly_revenue")\
.count("*", "order_count")\
.group_by("order_month")\
.order_by("order_month")\
.execute()
# Group by week
result = db.table("orders").select("*")\
.date_trunc("week", "created_at", "order_week")\
.sum("total", "weekly_revenue")\
.group_by("order_week")\
.execute()
# Available truncation periods:
# 'year', 'quarter', 'month', 'week', 'day', 'hour', 'minute'# Extract year
result = db.table("orders").select("*")\
.date_part("year", "created_at", "order_year")\
.execute()
# Extract month
result = db.table("orders").select("*")\
.extract("month", "created_at", "order_month")\
.execute()
# Extract day of week
result = db.table("orders").select("*")\
.date_part("dow", "created_at", "day_of_week")\
.execute()from datetime import datetime, timedelta
# Last 30 days
thirty_days_ago = datetime.now() - timedelta(days=30)
result = db.table("orders").select("*")\
.gte("created_at", thirty_days_ago)\
.execute()
# Date range
start_date = datetime(2024, 1, 1)
end_date = datetime(2024, 12, 31)
result = db.table("orders").select("*")\
.gte("created_at", start_date)\
.lte("created_at", end_date)\
.execute()# Number rows within partition
result = db.table("orders").select("*")\
.row_number(partition_by="user_id", order_by="created_at DESC", alias="row_num")\
.execute()
# Get latest order per user
result = db.table("orders").select("*")\
.row_number(partition_by="user_id", order_by="created_at DESC", alias="rn")\
.execute()
# Filter to get only row_num = 1
latest_orders = [row for row in result.data if row['rn'] == 1]# Rank orders by total
result = db.table("orders").select("*")\
.rank(order_by="total DESC", alias="order_rank")\
.execute()
# Dense rank (no gaps)
result = db.table("orders").select("*")\
.dense_rank(order_by="total DESC", alias="order_dense_rank")\
.execute()# Previous value
result = db.table("sales").select("*")\
.lag("revenue", offset=1, partition_by="region", order_by="month", alias="prev_revenue")\
.execute()
# Next value
result = db.table("sales").select("*")\
.lead("revenue", offset=1, partition_by="region", order_by="month", alias="next_revenue")\
.execute()
# Calculate growth
result = db.table("sales").select("*")\
.date_trunc("month", "date", "month")\
.sum("revenue", "monthly_revenue")\
.lag("monthly_revenue", offset=1, order_by="month", alias="prev_month")\
.group_by("month")\
.execute()# Custom window function
result = db.table("orders").select("*")\
.window(
"SUM(total) OVER (PARTITION BY user_id ORDER BY created_at)",
alias="running_total"
)\
.execute()# Single CTE
recent_users = db.table("users").select("*").gte("created_at", "2024-01-01")
result = db.table("orders").select("*")\
.with_cte("recent_users", recent_users)\
.inner_join("recent_users", "orders.user_id = recent_users.id")\
.execute()
# Multiple CTEs
active_users = db.table("users").select("*").eq("status", "active")
recent_orders = db.table("orders").select("*").gte("created_at", "2024-01-01")
result = db.table("payments").select("*")\
.with_cte("active_users", active_users)\
.with_cte("recent_orders", recent_orders)\
.execute()# UNION
query1 = db.table("users").select("id", "name", "email")
query2 = db.table("admins").select("id", "name", "email")
result = query1.union(query2).execute()
# UNION ALL (keeps duplicates)
result = query1.union_all(query2).execute()# Complex analytics query
result = db.table("orders").select("*")\
.date_trunc("month", "created_at", "month")\
.sum("total", "monthly_revenue")\
.count("*", "order_count")\
.count_distinct("user_id", "unique_customers")\
.avg("total", "avg_order_value")\
.group_by("month")\
.having("monthly_revenue", ">", 10000)\
.order_by("month")\
.execute()# Get user statistics
result = db.table("users").select("*")\
.count("*", "total_users")\
.count_distinct("country", "countries")\
.sum("CASE WHEN status = 'active' THEN 1 ELSE 0 END", "active_users")\
.execute()
stats = result.data[0]# Monthly revenue with growth
result = db.table("orders").select("*")\
.date_trunc("month", "created_at", "month")\
.sum("total", "revenue")\
.lag("revenue", offset=1, order_by="month", alias="prev_revenue")\
.case_when("prev_revenue > 0",
"((revenue - prev_revenue) / prev_revenue * 100)",
"0",
"growth_percent")\
.group_by("month")\
.order_by("month")\
.execute()# Top 10 customers by spending
result = db.table("orders").select("user_id")\
.sum("total", "total_spent")\
.count("*", "order_count")\
.group_by("user_id")\
.order_by("total_spent", ascending=False)\
.limit(10)\
.execute()# Daily metrics for dashboard
result = db.table("orders").select("*")\
.date_trunc("day", "created_at", "date")\
.sum("total", "daily_revenue")\
.count("*", "order_count")\
.count_distinct("user_id", "unique_customers")\
.avg("total", "avg_order")\
.group_by("date")\
.order_by("date")\
.limit(30)\
.execute()# User cohort by signup month
cohort_query = db.table("users").select("*")\
.date_trunc("month", "created_at", "signup_month")
result = db.table("orders").select("*")\
.with_cte("cohorts", cohort_query)\
.inner_join("cohorts", "orders.user_id = cohorts.id")\
.date_trunc("month", "orders.created_at", "order_month")\
.select("signup_month", "order_month")\
.count("*", "orders")\
.sum("total", "revenue")\
.group_by("signup_month", "order_month")\
.order_by("signup_month", "order_month")\
.execute()select(*fields)- Select columnsinsert(data)- Insert rowsupdate(data)- Update rowsdelete()- Delete rowsreturning(fields)- Return data after insert/update/delete
where(column, operator, value)- Custom WHERE conditioneq(column, value)- Equalsneq(column, value)- Not equalsgt(column, value)- Greater thangte(column, value)- Greater than or equallt(column, value)- Less thanlte(column, value)- Less than or equallike(column, pattern)- LIKE pattern matchilike(column, pattern)- Case-insensitive LIKEin_(column, values)- IN listnot_in(column, values)- NOT IN listis_null(column)- IS NULLis_not_null(column)- IS NOT NULLbetween(column, start, end)- BETWEEN rangesearch(term, *columns)- Search across columns
inner_join(table, on)- INNER JOINleft_join(table, on)- LEFT JOINright_join(table, on)- RIGHT JOINfull_join(table, on)- FULL OUTER JOIN
order(column, ascending, nulls_first)- ORDER BYorder_by(column, ascending)- ORDER BY aliaslimit(count)- LIMIToffset(count)- OFFSETrange(from_index, to_index)- Range (Supabase-style)
count(column)- COUNTsum(column, alias)- SUMavg(column, alias)- AVGmin(column, alias)- MINmax(column, alias)- MAXcount_distinct(column, alias)- COUNT DISTINCT
group_by(*columns)- GROUP BYhaving(column, operator, value)- HAVING clause
date_trunc(field, column, alias)- DATE_TRUNCdate_part(field, column, alias)- DATE_PARTextract(field, column, alias)- EXTRACT
window(function, partition_by, order_by, alias)- Custom window functionrow_number(partition_by, order_by, alias)- ROW_NUMBERrank(partition_by, order_by, alias)- RANKdense_rank(partition_by, order_by, alias)- DENSE_RANKlag(column, offset, partition_by, order_by, alias)- LAGlead(column, offset, partition_by, order_by, alias)- LEAD
case_when(condition, then_value, else_value, alias)- CASE WHENdistinct(value)- DISTINCTwith_cte(name, query_builder)- Common Table Expressionunion(query_builder, all)- UNIONunion_all(query_builder)- UNION ALL
execute()- Execute query and return QueryResult
class QueryResult:
data: List[Dict[str, Any]] # Query results as list of dictionaries
count: Optional[int] # Result count (for SELECT queries)- Always use WHERE for UPDATE/DELETE - Prevents accidental mass updates
- Use parameterized queries - All values are automatically parameterized
- Use aliases for aggregations - Makes result access easier
- Group related operations - Use GROUP BY for analytics
- Use CTEs for complex queries - Improves readability
- Index frequently filtered columns - Improves query performance
- Use date_trunc for time-series - More efficient than date extraction
- Limit result sets - Always use
.limit()for large datasets - Use indexes - Ensure columns in WHERE, JOIN, ORDER BY are indexed
- **Avoid SELECT *** - Select only needed columns
- Use EXPLAIN - Analyze query plans for optimization
- Batch operations - Use bulk INSERT for multiple rows
try:
result = db.table("users").select("*").eq("id", user_id).execute()
if result.data:
user = result.data[0]
else:
print("User not found")
except Exception as e:
logger.error(f"Query failed: {e}")
raiseThis query builder is part of the KLIKYAI-V3 project.