{"id":14053898,"url":"https://github.com/seeden/kysely-orm","last_synced_at":"2025-04-23T00:22:22.515Z","repository":{"id":53932052,"uuid":"519728029","full_name":"seeden/kysely-orm","owner":"seeden","description":"TypeSafe ORM for Kysely library","archived":false,"fork":false,"pushed_at":"2023-05-27T12:53:38.000Z","size":455,"stargazers_count":55,"open_issues_count":2,"forks_count":2,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-04-14T10:05:21.638Z","etag":null,"topics":["knex","kysely","mysql","nodejs","objectionjs","orm","postgres","postgresql","sql","sqllite","typescript"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/seeden.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2022-07-31T09:10:58.000Z","updated_at":"2025-02-24T18:06:39.000Z","dependencies_parsed_at":"2024-01-14T14:31:22.536Z","dependency_job_id":"bac8fe3c-f693-436d-a9d5-504d4bfc092c","html_url":"https://github.com/seeden/kysely-orm","commit_stats":{"total_commits":144,"total_committers":1,"mean_commits":144.0,"dds":0.0,"last_synced_commit":"39aa19547a86ca5a6cb22f6d2f338a8c4c1a9099"},"previous_names":["goodmodule/kysely-orm","seeden/kysely-orm"],"tags_count":88,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/seeden%2Fkysely-orm","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/seeden%2Fkysely-orm/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/seeden%2Fkysely-orm/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/seeden%2Fkysely-orm/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/seeden","download_url":"https://codeload.github.com/seeden/kysely-orm/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250344658,"owners_count":21415160,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["knex","kysely","mysql","nodejs","objectionjs","orm","postgres","postgresql","sql","sqllite","typescript"],"created_at":"2024-08-12T21:00:39.676Z","updated_at":"2025-04-23T00:22:22.496Z","avatar_url":"https://github.com/seeden.png","language":"TypeScript","readme":"# kysely-orm\nTypeSafe ORM for [kysely library](https://github.com/koskimas/kysely)\n\n# Define TypeSafe DB structure\n\n```ts ./@types/Database\nimport { type Generated } from 'kysely';\n\ninterface Users {\n  id: Generated\u003cnumber\u003e;\n  name: string;\n  email: string;\n}\n\ninterface Books {\n  id: Generated\u003cnumber\u003e;\n  title: string;\n  userId: number;\n}\n\ninterface DB {\n  users: Users;\n  books: Books;\n};\n```\n\nI will recommend using [library kysely-codegen](https://github.com/RobinBlomberg/kysely-codegen) for autogenerating this structure. \n\n# Define Database connection\n\n```ts: ./config/db.ts\nimport { PostgresDialect } from 'kysely';\nimport { Pool } from 'pg';\nimport { Database } from 'kysely-orm';\nimport type DB from './@types/Database';\n\nexport default new Database\u003cDB\u003e({\n  dialect: new PostgresDialect({\n    pool: new Pool({\n      connectionString,\n    }),\n  }),\n});\n```\n\n## SQLite Example\n\n```ts: ./config/db.ts\nimport { SqliteDialect } from 'kysely';\nimport SQLLiteDatabase from 'better-sqlite3';\nimport { Database } from 'kysely-orm';\nimport type DB from './@types/Database';\n\nexport default new Database\u003cDB\u003e({\n  dialect: new SqliteDialect({\n    database: new SQLLiteDatabase('test.db'),\n  }),\n});\n```\n\n# Define Model\n\n```ts ./models/User.ts\nimport db from './db';\n\nexport default class User extends db.model('users', 'id') {\n  static findByEmail(email: string) {\n    return this.findOne('email', email);\n  }\n}\n```\n\n## Export all models\n\n```ts ./models/index.ts\nexport { default as User } from './User';\nexport { default as Book } from './Book';\n```\n\n# Transactions\n\n```ts \nimport { User, Book } from '../models';\n\nasync function createUser(data) {\n  const newUser = User.transaction(async () =\u003e {\n    const user = await User.findByEmail(email);\n    if (user) {\n      throw new Error('User already exists');\n    }\n\n    return User.insert(data);\n  });\n\n  ...\n}\n```\n\nHow is it working?\nTransactions are using node AsyncLocalStorage whitch is stable node feature.\nTherefore you do not need to pass any transaction object to your current models.\nEverything working out of the box.\n\n### Use db.transaction instead of Model.transaction\nModel.transaction is alias for db.transaction\n\n```ts\nimport db from '../config/db';\nimport { User, Book } from '../models';\n\nasync function createUser(data) {\n  const newUser = db.transaction(async () =\u003e {\n    const user = await User.findByEmail(email);\n    if (user) {\n      throw new Error('User already exists');\n    }\n\n    return User.insert(data);\n  });\n\n  ...\n}\n```\n\n### AsyncLocalStorage pitfalls\n\nIf you are using everywhere async/await, you should be fine.\nIf you need to use a callback, you have two options:\n1. use utils.promisify and stay with async/await (preferred option)\n2. use AsyncResource.bind(yourCallback)\n\nWithout it, the thread chain will lose transaction details which are hard to track.\n\nPerformance of AsyncLocalStorage is fine with Node \u003e=16.2.0. \nMore details you can find here https://github.com/nodejs/node/issues/34493#issuecomment-845094849\nThis is the reason why I use it as a minimal nodejs version.\n\n### How to use multiple transactions\n\nWorking with multiple models and different transactions is not an easy task. For this purpose you can use\n\n```ts\nimport { User } from '../models';\n\nasync function createUsers(userData1, userData2) {\n  const [user1, user2] = await Promise.all([\n    User.transaction(() =\u003e User.insert(userData1)),\n    User.transaction(() =\u003e User.insert(userData2)),\n  ]);\n  ...\n}\n```\n\n### The afterCommit hook\n\nA transaction object allows tracking if and when it is committed.\n\nAn afterCommit hook can be added to both managed and unmanaged transaction objects:\n\n```ts \nimport { User } from '../models';\n\nasync function createUser(data) {\n  const newUser = User.transaction(async ({ afterCommit }) =\u003e {\n    const user = await User.findByEmail(email);\n    if (user) {\n      throw new Error('User already exists');\n    }\n\n    const user = await User.insert(data);\n\n    afterCommit(async () =\u003e {\n      await notifyUser(user);\n    });\n\n    ...\n\n    return user;\n  });\n\n  ...\n}\n```\n\nThe callback passed to afterCommit can be async. In this case transaction call will wait for it before settling.\n\nThe afterCommit hook is not raised if the transaction is rolled back.\nThe afterCommit hook does not modify the return value of the transaction.\n\n# Requests and models/transactions isolation\n\nFor each http request, you should create a new isolated model instance (best security practice). Here is an example of how to do that.\n\n```ts\nimport { isolate } from 'kysely-orm';\nimport { User } from '../models';\n\nconst { User: IsolatedUser } = isolate({ User });\n```\n\nFor example why to use it: \n1. when your model is using dataloaders\n2. when your model is storing data and using it later\n\n# Mixins\n\nSometimes you want to use same logic across your models. For example automatically set updatedAt when you update row data.\nHere is example how to define model which has support for mixins.\n\n```ts \nimport { updatedAt } from 'kysely-orm';\nimport db from './db';\n\nconst BaseModel = db.model('users', 'id');\n\nclass User extends updatedAt\u003cDB, 'users', 'id', typeof BaseModel\u003e(BaseModel, 'updatedAt') {\n  findByEmail(email: string) {\n    return this.findOne('email', email);\n  }\n}\n```\n\n## Helper applyMixins \n\nIf you are using many mixins it can be complicated and messy. Therefore you can use applyMixin which will help you to write \"nicer\" code.\n\n```ts \nimport { applyMixins, updatedAt, slug } from 'kysely-orm';\nimport db from './db';\n\nclass User extends applyMixins(db, 'users', 'id')(\n  (model) =\u003e \u003cDB, 'users', 'id', typeof model\u003eupdatedAt(model, 'updatedAt'),\n  (model) =\u003e \u003cDB, 'users', 'id', typeof model\u003eslug(model, {\n    field: 'username',\n    sources: ['name', 'firstName', 'lastName'],\n    slugOptions: {\n      truncate: 15,\n    },\n  }),\n) {\n  findByEmail(email: string) {\n    return this.findOne('email', email);\n  }\n}\n```\n\n## Mixin updatedAt\n\nIt will set your db field to NOW() during any update\n\n```ts \nimport { applyMixins, updatedAt } from 'kysely-orm';\nimport db from './db';\n\nexport default class User extends applyMixins(db, 'users', 'id')(\n  (model) =\u003e \u003cDB, 'users', 'id', typeof model\u003eupdatedAt(model, 'updatedAt'),\n) {\n  findByEmail(email: string) {\n    return this.findOne('email', email);\n  }\n}\n```\n\n## Mixin slug\n\nIt will automatically compute url slug from your data and use it during db insert\n\n```ts \nimport { applyPlugins, slug } from 'kysely-orm';\nimport type DB from './@types/DB';\n\nexport default class User extends applyMixins(db, 'users', 'id')(\n  (model) =\u003e \u003cDB, 'users', 'id', typeof model\u003eslug(model, {\n    field: 'username',\n    sources: ['name', 'firstName', 'lastName'],\n    slugOptions: {\n      truncate: 15,\n    },\n  }),\n) {\n  findByEmail(email: string) {\n    return this.findOne('email', email);\n  }\n}\n```\n\n# Use model as correct selectable type\n\nUntil TypeScript fix https://github.com/microsoft/TypeScript/issues/40451 there is a simple option how to use model as correct type. Interface named same as type in file will merge all attributes automatically.\n\n```ts\nimport { type Selectable, Database } from 'kysely-orm';\n\ninterface Users {\n  id: Generated\u003cnumber\u003e;\n  name: string;\n}\n\ninterface DB {\n  users: Users;\n};\n\nconst db = new Database\u003cDB\u003e({\n  connectionString: '...',\n});\n\nexport default interface User extends Selectable\u003cUsers\u003e {};\nexport default class User extends db.model('users', 'id') {\n\n}\n```\n\n```ts\nimport User from './User';\n\nconst user = new User({\n  id: 1,\n  name: 'Adam',\n});\n\nconsole.log(user.name); // name has correct type string\n```\n\nWithout interface, user.name will throw error about unknown property.\n\n# Best practices and coments and answer\n - Do not import models into your mixins. It will breaks isolation if you use it and throw errors\n - Models are not available from Database object because you can not ask for it from database object. It will breaks isolation, types and whole encapsulation.\n - Why not to use functions instead of classes? We need to bind db, table and id for all functions. If we use functions we will reinvent wheel.\n - When typescript fixed max limit issue we can use instance for each data row\n\n\n# Standard Model methods and properties\n\n```ts\nclass Model {\n  static readonly db: Database\u003cDB\u003e = db;\n  static readonly table: TableName = table;\n  static readonly id: IdColumnName = id;\n  static readonly noResultError: typeof NoResultError = noResultError;\n  static isolated: boolean = false;\n\n  // constructor(data: Data);\n  constructor(...args: any[]) {\n    Object.assign(this, args[0]);\n  }\n\n  static relation\u003c\n    FromColumnName extends keyof DB[TableName] \u0026 string,\n    FromReferenceExpression extends ReferenceExpression\u003cDB, TableName, FromColumnName\u003e,\n    ToTableName extends keyof DB \u0026 string,\n    ToColumnName extends keyof DB[ToTableName] \u0026 string,\n  \u003e(\n    type: RelationType.BelongsToOneRelation | RelationType.HasOneRelation | RelationType.HasOneThroughRelation, \n    from: FromReferenceExpression, \n    to: ReferenceExpression\u003cDB, ToTableName, ToColumnName\u003e\n  ): OneRelation\u003c\n    DB, \n    TableName, \n    FromColumnName, \n    ToTableName,\n    ToColumnName\n  \u003e;\n  static relation\u003c\n    FromColumnName extends keyof DB[TableName] \u0026 string,\n    FromReferenceExpression extends ReferenceExpression\u003cDB, TableName, FromColumnName\u003e,\n    ToTableName extends keyof DB \u0026 string,\n    ToColumnName extends keyof DB[ToTableName] \u0026 string,\n  \u003e(\n    type: RelationType.BelongsToManyRelation | RelationType.HasManyRelation | RelationType.HasManyThroughRelation, \n    from: FromReferenceExpression, \n    to: ReferenceExpression\u003cDB, ToTableName, ToColumnName\u003e\n  ): ManyRelation\u003c\n    DB, \n    TableName, \n    FromColumnName, \n    ToTableName,\n    ToColumnName\n  \u003e;\n  static relation\u003c\n    FromColumnName extends keyof DB[TableName] \u0026 string,\n    FromReferenceExpression extends ReferenceExpression\u003cDB, TableName, FromColumnName\u003e,\n    ToTableName extends keyof DB \u0026 string,\n    ToColumnName extends keyof DB[ToTableName] \u0026 string,\n  \u003e(type: RelationType, from: FromReferenceExpression, to: ReferenceExpression\u003cDB, ToTableName, ToColumnName\u003e): any {\n    return {\n      type,\n      from,\n      to,\n    };\n  }\n\n  static transaction\u003cType\u003e(callback: TransactionCallback\u003cDB, Type\u003e) {\n    return this.db.transaction(callback);\n  }\n\n  static get dynamic() {\n    return this.db.dynamic;\n  }\n\n  static ref(reference: string) {\n    return this.db.dynamic.ref(reference);\n  }\n\n  static get fn() {\n    return this.db.fn;\n  }\n\n  static selectFrom() {\n    if (this.db.isolated \u0026\u0026 !this.isolated) {\n      throw new Error('Cannot use selectFrom() in not isolated model. Call isolate({ Model }) first.');\n    }\n    return this.db.selectFrom(this.table);\n  }\n\n  static updateTable() {\n    if (this.db.isolated \u0026\u0026 !this.isolated) {\n      throw new Error('Cannot use updateTable() in not isolated model. Call isolate({ Model }) first.');\n    }\n    return this.db.updateTable(this.table);\n  }\n\n  static insertInto() {\n    if (this.db.isolated \u0026\u0026 !this.isolated) {\n      throw new Error('Cannot use insertInto() in not isolated model. Call isolate({ Model }) first.');\n    }\n    return this.db.insertInto(this.table);\n  }\n\n  static deleteFrom() {\n    if (this.db.isolated \u0026\u0026 !this.isolated) {\n      throw new Error('Cannot use deleteFrom() in not isolated model. Call isolate({ Model }) first.');\n    }\n    return this.db.deleteFrom(this.table);\n  }\n\n  static with\u003cName extends string, Expression extends CommonTableExpression\u003cDB, Name\u003e\u003e(name: Name, expression: Expression) {\n    return this.db.with(name, expression);\n  }\n\n  static async afterSingleInsert(singleResult: Selectable\u003cTable\u003e) {\n    return singleResult;\n  }\n\n  static async afterSingleUpdate(singleResult: Selectable\u003cTable\u003e) {\n    return singleResult;\n  }\n\n  static async afterSingleUpsert(singleResult: Selectable\u003cTable\u003e) {\n    return singleResult;\n  }\n\n  static processDataBeforeUpdate(data: UpdateExpression\u003cDB, TableName, TableName\u003e): UpdateExpression\u003cDB, TableName, TableName\u003e;\n  static processDataBeforeUpdate(data: UpdateExpression\u003cOnConflictDatabase\u003cDB, TableName\u003e, OnConflictTables\u003cTableName\u003e, OnConflictTables\u003cTableName\u003e\u003e): UpdateExpression\u003cOnConflictDatabase\u003cDB, TableName\u003e, OnConflictTables\u003cTableName\u003e, OnConflictTables\u003cTableName\u003e\u003e;\n  static processDataBeforeUpdate(data: UpdateExpression\u003cDB, TableName, TableName\u003e | UpdateExpression\u003cOnConflictDatabase\u003cDB, TableName\u003e, OnConflictTables\u003cTableName\u003e, OnConflictTables\u003cTableName\u003e\u003e) {\n    return data;\n  }\n\n  static processDataBeforeInsert(data: InsertObjectOrList\u003cDB, TableName\u003e) {\n    return data;\n  }\n\n  static async find\u003cColumnName extends keyof Table \u0026 string\u003e(\n    column: ColumnName,\n    values: Readonly\u003cSelectType\u003cTable[ColumnName]\u003e[]\u003e | Readonly\u003cSelectType\u003cTable[ColumnName]\u003e\u003e,\n    func?: (qb: SelectQueryBuilder\u003cDB, TableName, {}\u003e) =\u003e SelectQueryBuilder\u003cDB, TableName, {}\u003e,\n  ) {\n    const isArray = Array.isArray(values);\n\n    return this\n      .selectFrom()\n      .selectAll()\n      .where(this.ref(`${this.table}.${column}`), isArray ? 'in' : '=', values)\n      .$if(!!func, (qb) =\u003e func?.(qb as unknown as SelectQueryBuilder\u003cDB, TableName, {}\u003e) as unknown as typeof qb)\n      .execute();\n  }\n\n  static async findOne\u003cColumnName extends keyof Table \u0026 string\u003e(\n    column: ColumnName,\n    value: Readonly\u003cSelectType\u003cTable[ColumnName]\u003e\u003e,\n    func?: (qb: SelectQueryBuilder\u003cDB, TableName, {}\u003e) =\u003e SelectQueryBuilder\u003cDB, TableName, {}\u003e,\n  ) {\n    return this\n      .selectFrom()\n      .selectAll()\n      .where(this.ref(`${this.table}.${column}`), '=', value)\n      .$if(!!func, (qb) =\u003e func?.(qb as unknown as SelectQueryBuilder\u003cDB, TableName, {}\u003e) as unknown as typeof qb)\n      .limit(1)\n      .executeTakeFirst();\n  }\n\n  static async findByFields(\n    fields: Readonly\u003cPartial\u003c{\n      [ColumnName in keyof Table \u0026 string]: SelectType\u003cTable[ColumnName]\u003e | SelectType\u003cTable[ColumnName]\u003e[];\n    }\u003e\u003e,\n    func?: (qb: SelectQueryBuilder\u003cDB, TableName, {}\u003e) =\u003e SelectQueryBuilder\u003cDB, TableName, {}\u003e,\n  ) {\n    return this\n      .selectFrom()\n      .selectAll()\n      .where((qb) =\u003e {\n        let currentQuery = qb;\n        for (const [column, value] of Object.entries(fields)) {\n          const isArray = Array.isArray(value);\n          currentQuery = currentQuery.where(this.ref(`${this.table}.${column}`), isArray ? 'in' : '=', value);\n        }\n        return currentQuery;\n      })\n      .$if(!!func, (qb) =\u003e func?.(qb as unknown as SelectQueryBuilder\u003cDB, TableName, {}\u003e) as unknown as typeof qb)\n      .execute();\n  }\n\n  static async findOneByFields(\n    fields: Readonly\u003cPartial\u003c{\n      [ColumnName in keyof Table \u0026 string]: SelectType\u003cTable[ColumnName]\u003e;\n    }\u003e\u003e,\n    func?: (qb: SelectQueryBuilder\u003cDB, TableName, {}\u003e) =\u003e SelectQueryBuilder\u003cDB, TableName, {}\u003e,\n  ) {\n    return this\n      .selectFrom()\n      .selectAll()\n      .where((qb) =\u003e {\n        let currentQuery = qb;\n        for (const [column, value] of Object.entries(fields)) {\n          const isArray = Array.isArray(value);\n          currentQuery = currentQuery.where(this.ref(`${this.table}.${column}`), isArray ? 'in' : '=', value);\n        }\n        return currentQuery;\n      })\n      .$if(!!func, (qb) =\u003e func?.(qb as unknown as SelectQueryBuilder\u003cDB, TableName, {}\u003e) as unknown as typeof qb)\n      .executeTakeFirst();\n  }\n\n  static async getOneByFields(\n    fields: Readonly\u003cPartial\u003c{\n      [ColumnName in keyof Table \u0026 string]: SelectType\u003cTable[ColumnName]\u003e;\n    }\u003e\u003e,\n    func?: (qb: SelectQueryBuilder\u003cDB, TableName, {}\u003e) =\u003e SelectQueryBuilder\u003cDB, TableName, {}\u003e,\n    error: typeof NoResultError = this.noResultError,\n  ) {\n    return this\n      .selectFrom()\n      .where((qb) =\u003e {\n        let currentQuery = qb;\n        for (const [column, value] of Object.entries(fields)) {\n          const isArray = Array.isArray(value);\n          currentQuery = currentQuery.where(this.ref(`${this.table}.${column}`), isArray ? 'in' : '=', value);\n        }\n        return currentQuery;\n      })\n      .selectAll()\n      .$if(!!func, (qb) =\u003e func?.(qb as unknown as SelectQueryBuilder\u003cDB, TableName, {}\u003e) as unknown as typeof qb)\n      .executeTakeFirstOrThrow(error);\n  }\n\n  static findById(\n    id: Id,\n    func?: (qb: SelectQueryBuilder\u003cDB, TableName, {}\u003e) =\u003e SelectQueryBuilder\u003cDB, TableName, {}\u003e,\n  ) {\n    return this.findOne(this.id, id, func);\n  }\n\n  static findByIds(\n    ids: Readonly\u003cSelectType\u003cIdColumn\u003e[]\u003e,\n    func?: (qb: SelectQueryBuilder\u003cDB, TableName, {}\u003e) =\u003e SelectQueryBuilder\u003cDB, TableName, {}\u003e,\n  ) {\n    return this.find(this.id, ids, func);\n  }\n\n  static async getOne\u003cColumnName extends keyof Table \u0026 string\u003e(\n    column: ColumnName,\n    value: Readonly\u003cSelectType\u003cTable[ColumnName]\u003e\u003e,\n    func?: (qb: SelectQueryBuilder\u003cDB, TableName, {}\u003e) =\u003e SelectQueryBuilder\u003cDB, TableName, {}\u003e,\n    error: typeof NoResultError = this.noResultError,\n  ) {\n    const item = await this\n      .selectFrom()\n      .selectAll()\n      .where(this.ref(`${this.table}.${column}`), '=', value)\n      .$if(!!func, (qb) =\u003e func?.(qb as unknown as SelectQueryBuilder\u003cDB, TableName, {}\u003e) as unknown as typeof qb)\n      .limit(1)\n      .executeTakeFirstOrThrow(error);\n\n    return item;\n  }\n\n  static getById(\n    id: Id,\n    func?: (qb: SelectQueryBuilder\u003cDB, TableName, {}\u003e) =\u003e SelectQueryBuilder\u003cDB, TableName, {}\u003e,\n    error: typeof NoResultError = this.noResultError,\n  ) {\n    return this.getOne(this.id, id, func, error);\n  }\n  \n  static async findOneAndUpdate\u003cColumnName extends keyof Table \u0026 string\u003e(\n    column: ColumnName,\n    value: Readonly\u003cSelectType\u003cTable[ColumnName]\u003e\u003e,\n    data: UpdateExpression\u003cDB, TableName, TableName\u003e,\n    func?: (qb: UpdateQueryBuilder\u003cDB, TableName, TableName, UpdateResult\u003e) =\u003e UpdateQueryBuilder\u003cDB, TableName, TableName, UpdateResult\u003e,\n  ) {\n    const updatedData = this.processDataBeforeUpdate(data);\n    const record = await this\n      .updateTable()\n      // @ts-ignore\n      .set(updatedData)\n      .where(this.ref(`${this.table}.${column}`), '=', value)\n      .$if(!!func, (qb) =\u003e func?.(qb as unknown as UpdateQueryBuilder\u003cDB, TableName, TableName, UpdateResult\u003e) as unknown as typeof qb)\n      .returningAll()\n      .executeTakeFirst();\n\n    return record ? this.afterSingleUpdate(record as Selectable\u003cTable\u003e) : record;\n  }\n\n  static async findByFieldsAndUpdate(\n    fields: Readonly\u003cPartial\u003c{\n      [ColumnName in keyof Table \u0026 string]: SelectType\u003cTable[ColumnName]\u003e | SelectType\u003cTable[ColumnName]\u003e[];\n    }\u003e\u003e, \n    data: UpdateExpression\u003cDB, TableName, TableName\u003e,\n    func?: (qb: UpdateQueryBuilder\u003cDB, TableName, TableName, UpdateResult\u003e) =\u003e UpdateQueryBuilder\u003cDB, TableName, TableName, UpdateResult\u003e,\n  ) {\n    const updatedData = this.processDataBeforeUpdate(data);\n\n    return await this\n      .updateTable()\n      // @ts-ignore\n      .set(updatedData)\n      .where((qb) =\u003e {\n        let currentQuery = qb;\n        for (const [column, value] of Object.entries(fields)) {\n          if (Array.isArray(value)) {\n            currentQuery = currentQuery.where(this.ref(`${this.table}.${column}`), 'in', value);\n          } else {\n            currentQuery = currentQuery.where(this.ref(`${this.table}.${column}`), '=', value);\n          }\n        }\n        return currentQuery;\n      })\n      .$if(!!func, (qb) =\u003e func?.(qb as unknown as UpdateQueryBuilder\u003cDB, TableName, TableName, UpdateResult\u003e) as unknown as typeof qb)\n      .returningAll()\n      .execute();\n  }\n\n  static async findOneByFieldsAndUpdate(\n    fields: Readonly\u003cPartial\u003c{\n      [ColumnName in keyof Table \u0026 string]: SelectType\u003cTable[ColumnName]\u003e | SelectType\u003cTable[ColumnName]\u003e[];\n    }\u003e\u003e, \n    data: UpdateExpression\u003cDB, TableName, TableName\u003e,\n    func?: (qb: UpdateQueryBuilder\u003cDB, TableName, TableName, UpdateResult\u003e) =\u003e UpdateQueryBuilder\u003cDB, TableName, TableName, UpdateResult\u003e,\n  ) {\n    // TODO use with and select with limit 1\n    const updatedData = this.processDataBeforeUpdate(data);\n    const record = await this\n      .updateTable()\n      // @ts-ignore\n      .set(updatedData)\n      .where((qb) =\u003e {\n        let currentQuery = qb;\n        for (const [column, value] of Object.entries(fields)) {\n          if (Array.isArray(value)) {\n            currentQuery = currentQuery.where(this.ref(`${this.table}.${column}`), 'in', value);\n          } else {\n            currentQuery = currentQuery.where(this.ref(`${this.table}.${column}`), '=', value);\n          }\n        }\n        return currentQuery;\n      })\n      .$if(!!func, (qb) =\u003e func?.(qb as unknown as UpdateQueryBuilder\u003cDB, TableName, TableName, UpdateResult\u003e) as unknown as typeof qb)\n      .returningAll()\n      .executeTakeFirst();\n\n    return record ? this.afterSingleUpdate(record as Selectable\u003cTable\u003e) : record;\n  }\n\n  static async getOneByFieldsAndUpdate(\n    fields: Readonly\u003cPartial\u003c{\n      [ColumnName in keyof Table \u0026 string]: SelectType\u003cTable[ColumnName]\u003e | SelectType\u003cTable[ColumnName]\u003e[];\n    }\u003e\u003e, \n    data: UpdateExpression\u003cDB, TableName, TableName\u003e,\n    func?: (qb: UpdateQueryBuilder\u003cDB, TableName, TableName, UpdateResult\u003e) =\u003e UpdateQueryBuilder\u003cDB, TableName, TableName, UpdateResult\u003e,\n    error: typeof NoResultError = this.noResultError,\n  ) {\n    // TODO use with and select with limit 1\n    const updatedData = this.processDataBeforeUpdate(data);\n    const record = await this\n      .updateTable()\n      // @ts-ignore\n      .set(updatedData)\n      .where((qb) =\u003e {\n        let currentQuery = qb;\n        for (const [column, value] of Object.entries(fields)) {\n          if (Array.isArray(value)) {\n            currentQuery = currentQuery.where(this.ref(`${this.table}.${column}`), 'in', value);\n          } else {\n            currentQuery = currentQuery.where(this.ref(`${this.table}.${column}`), '=', value);\n          }\n        }\n        return currentQuery;\n      })\n      .$if(!!func, (qb) =\u003e func?.(qb as unknown as UpdateQueryBuilder\u003cDB, TableName, TableName, UpdateResult\u003e) as unknown as typeof qb)\n      .returningAll()\n      .executeTakeFirstOrThrow(error);\n\n    return this.afterSingleUpdate(record  as Selectable\u003cTable\u003e);\n  }\n\n  static findByIdAndUpdate(\n    id: SelectType\u003cIdColumn\u003e, \n    data: UpdateExpression\u003cDB, TableName, TableName\u003e,\n    func?: (qb: UpdateQueryBuilder\u003cDB, TableName, TableName, UpdateResult\u003e) =\u003e UpdateQueryBuilder\u003cDB, TableName, TableName, UpdateResult\u003e,\n  ) {\n    return this.findOneAndUpdate(this.id, id, data, func);\n  }\n  \n  static async getOneAndUpdate\u003cColumnName extends keyof Table \u0026 string\u003e(\n    column: ColumnName,\n    value: Readonly\u003cSelectType\u003cTable[ColumnName]\u003e\u003e,\n    data: UpdateExpression\u003cDB, TableName, TableName\u003e,\n    func?: (qb: UpdateQueryBuilder\u003cDB, TableName, TableName, UpdateResult\u003e) =\u003e UpdateQueryBuilder\u003cDB, TableName, TableName, UpdateResult\u003e,\n    error: typeof NoResultError = this.noResultError,\n  ) {\n    const updatedData = this.processDataBeforeUpdate(data);\n    const record = await this\n      .updateTable()\n      // @ts-ignore\n      .set(updatedData)\n      .where(this.ref(`${this.table}.${column}`), '=', value)\n      .$if(!!func, (qb) =\u003e func?.(qb as unknown as UpdateQueryBuilder\u003cDB, TableName, TableName, UpdateResult\u003e) as unknown as typeof qb)\n      .returningAll()\n      .executeTakeFirstOrThrow(error);\n\n    return this.afterSingleUpdate(record as Selectable\u003cTable\u003e);\n  }\n\n  static getByIdAndUpdate(\n    id: SelectType\u003cIdColumn\u003e, \n    data: UpdateExpression\u003cDB, TableName, TableName\u003e,\n    func?: (qb: UpdateQueryBuilder\u003cDB, TableName, TableName, UpdateResult\u003e) =\u003e UpdateQueryBuilder\u003cDB, TableName, TableName, UpdateResult\u003e,\n    error: typeof NoResultError = this.noResultError,\n  ) {\n    return this.getOneAndUpdate(this.id, id, data, func, error);\n  }\n  \n  static lock\u003cColumnName extends keyof Table \u0026 string\u003e(\n    column: ColumnName,\n    value: Readonly\u003cSelectType\u003cTable[ColumnName]\u003e\u003e,\n  ) {\n    return this\n      .selectFrom()\n      .where(this.ref(`${this.table}.${column}`), '=', value)\n      .selectAll()\n      .forUpdate()\n      .executeTakeFirst();\n  }\n\n  static lockById(id: SelectType\u003cIdColumn\u003e) {\n    return this.lock(this.id, id);\n  }\n  \n  static async insertOne(\n    values: InsertObject\u003cDB, TableName\u003e,\n    error: typeof NoResultError = this.noResultError,\n  ) {\n    const record = await this\n      .insertInto()\n      .values(this.processDataBeforeInsert(values))\n      .returningAll()\n      .executeTakeFirstOrThrow(error);\n\n    return this.afterSingleInsert(record);\n  }\n\n  static async insert(\n    values: InsertObjectOrList\u003cDB, TableName\u003e,\n  ) {\n    return this\n      .insertInto()\n      .values(this.processDataBeforeInsert(values))\n      .returningAll()\n      .execute();\n  }\n\n  static async upsertOne(\n    values: InsertObject\u003cDB, TableName\u003e,\n    upsertValues: UpdateExpression\u003cOnConflictDatabase\u003cDB, TableName\u003e, OnConflictTables\u003cTableName\u003e, OnConflictTables\u003cTableName\u003e\u003e,\n    conflictColumns: Readonly\u003c(keyof Table \u0026 string)[]\u003e | Readonly\u003ckeyof Table \u0026 string\u003e,\n    func?: (qb: OnConflictUpdateBuilder\u003cDB, TableName\u003e) =\u003e OnConflictUpdateBuilder\u003cDB, TableName\u003e,\n    error: typeof NoResultError = this.noResultError,\n  ) {\n    const record = await this\n      .insertInto()\n      .values(this.processDataBeforeInsert(values))\n      .onConflict((ocb) =\u003e {\n        const updatedOCB = ocb\n          .columns(Array.isArray(conflictColumns) ? conflictColumns : [conflictColumns])\n          .doUpdateSet(this.processDataBeforeUpdate(upsertValues)) as OnConflictUpdateBuilder\u003cDB, TableName\u003e;\n\n        return func ? func(updatedOCB) : updatedOCB;\n      })\n      .returningAll()\n      .executeTakeFirstOrThrow(error);\n\n    return this.afterSingleUpsert(record);\n  }\n\n  static async upsert(\n    values: InsertObjectOrList\u003cDB, TableName\u003e,\n    upsertValues: UpdateExpression\u003cOnConflictDatabase\u003cDB, TableName\u003e, OnConflictTables\u003cTableName\u003e, OnConflictTables\u003cTableName\u003e\u003e,\n    conflictColumns: Readonly\u003c(keyof Table \u0026 string)[]\u003e | Readonly\u003ckeyof Table \u0026 string\u003e,\n    func?: (qb: OnConflictUpdateBuilder\u003cDB, TableName\u003e) =\u003e OnConflictUpdateBuilder\u003cDB, TableName\u003e,\n  ) {\n    return await this\n      .insertInto()\n      .values(this.processDataBeforeInsert(values))\n      .onConflict((ocb) =\u003e {\n        const updatedOCB = ocb\n          .columns(Array.isArray(conflictColumns) ? conflictColumns : [conflictColumns])\n          .doUpdateSet(this.processDataBeforeUpdate(upsertValues)) as OnConflictUpdateBuilder\u003cDB, TableName\u003e;\n\n        return func ? func(updatedOCB) : updatedOCB;\n      })\n      .returningAll()\n      .execute();\n  }\n\n  static async insertOneIfNotExists\u003cValues extends InsertObject\u003cDB, TableName\u003e\u003e(\n    values: Values,\n    sameColumn: keyof DB[TableName] \u0026 string,\n    conflictColumns: Readonly\u003c(keyof Table \u0026 string)[]\u003e | Readonly\u003ckeyof Table \u0026 string\u003e,\n    func?: (qb: OnConflictUpdateBuilder\u003cDB, TableName\u003e) =\u003e OnConflictUpdateBuilder\u003cDB, TableName\u003e,\n    error: typeof NoResultError = this.noResultError,\n  ) {\n    const record = await this\n      .insertInto()\n      .values(values)\n      .onConflict((ocb) =\u003e {\n        const updatedOCB = ocb\n          .columns(Array.isArray(conflictColumns) ? conflictColumns : [conflictColumns])\n          .doUpdateSet({\n            // use current value instead of excluded because excluded value is not required\n            [sameColumn]: (eb: any) =\u003e eb.ref(`${this.table}.${sameColumn}`)\n          } as UpdateExpression\u003cOnConflictDatabase\u003cDB, TableName\u003e, OnConflictTables\u003cTableName\u003e, OnConflictTables\u003cTableName\u003e\u003e) as OnConflictUpdateBuilder\u003cDB, TableName\u003e;\n        \n        return func ? func(updatedOCB) : updatedOCB;\n      })\n      .returningAll()\n      .executeTakeFirstOrThrow(error);\n\n    return this.afterSingleInsert(record);\n  }\n  \n  // todo add limit via with\n  static async deleteOne\u003cColumnName extends keyof Table \u0026 string\u003e(\n    column: ColumnName,\n    value: Readonly\u003cSelectType\u003cTable[ColumnName]\u003e\u003e,\n    func?: (qb: DeleteQueryBuilder\u003cDB, TableName, DeleteResult\u003e) =\u003e DeleteQueryBuilder\u003cDB, TableName, DeleteResult\u003e,\n    error: typeof NoResultError = this.noResultError,\n  ) {\n    const { numDeletedRows } = await this\n      .deleteFrom()\n      .where(this.ref(`${this.table}.${column}`), '=', value)\n      .$if(!!func, (qb) =\u003e func?.(qb as unknown as DeleteQueryBuilder\u003cDB, TableName, DeleteResult\u003e) as unknown as typeof qb)\n      .executeTakeFirstOrThrow(error);\n\n    return numDeletedRows;\n  }\n\n  // todo add limit via with\n  static async deleteOneByFields(\n    fields: Readonly\u003cPartial\u003c{\n      [ColumnName in keyof Table \u0026 string]: SelectType\u003cTable[ColumnName]\u003e | SelectType\u003cTable[ColumnName]\u003e[];\n    }\u003e\u003e, \n    func?: (qb: DeleteQueryBuilder\u003cDB, TableName, DeleteResult\u003e) =\u003e DeleteQueryBuilder\u003cDB, TableName, DeleteResult\u003e,\n    error: typeof NoResultError = this.noResultError,\n  ) {\n    const { numDeletedRows } = await this\n      .deleteFrom()\n      .where((qb) =\u003e {\n        let currentQuery = qb;\n        for (const [column, value] of Object.entries(fields)) {\n          if (Array.isArray(value)) {\n            currentQuery = currentQuery.where(this.ref(`${this.table}.${column}`), 'in', value);\n          } else {\n            currentQuery = currentQuery.where(this.ref(`${this.table}.${column}`), '=', value);\n          }\n        }\n        return currentQuery;\n      })\n      .$if(!!func, (qb) =\u003e func?.(qb as unknown as DeleteQueryBuilder\u003cDB, TableName, DeleteResult\u003e) as unknown as typeof qb)\n      .executeTakeFirstOrThrow(error);\n    \n    return numDeletedRows;\n  }\n\n  static async deleteMany\u003cColumnName extends keyof Table \u0026 string\u003e(\n    column: ColumnName,\n    values: Readonly\u003cSelectType\u003cTable[ColumnName]\u003e[]\u003e,\n    func?: (qb: DeleteQueryBuilder\u003cDB, TableName, DeleteResult\u003e) =\u003e DeleteQueryBuilder\u003cDB, TableName, DeleteResult\u003e,\n    error: typeof NoResultError = this.noResultError,\n  ) {\n    const { numDeletedRows } = await this\n      .deleteFrom()\n      .where(this.ref(`${this.table}.${column}`), 'in', values)\n      .$if(!!func, (qb) =\u003e func?.(qb as unknown as DeleteQueryBuilder\u003cDB, TableName, DeleteResult\u003e) as unknown as typeof qb)\n      .executeTakeFirstOrThrow(error);\n\n    return numDeletedRows;\n  }\n\n  static deleteById(id: SelectType\u003cIdColumn\u003e) {\n    return this.deleteOne(this.id, id);\n  }\n\n  static findByIdAndIncrementQuery(\n    id: Id, \n    columns: Partial\u003cRecord\u003ckeyof Table, number\u003e\u003e,\n    func?: (qb: UpdateQueryBuilder\u003cDB, TableName, TableName, UpdateResult\u003e) =\u003e UpdateQueryBuilder\u003cDB, TableName, TableName, UpdateResult\u003e,\n  ) {\n    const setData: Updateable\u003cTable\u003e = {};\n\n    Object.keys(columns).forEach((column) =\u003e {\n      const value = columns[column as keyof Table] as number;\n      const correctColumn = column as keyof Updateable\u003cTable\u003e;\n\n      setData[correctColumn] = sql`${sql.ref(`${this.table}.${column}`)} + ${value}` as any;\n    });\n\n    return this\n      .updateTable()\n      // @ts-ignore\n      .set(setData)\n      .where(this.ref(this.id), '=', id)\n      .$if(!!func, (qb) =\u003e func?.(qb as unknown as UpdateQueryBuilder\u003cDB, TableName, TableName, UpdateResult\u003e) as unknown as typeof qb)\n      .returningAll();\n  }\n\n  static async findByIdAndIncrement(\n    id: Id, \n    columns: Partial\u003cRecord\u003ckeyof Table, number\u003e\u003e,\n    func?: (qb: UpdateQueryBuilder\u003cDB, TableName, TableName, UpdateResult\u003e) =\u003e UpdateQueryBuilder\u003cDB, TableName, TableName, UpdateResult\u003e,\n  ) {\n    const record = await this.findByIdAndIncrementQuery(id, columns, func).executeTakeFirst();\n\n    return record ? this.afterSingleUpdate(record as Selectable\u003cTable\u003e) : record;\n  }\n\n  static async getByIdAndIncrement(\n    id: Id, \n    columns: Partial\u003cRecord\u003ckeyof Table, number\u003e\u003e,\n    func?: (qb: UpdateQueryBuilder\u003cDB, TableName, TableName, UpdateResult\u003e) =\u003e UpdateQueryBuilder\u003cDB, TableName, TableName, UpdateResult\u003e,\n    error: typeof NoResultError = this.noResultError,\n  ) {\n    const record = await this\n      .findByIdAndIncrementQuery(id, columns, func)\n      .executeTakeFirstOrThrow(error);\n\n    return this.afterSingleUpdate(record as Selectable\u003cTable\u003e);\n  }\n\n  static relatedQuery\u003c\n    FromTableName extends TableName,\n    FromColumnName extends keyof DB[TableName] \u0026 string,\n    ToTableName extends keyof DB \u0026 string,\n    ToColumnName extends keyof DB[ToTableName] \u0026 string,\n  \u003e(relation: AnyRelation\u003cDB, FromTableName, FromColumnName, ToTableName, ToColumnName\u003e, ids: Id | Id[] = []) {\n    const { from, to } = relation;\n    const [fromTable] = from.split('.') as [FromTableName, FromColumnName];\n    const [toTable] = to.split('.') as [ToTableName, ToColumnName];\n\n    return this.db\n      .selectFrom(fromTable)\n      .innerJoin(toTable, (jb) =\u003e jb.onRef(this.ref(from), '=', this.ref(to)))\n      .where(this.ref(`${fromTable}.${this.id}`), Array.isArray(ids) ? 'in' : '=', ids)\n      .selectAll(toTable);\n  }\n\n  static async findRelatedById\u003c\n    FromTableName extends TableName,\n    FromColumnName extends keyof DB[TableName] \u0026 string,\n    ToTableName extends keyof DB \u0026 string,\n    ToColumnName extends keyof DB[ToTableName] \u0026 string,\n  \u003e(\n    relation: OneRelation\u003cDB, FromTableName, FromColumnName, ToTableName, ToColumnName\u003e, \n    id: Id,\n    error?: typeof NoResultError,\n  ): Promise\u003cSelectable\u003cDB[ToTableName]\u003e | undefined\u003e;\n\n  static async findRelatedById\u003c\n    FromTableName extends TableName,\n    FromColumnName extends keyof DB[TableName] \u0026 string,\n    ToTableName extends keyof DB \u0026 string,\n    ToColumnName extends keyof DB[ToTableName] \u0026 string,\n  \u003e(\n    relation: ManyRelation\u003cDB, FromTableName, FromColumnName, ToTableName, ToColumnName\u003e, \n    id: Id,\n    error?: typeof NoResultError,\n  ): Promise\u003cSelectable\u003cDB[ToTableName]\u003e[]\u003e;\n\n  static async findRelatedById\u003c\n    FromTableName extends TableName,\n    FromColumnName extends keyof DB[TableName] \u0026 string,\n    ToTableName extends keyof DB \u0026 string,\n    ToColumnName extends keyof DB[ToTableName] \u0026 string,\n  \u003e(\n    relation: AnyRelation\u003cDB, FromTableName, FromColumnName, ToTableName, ToColumnName\u003e, \n    id: Id,\n  ): Promise\u003cSelectable\u003cDB[ToTableName]\u003e | undefined | Selectable\u003cDB[ToTableName]\u003e[]\u003e {\n    const { type } = relation;\n    const oneResult = type === RelationType.HasOneRelation || type === RelationType.BelongsToOneRelation;\n    if (oneResult) {\n      return await this.relatedQuery(relation, id).executeTakeFirst() as Selectable\u003cDB[ToTableName]\u003e | undefined;\n    }\n\n    return await this.relatedQuery(relation, id).execute() as Selectable\u003cDB[ToTableName]\u003e[];\n  }\n\n  static async getRelatedById\u003c\n    FromTableName extends TableName,\n    FromColumnName extends keyof DB[TableName] \u0026 string,\n    ToTableName extends keyof DB \u0026 string,\n    ToColumnName extends keyof DB[ToTableName] \u0026 string,\n  \u003e(\n    relation: OneRelation\u003cDB, FromTableName, FromColumnName, ToTableName, ToColumnName\u003e, \n    id: Id,\n    error?: typeof NoResultError,\n  ): Promise\u003cSelectable\u003cDB[ToTableName]\u003e\u003e;\n\n  static async getRelatedById\u003c\n    FromTableName extends TableName,\n    FromColumnName extends keyof DB[TableName] \u0026 string,\n    ToTableName extends keyof DB \u0026 string,\n    ToColumnName extends keyof DB[ToTableName] \u0026 string,\n  \u003e(\n    relation: ManyRelation\u003cDB, FromTableName, FromColumnName, ToTableName, ToColumnName\u003e, \n    id: Id,\n    error?: typeof NoResultError,\n  ): Promise\u003cSelectable\u003cDB[ToTableName]\u003e[]\u003e;\n\n  static async getRelatedById\u003c\n    FromTableName extends TableName,\n    FromColumnName extends keyof DB[TableName] \u0026 string,\n    ToTableName extends keyof DB \u0026 string,\n    ToColumnName extends keyof DB[ToTableName] \u0026 string,\n  \u003e(\n    relation: AnyRelation\u003cDB, FromTableName, FromColumnName, ToTableName, ToColumnName\u003e, \n    id: Id,\n    error: typeof NoResultError = this.noResultError,\n  ): Promise\u003cSelectable\u003cDB[ToTableName]\u003e | Selectable\u003cDB[ToTableName]\u003e[]\u003e {\n    const { type } = relation;\n    const oneResult = type === RelationType.HasOneRelation || type === RelationType.BelongsToOneRelation;\n    if (oneResult) {\n      return await this.relatedQuery(relation, id).executeTakeFirstOrThrow(error) as Selectable\u003cDB[ToTableName]\u003e;\n    }\n\n    return await this.relatedQuery(relation, id).execute() as Selectable\u003cDB[ToTableName]\u003e[];\n  }\n\n  static async findRelated\u003c\n    FromTableName extends TableName,\n    FromColumnName extends keyof DB[TableName] \u0026 string,\n    ToTableName extends keyof DB \u0026 string,\n    ToColumnName extends keyof DB[ToTableName] \u0026 string,\n  \u003e(relation: AnyRelation\u003cDB, FromTableName, FromColumnName, ToTableName, ToColumnName\u003e, models: Data[]) {\n    const { from, to } = relation;\n    const [fromTable, fromColumn] = from.split('.') as [FromTableName, FromColumnName];\n    const [toTable] = to.split('.') as [ToTableName, ToColumnName];\n\n    // @ts-ignore\n    const ids = models.map((model) =\u003e model[fromColumn]);\n\n    return this\n      .db\n      .selectFrom(fromTable)\n      .innerJoin(toTable, (jb) =\u003e jb.onRef(this.ref(from), '=', this.ref(to)))\n      .where(this.ref(from), 'in', ids)\n      .selectAll(toTable)\n      .execute();\n  }\n\n  static async findRelatedAndCombine\u003c\n    FromTableName extends TableName,\n    FromColumnName extends keyof DB[TableName] \u0026 string,\n    ToTableName extends keyof DB \u0026 string,\n    ToColumnName extends keyof DB[ToTableName] \u0026 string,\n    Field extends string,\n  \u003e(relation: OneRelation\u003cDB, FromTableName, FromColumnName, ToTableName, ToColumnName\u003e, models: Data[], field: Field): Promise\u003c(Data \u0026 {\n    [key in Field]: Selectable\u003cDB[ToTableName]\u003e | undefined;\n  })[]\u003e;\n  static async findRelatedAndCombine\u003c\n    FromTableName extends TableName,\n    FromColumnName extends keyof DB[TableName] \u0026 string,\n    ToTableName extends keyof DB \u0026 string,\n    ToColumnName extends keyof DB[ToTableName] \u0026 string,\n    Field extends string,\n  \u003e(relation: ManyRelation\u003cDB, FromTableName, FromColumnName, ToTableName, ToColumnName\u003e, models: Data[], field: Field): Promise\u003c(Data \u0026 {\n    [key in Field]: Selectable\u003cDB[ToTableName]\u003e[];\n  })[]\u003e;\n\n  static async findRelatedAndCombine\u003c\n    FromTableName extends TableName,\n    FromColumnName extends keyof DB[TableName] \u0026 string,\n    ToTableName extends keyof DB \u0026 string,\n    ToColumnName extends keyof DB[ToTableName] \u0026 string,\n    Field extends string,\n  \u003e(relation: AnyRelation\u003cDB, FromTableName, FromColumnName, ToTableName, ToColumnName\u003e, models: Data[], field: Field): Promise\u003cany\u003e {\n    const rows = await this.findRelated(relation, models);\n\n    const { type, from, to } = relation;\n    const [_fromTable, fromColumn] = from.split('.') as [FromTableName, FromColumnName];\n    const [_toTable, toColumn] = to.split('.') as [ToTableName, ToColumnName];\n\n    const oneResult = type === RelationType.HasOneRelation || type === RelationType.BelongsToOneRelation;\n\n    // combine models and rows\n    return models.map((model) =\u003e {\n      // @ts-ignore\n      const id = model[fromColumn];\n      \n      const row = oneResult \n        // @ts-ignore\n        ? rows.find((row) =\u003e row[toColumn] === id)\n        // @ts-ignore\n        : rows.filter((row) =\u003e row[toColumn] === id);\n\n      return { ...model, [field]: row };\n    });\n  }\n\n  static jsonbIncrement(column: keyof Table \u0026 string, data: Record\u003cstring, number\u003e) {\n    const entries = Object.entries(data);\n    if (!entries.length) {\n      throw new Error('Data is empty');\n    }\n\n    const [[key, value], ...rest] = entries;\n\n    let update: RawBuilder\u003cstring\u003e = sql`jsonb_set(\n      COALESCE(${sql.ref(`${this.table}.${column}`)}, '{}'), \n      ${sql.lit(`{${key}}`)}, \n      (COALESCE(${sql.ref(`${this.table}.${column}`)}-\u003e\u003e${sql.lit(key)}, '0')::int + ${value})::text::jsonb\n    )`;\n\n    rest.forEach(([key, value]) =\u003e {\n      update = sql`jsonb_set(\n        ${update}, \n        ${sql.lit(`{${key}}`)}, \n        (COALESCE(${sql.ref(`${this.table}.${column}`)}-\u003e\u003e${sql.lit(key)}, '0')::int + ${value})::text::jsonb\n      )`;\n    });\n  \n    return update;\n  }\n}\n```\n","funding_links":[],"categories":["ORMs"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fseeden%2Fkysely-orm","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fseeden%2Fkysely-orm","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fseeden%2Fkysely-orm/lists"}