This version is in beta. Some features may change before release.

inspectdb

Introspect an existing database into models and a 0001_initial migration.

inspectdb is the porting on-ramp. Point it at an existing SQLite database and it generates a models.rs with one #[derive(Model)] struct per table, plus a 0001_initial.json migration that recreates the schema. The output drops into the same M5 migration loop - no parallel porting code path.

Run it

Code
bash
cargo run -- inspectdb --output plugins/imported
# -> Inspected 12 table(s), 47 column(s)
# -> Wrote plugins/imported/models.rs
# -> Wrote plugins/imported/migrations/app/0001_initial.json

The output:

Code
txt
plugins/imported/
├── models.rs # one #[derive(Model)] per table
└── migrations/
└── app/
└── 0001_initial.json # one CreateTable per table

Wire each generated struct with App::builder().model::<T>() (or move them into a real plugin once M7's plugin contract suits your project shape) and the loop runs normally from there.

Marking the initial migration applied

When the target database already holds the tables you just introspected, running the migration would fail on "table already exists". Pass --mark-applied to record the row in umbral_migrations without running the SQL:

Code
bash
cargo run -- inspectdb --output plugins/imported --mark-applied

The next migrate is a no-op until you actually change a model.

inspectdb dispatches on the active backend: SQLite reads sqlite_master plus PRAGMA table_info, and Postgres reads information_schema (tables, columns, and the constraint joins that recover the primary key). Point the CLI at whichever backend DATABASE_URL resolves to; the same --output shape comes out either way. See the Postgres backend page for the Postgres specifics.

The SQLite type catalogue

The columns inspectdb's SQLite path knows about today (the Postgres path additionally recovers JSONB, native arrays, and INET / CIDR / MACADDR; see the Postgres backend page):

Integers

SMALLINT, INTEGER, BIGINT and their aliases map to i16 / i32 / i64.

Floats

REAL → f32; DOUBLE / FLOAT8 → f64.

Booleans

BOOLEAN / BOOL → bool.

Text

TEXT, VARCHAR, CHAR, CLOB all map to String. VARCHAR(n) width is recorded as a comment.

Dates and times

DATE → NaiveDate, TIME → NaiveTime, TIMESTAMP / DATETIME → DateTime<Utc>.

UUIDs

UUID → uuid::Uuid.

A JSON / JSONB-declared column maps to serde_json::Value and a BLOB / BYTEA column maps to a bytes field. A SQL type still outside the catalogue (NUMERIC, custom types) makes inspectdb stop with an UnsupportedColumnType error naming the offending column. Either add a matching SqlType variant or edit the generated models.rs by hand.

Info

umbral_migrations, every sqlite_* internal table, and any table with an SQL type the catalogue doesn't know are excluded automatically.

Still deferred

  • Foreign-key and index detection. The generated CreateTable ops carry columns only; a Postgres FK column comes back as a plain i64 and indexes are not read out. Once the field-level FK / index types land in the introspector, inspectdb picks them up. (Both backends.)
  • Generated plugin crates with a Plugin impl. Today the output is a flat models.rs you wire by hand. M7's full plugin shape ships the crate too.

Postgres introspection has shipped (introspect_pool_pg, covered by crates/umbral-core/tests/postgres_inspect.rs); it is no longer on this list.

The full target shape lives in docs/specs/07-inspectdb.md.