Loading your schema
sqlsift never connects to a database. It builds an in-memory picture of your schema from SQL files: CREATE TABLE, CREATE VIEW, CREATE TYPE ... AS ENUM and ALTER TABLE statements, applied in order.
Schema files and directories
| Option | sqlsift.toml key | What it loads |
|---|---|---|
--schema <FILE> / -s (repeatable, globs allowed) | schema = [...] | The listed files, in the order given |
--schema-dir <DIR> | schema_dir = "..." | Every .sql file under the directory, recursively, sorted by file name |
Both can be combined. Statements later in the order see the effect of earlier ones, so a migration that renames a column is reflected in the final schema.
Use it with your stack
sqlsift only needs SQL files for the schema, so it works with whatever produces them.
| Stack | Schema source |
|---|---|
| Prisma | sqlsift check --schema-dir prisma/migrations queries/*.sql |
Rails (schema_format = :sql) | sqlsift check --schema db/structure.sql queries/*.sql |
| sqlx / golang-migrate / goose / Flyway / dbmate | sqlsift check --schema-dir migrations queries/*.sql |
pg_dump --schema-only | sqlsift check --schema schema.sql queries/*.sql |
mysqldump --no-data | sqlsift check -d mysql --schema schema.sql queries/*.sql |
| Hand-written DDL | sqlsift check --schema schema/*.sql queries/**/*.sql |
The example projects show complete setups for sqlc, Prisma TypedSQL, postgres.js, plain SQL migrations, MySQL and dbt.
Migrations: only the "up" direction
When reading migrations, sqlsift applies only the "up" direction:
--schema-dirskips rollback files:*.down.sql(sqlx, golang-migrate) and Flyway undo filesU<version>__*.sql.- In any schema file, everything after a down marker (up to the next up marker) is ignored: dbmate's
-- migrate:down/-- migrate:up, goose's-- +goose Down/-- +goose Upand sql-migrate's-- +migrate Down/-- +migrate Up. - Files passed explicitly with
--schemaare always loaded, even if their name looks like a rollback.
What sqlsift understands
CREATE TABLEwith column types,NOT NULL, defaults, primary keys, foreign keys,UNIQUEandCHECKconstraintsSERIAL,GENERATED ... AS IDENTITYandAUTO_INCREMENTcolumns (they count as having a default)CREATE VIEWandCREATE MATERIALIZED VIEW, with column names and types inferred from the queryCREATE TYPE ... AS ENUM, also schema-qualified (CREATE TYPE billing.state AS ENUM ..., columns of typepublic.mood), and MySQL inlineENUM(...)columnsCREATE UNLOGGED TABLE,CREATE TABLE ... AS SELECT ... WITH [NO] DATAandSELECT ... INTO tSET search_path TO ..., for the rest of the file it is inCOPY ... FROM stdindata blocks inpg_dumpoutput are skippedALTER TABLE:ADD/DROP/RENAME COLUMN,ADD CONSTRAINT,RENAME TO
Statements sqlsift doesn't model (functions, triggers, domains, grants, …) are skipped, and the rest of the file is still loaded. Problems while loading the schema (such as an ALTER TABLE on a table that doesn't exist) are reported as warnings on stderr by both check and schema.
Inspecting the loaded schema
When a query is flagged unexpectedly, check what sqlsift actually understood from your schema. sqlsift schema takes the same schema options as check (--schema, --schema-dir, --config, --dialect) and falls back to sqlsift.toml:
$ sqlsift schema --schema-dir migrations
Schema Information:
==================
Dialect: postgresql
Schema files:
migrations/001_init.sql
Schema: public
Table: users
- id integer NOT NULL PRIMARY KEY DEFAULT nextval('users_id_seq'::regclass)
- name text NOT NULL
- feeling mood NULL
View: user_names
- id integer
- name text
Materialized view: user_count
- n bigint
Enum types:
mood: 'sad', 'ok', 'happy'
Objects are listed per schema in definition order. sqlsift schema --format json prints the same information as JSON; see Output formats.