Skip to main content

Module generator

Module generator 

Source
Available on non-WebAssembly only.
Expand description

rws gen model|route|migration|test: code generators for the conventional layout (18.29.0). rws gen model|route|migration|test: code generators for the conventional layout (18.29.0). rws gen model|route|migration|test (18.29.0, roadmap #88): code generators for a project in the conventional layout (crate::app_manifest), as a library — the rws gen command and the dev MCP endpoint’s gen_* tools (crate::dev_mcp) are front ends.

GeneratorWritesAdds to
Generate::Modelsrc/models/<name>.rs (#[derive(Model)], id auto-increment, a test), migrations/NNNN_create_<table>.sql + .down.sqlsrc/models/mod.rs, src/lib.rs (pub mod models;), Cargo.toml (the model-<db> feature)
Generate::Routesrc/routes/<resource>.rs (typed handlers, register(app))src/routes/mod.rs, app() in src/lib.rs
Generate::Migrationmigrations/NNNN_<name>.sql + .down.sql—
Generate::Testtests/<resource>.rs (TestClient against app())—

The paths come from rws.app.toml. The output is pinned to this release’s API: it compiles against the rust-web-server it came with (CI generates into every starter and runs the generated tests).

plan only reads; it answers a Plan — each file created, edited or left alone, with a unified diff. Plan::apply writes it. Nothing is ever overwritten: a file that exists with other content is a ChangeKind::Conflict (the diff shows what the generator would have written) and the whole plan is refused, so running a generator twice changes nothing the second time. Edits to existing files only add a line (pub mod posts;, a feature, a register call) and are skipped when it is there; what can’t be added safely is a Plan::notes line saying what to add by hand.

use rust_web_server::generator::{plan, Field, Generate};

let request = Generate::Model {
    name: "Post".into(),
    fields: vec![Field::parse("title:String").unwrap(), Field::parse("views:i64").unwrap()],
    db: None, // from Cargo.toml's model-* feature, else SQLite
};
let plan = plan(".", &request).unwrap();
println!("{}", plan.render(true)); // what would change, with diffs
if !plan.has_conflicts() {
    plan.apply(".").unwrap();
}

Names are identifiers (letters, digits, _), so no path leaves the project; field types are a fixed list (FieldType).

Structs§

Field
One name:type field of a model or a route’s resource.
FieldType
A field’s type: i64, i32, f64, bool, String, or Option<T> of one of those.
FileChange
One file of a Plan.
GenError
Why a generator refused.
Plan
What a generator would do: the files, and what to add by hand.

Enums§

BaseType
A column type: one of the fixed list, optionally Option<…>.
ChangeKind
What happens to one file.
Db
The database a model’s migration is written for.
Generate
What to generate.
RouteAction
One of the routes rws gen route writes for a resource.

Constants§

EXIT_CONFLICT
A conflict (a file exists with other content) or the project refused (no app(), no route module, …): nothing written.
EXIT_OK
Written (or nothing to write: every file already as generated).
EXIT_USAGE
Bad arguments.
FIELD_TYPES
The types a field may have, as the error message lists them.
MAX_NAME_LEN
The longest name rws gen accepts (a resource, model, migration or field).

Functions§

parse_fields
Parse every name:type; names must not repeat.
plan
What request would change in the project at dir (reads only).
requested
rws gen … asked for: the arguments after gen.
run
Run rws gen <args> (the arguments after gen), writing to out and err; answers the exit code (EXIT_OK, EXIT_CONFLICT, EXIT_USAGE).