You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
We need to flesh out the Select query builder to support the full range of standard SQL SELECT capabilities, with specific parity for PostgreSQL features.
The goal is to allow users to construct complex queries using a fluent Rust API that mirrors the structure of the underlying SQL while maintaining type safety. The syntax should be approachable, similar to Python's sqlmodel.
Reference Syntax:
let users = User::select().filter(User::active().eq(true)).order_by(User::created_at().desc()).limit(10).fetch_all(&db).await?;
1. Basic Selection & Clauses
Projection (SELECT):
Default to * (all fields) if not specified.
Support selecting specific columns: .select_only(&[User::id(), User::name()]).
Distinct (DISTINCT):
.distinct(): Removes duplicate rows.
.distinct_on(User::column()): (Postgres) Keep the first row of each set of rows where the given expressions evaluate to equal.
Limit & Offset:
.limit(n: i64)
.offset(n: i64)
2. Filtering (WHERE)
The .filter() method should accept expressions generated by column helper methods. We need to implement the following traits/methods on Column types.
Labels:
enhancement,core,databaseDescription
We need to flesh out the
Selectquery builder to support the full range of standard SQLSELECTcapabilities, with specific parity for PostgreSQL features.The goal is to allow users to construct complex queries using a fluent Rust API that mirrors the structure of the underlying SQL while maintaining type safety. The syntax should be approachable, similar to Python's
sqlmodel.Reference Syntax:
1. Basic Selection & Clauses
Projection (
SELECT):Default to
*(all fields) if not specified.Support selecting specific columns:
.select_only(&[User::id(), User::name()]).Distinct (
DISTINCT):.distinct(): Removes duplicate rows..distinct_on(User::column()): (Postgres) Keep the first row of each set of rows where the given expressions evaluate to equal.Limit & Offset:
.limit(n: i64).offset(n: i64)2. Filtering (
WHERE)The
.filter()method should accept expressions generated by column helper methods. We need to implement the following traits/methods on Column types.Comparison Operators
.eq(val),.ne(val).gt(val),.gte(val),.lt(val),.lte(val).between(low, high),.not_between(low, high)Pattern Matching (String)
.like("%pattern%"),.not_like("%pattern%").ilike("%pattern%"),.not_ilike("%pattern%").starts_with(str)(Compiles toLIKE 'str%').ends_with(str)(Compiles toLIKE '%str').contains(str)(Compiles toLIKE '%str%')Nullability
.is_null(),.is_not_null()Set Operations
.is_in(vec![...]),.is_not_in(vec![...])Logical Combinators
The
.filter()method should implicitlyANDmultiple calls. We also need explicit combinators for complex logic within a single filter..and(expr).or(expr)(e.g.,User::age().lt(10).or(User::age().gt(60)))not(expr)3. Ordering (
ORDER BY)Direction:
.asc():ORDER BY col ASC.desc():ORDER BY col DESCNull Handling (Postgres):
.nulls_first().nulls_last()Chaining: Support multiple order clauses (e.g.,
.order_by(User::role().asc()).order_by(User::name().desc())).4. Grouping & Aggregation (
GROUP BY/HAVING).group_by(User::column()).having(expr)(Applies filters after grouping).count(),sum(),avg(),min(),max()5. Joins (
JOIN)Drafting initial support for joining other models.
.join::<OtherModel>(on_expr).left_join::<OtherModel>(on_expr).right_join::<OtherModel>(on_expr).full_join::<OtherModel>(on_expr)6. Locking (
FOR UPDATE)Essential for transactional integrity.
.for_update().for_no_key_update().skip_locked().nowait()7. Execution Methods
Finalisers that execute the built query.
.fetch_one(&db): ReturnsResult<T, Error>. Errors if 0 or >1 rows found..fetch_optional(&db): ReturnsResult<Option<T>, Error>. ReturnsNoneif 0 rows..fetch_all(&db): ReturnsResult<Vec<T>, Error>..stream(&db): Returnsimpl Stream<Item = Result<T, Error>>(Async iteration).Implementation Details & Questions
.eq(),.gt(), etc., are strictly parameterised ($1,$2) to prevent SQL injection.WHEREclause internally? (Likely an AST enum:And(Box<Expr>, Box<Expr>),Eq(Col, Val))..ilikeis only available on String columns and.gtonly on Numeric/Date columns?