brick.ts

Primary Keys and Identifiers

Configure custom primary keys, UUIDs, and auto-minted column IDs.

llms.txt

Brick-TS uses whatever primary key your Drizzle table defines: autoincrement integers, UUIDs, or custom prefixed string identifiers minted with $defaultFn().

Minimal Example

Define an auto-minted UUID primary key and register it with the resource:

src/services/items.ts
import {
  defineDatabase,
  defineService,
  sqliteTable,
  text,
} from "@brickkit/core";
import { crud } from "@brickkit/crud";

export const items = sqliteTable("items", {
  // Auto-minted UUID primary key
  id: text("id")
    .primaryKey()
    .$defaultFn(() => crypto.randomUUID()),
  name: text("name").notNull(),
});

const database = defineDatabase({ tables: { items } });
export const itemsService = defineService("items", { database });

// Register resource identity using items.id
export const itemResource = itemsService
  .resource({
    name: "item",
    table: items,
    id: items.id, // Optional here: items has a single primary key
  })
  .use(
    crud({
      access: "public",
      fields: {
        id: { read: true, filter: ["eq", "in"] },
        name: { read: true, create: true, update: true },
      },
    }),
  );

Schema

These columns match the Drizzle tables in the example. Defaults marked as application defaults run in Drizzle, rather than in SQL.

Table Name: items

FieldTypeDescription
idtextRow identifier. PK Default: crypto.randomUUID() (application)
nametextDisplay name.

Table Name: documents

FieldTypeDescription
idtextRow identifier. PK Default: crypto.randomUUID() (application)
titletextDisplay title.

Table Name: users

FieldTypeDescription
idtextRow identifier. PK Default: mintId("usr") (application)
nametextDisplay name.

Table Name: logs

FieldTypeDescription
idintegerRow identifier. PK Default: autoincrement
messagetextLog message.

Supported Primary Key Strategies

Drizzle column builders define primary key generation strategies:

1. Auto-Minted UUIDs

Generates random RFC 4122 UUID strings on row creation:

src/schema.ts
export const documents = sqliteTable("documents", {
  id: text("id")
    .primaryKey()
    .$defaultFn(() => crypto.randomUUID()),
  title: text("title").notNull(),
});

2. Prefixed Identifiers (Stripe-Style)

Prefix IDs with entity tags (e.g. usr_..., inv_...) to improve readability and debugging:

src/schema.ts
function mintId(prefix: string): string {
  return `${prefix}_${crypto.randomUUID().replace(/-/g, "").slice(0, 16)}`;
}

export const users = sqliteTable("users", {
  id: text("id")
    .primaryKey()
    .$defaultFn(() => mintId("usr")),
  name: text("name").notNull(),
});

3. Autoincrement Integers

Standard sequential integer identifiers:

src/schema.ts
import { integer, sqliteTable, text } from "@brickkit/core";

export const logs = sqliteTable("logs", {
  id: integer("id").primaryKey({ autoIncrement: true }),
  message: text("message").notNull(),
});

When using integer keys, Brick automatically types action parameters such as id in item.get and item.update as number.

Resource Identity Registration

service.resource() takes an optional id column. If you omit it, Brick uses the table's primary key when the table has exactly one primary-key column. Pass id explicitly when the table has no single primary key (for example a composite key) or when you want lookups to use a different unique column; the column must belong to the resource's table, otherwise resource() throws Resource '<name>' requires an id column belonging to its table.

src/services/catalog.ts
const product = service
  .resource({
    name: "product",
    table: productsTable,
    id: productsTable.id, // Column CRUD uses for get/update/delete lookups
  })
  .use(crud({ access: "public", fields: {/* ... */} }));

The CRUD plugin uses this column for single-record operations, and types id from the column's data type:

  • product.get({ input: { id: "prod_1" } })
  • product.update({ input: { id: "prod_1", data: { name: "New Name" } } })
  • product.delete({ input: { id: "prod_1" } })