Drizzle Castor manages table relationships in its own metadata layer, separate from Drizzle’s native relation system. You register every relation by callingDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/fajarnugraha37/drizzle-castor/llms.txt
Use this file to discover all available pages before exploring further.
builder.table(tableName, config) on the schema builder. At query time, the AST translator reads this registry to decide which LEFT JOIN statements to emit and how to wire up foreign keys — all without any manual SQL. The same table call also configures soft-delete behaviour, keeping both concerns co-located.
Registering a table with builder.table()
builder.table(tableName, config) returns a new SchemaBuilder instance with the table config merged into the type-level metadata map. You can chain multiple .table() calls fluently.
Must match the Drizzle table’s
._name value exactly. TypeScript narrows this to TableName<TTables[number]>.An object that may contain any combination of
oneToOne, oneToMany, manyToOne, manyToMany, and softDelete.Relation types
Castor supports four relation types. Every relation node requires at minimum arelationName, a relatedTable, and the key pair that joins the two tables.
oneToOne
A 1:1 relation where the local table holds the primary key and the related table holds a foreign key pointing back (or vice versa). Query results hydrate as a single nested object rather than an array.
projection: ["profile.bio"] on a users repository now emits:
oneToMany
A 1:N relation where one local row corresponds to many rows on the related table. Query results hydrate as an array nested under the relation name.
manyToOne
A N:1 relation where the local table holds the foreign key. The hydrated result is a single nested object (not an array) because each local row belongs to exactly one parent.
manyToMany
A M:N relation that requires a join table. Castor joins through the junction table automatically; you never need to query it directly.
The name of the junction table (e.g.,
"users_to_groups").The column on the join table that references the local table’s primary key (e.g.,
"users_to_groups.userId").The column on the join table that references the related table’s primary key (e.g.,
"users_to_groups.groupId").The primary key column on the local table (e.g.,
"users.id").The primary key column on the related table (e.g.,
"groups.id").The RelationNode shape
Castor stores every registered relation as a RelationNode object internally. Understanding this shape helps when reading error messages or extending the library.
How nested paths are resolved
When a query contains a path like"posts.comments.content", the AST translator resolves each segment step by step:
Segment 1: posts
The translator looks up the
users metadata and finds a oneToMany relation with relationName: "posts". It records the alias rel_posts and the join condition users.id = rel_posts.userId.Segment 2: comments
The translator looks up the
posts metadata and finds a oneToMany relation with relationName: "comments". It records the alias rel_posts_comments and the join condition rel_posts.id = rel_posts_comments.postId.Soft-delete configuration
ThesoftDelete key on a table config enables soft-delete and restore behaviour. When set, active queries automatically exclude soft-deleted rows, and soft-delete join conditions are injected into any LEFT JOIN involving this table.
The column values written when
softDeleteOne or softDeleteMany is called. Each key must be a valid column name.The column values written when
restoreOne or restoreMany is called.searchOne, searchMany, and searchPage call on the users repository automatically appends WHERE "users"."deleted_flag" = 0 (or the equivalent condition for your dialect). The same filter is also injected into any join involving users as the related table, so nested queries on posts that join up to users will not surface deleted user records.
Full example using the example schema
The following registers the complete set of tables fromexample/schema.ts, covering all four relation types and soft-delete configuration.
Related pages
JSON-based querying
See how relational dot-notation paths are used in filters, projections, and order queries.
Soft deletes
Learn the full lifecycle of soft-deleted records and how to query them explicitly.
Schema builder
Understand the complete builder API that wraps relation and policy registration.
API: schema builder methods
Full API reference for all SchemaBuilder methods including table() overloads.