Expand description
Core primitives for keelson.
Everything else — the three dialect crates, the generated models, the backend adapters — is built out of what is defined here:
Value, the bound argument. keelson carries its own value enum instead of being generic over a driver’s parameter type, which keepsExpressionfree of type parameters and makes a built query’s arguments inspectable.Dialect, the per-database syntax decisions, and nothing else.Expression, a fragment that can render itself, andSqlWriter, which owns the SQL buffer, the argument list and the placeholder counter together so that nesting re-indexes for free.Mod, the composition unit: a tuple of mods is a mod, and so isOption<M>,Vec<M>and[M; N].QueryandQueryType, the little a runnable statement owes the layers above.
Two properties are worth stating up front because the rest of the design leans
on them. Rendering is infallible — write_sql returns nothing, and the one
genuine failure (a named argument asked of a dialect without them) is recorded
on the writer and surfaced once, by build. And no public type carries a
lifetime parameter: identifiers and raw SQL are stored as
Cow<'static, str>, so a query type is SelectQuery, never SelectQuery<'a>.
The only lifetime in this crate is the transient one on SqlWriter, which
borrows the dialect for the duration of a single build.
Building is entirely synchronous and driver-independent: it produces a String
and a Vec<Value> and nothing more.
#[derive(Debug)]
struct AgeAtLeast(i32);
impl Expression for AgeAtLeast {
fn write_sql(&self, w: &mut SqlWriter<'_>) {
w.push_str("(");
w.push_quoted(&["age"]);
w.push_str(" >= ");
w.push_arg(self.0);
w.push_str(")");
}
}
let (sql, args) = build(&Psql, &AgeAtLeast(21))?;
assert_eq!(sql, r#"("age" >= $1)"#);
assert_eq!(args, vec![Value::I32(21)]);§Where this sits
Layer 0 of keelson: the vocabulary, and the only crate every other one
depends on. Above it sit the three Layer 1 dialects
(keelson-psql, keelson-mysql,
keelson-sqlite), which is where a user starts —
a statement type comes from a dialect, never from here. Layer 2
(keelson-exec) runs what build returns, and Layer 3
(keelson-models) is written against the
clause traits defined here. The whole map, and one dependency line for
it, is the keelson facade crate.
Modules§
- clause
- The SQL clauses the three dialects share, as data.
- expr
- Expressions: one enum, its rendering, and the operator chain.
Structs§
- ExprFn
- An expression from a closure, for fragments with no natural struct — notably generated code.
- ModFn
- A
Modfrom a closure. - RawQuery
- A whole statement, written by hand.
- SqlWriter
- The SQL buffer, the bound arguments, the placeholder counter and the dialect, together.
Enums§
- Error
- Everything that can go wrong while building a query.
- Query
Type - Which statement a query renders.
- Value
- A bound argument.
Traits§
- Build
Mod - A mod that runs when the query is built rather than when it is assembled.
- Custom
Value - A dialect-specific value that keelson itself never interprets.
- Dialect
- The per-database syntax an expression needs in order to render itself.
- Expression
- A fragment of SQL that can render itself.
- From
Value - Conversion out of a value read back from the database.
- Mod
- Something that modifies a query in place.
- Query
- A complete, runnable statement.
- Query
Extensions - The execution layer’s extension points, hung on the query rather than discovered by downcasting.
- ToValue
- Conversion into a bound argument.
Functions§
- build
- Render an expression to SQL and arguments, numbering placeholders from 1.
- build_
from buildwith a different first placeholder position — bob’sBuildN.- dyn_
expr - Erase an expression into a
DynExpr. - expr_fn
- Wrap a closure as an
Expression. - from_
value_ array - Read a
Value::Arrayelement-wise. - mod_fn
- Wrap a closure as a
Mod.