Warnings

Development advice for a query. The level is configuration. The code number is the subject.

okmodel/warnings exports warnings. Pass it to connect. Production reports nothing until a level is set. Development reports a hint for low severity and a warn for medium or high. error throws and is meant for a test.

An ignore needs a reason. okm check does not run the query rules. It lists project ignores and runs the schema rules below.

warnings.ts
import { connect } from "okmodel/pg/postgresjs";
import { id, schema, table, text } from "okmodel/pg";
import { warnings } from "okmodel/warnings";

const notes = table("notes", { id: id(), title: text() });
const app = schema({ tables: [notes] });

export const db = connect(process.env.DATABASE_URL ?? "", {
  schema: app,
  warnings: warnings({
    levels: { "deep-offset": "warn" },
    ignore: [{ rule: "unordered-limit", reason: "one row" }],
  }),
});

offset above 1,000 is OKM2004. A limit whose order does not end in a unique key is OKM2005. A value list above 500 elements is OKM2007. An include whose row product is above 10,000 is OKM2008. A read that took a default from connect({ limits }) and returned exactly that many rows is OKM2011. page() is the cursor alternative to a deep offset.

Schema rules in okm check

okm check reads the schema, the catalog, and the project source. It needs no database. A finding is a warning and the exit code stays 0. A rule at level error exits non-zero.

  • OKM2101 (unindexed-foreign-key): no index starts with the columns of a foreign key. A composite index that starts with them counts.
  • OKM2102 (table-without-primary-key): a managed table has no primary key.
  • OKM2103 (unindexed-filter-column): a column in a filters() allow or sort list, or used by a preset, has no index that starts with it. A primary key, a unique index, and the tenant prefix count.

A rule that cannot decide, such as one facing an expression index, stays silent. A project ignore names a target (events or orders.user_id) and a reason. okm check lists every ignore and marks one that matched nothing as stale.

okmodel.config.ts
import { defineConfig } from "okmodel/migrate";

export default defineConfig({
  schema: "./schema.ts",
  warnings: {
    levels: { "unindexed-foreign-key": "error" },
    ignore: [{ rule: "table-without-primary-key", target: "events", reason: "append-only log" }],
  },
});