Skip to main content

Documentation 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.

The read methods on a Repository instance cover every querying pattern you need: fetching a single record, retrieving an unbounded list, paginating results, and querying soft-deleted records in isolation. All methods accept an optional profile argument that the RBAC engine uses to enforce field-level access control before any SQL is executed. The query parameter in every method uses dot-notation paths so you can filter, project, and sort across JSON columns and related tables with full TypeScript autocompletion.

searchOne

Returns the first record matching the query, or null if no match is found. The query is limited to one row internally, so it is always efficient regardless of the underlying table size. Signature
searchOne<Q extends Pick<SearchQuery<TEntity>, "projection" | "filter" | "order">>(
  query: Q,
  profile?: string | string[],
): Promise<DbQueryResult<TEntity, Q> | null>

Parameters

query
object
required
The query descriptor. Accepts projection, filter, and order — but not page or pageSize.
profile
string | string[]
The RBAC profile (or profiles) to evaluate. Defaults to "default" when omitted. Pass an array to merge the permissions of multiple profiles.

Return value

result
DbQueryResult<TEntity, Q> | null
When projection is provided, returns a deeply-picked subset of TEntity matching exactly the paths listed. When projection is omitted, returns the full entity shape. Returns null when no record matches.

Example

const user = await userRepo.searchOne(
  {
    projection: [
      "name",
      "profile.bio",            // 1:1 relation
      "posts.title",            // 1:N relation
      "settings.theme",         // JSON column extraction
      "persona.skills.0",       // JSON array index
    ],
    filter: {
      $or: [
        { name: { $like: "%John%" } },
        { "settings.theme": { $eq: "dark" } },
        { "persona.skills.0": { $eq: "Node.js" } },
        { "posts.title": { $like: "%Drizzle%" } },
      ],
    },
    order: {
      createdAt: "desc",
      "posts.comments.createdAt": "desc",
    },
  },
  "admin",
);
The library automatically builds the required SQL JOINs and JSON extraction functions. The raw rows are then hydrated into a clean nested object:
{
  "name": "John Doe",
  "settings": { "theme": "dark" },
  "persona": { "skills": ["Node.js"] },
  "profile": { "bio": "Backend Developer" },
  "posts": [
    {
      "title": "Learning Drizzle",
      "comments": [{ "content": "Great post!" }]
    }
  ]
}

searchMany

Returns all records that match the query as an array. There is no built-in limit, so apply a filter or use searchPage for large tables. Signature
searchMany<Q extends Omit<SearchQuery<TEntity>, "page" | "pageSize">>(
  query: Q,
  profile?: string | string[],
): Promise<DbQueryResult<TEntity, Q>[]>

Parameters

query
object
required
Accepts projection, filter, and order. The page and pageSize fields are not accepted — use searchPage for pagination.
profile
string | string[]
RBAC profile(s) to evaluate against the access policy.

Return value

result
DbQueryResult<TEntity, Q>[]
An array of entities (or projected subsets). Returns an empty array when no records match.

Example

// Fetch all users ordered by creation date
const users = await userRepo.searchMany(
  {
    order: { createdAt: "desc" },
  },
  "admin",
);

// Fetch users with a specific JSON field value
const darkThemeUsers = await userRepo.searchMany(
  {
    projection: ["name", "settings.theme"],
    filter: {
      "settings.theme": { $eq: "dark" },
    },
  },
  "public",
);

searchPage

Returns a paginated result set together with metadata about the total number of items and pages. Use this method whenever you need cursor-free offset pagination. Signature
searchPage<Q extends SearchQuery<TEntity>>(
  query: Q,
  profile?: string | string[],
): Promise<{
  data: DbQueryResult<TEntity, Q>[];
  meta: {
    currentPage: number;
    pageSize: number;
    totalPages: number;
    totalItems: number;
  };
}>

Parameters

query
object
required
The full SearchQuery including pagination controls.
profile
string | string[]
RBAC profile(s) to evaluate against the access policy.

Return value

data
DbQueryResult<TEntity, Q>[]
The records for the requested page, hydrated into nested objects.
meta
object
Pagination metadata.

Example

const result = await userRepo.searchPage(
  {
    page: 1,
    pageSize: 10,
    filter: { "posts.comments.content": { $isNull: false } },
  },
  "public",
);

// result.data  → array of up to 10 user objects
// result.meta  → { currentPage: 1, pageSize: 10, totalPages: 5, totalItems: 42 }

searchDeletedOne

Identical in signature to searchOne, but scopes the query to soft-deleted records only. Active records are excluded. Signature
searchDeletedOne<Q extends Pick<SearchQuery<TEntity>, "projection" | "filter" | "order">>(
  query: Q,
  profile?: string | string[],
): Promise<DbQueryResult<TEntity, Q> | null>
This method requires softDelete to be configured on the table via the schema builder. If the table has no soft-delete config, it will throw at runtime.

Parameters

query
object
required
Same structure as searchOne: accepts projection, filter, and order.
profile
string | string[]
RBAC profile(s) to evaluate.

Return value

result
DbQueryResult<TEntity, Q> | null
The first matching soft-deleted record, or null.

Example

const deletedUser = await userRepo.searchDeletedOne(
  {
    projection: ["name", "email"],
    filter: { name: { $eq: "Jane Doe" } },
  },
  "admin",
);

searchDeletedMany

Returns all soft-deleted records matching the query as an array. Signature
searchDeletedMany<Q extends Omit<SearchQuery<TEntity>, "page" | "pageSize">>(
  query: Q,
  profile?: string | string[],
): Promise<DbQueryResult<TEntity, Q>[]>
Requires softDelete to be configured on the table builder.

Parameters

query
object
required
Accepts projection, filter, and order.
profile
string | string[]
RBAC profile(s) to evaluate.

Return value

result
DbQueryResult<TEntity, Q>[]
Array of soft-deleted entities, or an empty array if none match.

Example

const allDeleted = await userRepo.searchDeletedMany(
  {
    order: { createdAt: "desc" },
  },
  "admin",
);

searchDeletedPage

Returns a paginated result of soft-deleted records, with the same meta structure as searchPage. Signature
searchDeletedPage<Q extends SearchQuery<TEntity>>(
  query: Q,
  profile?: string | string[],
): Promise<{
  data: DbQueryResult<TEntity, Q>[];
  meta: {
    currentPage: number;
    pageSize: number;
    totalPages: number;
    totalItems: number;
  };
}>
Requires softDelete to be configured on the table builder.

Parameters

query
object
required
Full SearchQuery including page and pageSize.
profile
string | string[]
RBAC profile(s) to evaluate.

Return value

data
DbQueryResult<TEntity, Q>[]
Soft-deleted records for the requested page.
meta
object
Pagination metadata scoped to the deleted records set.

Example

const page = await userRepo.searchDeletedPage(
  { page: 1, pageSize: 20 },
  "admin",
);

Factory helpers

These methods do not perform any database operation. They are type-narrowing helpers that let you define reusable query fragments with full TypeScript inference.

defineFilter

defineFilter: (filter: FilterQuery<TEntity>) => FilterQuery<TEntity>
Validates and returns a FilterQuery object. Useful for building shared filter presets.
const activeFilter = userRepo.defineFilter({
  "settings.theme": { $eq: "dark" },
});

const user = await userRepo.searchOne({ filter: activeFilter }, "admin");

defineProjection

defineProjection: <P extends FlattenPaths<TEntity>[]>(p: P) => P
Validates an array of projection paths against the entity type. Autocomplete ensures only valid paths are accepted.
const publicFields = userRepo.defineProjection(["name", "profile.bio"]);

const users = await userRepo.searchMany({ projection: publicFields }, "public");

defineQuery

defineQuery: <Q extends SearchQuery<TEntity>["order"]>(query: Q) => Q
Validates an order query object for reuse across multiple calls.
const defaultOrder = userRepo.defineQuery({ createdAt: "desc" });

const users = await userRepo.searchMany({ order: defaultOrder }, "admin");

Build docs developers (and LLMs) love