# Pull and import

## pull

`okm pull` reads one database and writes one table file per table, plus the schema file. It does not write the selected namespaces, so a protected target is allowed. It creates a scratch schema to verify functions and views, then drops it. An existing file is OKM1855 and nothing is written. `--out <directory>` is the other place to write. The default namespace is the target's current schema. `--schema <name>` selects others and may be repeated. A column, constraint, or index whose name or column is a reserved word (`order`, `Order`) is listed under `not pulled yet` and is not written. That index is recorded in `.okm/pull.json`, and push does not drop it. The other tables and columns are still written. A foreign key to a table outside the selected schemas is listed under `not pulled yet` and is not written. `--schema billing` alone still writes `.references("users")` for a key that points at `public.users`, so the key is rebound onto `billing.users`. `okm build` then reports OKM1022 when the column types differ; when they match, the key points at the wrong table. Repeating `--schema` for both namespaces writes nothing: OKM1023 when both schemas contain the same table name, or OKM1021 when the foreign key's target is not a table in the one namespace `schema()` can hold.

Export bindings and file stems are unique when folded to lowercase, so `Tasks` and `tasks` become `Tasks` / `tasks_2` and do not collide on a case-insensitive volume or in row types. A Windows-reserved stem (`con`, `aux`, `nul`, `com1`–`com9`, `lpt1`–`lpt9`, any case) gets a `_` prefix. The SQL name stays in `sqlName` when the binding differs. A name that is an okmodel import (`t`, `table`, `columns`, `sql`, `index`, `schema`, `extension`, `fn`, `trigger`, `view`, `materializedView`) gets `Name` on the end so the file can load. A column named `__proto__` is written as a computed key. Single-column foreign keys name the exported table binding, not the raw SQL table name. Relative imports keep the `.ts` extension so Node type stripping and `bunx okm` can load the schema. When `tsc` typechecks that output, set `allowImportingTsExtensions` with `noEmit`, or set `rewriteRelativeImportExtensions` so emit rewrites them to `.js`. `--import-ext js` writes `.js` specifiers. `--import-ext none` writes none. The default is `ts`. When `oxfmt` is missing, the files stay unformatted, a notice is printed, and the report still returns.

`--casing snake` or `--casing camel` is opt-in. The default keeps each database name as the TypeScript key. With the flag, the key is the other spelling and `schema({ casing })` is written. `.sqlName()` is added where that key does not spell the database name, and each of those names is listed in the report.

Tables, columns, keys, uniques, checks, single-column foreign keys, indexes, identity sequences, enums, domains, extensions, functions, triggers, views, and materialized views are written. An integer `generated always as identity` column that is the only primary key is `t.integerIdentity()`. A bigint one stays `t.identity()`. `.okm/pull.json` is written at the project root, including when `--out` writes the target named `default` or the only configured target. A `--out` pull of any other `--target`, or one that passes `--schema`, leaves an existing record in place. That holds when `--out` is the project schema directory. `okm push` refuses OKM1897 when the plan would drop a column or constraint listed under `not pulled yet`. `okm check` omits those objects, so an ok report does not list the drops. A pull with no `--out` replaces `.okm/pull.json`, including `pull --target other` when several targets are configured. Push of the original target is then OKM1898 when that replacement no longer lists the drop and the table has a row. A view is SQL text with its columns. Views and `BEGIN ATOMIC` bodies take dependencies from `pg_depend`. A plpgsql or SQL-string body gets `dependsOn` candidates from a lexical match. The report marks each function `verified` (the scratch replay created it with `check_function_bodies` on), `candidate-only` (plpgsql: creation does not prove the body), or `unverified` (creation failed). A comment above the declaration says the same thing. Policies, enable and force row level security, roles, grants, aggregates, procedures, event triggers, and rules are printed under `not pulled yet` with a count, and so is anything `table()` cannot say. Enable and force are one line each, with the `alter table` statement, when a table has a policy. `okm check` after `migrate baseline` does not plan to drop that security when the schema declares no policy. A column type with no builder is that list, with the table and the column. Nothing is dropped without a line. A column the database holds as `NOT NULL … NOT VALID` (PostgreSQL 18) is written `.nullable()` with a comment and listed under `not validated`, because rows with NULL may exist.

```sh
bunx okm pull
bunx okm pull --schema public --out ./adopted
```

## import drizzle

`okm import drizzle <path>` reads a Drizzle schema and writes one table file per table, plus the schema file. It imports that path, so the file runs. The `drizzle-orm` package is the one installed in the project. okmodel does not depend on it. A missing package is OKM1856: install `drizzle-orm` in the project. An existing file is OKM1855 and nothing is written. The command does not connect.

The report starts with `namespace <name>`. When the name is not `public`, set [namespace](/docs/reference/config#namespace) to it. `schema()` still compiles `public`. File stems follow the same lowercase-folded uniqueness and Windows-reserved rules as [pull](#pull). Composite primary-key columns are not null even when Drizzle omitted `.notNull()` on the column. An index with no name keeps drizzle-kit's `{table}_{columns}_index`. A name that is already `{table}_{columns}_idx` is left as `index(...)`.

Casing is the `--drizzle-casing snake_case|camelCase|none` flag, then a `snakeCase` or `camelCase` builder, then `casing` on `drizzle()` and `drizzle.config.*`, then `none`. `none` reports each `keyAsName` column. An empty SQL name is reported and not written. See [From Drizzle](/docs/migrations/from-drizzle).

Composite foreign keys, `relations()`, and custom column types are printed under `not imported` with the table and the reason. A `serial` column is written as `integer` not null. The sequence `serial` would create is listed, not written.

```sh
bunx okm import drizzle ./src/db/schema.ts --out ./adopted
```

## ext

`okm ext list` and `okm ext check` connect to the selected target as the read-only `check` class. A protected target is allowed. A pooler host is not refused.

`list` prints a tab-separated table. The header is `name`, `default`, `installed`, `schema`.

`check` compares extensions declared on the schema with what is installed. No declaration is `no extensions`. A missing install is OKM1811: `Extension <name> is not installed on the server.` A version the declaration rejects is OKM1812: `Extension <name> needs <declared> or higher. The server has <installed>. Install a version the declaration accepts, or change the pin.` An exact pin omits "or higher". A match prints `name`, `declared`, `installed`. An omitted pin prints the extension name. A pin prints that version or floor. Declarations are on [Extensions](/docs/schema/extensions).

`scaffold <name>` reads `pg_depend`, `pg_type`, `pg_proc`, `pg_operator`, and `pg_settings` for an extension that is already installed. A missing install is OKM1811. The text is a starting `extension()` definition the project owns. `--out <file>` writes that text. An existing file is `invalid` and nothing is written. Without `--out` the text is printed.

`test <file>` loads that module and checks each exported `extension()`. Every declared type, operator, function, and index method must exist with that signature. A mismatch is `invalid` and the message lists each one. A `requires` version or Postgres floor the server does not meet is OKM1812. A match prints `ok <name>`.

Another name is `Unknown command ext <name>.`

```sh
bunx okm ext check
```

Index: [/llms.txt](/llms.txt)
