# cratestack-macros
Procedural macros for compile-time schema processing.
## Overview
`cratestack-macros` exposes three role-specific proc-macros that parse a `.cstack` file at compile time and emit Rust code inside a `cratestack_schema` module. Each macro maps to a deployment shape:
| `include_server_schema!` | Server (Postgres via sqlx) | full ORM + axum router + procedures + events + sqlx FromRow |
| `include_embedded_schema!` | Embedded ORM (mobile / desktop / browser via OPFS) | model structs + descriptors + rusqlite FromRow + inputs |
| `include_client_schema!` | HTTP client (talks to a server, owns no DB) | model/input/procedure stubs, no DB |
The split is **strict**: `include_server_schema!` never emits rusqlite items, `include_embedded_schema!` never emits sqlx items. Each deployment pays only for its own surface.
All three are re-exported through the facade crates `cratestack-pg` and `cratestack-sqlite`; most consumers should depend on one of those (renamed to `cratestack` via Cargo's `package =` field) rather than this crate directly. The choice of facade picks which side of the strict split the macro emits against — backend services use `cratestack-pg`, embedded / mobile / wasm builds use `cratestack-sqlite`.
## Installation
```toml
[dependencies]
# Server-side
cratestack = { package = "cratestack-pg", version = "0.4" }
# OR embedded-side
# cratestack = { package = "cratestack-sqlite", version = "0.4" }
```
## `include_server_schema!`
```rust
use cratestack::include_server_schema;
include_server_schema!("schema.cstack", db = Postgres);
let pool = sqlx::PgPool::connect(&database_url).await?;
let cool = cratestack_schema::Cratestack::builder(pool).build();
```
Only `db = Postgres` is currently accepted. The parser is wired so adding `MySql` / `Sqlite`-via-sqlx in a future release is non-breaking at call sites that already pass `db = Postgres`.
The macro emits, inside a `cratestack_schema` module:
- model structs + `sqlx::FromRow<PgRow>` impls for each `model`
- `Create<Model>Input` and `Update<Model>Input` structs
- per-model selection / include builders
- per-model filter/order helper modules (e.g. `cratestack_schema::post::published()`)
- the `Cratestack` runtime struct with `builder(pool)`, `bind_context(ctx)`, `bind_auth(principal)`, and per-model accessors (`cool.post()`, `cool.user()`, ...)
- `axum::model_router(cool, codec, auth_provider)` and `axum::procedure_router(...)`
- procedure dispatch glue and `events::Subscriptions` for `@@emit` model events
- for each `view` block: a typed struct, `<UPPER>_VIEW: ViewDescriptor<...>` const, `sqlx::FromRow<PgRow>` impl, and an accessor on `cool.views().<view_snake>()` returning `ViewDelegate` (or `ViewDelegateNoUnique` for `@@no_unique` views). `@@materialized` views also get a `refresh()` method. See [ADR-0003](https://cratestack.dev/internals/views-adr).
## `include_embedded_schema!`
```rust
use cratestack::include_embedded_schema;
use cratestack_rusqlite::{ModelDelegate, RusqliteRuntime, rusqlite_backend::ddl::create_table_sql};
include_embedded_schema!("schema.cstack");
let runtime = RusqliteRuntime::open("app.db")?;
runtime.with_connection(|conn| {
conn.execute_batch(&create_table_sql(&cratestack_schema::NOTE_MODEL))?;
Ok(())
})?;
let notes = ModelDelegate::new(&runtime, &cratestack_schema::NOTE_MODEL);
```
The macro emits:
- model structs + `cratestack_rusqlite::FromRusqliteRow` impls
- `ModelDescriptor` constants (needed by `ModelDelegate`)
- `Create<Model>Input` / `Update<Model>Input` with `CreateModelInput` / `UpdateModelInput` impls
- per-model filter helper modules
- for each non-`@@materialized` `view` block: a typed struct, `<UPPER>_VIEW: ViewDescriptor<...>` const, and `cratestack_rusqlite::FromRusqliteRow` impl. `@@materialized` views are rejected at expansion time with a `compile_error!` referencing [ADR-0003](https://cratestack.dev/internals/views-adr) — SQLite has no materialized views.
It **does not** emit: `sqlx::FromRow`, the `Cratestack` server runtime, axum routes, procedure handlers, or events. Policies (`@@allow` / `@@deny`) are silently dropped — clients are untrusted; authorization is the server's job.
`@@audit` and `@@emit` directives are currently no-ops in this macro. The local-journal / local-event-bus implementations land in a follow-up release.
## `include_client_schema!`
Emits a strict subset of the server surface — model and input types, enums, selection/projection helpers, and the `client::Client` wrapper — with no SQLx or Axum integration. Renamed from `include_client_macro!` in 0.3.0.
```rust
use cratestack::include_client_schema;
include_client_schema!("../schemas/api.cstack");
```
## Migration from 0.2.x
`include_schema!` and `include_client_macro!` were removed in 0.3.0. Migrate:
| `include_schema!("schema.cstack");` (server context) | `include_server_schema!("schema.cstack", db = Postgres);` |
| `include_schema!("schema.cstack");` (sqlite/embedded context) | `include_embedded_schema!("schema.cstack");` |
| `include_client_macro!("schema.cstack");` | `include_client_schema!("schema.cstack");` |
See the workspace `CHANGELOG.md` for full release notes.
## Decimal Backend
Generated code references `cratestack::Decimal`, which resolves at compile time to either `rust_decimal::Decimal` (`decimal-rust-decimal`, default) or the reserved `decimal-bigdecimal` backend.
## See Also
- `cratestack` — facade crate that re-exports the macros
- `cratestack-parser` — the parser the macros call
- [Quickstart](https://cratestack.dev/getting-started/quickstart)
## License
MIT