SQL Macros (V2)
January 19, 2026 ยท View on GitHub
SQL Macros in SnackBase allow you to define reusable permission logic via text substitution or custom SQL subqueries. They are expanded before your rule expressions are compiled to SQL, making them highly efficient and compatible with Row-Level Security (RLS).
1. Built-in Macros
SnackBase provides several optimized macros for common scenarios. These act as text fragments that are substituted into your rule.
@owns_record(field = "created_by")
Checks if the current user ID matches a field on the record.
- Expands to:
[field] = @request.auth.id - Default Use:
@owns_record()->created_by = @request.auth.id - Custom Use:
@owns_record("owner_id")->owner_id = @request.auth.id
@is_creator()
An alias for @owns_record().
- Expands to:
created_by = @request.auth.id
@is_public()
Check if a record is marked as public.
- Expands to:
public = true
@has_role(role_name)
Check if the current user has a specific role.
- Example:
@has_role("admin") - Expands to:
@request.auth.role = "admin"
2. Custom SQL Macros (Subqueries)
Custom macros allow you to define complex relationship checks using raw SQL. These are stored in the database and executed as SQL Subqueries.
Creating a Custom Macro
When creating a macro, you define a SQL template. You can use positional parameters like $1, $2 which will be replaced by arguments during rule execution.
Example: @is_project_member(project_id)
- Name:
is_project_member - SQL Query:
SELECT count(*) > 0 FROM project_members WHERE project_id = \$1 AND user_id = @request.auth.id
Using in Rules
Macros can be combined with standard logic:
# Allow access if user is admin OR they own the record
@has_role("admin") || @owns_record()
# Allow access if user is a member of the project
@is_project_member(project_id)
API Management
List Macros
GET /api/v1/macros
Create Macro
POST /api/v1/macros
Payload:
{
"name": "has_active_subscription",
"description": "Checks if user has a paid plan",
"sql_query": "SELECT count(*) > 0 FROM subscriptions WHERE user_id = @request.auth.id AND status = 'active'"
}
Best Practices
- Return Boolean: Custom SQL macros must return a boolean (usually
count(*) > 0orEXISTS(...)). - Performance: Macros are executed as subqueries. Ensure the underlying tables (e.g.,
project_members.user_id) are indexed. - Naming: Use descriptive names like
can_edit_documentoris_account_owner. - Parameter Safety: Always use
$1,$2for arguments; SnackBase handles the substitution safely. - Multi-tenancy: Note that
@request.auth.idautomatically respects isolation when combined with RLS.