qraft-core 0.1.2

Core type system, query model, decoding, and SQL lowering primitives for qraft.
Documentation
# qraft

`qraft` is a typed SQL query builder for rust, built around generated schema modules and `quex` for execution.

You define a rust struct, derive `Qraft`, and get a table handle, typed columns, and model helpers such as `query()`, `find()`, and `create()`. The point is simple: write query code in rust, keep column names and result shapes checked, and stop passing SQL around as loose strings unless you actually want raw SQL.

## What it covers

`qraft` handles the parts of query building that tend to get messy once a project grows:

- typed `select`, `insert`, `update`, and `delete` builders
- derive macros for models, row decoding, projections, pivots, and CTEs
- common table expressions
- aliasing for self-joins and readable multi-table queries
- optional soft-delete scopes and restore helpers
- `quex` pool and executor types re-exported from the top-level crate

## Install

Pick the features you need. Most projects will want `derive` plus one database backend.

```toml
[dependencies]
qraft = { version = "0.1.1", features = ["derive", "sqlite"] }
tokio = { version = "1", features = ["macros", "rt-multi-thread"] }
```

Feature flags:

- `derive`: enables `Qraft`, `Cte`, `FromRow`, `Projection`, `Insertable`, and `Pivot`
- `sqlite`, `postgres`, `mariadb`: enables the matching `quex` backend
- `soft-delete`: enables derived soft-delete scopes and restore helpers
- `chrono`, `serde_json`, `uuid`: enables optional type support
- `hash`: enables `Hashed`, a bcrypt-backed text wrapper for stored passwords

## Quick start

This is the core workflow. Derive `Qraft`, then build queries with the generated schema module.

```rust
use qraft::prelude::*;

#[derive(Debug, qraft::Qraft)]
struct User {
    id: i64,
    email: String,
    active: bool,
}

let sql = User::query()
    .filter(users::active.eq(true))
    .to_debug_sql::<qraft::Postgres>();

assert_eq!(
    sql,
    r#"select * from "users" where "users"."active" = $1; params=[true]"#
);
```

The derive generates a `users` module with:

- `users::table`
- typed column values such as `users::id` and `users::email`
- helpers on the model, including `User::query()`, `User::find(id)`, and `User::create(values)`

That gives you a fairly direct style of query code. You are still writing SQL-shaped logic, but with rust types attached to it.

## Running queries

`qraft` re-exports `quex`, so you can open a pool and execute queries from the same crate surface.

```rust
use qraft::prelude::*;
use qraft::quex;

#[derive(Debug, qraft::Qraft)]
struct AuditLog {
    id: i64,
    message: String,
}

# async fn run() -> qraft::Result<()> {
let pool = quex::Pool::connect("sqlite::memory:")?.build().await?;

quex::query(
    r#"
    create table audit_logs (
        id integer primary key,
        message text not null
    )
    "#,
)
.execute(&pool)
.await?;

AuditLog::create((
    audit_logs::id.eq(1),
    audit_logs::message.eq("created"),
))
.execute(&pool)
.await?;

let row = AuditLog::find(1).one(&pool).await?;
assert_eq!(row.message, "created");
# Ok(())
# }
```

## Common table expressions

CTEs use the same pattern. Derive `Cte`, build the inner query, then attach it with `with(...)`.

```rust
use qraft::prelude::*;
use qraft::query::select;

#[derive(Debug, qraft::Qraft)]
struct User {
    id: i64,
    email: String,
    active: bool,
}

#[derive(Debug, qraft::Cte)]
struct RecentUser {
    id: i64,
    email: String,
}

let sql = with(recent_users::from(
    select((users::id, users::email))
        .from(users::table)
        .filter(users::active.eq(true)),
))
.select(recent_users::star)
.from(recent_users::table)
.to_debug_sql::<qraft::Postgres>();

assert_eq!(
    sql,
    r#"with "recent_users"("id", "email") as (select "users"."id", "users"."email" from "users" where "users"."active" = $1) select "recent_users".* from "recent_users"; params=[true]"#
);
```

This matters once queries stop being one flat `select`. You can keep intermediate shapes named and typed instead of dropping to handwritten SQL early.

## Soft deletes

With the `soft-delete` feature, a model can hide deleted rows by default and expose explicit scopes when you need them.

```rust
use qraft::prelude::*;

#[derive(Debug, qraft::Qraft)]
#[qraft(soft_delete)]
struct User {
    id: i64,
    email: String,
    deleted_at: Option<String>,
}

let active = User::query().to_debug_sql::<qraft::Sqlite>();
let deleted = User::only_deleted().to_debug_sql::<qraft::Sqlite>();

assert_eq!(
    active,
    r#"select * from "users" where ("users"."deleted_at") is null; params=[]"#
);
assert_eq!(
    deleted,
    r#"select * from "users" where ("users"."deleted_at") is not null; params=[]"#
);
```

The derived API also adds:

- `User::with_deleted()`
- `User::only_deleted()`
- `query.restore(exec)`
- `query.restore_query()`
- `query.delete(exec)` for soft delete
- `query.force_delete(exec)` for physical delete

## Hashed values

With the `hash` feature, `qraft` re-exports `Hashed`. It stores bcrypt hashes as text and gives you helpers for hashing and verification.

`Hashed` implements `Encode`, `Decode`, and `Compatible<Text>`, so it can be stored in text columns and used directly in derived models.

```rust
use qraft::Hashed;

# async fn run() -> Result<(), Box<dyn std::error::Error>> {
let password = Hashed::make("hunter2").await?;
assert!(password.verify("hunter2").await?);
assert!(!password.verify("wrong-password").await?);
# Ok(())
# }
```

This is useful when a model field should decode from the database as a password hash instead of a plain `String`.

## Derives

- `Qraft`: maps a model to a table and generates the schema module
- `Cte`: declares a named common table expression
- `FromRow`: decodes a result row into a custom rust type
- `Projection`: derives projected field metadata
- `Insertable`: derives insert assignments
- `Pivot`: derives projected fields for pivot types

## Workspace

- `crates/qraft`: public API and re-exports
- `crates/core`: query builders, expressions, lowering, and execution glue
- `crates/derive`: proc macros exposed by `qraft`
- `crates/derive-core`: shared derive implementation
- `crates/expression-macro`: expression macro support

## License

`qraft` is available under `MIT` or `Apache-2.0`.