Libraries
    Preparing search index...

    Class SchemaQueryBuilder<TLocalSchema, TResult>

    Type-safe, schema-driven query builder for Knex.

    SchemaQueryBuilder wraps a Knex.QueryBuilder and adds:

    • Type-safe column references — pass a property accessor (t => t.name) or a string property name; both are resolved to the correct SQL column through the schema's hasColumnName() metadata automatically.
    • Eager loading without N+1joinOne and joinMany use PostgreSQL CTEs and jsonb_agg to load related rows in a single query.
    • Bidirectional result mapping — rows returned from Postgres (column names) are converted back to schema property names before being returned.
    • Thenable protocol — the builder itself is await-able so you can write await query(db, Schema) without calling execute explicitly.

    Create instances via the query factory function rather than calling the constructor directly.

    import knex from 'knex';
    import { query, object, string, number } from '@cleverbrush/knex-schema';

    const UserSchema = object({
    id: number(),
    name: string(),
    age: number().optional(),
    }).hasTableName('users');

    const db = knex({ client: 'pg', connection: process.env.DB_URL });

    // Fetch all users older than 18, ordered by name
    const adults = await query(db, UserSchema)
    .where(t => t.age, '>', 18)
    .orderBy(t => t.name);
    // adults: Array<{ id: number; name: string; age?: number }>

    Type Parameters

    • TLocalSchema extends ObjectSchemaBuilder<any, any, any, any, any, any, any>

      The ObjectSchemaBuilder describing the main table.

    • TResult

      The inferred row type, widened automatically as joins are registered via joinOne / joinMany.

    Index

    Constructors

    • Type Parameters

      • TLocalSchema extends ObjectSchemaBuilder<any, any, any, any, any, any, any>

        The ObjectSchemaBuilder describing the main table.

      • TResult

        The inferred row type, widened automatically as joins are registered via joinOne / joinMany.

      Parameters

      • knex: Knex

        A configured Knex instance.

      • localSchema: TLocalSchema

        The ObjectSchemaBuilder for the primary table. Must have a table name set via .hasTableName().

      • OptionalbaseQuery: QueryBuilder<any, any>

        Optional pre-configured Knex.QueryBuilder to use as the base query instead of the default knex(tableName). Useful when you need custom joins, CTEs, or other Knex features not exposed by this API.

      Returns SchemaQueryBuilder<TLocalSchema, TResult>

    Methods

    • Alias for where — explicitly adds an AND WHERE clause. Identical to calling .where() when no logical-OR grouping is needed.

      Parameters

      Returns this

      this for chaining.

    • Alias for where — explicitly adds an AND WHERE clause. Identical to calling .where() when no logical-OR grouping is needed.

      Parameters

      Returns this

      this for chaining.

    • Alias for where — explicitly adds an AND WHERE clause. Identical to calling .where() when no logical-OR grouping is needed.

      Parameters

      • record: Record<string, any>

      Returns this

      this for chaining.

    • Alias for where — explicitly adds an AND WHERE clause. Identical to calling .where() when no logical-OR grouping is needed.

      Parameters

      • callback: (builder: QueryBuilder) => void

      Returns this

      this for chaining.

    • Alias for where — explicitly adds an AND WHERE clause. Identical to calling .where() when no logical-OR grouping is needed.

      Parameters

      • raw: Raw

      Returns this

      this for chaining.

    • Escape hatch: apply any Knex method to the underlying base query.

      Use this when you need a Knex feature not exposed by this API (e.g. forUpdate(), CTEs, join(), union()).

      Parameters

      • fn: (builder: QueryBuilder) => void

        A callback that receives the raw Knex.QueryBuilder and may mutate it in place.

      Returns this

      this for chaining.

      query(db, UserSchema).apply(qb => qb.forUpdate().noWait());
      
    • Delete all rows that match the current WHERE clause.

      Returns Promise<number>

      The number of rows deleted.

      const count = await query(db, UserSchema).where(t => t.id, id).delete();
      
    • Execute the query and return all matching rows, mapped back to schema property names.

      Returns Promise<TResult[]>

      A promise that resolves to an array of result objects typed as TResult[].

      const users = await query(db, UserSchema).execute();
      
    • Execute the query and return only the first row, or undefined if no rows match.

      Returns Promise<TResult | undefined>

      const user = await query(db, UserSchema).where(t => t.id, id).first();
      if (user) { /* ... */ }
    • Add a raw GROUP BY expression.

      Parameters

      • sql: string
      • ...bindings: any[]

      Returns this

      this for chaining.

    • Add a raw HAVING expression.

      Parameters

      • sql: string
      • ...bindings: any[]

      Returns this

      this for chaining.

    • Insert a single row into the table and return the inserted record.

      Property keys are mapped to SQL column names via the schema's hasColumnName() metadata before the INSERT is executed. The returned row is mapped back to property names.

      Parameters

      Returns Promise<TResult>

      The full inserted row (including database-generated fields).

      const user = await query(db, UserSchema).insert({ name: 'Alice', age: 30 });
      // user.id is populated by the database DEFAULT / SERIAL
    • Eager-load a collection of related rows (one-to-many relationship).

      Related rows are fetched via a single CTE + jsonb_agg query. The collection is attached to each result row under the field name specified by spec.as. Supports limit, offset, and orderBy per-parent using a row_number() window function to avoid fetching the full relation before slicing.

      Type Parameters

      • TForeignSchema extends ObjectSchemaBuilder<any, any, any, any, any, any, any>
      • TFieldName extends string

      Parameters

      • spec: JoinManySpec<TLocalSchema, TForeignSchema, TFieldName>

        Join specification. Key fields:

        • foreignSchema — the ObjectSchemaBuilder of the related table.
        • localColumn — the primary/unique key on the local table.
        • foreignColumn — the column on the foreign table that references localColumn.
        • as — the property name to attach the array under.
        • limit / offset — optional pagination per parent row.
        • orderBy — optional { column, direction } for the sub-collection.
        • foreignQuery — optional pre-filtered Knex.QueryBuilder.

      Returns SchemaQueryBuilder<
          TLocalSchema,
          WithJoinedMany<TResult, TFieldName, TForeignSchema>,
      >

      this (with an updated TResult type that includes the new field) for chaining.

      const UserSchema = object({
      id: number(),
      name: string(),
      }).hasTableName('users');

      const PostSchema = object({
      id: number(),
      title: string(),
      authorId: number(),
      }).hasTableName('posts');

      const users = await query(db, UserSchema)
      .joinMany({
      foreignSchema: PostSchema,
      localColumn: t => t.id,
      foreignColumn: t => t.authorId,
      as: 'posts',
      limit: 5,
      orderBy: { column: t => t.id, direction: 'desc' },
      });
      // users[0].posts — typed as Array<{ id: number; title: string; authorId: number }>
    • Eager-load a single related row (one-to-one / many-to-one relationship).

      The related rows are fetched using a single CTE + jsonb_agg — no N+1 queries. The related object is attached to each result row under the field name specified by spec.as.

      Type Parameters

      • TForeignSchema extends ObjectSchemaBuilder<any, any, any, any, any, any, any>
      • TFieldName extends string
      • TRequired extends boolean = true

      Parameters

      • spec: JoinOneSpec<TLocalSchema, TForeignSchema, TFieldName, TRequired>

        Join specification. Key fields:

        • foreignSchema — the ObjectSchemaBuilder of the related table.
        • localColumn — the local column that holds the foreign-table reference.
        • foreignColumn — the primary/unique key on the foreign table.
        • as — the property name to attach the related object under.
        • required — if true (default), rows without a matching related record are excluded (inner join); if false, they are included with null (left join).
        • foreignQuery — optional pre-filtered Knex.QueryBuilder for the foreign table (e.g. to apply scopes).

      Returns SchemaQueryBuilder<
          TLocalSchema,
          WithJoinedOne<TResult, TFieldName, TForeignSchema, TRequired>,
      >

      this (with an updated TResult type that includes the new field) for chaining.

      const PostSchema = object({
      id: number(),
      title: string(),
      authorId: number(),
      }).hasTableName('posts');

      const AuthorSchema = object({
      id: number(),
      name: string(),
      }).hasTableName('authors');

      const posts = await query(db, PostSchema)
      .joinOne({
      foreignSchema: AuthorSchema,
      localColumn: t => t.authorId,
      foreignColumn: t => t.id,
      as: 'author',
      });
      // posts[0].author.name — typed as string ✓
    • Limit the number of rows returned.

      Parameters

      • n: number

        Maximum number of rows.

      Returns this

      this for chaining.

    • Skip the first n rows in the result set (for cursor/offset pagination).

      Parameters

      • n: number

        Number of rows to skip.

      Returns this

      this for chaining.

    • Order the results by a column.

      Parameters

      • column: Raw<any> | ColumnRef<TLocalSchema>

        Column reference or raw expression.

      • Optionaldirection: "asc" | "desc"

        'asc' (default) or 'desc'.

      Returns this

      this for chaining.

      query(db, UserSchema).orderBy(t => t.name).orderBy(t => t.createdAt, 'desc');
      
    • Order the results by a raw SQL expression.

      Parameters

      • sql: string

        Raw SQL (e.g. 'LOWER(name) ASC').

      • ...bindings: any[]

      Returns this

      this for chaining.

    • Add an OR WHERE clause. Use this to create alternative filter branches.

      Parameters

      Returns this

      this for chaining.

    • Add an OR WHERE clause. Use this to create alternative filter branches.

      Parameters

      Returns this

      this for chaining.

    • Add an OR WHERE clause. Use this to create alternative filter branches.

      Parameters

      • record: Record<string, any>

      Returns this

      this for chaining.

    • Add an OR WHERE clause. Use this to create alternative filter branches.

      Parameters

      • callback: (builder: QueryBuilder) => void

      Returns this

      this for chaining.

    • Add an OR WHERE clause. Use this to create alternative filter branches.

      Parameters

      • raw: Raw

      Returns this

      this for chaining.

    • Select specific columns instead of *. Each column reference is resolved to its SQL column name through the schema.

      Parameters

      Returns this

      this for chaining.

    • Returns the underlying Knex query builder. Useful when passing this query as a foreignQuery in .joinOne() / .joinMany(), or any context that expects a raw Knex.QueryBuilder.

      Returns QueryBuilder

    • Return the raw SQL string that would be executed, for debugging. Does not execute the query against the database.

      Returns string

    • Bind this query builder to a Knex transaction.

      Returns a new builder that runs all operations — SELECT, INSERT, UPDATE, DELETE, and eager-loaded sub-queries — within the given transaction. The original builder is left unchanged.

      Use this when you already have a transaction obtained from knex.transaction() and want all operations performed by the returned builder to participate in that transaction.

      Parameters

      • trx: Transaction

        The Knex transaction obtained from knex.transaction().

      Returns SchemaQueryBuilder<TLocalSchema, TResult>

      A new SchemaQueryBuilder bound to the transaction.

      async function createUser(
      data: InsertType<typeof UserSchema>,
      trx: Knex.Transaction
      ) {
      return query(db, UserSchema).transacting(trx).insert(data);
      }

      await db.transaction(async trx => {
      const user = await createUser({ name: 'Alice' }, trx);
      await query(db, PostSchema).transacting(trx).insert({ authorId: user.id, title: 'Hello' });
      });
    • Update all rows that match the current WHERE clause and return the updated records.

      Only the keys present in data are updated (partial update). Property keys are resolved to column names automatically.

      Parameters

      • data: Partial<InferType<TLocalSchema>>

        Partial schema object with fields to update.

      Returns Promise<TResult[]>

      All rows that were updated.

      const updated = await query(db, UserSchema)
      .where(t => t.id, userId)
      .update({ name: 'Bob' });
    • Add a WHERE clause to the query.

      Accepts a column reference, an optional operator, and a value:

      • where(t => t.age, '>', 18) — property accessor + operator + value.
      • where('age', 18) — string key + value (defaults to =).
      • where({ name: 'Alice' }) — record object; property keys are mapped to column names automatically.
      • where(builder => { ... }) — Knex sub-builder callback for grouped conditions.
      • where(knex.raw('...')) — raw SQL expression.

      Multiple .where() calls are combined with AND.

      Parameters

      Returns this

      this for chaining.

    • Add a WHERE clause to the query.

      Accepts a column reference, an optional operator, and a value:

      • where(t => t.age, '>', 18) — property accessor + operator + value.
      • where('age', 18) — string key + value (defaults to =).
      • where({ name: 'Alice' }) — record object; property keys are mapped to column names automatically.
      • where(builder => { ... }) — Knex sub-builder callback for grouped conditions.
      • where(knex.raw('...')) — raw SQL expression.

      Multiple .where() calls are combined with AND.

      Parameters

      Returns this

      this for chaining.

    • Add a WHERE clause to the query.

      Accepts a column reference, an optional operator, and a value:

      • where(t => t.age, '>', 18) — property accessor + operator + value.
      • where('age', 18) — string key + value (defaults to =).
      • where({ name: 'Alice' }) — record object; property keys are mapped to column names automatically.
      • where(builder => { ... }) — Knex sub-builder callback for grouped conditions.
      • where(knex.raw('...')) — raw SQL expression.

      Multiple .where() calls are combined with AND.

      Parameters

      • raw: Raw
      • operator: string
      • value: any

      Returns this

      this for chaining.

    • Add a WHERE clause to the query.

      Accepts a column reference, an optional operator, and a value:

      • where(t => t.age, '>', 18) — property accessor + operator + value.
      • where('age', 18) — string key + value (defaults to =).
      • where({ name: 'Alice' }) — record object; property keys are mapped to column names automatically.
      • where(builder => { ... }) — Knex sub-builder callback for grouped conditions.
      • where(knex.raw('...')) — raw SQL expression.

      Multiple .where() calls are combined with AND.

      Parameters

      • callback: (builder: QueryBuilder) => void

      Returns this

      this for chaining.

    • Add a WHERE clause to the query.

      Accepts a column reference, an optional operator, and a value:

      • where(t => t.age, '>', 18) — property accessor + operator + value.
      • where('age', 18) — string key + value (defaults to =).
      • where({ name: 'Alice' }) — record object; property keys are mapped to column names automatically.
      • where(builder => { ... }) — Knex sub-builder callback for grouped conditions.
      • where(knex.raw('...')) — raw SQL expression.

      Multiple .where() calls are combined with AND.

      Parameters

      • record: Record<string, any>

      Returns this

      this for chaining.

    • Add a WHERE clause to the query.

      Accepts a column reference, an optional operator, and a value:

      • where(t => t.age, '>', 18) — property accessor + operator + value.
      • where('age', 18) — string key + value (defaults to =).
      • where({ name: 'Alice' }) — record object; property keys are mapped to column names automatically.
      • where(builder => { ... }) — Knex sub-builder callback for grouped conditions.
      • where(knex.raw('...')) — raw SQL expression.

      Multiple .where() calls are combined with AND.

      Parameters

      • raw: Raw

      Returns this

      this for chaining.

    • Add a WHERE EXISTS (subquery) clause.

      Parameters

      • callback: QueryBuilder<any, any> | QueryCallback<any, unknown[]>

        A Knex query callback or sub-query builder.

      Returns this

      this for chaining.

    • Add a WHERE column IN (values) clause.

      Parameters

      • column: ColumnRef<TLocalSchema>

        Column reference (property accessor or string key).

      • values: readonly any[] | QueryBuilder<any, any>

        Array of values or a sub-query.

      Returns this

      this for chaining.

    • Add a WHERE NOT clause — negates the condition.

      Parameters

      Returns this

      this for chaining.

    • Add a WHERE NOT clause — negates the condition.

      Parameters

      Returns this

      this for chaining.

    • Add a WHERE NOT clause — negates the condition.

      Parameters

      • record: Record<string, any>

      Returns this

      this for chaining.

    • Add a WHERE NOT clause — negates the condition.

      Parameters

      • callback: (builder: QueryBuilder) => void

      Returns this

      this for chaining.

    • Add a WHERE NOT clause — negates the condition.

      Parameters

      • raw: Raw

      Returns this

      this for chaining.

    • Add a WHERE column NOT IN (values) clause.

      Parameters

      • column: ColumnRef<TLocalSchema>

        Column reference.

      • values: readonly any[] | QueryBuilder<any, any>

        Array of values or a sub-query.

      Returns this

      this for chaining.

    • Add a raw WHERE clause. Useful for database-specific expressions.

      Parameters

      • sql: string

        Raw SQL string with optional :binding: or ? placeholders.

      • ...bindings: any[]

        Values for the placeholders.

      Returns this

      this for chaining.