A typed, injection-safe SQL query builder with a pluggable connection boundary and a dependency-free in-memory backend.
///|
let age : Column[Int] = Column::new("users", "age")
///|
let stmt = Select::from("users")
.where_(age.gte(18))
.order_by(age.desc())
.limit(10)
.build()
// stmt.to_sql() == SELECT * FROM "users" WHERE "users"."age" >= ? ORDER BY "users"."age" DESC LIMIT 10
// stmt.to_params() == [Value::int(18)]moon test # 48 tests on wasm-gc: SQL rendering, errors, CRUD, joins, subqueries
moon test --target native # + 3 SQLite tests (CRUD, null/float, transactions)
moon run cmd/main # in-memory demo: build -> execute -> rows
moon run cmd/sqlite_demo --target native # the same demo against SQLite///|
let id : Column[Int] = Column::new("users", "id")
///|
let email : Column[String] = Column::new("users", "email")
// where id = 1 AND (email LIKE '%@example.com' OR email IS NULL)
///|
let cond = id.eq(1).and_(email.like("%@example.com").or_(email.is_null()))///|
let stmt = Select::from("orders")
.group_by(Column::new("orders", "status"))
.count()
.build()
// SELECT "orders"."status", COUNT(*) FROM "orders" GROUP BY "orders"."status"///|
let user_id : Column[Int] = Column::new("orders", "user_id")
///|
let stmt = Select::from("orders")
.left_join("users", user_id.eq(Column::new("users", "id")))
.build()
// SELECT * FROM "orders" LEFT JOIN "users" ON "orders"."user_id" = "users"."id"
// `.join` is the inner join; `.left_join`, `.right_join`, and `.full_join`
// are the outer joins.///|
let user_id : Column[Int] = Column::new("orders", "user_id")
///|
let stmt = Select::from("users")
.where_(
Column::new("users", "id").in_select(
Select::from("orders").columns([user_id.to_ref()]),
),
)
.build()
// SELECT * FROM "users" WHERE "users"."id" IN (SELECT "orders"."user_id" FROM "orders")
// `Condition::exists(sub)` gives EXISTS; wrap in `.not_()` for NOT EXISTS.///|
let uid : Column[Int] = Column::new("users", "id")
///|
let ouid : Column[Int] = Column::new("orders", "user_id")
///|
let stmt = Select::from("users")
.where_(Condition::exists(Select::from("orders").where_(ouid.eq_col(uid))))
.build()
// SELECT * FROM "users" WHERE EXISTS (SELECT * FROM "orders" WHERE "orders"."user_id" = "users"."id")
///|
let age : Column[Int] = Column::new("users", "age")
// users whose age is above the average:
///|
let stmt2 = Select::from("users")
.where_(age.gt_sub(Select::from("users").avg(age)))
.build()
// SELECT * FROM "users" WHERE "users"."age" > (SELECT AVG("users"."age") FROM "users")///|
pub(open) trait Connection {
fn select(Self, Select) -> Array[Row] raise OrmError
fn insert(Self, Insert) -> ExecResult raise OrmError
fn update(Self, Update) -> ExecResult raise OrmError
fn delete(Self, Delete) -> ExecResult raise OrmError
}let db = Memory::new()
db.create_table("users", ["id", "name", "age"])
db.insert(Insert::into("users").set(id.set(1)).set(name.set("alice")).set(age.set(30)))
let rows = db.select(Select::from("users").where_(age.gte(18)))let db = Sqlite::open(":memory:")
db.exec("CREATE TABLE users (id INTEGER, name TEXT, age INTEGER)")
db.insert(Insert::into("users").set(id.set(1)).set(name.set("alice")).set(age.set(30)))
let rows = db.select(Select::from("users").where_(age.gte(18)))///|
pub(open) trait Transactional {
fn begin(Self) -> Unit raise OrmError
fn commit(Self) -> Unit raise OrmError
fn rollback(Self) -> Unit raise OrmError
}pub(open) trait Connection {
fn select(Self, Select) -> Array[Row] raise OrmError
fn insert(Self, Insert) -> ExecResult raise OrmError
fn update(Self, Update) -> ExecResult raise OrmError
fn delete(Self, Delete) -> ExecResult raise OrmError
}pub suberror OrmError {
InvalidIdentifier(String)
InvalidQuery(String)
Backend(String)
}let email : Column[String] = Column::new("users", "email")pub enum Condition {
Compare(ColumnRef, CompareOp, Value)
CompareCol(ColumnRef, CompareOp, ColumnRef)
CompareSub(ColumnRef, CompareOp, Select)
In(ColumnRef, Array[Value])
InSelect(ColumnRef, Select)
IsNull(ColumnRef)
IsNotNull(ColumnRef)
Exists(Select)
And(Condition, Condition)
Or(Condition, Condition)
Not(Condition)
Raw(String)
} derive(Eq, Debug)impl Connection for MemoryInstall
Download zipA typed, injection-safe SQL query builder with a pluggable connection boundary and a dependency-free in-memory backend.