cratefield_tables/lib.rs
1//! `cratefield-tables` is the schema a venture declares in its manifest,
2//! and the artifacts derived from that one declaration.
3//!
4//! A venture edits `[tables]` in `venture.toml` and redeploys without a
5//! rebuild, so the schema is a runtime value: rows are dynamic values
6//! checked by an interpreter reading that value, not typed structs fixed
7//! at compile time. Rust cannot infer a compile-time type from a runtime
8//! value, so the two do not mix, and this is the representation for every
9//! declared table.
10//!
11//! The schema type is a small purpose-built enum, not JSON Schema. JSON
12//! Schema is sprawling and says nothing about the SQLite and Postgres DDL
13//! mapping, so it is emitted as a derived view instead.
14//!
15//! # What one declaration produces
16//!
17//! - [`Schema::validate`] checks the declaration itself and reports every
18//! violation together.
19//! - [`Schema::ddl`] renders forward-only, deterministic SQLite and
20//! Postgres DDL.
21//! - [`validate_row`] checks a `serde_json` object against a table and
22//! answers with a [`cratefield_core::Problem`].
23//! - [`json_schema`] renders a table as JSON Schema, for interop only.
24//!
25//! # The bound on a declaration
26//!
27//! A field can say required, length, range, format, enum, uniqueness,
28//! foreign key, default and index. Anything that has to read another row
29//! or another request is a function, not a field: overlap checks, state
30//! machines and side effects belong in a module or a sidecar. Uniqueness
31//! is on that list because the database enforces it, not the validator.
32//!
33//! # Where the rules are pinned
34//!
35//! `corpus/rows.json` holds triples of table, input and expected verdict,
36//! run by `tests/corpus.rs`. It is a plain data file so a second
37//! implementation in another language can be run over the same cases.
38//! That is what keeps this validator and a generated client from
39//! disagreeing about empty versus absent, number coercion, null versus
40//! missing, Unicode length and whitespace.
41//!
42//! # Pure logic
43//!
44//! No I/O, no driver, no clock and no randomness. SQL is generated as
45//! strings, so the crate builds for `wasm32-unknown-unknown` alongside
46//! `cratefield-core`.
47//!
48//! # Not built here
49//!
50//! This crate is the schema definition and nothing downstream of it. The
51//! following are deliberately absent, each its own follow-up:
52//!
53//! - CRUD route handlers, the access vocabulary and the batched read
54//! endpoint.
55//! - The migration diff between two versions of a definition. Everything
56//! here only creates.
57//! - The generated `@cratefield/client` TypeScript package, and the
58//! second run of `corpus/rows.json` against its Zod schemas.
59//! - Publishing the declared tables on `/__surface`, and any control
60//! plane or manifest generator wiring.
61
62#![doc = include_str!("../README.md")]
63#![forbid(unsafe_code)]
64
65mod ddl;
66mod diff;
67mod json_schema;
68mod manifest;
69mod schema;
70mod sql;
71mod validate;
72mod value;
73
74pub use ddl::{SqlDialect, index_name};
75pub use diff::{Change, Step, diff};
76pub use json_schema::{JSON_SCHEMA_DIALECT, json_schema};
77pub use schema::{
78 FieldDef, FieldKind, ForeignKey, MAX_IDENTIFIER_CHARS, RESERVED_PREFIXES, RESERVED_WORDS,
79 Schema, TableDef, TextFormat, is_identifier,
80};
81pub use sql::{
82 DecodeError, Filter, Owned, Page, Sort, UpdateError, delete, from_sql, insert, row_json,
83 select_one, select_page, to_sql, update,
84};
85pub use validate::{
86 MAX_DETAIL_ERRORS, MAX_UNKNOWN_KEY_CHARS, RowError, RowErrors, normalize_row, validate_row,
87};
88pub use value::{ErrorCode, ValueError, check_value, is_rfc3339, is_url, is_uuid};