{"id":354126,"date":"2024-05-20T22:42:10","date_gmt":"2024-05-20T22:42:10","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=354126"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=354126","title":{"rendered":"<span>Kysely.js \u0442\u0438\u043f\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 sql builder<\/span>"},"content":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p><strong>Kysely.js <\/strong>\u2013 \u044d\u0442\u043e \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430, \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u044e\u0449\u0430\u044f \u043f\u0438\u0441\u0430\u0442\u044c \u0442\u0438\u043f\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 SQL \u0437\u0430\u043f\u0440\u043e\u0441\u044b. \u0411\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 \u0434\u0435\u043b\u0430\u0435\u0442 \u0440\u0430\u0431\u043e\u0442\u0443 \u0441 SQL \u0432 \u0432\u0430\u0448\u0435\u043c \u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u0431\u043e\u043b\u0435\u0435 \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0439, \u0438\u0437\u0431\u0430\u0432\u043b\u044f\u044f \u043e\u0442 \u0442\u0430\u043a\u0438\u0445 \u043e\u0448\u0438\u0431\u043e\u043a \u043a\u0430\u043a \u043e\u043f\u0435\u0447\u0430\u0442\u043a\u0438 \u0432 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u044f\u0445 \u043a\u043e\u043b\u043e\u043d\u043e\u043a \u0438\u043b\u0438 \u0442\u0430\u0431\u043b\u0438\u0446 \u0438 \u043d\u0435\u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 SQL \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440\u043e\u0432 \u0432 \u043a\u043e\u0434\u0435 (\u043a\u043e\u0434 \u043d\u0435 \u0441\u043a\u043e\u043c\u043f\u0438\u043b\u0438\u0440\u0443\u0435\u0442\u0441\u044f). \u041a\u043e \u0432\u0441\u0435\u043c\u0443 \u043f\u0440\u043e\u0447\u0435\u043c\u0443 \u043e\u043d\u0430 \u0434\u0435\u043b\u0430\u0435\u0442 \u0440\u0430\u0431\u043e\u0442\u0443 \u0441 SQL \u0431\u043e\u043b\u0435\u0435 \u0443\u0434\u043e\u0431\u043d\u043e\u0439, \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u044f \u043f\u0440\u0438 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u0430\u0432\u0442\u043e\u0434\u043e\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u0434\u043b\u044f \u0442\u0430\u0431\u043b\u0438\u0446, \u043a\u043e\u043b\u043e\u043d\u043e\u043a, \u0430\u043b\u0438\u0430\u0441\u043e\u0432 \u0438 \u0434\u0440\u0443\u0433\u0438\u0445 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0435\u0439. Kysely \u0438\u043c\u0435\u0435\u0442 \u043d\u0435\u0437\u043d\u0430\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u0441\u043b\u043e\u0439 \u0430\u0431\u0441\u0442\u0440\u0430\u043a\u0446\u0438\u0438 \u043d\u0430\u0434 SQL \u0434\u043b\u044f \u0442\u043e\u0433\u043e \u0447\u0442\u043e\u0431\u044b \u043c\u043e\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0432\u0441\u0435\u0439 \u043c\u043e\u0449\u044c\u044e SQL \u0438 \u043f\u0440\u0438 \u044d\u0442\u043e\u043c \u043d\u0435 \u0438\u0437\u0443\u0447\u0430\u0442\u044c \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u043e \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0435\u0439. \u0411\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442 MySQL, PostgreSQL, SQLite, PlanetScale, D3, SurrealDB \u0438 \u0434\u0440\u0443\u0433\u0438\u0435.<\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043f\u043e\u0433\u0440\u0443\u0437\u0438\u043c\u0441\u044f \u0432 \u043d\u0430\u0448 \u043a\u0438\u0441\u0435\u043b\u044c ?.<\/p>\n<h2>\u0421\u0445\u0435\u043c\u0430 \u0411\u0414<\/h2>\n<p>\u0423\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043c \u0441\u0430\u043c \u043c\u043e\u0434\u0443\u043b\u044c:<\/p>\n<pre><code class=\"bash\">npm i kysely -S<\/code><\/pre>\n<p>\u0417\u0430\u0442\u0435\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u0434\u0438\u0430\u043b\u0435\u043a\u0442. \u0412 \u043d\u0430\u0448\u0438\u0445 \u043f\u0440\u0438\u043c\u0435\u0440\u0430\u0445 \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0441 MySQL. \u041d\u043e \u0435\u0441\u0442\u044c \u043e\u0444\u0438\u0446\u0438\u0430\u043b\u044c\u043d\u0430\u044f \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0430 PostgreSQL \u0438 SQLite:<\/p>\n<pre><code class=\"bash\"># MySQL npm i mysql2 -S   # PostgreSQL # npm install pg -S   # SQLite # npm install better-sqlite3<\/code><\/pre>\n<p><a href=\"https:\/\/kysely.dev\/docs\/dialects\" rel=\"noopener noreferrer nofollow\">\u0421\u043f\u0438\u0441\u043e\u043a \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u0445 \u0434\u0438\u0430\u043b\u0435\u043a\u0442\u043e\u0432<\/a>. \u041f\u043e\u0441\u043b\u0435 \u044d\u0442\u043e\u0433\u043e \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0437\u0430\u0434\u0435\u043a\u043b\u0430\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0441\u0445\u0435\u043c\u0443 \u043d\u0430\u0448\u0435\u0439 \u0431\u0430\u0437\u044b \u0438 \u0442\u0430\u0431\u043b\u0438\u0446:<\/p>\n<pre><code class=\"typescript\">\/\/ schema.ts  import { ColumnType, Generated, Insertable, Selectable, Updateable } from 'kysely';  export interface UserTable {   id: Generated&lt;number>;   name: string;   gender: 'man' | 'woman' | null;   last_name: string | null;   created_at: ColumnType&lt;Date, string | Date | undefined, never> }  export type User = Selectable&lt;UserTable> export type NewUser = Insertable&lt;UserTable> export type UserUpdate = Updateable&lt;UserTable>  export interface OrderTable {   id: Generated&lt;number>;   user_id: number;   amount: number;   status: 'pending' | 'approved' | 'canceled' | 'paid';   created_at: ColumnType&lt;Date, string | undefined, never>;   updated_at: ColumnType&lt;Date, string | undefined, Date>; }  export type Order = Selectable&lt;OrderTable> export type NewOrder = Insertable&lt;OrderTable> export type OrderUpdate = Updateable&lt;OrderTable>  export interface Database {   user: UserTable;   order: OrderTable; } <\/code><\/pre>\n<p><code>Generated<\/code> \u044d\u0442\u043e \u0442\u0438\u043f, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u0442\u044c \u0434\u043b\u044f \u043a\u043e\u043b\u043e\u043d\u043e\u043a, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0433\u0435\u043d\u0435\u0440\u0438\u0442 \u0441\u0430\u043c\u0430 \u0431\u0430\u0437\u0430 \u0434\u0430\u043d\u043d\u044b\u0445, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043f\u043e\u043b\u0435 \u0441 \u0430\u0432\u0442\u043e\u0438\u043d\u043a\u0440\u0435\u043c\u0435\u043d\u0442\u043e\u043c. \u0418 \u0442\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c \u043f\u0440\u0438 update\/insert \u044d\u0442\u043e \u043f\u043e\u043b\u0435 \u0441\u0442\u0430\u043d\u0435\u0442 \u043e\u043f\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u044b\u043c. <\/p>\n<p>\u0415\u0441\u043b\u0438 \u043f\u043e\u043b\u0435 \u0432 \u0411\u0414 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c <code>null<\/code>, \u0442\u043e \u043d\u0435 \u043d\u0430\u0434\u043e \u0434\u0435\u043b\u0430\u0442\u044c \u0435\u0433\u043e \u043e\u043f\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u044b\u043c (<code>last_name?<\/code>).  Kysely \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0441\u0434\u0435\u043b\u0430\u0435\u0442 \u044d\u0442\u043e \u0437\u0430 \u0432\u0430\u0441.<\/p>\n<p>C \u043f\u043e\u043c\u043e\u0449\u044c\u044e <code>ColumnType<\/code> \u043c\u043e\u0436\u043d\u043e \u0443\u043a\u0430\u0437\u0430\u0442\u044c \u0440\u0430\u0437\u043d\u044b\u0435 \u0442\u0438\u043f\u044b \u0434\u043b\u044f \u043a\u043e\u043b\u043e\u043d\u043e\u043a \u0432 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u0442\u043e\u0433\u043e \u0434\u0435\u043b\u0430\u0435\u043c \u043c\u044b select, insert \u0438\u043b\u0438 update. \u0422\u0438\u043f  <code>ColumnType&lt;SelectType, InsertType, UpdateType><\/code> \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 \u043d\u0430 \u0432\u0445\u043e\u0434 3 \u0434\u0436\u0435\u043d\u0435\u0440\u0438\u043a \u0442\u0438\u043f\u0430 \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0442\u0438\u043f\u0430 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e. \u042d\u0442\u043e \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u0443\u0434\u043e\u0431\u043d\u043e, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0434\u043b\u044f \u043a\u043e\u043b\u043e\u043d\u043e\u043a \u0441 \u0442\u0438\u043f\u043e\u043c <code>datetime<\/code> \u0438\u043b\u0438 <code>timestamp<\/code>.  \u0414\u043b\u044f \u0442\u0430\u0431\u043b\u0438\u0446\u044b <code>user<\/code> \u043c\u044b \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u043b\u0438, \u0447\u0442\u043e \u043a\u043e\u043b\u043e\u043d\u043a\u0430 <code>created_at<\/code> \u0434\u043b\u044f <code>select<\/code> \u0431\u0443\u0434\u0435\u0442 \u0438\u043c\u0435\u0442\u044c \u0442\u0438\u043f <code>Date<\/code>, \u0434\u043b\u044f <code>insert<\/code> \u043e\u043d\u0430 \u0431\u0443\u0434\u0435\u0442 \u043e\u043f\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0439 \u0438 \u0431\u0443\u0434\u0435\u0442 \u0438\u043c\u0435\u0442\u044c \u0442\u0438\u043f <code>Date<\/code> \u0438\u043b\u0438 <code>string<\/code> (\u0432\u0440\u0435\u043c\u044f \u0432 \u0444\u043e\u0440\u043c\u0430\u0442\u0435 \u0441\u0442\u0440\u043e\u043a\u0438), \u0430 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u044f<code>update<\/code>\u043d\u0430\u0434 \u043d\u0435\u0439 \u0431\u0443\u0434\u0435\u0442 \u0437\u0430\u043f\u0440\u0435\u0449\u0435\u043d\u0430 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0442\u0438\u043f\u0430 <code>never<\/code>.<\/p>\n<p>\u0412\u0430\u043c \u043c\u043e\u0436\u0435\u0442 \u043f\u043e\u0442\u0440\u0435\u0431\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043d\u0430\u043f\u0440\u044f\u043c\u0443\u044e \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u044b \u0442\u0430\u0431\u043b\u0438\u0446 \u0432\u0430\u0448\u0435\u0439 \u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445. \u041d\u0435 \u0441\u0442\u043e\u0438\u0442 \u044d\u0442\u043e\u0433\u043e \u0434\u0435\u043b\u0430\u0442\u044c, kysely \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0442\u0438\u043f\u044b \u043e\u0431\u0435\u0440\u0442\u043a\u0438 <code>Selectable<\/code>, <code>Insertable<\/code>, <code>Updateable<\/code>\u0434\u043b\u044f \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0445 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0439. \u041e\u043d\u0438 \u0433\u0430\u0440\u0430\u043d\u0442\u0438\u0440\u0443\u044e\u0442, \u0447\u0442\u043e \u0431\u0443\u0434\u0443\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u044b\u0435 \u0442\u0438\u043f\u044b \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0442\u0438\u043f\u0430 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0439.<\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u043a \u0411\u0414:<\/p>\n<pre><code class=\"typescript\">\/\/ db.ts  \/\/ \u0421\u0445\u0435\u043c\u0430 \u0411\u0414 import { Database } from '.\/schema'  \/\/ do not use 'mysql2\/promises'! import * as mysql from 'mysql2'  import { Kysely, MysqlDialect } from 'kysely'  const dialect = new MysqlDialect({   pool: mysql.createPool({     database: 'test',     host: 'localhost',     user: 'test',     password: 'test',     port: 3306,     connectionLimit: 10,   }) })   const db = new Kysely&lt;Database>({   dialect, });  export default db;  <\/code><\/pre>\n<p>\u041c\u044b \u0441\u043e\u0437\u0434\u0430\u0435\u043c \u0438\u043d\u0441\u0442\u0430\u043d\u0441 \u0411\u0414, \u043f\u0435\u0440\u0435\u0434\u0430\u0432 \u0434\u0438\u0430\u043b\u0435\u043a\u0442, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0441\u0445\u0435\u043c\u0443 \u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445 \u043a\u0430\u043a \u0434\u0436\u0435\u043d\u0435\u0440\u0438\u043a \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 \u0434\u043b\u044f \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e\u0439 \u0442\u0438\u043f\u0438\u0437\u0430\u0446\u0438\u0438.<\/p>\n<p>\u041f\u0440\u0438\u043c\u0435\u0440 user repository c kysely:<\/p>\n<pre><code class=\"typescript\">import { Kysely } from 'kysely'; import { Database, User, NewUser, UserUpdate } from '.\/schema';  class UserRepo {   constructor(private readonly db: Kysely&lt;Database>) {}    async getAll() {     return await this.db       .selectFrom('user')       .select(['id', 'name'])       .execute();   }    async getById(id: number) {     return await this.db       .selectFrom('user')       .select(['id', 'name'])       .where('id', '=', id)       .executeTakeFirst()     ;   }    async search(params: Partial&lt;User>) {     return await this.db       .selectFrom('user')       .select([ 'id', 'name', 'last_name' ])       .where((eb) => eb.and(params)).executeTakeFirst();   }    async create(data: NewUser) {     const { insertId } = await this.db       .insertInto('user')       .values(data)       .executeTakeFirst();          if (!insertId) {       throw new Error(`Not found id ${insertId}`);     }     return Number(insertId);   }    async updateById(id: number, data: UserUpdate) {     return await this.db       .updateTable('user')       .set(data)       .where('id', '=', id)       .execute();   }    async delete(id: number) {     return await this.db       .deleteFrom('user')       .where('id', '=', id)       .execute();   } }   const userRepo = new UserRepo(db); const userId = await userRepo.create({   name: '\u041e\u043b\u0435\u0433',   last_name: '\u0418\u0432\u0430\u043d\u043e\u0432',   gender: 'man', });  const users = await userRepo.getAll(); \/\/ [ { id: 2, name: '\u041e\u043b\u0435\u0433' } ]   console.log(users);  const user = await userRepo.getById(userId); \/\/ { id: 2, name: '\u041e\u043b\u0435\u0433' } console.log(user);  await userRepo.updateById(userId, { last_name: '' });  const foundedUser = await userRepo.search({ name: '\u041e\u043b\u0435\u0433', last_name: '' }); \/\/ { id: 2, name: '\u041e\u043b\u0435\u0433', last_name: '' } console.log(foundedUser);<\/code><\/pre>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435 \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 kysely.<\/p>\n<h2>Insert\/Update\/Delete<\/h2>\n<p>\u0412\u0441\u0442\u0430\u0432\u043a\u0430:<\/p>\n<pre><code class=\"typescript\">const result = await db.insertInto('user').values({   name: '\u0418\u0432\u0430\u043d',   last_name: '\u0418\u0432\u0430\u043d\u043e\u0432',   gender: 'man',   created_at: new Date().toISOString(), }).executeTakeFirst();    console.log({ userId: result.insertId }); <\/code><\/pre>\n<p>\u041c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u0430\u044f \u0432\u0441\u0442\u0430\u0432\u043a\u0430:<\/p>\n<pre><code class=\"typescript\">const result = await db.insertInto('user').values([{   name: '\u0418\u0432\u0430\u043d',   last_name: '\u0418\u0432\u0430\u043d\u043e\u0432',   gender: 'man',   created_at: new Date(), }, {   name: '\u0410\u043b\u0435\u043d\u0430',   last_name: '\u041f\u0435\u0442\u0440\u043e\u0432\u0430',   gender: 'woman',   created_at: new Date(), }]).executeTakeFirstOrThrow();    console.log(result.numInsertedOrUpdatedRows); \/\/ 2<\/code><\/pre>\n<p>\u0414\u043b\u044f \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442\u0441\u044f \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u043c\u0435\u0442\u043e\u0434\u044b: <code>execute<\/code> (\u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u043c\u0430\u0441\u0441\u0438\u0432 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439), <code>executeTakeFirst<\/code> (\u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u043f\u0435\u0440\u0432\u043e\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435), <code>executeTakeFirstOrThrow<\/code> (\u0430\u043d\u0430\u043b\u043e\u0433 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0435\u0433\u043e \u043c\u0435\u0442\u043e\u0434\u0430, \u043d\u043e \u0431\u0440\u043e\u0441\u0430\u044e\u0449\u0438\u0439 \u043e\u0448\u0438\u0431\u043a\u0443, \u0435\u0441\u043b\u0438 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d).<\/p>\n<p>\u0418\u043c\u0435\u0435\u0442\u0441\u044f \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0430 \u0411\u0414 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0433\u043e \u0441\u0438\u043d\u0442\u0430\u043a\u0441\u0438\u0441\u0430:<\/p>\n<pre><code class=\"typescript\">\/\/ Only MySQL: \u0438\u0433\u043d\u043e\u0440\u0438\u043c \u043e\u0448\u0438\u0431\u043a\u0443 \u043f\u0440\u0438 \u0432\u0441\u0442\u0430\u0432\u043a\u0435 \u0432 \u0442\u0430\u0431\u043b\u0438\u0446\u0443 \u0434\u0443\u0431\u043b\u0438\u043a\u0430\u0442\u0430 const result = await db.insertInto('user').ignore().values({   id: 2,   name: '\u0410\u043b\u0435\u043d\u0430',   last_name: '\u041f\u0435\u0442\u0440\u043e\u0432\u0430',   gender: 'woman',   created_at: new Date(), }).executeTakeFirst();    console.log(result.numInsertedOrUpdatedRows); \/\/ 0   \/\/ Only MySQL: \u0432 \u0441\u043b\u0443\u0447\u0430\u0435 \u043e\u0448\u0438\u0431\u043a\u0438 \u0434\u0443\u0431\u043b\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043f\u0440\u0438 \u0432\u0441\u0442\u0430\u0432\u043a\u0435,  \/\/ \u0442\u043e last_name \u0434\u0435\u043b\u0430\u0435\u043c \u043f\u0443\u0441\u0442\u044b\u043c const result = await db.insertInto('user').values({   id: 2,   name: '\u0410\u043b\u0435\u043d\u0430',   last_name: '\u041f\u0435\u0442\u0440\u043e\u0432\u0430',   gender: 'woman',   created_at: new Date(), }).onDuplicateKeyUpdate({ last_name: '' }).executeTakeFirst();  console.log(result.numInsertedOrUpdatedRows); \/\/ 2   \/\/ Only PostgreSQL: \u0432 \u0441\u043b\u0443\u0447\u0430\u0435 \u043e\u0448\u0438\u0431\u043a\u0438 \u0434\u0443\u0431\u043b\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043f\u0440\u0438 \u0432\u0441\u0442\u0430\u0432\u043a\u0435,  \/\/ \u0442\u043e last_name \u0434\u0435\u043b\u0430\u0435\u043c \u043f\u0443\u0441\u0442\u044b\u043c const result = await db.insertInto('user').values({   id: 2,   name: '\u0410\u043b\u0435\u043d\u0430',   last_name: '\u041f\u0435\u0442\u0440\u043e\u0432\u0430',   gender: 'woman',   \u0441reated_at: new Date(), }).onConflict((oc) =>      oc.column('id').doUpdateSet({ last_name: '' }) ).executeTakeFirst();  console.log(result.numInsertedOrUpdatedRows); \/\/ 2  \/\/ Only PostgreSQL: \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u043a\u043e\u043b\u043e\u043d\u043e\u043a, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0431\u044b\u043b\u0438 \u0432\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u044b   const result = await db.insertInto('user').values({   name: '\u0410\u043b\u0435\u043d\u0430',   last_name: '\u041f\u0435\u0442\u0440\u043e\u0432\u0430',   gender: 'woman',   created_at: new Date(), }).returning([ 'id', 'name' ]).executeTakeFirst();  console.log(result); \/\/ { id: 3, name: '\u0410\u043b\u0435\u043d\u0430' }<\/code><\/pre>\n<p>\u041e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435:<\/p>\n<pre><code class=\"typescript\">const result = await db   .updateTable('user')   .set({     last_name: '\u0418\u0432\u0430\u043d\u043e\u0432\u0430'   })   .where('id', '=', 2)   .executeTakeFirst()  console.log(result.numUpdatedRows) \/\/ 1<\/code><\/pre>\n<p>\u0423\u0434\u0430\u043b\u0435\u043d\u0438\u0435:<\/p>\n<pre><code class=\"typescript\">const result = await db   .deleteFrom('user')   .where('user.id', '=', 1).executeTakeFirst();  console.log(result.numDeletedRows); \/\/ 1<\/code><\/pre>\n<h2>Select<\/h2>\n<p>\u0412\u044b\u0431\u043e\u0440\u043a\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c alias:<\/p>\n<pre><code class=\"typescript\">const users = await db   .selectFrom('user')   .select(['id', 'user.name as name', 'created_at as createdAt'])   .where('gender', '!=', 'man')   .execute();  \/\/ [{ id: 2, name: '\u0410\u043b\u0435\u043d\u0430', createdAt: 2023-09-07T07:38:49.000Z }] console.log(users); <\/code><\/pre>\n<p>\u0412\u044b\u0431\u043e\u0440\u043a\u0430 \u043e\u0434\u043d\u043e\u0439 \u0441\u0442\u0440\u043e\u043a\u0438 \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c <code>limit<\/code> \u0438 <code>order by<\/code> :<\/p>\n<pre><code class=\"typescript\">const user = await db   .selectFrom('user')   .select(['id', 'user.name as name', 'created_at as createdAt'])   .where('gender', '!=', 'man')   .orderBy('id', 'desc')   .limit(1)   .executeTakeFirst();  \/\/ { id: 2, name: '\u0410\u043b\u0435\u043d\u0430', createdAt: 2023-09-07T07:38:49.000Z } console.log(user); <\/code><\/pre>\n<p>\u0420\u0430\u0437\u0443\u043c\u0435\u0435\u0442\u0441\u044f \u0435\u0441\u0442\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0434\u0435\u043b\u0430\u0442\u044c \u043f\u043e\u0434\u0437\u0430\u043f\u0440\u043e\u0441\u044b, \u0438 \u0445\u043e\u0442\u044f kysely \u043d\u0435 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f ORM, \u043e\u043d \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0443\u044e \u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e \u0434\u0430\u043d\u043d\u044b\u0445 \u0432 \u043e\u0431\u044a\u0435\u043a\u0442 \u0438\u043b\u0438 \u043c\u0430\u0441\u0441\u0438\u0432:<\/p>\n<pre><code class=\"typescript\">\/\/ mysql import { jsonObjectFrom, jsonArrayFrom } from 'kysely\/helpers\/mysql' \/\/ postgres \/\/ import { jsonObjectFrom, jsonArrayFrom } from 'kysely\/helpers\/postgres'  \/\/ \u041f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0432\u0441\u0435\u0445 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 \u0432\u043c\u0435\u0441\u0442\u0435 \u0441 \u043e\u043f\u043b\u0430\u0447\u0435\u043d\u043d\u044b\u043c \u0437\u0430\u043a\u0430\u0437\u043e\u043c const result = await db   .selectFrom('user')   \/\/ \u043f\u043e\u0434\u0437\u0430\u043f\u0440\u043e\u0441   .select((eb) => [     'id',     jsonObjectFrom(       eb.selectFrom('order')         .select(['order.id as orderId', 'order.amount'])         .whereRef('order.user_id', '=', 'user.id')         .where('order.status', '=', 'paid')         .where('order.amount', '>', 100)         .limit(1)     ).as('paid_order')   ])   .execute();  \/* [   { id: 1, paid_order: { amount: 546, orderId: 2 } },   { id: 2, paid_order: null } ] *\/ console.log(result);  \/\/ \u041f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0432\u0441\u0435\u0445 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 \u0432\u043c\u0435\u0441\u0442\u0435 \u0441 \u043e\u043f\u043b\u0430\u0447\u0435\u043d\u043d\u044b\u043c\u0438 \u0437\u0430\u043a\u0430\u0437\u0430\u043c\u0438 const result = await db   .selectFrom('user')   \/\/ \u043f\u043e\u0434\u0437\u0430\u043f\u0440\u043e\u0441   .select((eb) => [     'id',     jsonArrayFrom(       eb.selectFrom('order')         .select(['order.id as orderId', 'order.amount'])         .whereRef('order.user_id', '=', 'user.id')         .where('order.status', '=', 'paid')         .where('order.amount', '>', 100)     ).as('paid_orders')   ])  .execute(); \/* [   { id: 1, paid_orders: [ { amount: 546, orderId: 2 } ] },   { id: 2, paid_orders: [] } ] *\/ console.dir(result, { depth: 10 });<\/code><\/pre>\n<p><code>whereRef<\/code> \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0432 \u043f\u043e\u0434\u0437\u0430\u043f\u0440\u043e\u0441\u0430\u0445 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0432 \u0443\u0441\u043b\u043e\u0432\u0438\u0438 \u043a\u043e\u043b\u043e\u043d\u043a\u0438 \u0438\u0437 \u0434\u0440\u0443\u0433\u043e\u0439 \u0442\u0430\u0431\u043b\u0438\u0446\u044b.<\/p>\n<p>\u0420\u0430\u0437\u0443\u043c\u0435\u0435\u0442\u0441\u044f \u043c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c sql \u0444\u0443\u043d\u043a\u0446\u0438\u0438:<\/p>\n<pre><code class=\"typescript\">const result = await db.selectFrom('order')   .select(({ fn }) => [     \/\/ `fn` \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u0432\u0441\u0435 \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u0438     fn.count&lt;number>('order.id').as('order_count'),      \/\/ \u0421 \u043f\u043e\u043c\u043e\u0449\u044c\u044e `agg` \u043c\u043e\u0436\u043d\u043e \u0432\u044b\u0437\u0432\u0430\u0442\u044c \u043b\u044e\u0431\u0443\u044e \u0444\u0443\u043d\u043a\u0446\u0438\u044e.     \/\/ \u041f\u0435\u0440\u0432\u044b\u043c \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u043e\u043c \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u043c \u0442\u0438\u043f \u043a\u043e\u043b\u043e\u043d\u043a\u0438     fn.agg&lt;string>('GROUP_CONCAT', ['order.id']).as('order_ids')   ])   .groupBy('order.user_id')   .execute() ; \/* [   { order_count: 2, order_ids: '1,2' },   { order_count: 1, order_ids: '3' } ] *\/ console.log(result);<\/code><\/pre>\n<p>\u0415\u0441\u043b\u0438 \u0437\u0430\u043f\u0440\u043e\u0441 \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0441\u043b\u043e\u0436\u043d\u044b\u0439 \u0438 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0433\u043b\u044f\u043d\u0443\u0442\u044c, \u0447\u0442\u043e \u0437\u0430 sql \u043d\u0430 \u0432\u044b\u0445\u043e\u0434\u0435 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442\u0441\u044f, \u0442\u043e \u044d\u0442\u043e \u043c\u043e\u0436\u043d\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043c\u0435\u0442\u043e\u0434\u0430 <code>compile<\/code><\/p>\n<pre><code class=\"typescript\">const sql = db.selectFrom('order')   .select(({ fn }) => [     fn.count&lt;number>('order.id').as('order_count'),     fn.agg&lt;string>('GROUP_CONCAT', ['order.id']).as('order_ids')   ])   .groupBy('order.user_id')   .compile();  \/*{   query: {     kind: 'SelectQueryNode',     from: { kind: 'FromNode', froms: [Array] },     selections: [ [Object], [Object] ],     groupBy: { kind: 'GroupByNode', items: [Array] }   },   sql: 'select count(`order`.`id`) as `order_count`, GROUP_CONCAT(`order`.`id`) as `order_ids` from `order` group by `order`.`user_id`',   parameters: [] }*\/ console.log(sql);<\/code><\/pre>\n<p>\u0411\u043b\u0430\u0433\u043e\u0434\u0430\u0440\u044f chaining \u0432 js \u0432\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u043f\u043e\u044d\u0442\u0430\u043f\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0442\u044c \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440\u044b sql \u0432 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u0443\u0441\u043b\u043e\u0432\u0438\u0439. \u041d\u043e \u044d\u0442\u043e \u043c\u043e\u0436\u0435\u0442 \u043f\u043e\u0440\u043e\u0434\u0438\u0442\u044c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0443\u044e \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0443:<\/p>\n<pre><code class=\"typescript\">async function getUser(id: number, withLastName: boolean) {   let query = db.selectFrom('user').select('name').where('id', '=', id);    if (withLastName) {     query = query.select('last_name')   }    return await query.executeTakeFirstOrThrow() }  const user = await getUser(1, true);  \/\/ Property 'last_name' does not exist on type '{ name: string; }' console.log(user.last_name);<\/code><\/pre>\n<p>\u042d\u0442\u043e \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0430 \u0431\u0443\u0434\u0435\u0442 \u0432\u043e\u0437\u043d\u0438\u043a\u0430\u0442\u044c \u0441 \u0442\u0430\u043a\u0438\u043c\u0438 \u0444\u0443\u043d\u043a\u0446\u0438\u044f\u043c\u0438, \u043a\u0430\u043a <code>select<\/code>,\u00a0<code>returning<\/code>,\u00a0<code>innerJoin<\/code> \u0438 \u0432\u0441\u0435\u043c\u0438 \u0434\u0440\u0443\u0433\u0438\u043c\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0432\u043b\u0438\u044f\u044e\u0442 \u043d\u0430 \u043a\u043e\u043b-\u0432\u043e \u043f\u043e\u043b\u0435\u0439 \u0432 \u0437\u0430\u043f\u0440\u043e\u0441\u0435 \u0438 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u043d\u0430 \u0442\u0438\u043f \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445. \u0422\u0430\u043a\u0438\u0445 \u043f\u0440\u043e\u0431\u043b\u0435\u043c \u043d\u0435 \u0431\u0443\u0434\u0435\u0442 \u0441 \u0444\u0443\u043d\u043a\u0446\u0438\u044f\u043c\u0438 <code>where<\/code>,\u00a0<code>groupBy<\/code>,\u00a0<code>orderBy<\/code> \u0438 \u0434\u0440\u0443\u0433\u0438\u043c\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043d\u0435 \u0432\u043b\u0438\u044f\u044e\u0442 \u043d\u0430 \u0442\u0438\u043f query builder.  <\/p>\n<p>\u0420\u0435\u0448\u0435\u043d\u0438\u0435 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u044b \u0435\u0441\u0442\u044c, \u043e\u043d\u043e \u0437\u0430\u043a\u043b\u044e\u0447\u0430\u0435\u0442\u0441\u044f \u0432 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0438 \u043c\u0435\u0442\u043e\u0434\u0430 <code>$if<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043e\u043f\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0442\u044c sql \u043a\u043e\u0434 \u0438 \u043f\u0440\u0438 \u044d\u0442\u043e\u043c \u0438\u0442\u043e\u0433\u043e\u0432\u044b\u0439 \u0442\u0438\u043f \u0434\u0430\u043d\u043d\u044b\u0445 \u0431\u0443\u0434\u0435\u0442 \u0432\u0435\u0440\u043d\u044b\u0439: <\/p>\n<pre><code class=\"typescript\">async function getUser(id: number, withLastName: boolean) {   return await db     .selectFrom('user')     .select('name')     .$if(withLastName, (qb) => qb.select('last_name'))     .where('id', '=', id)     .executeTakeFirstOrThrow()   ; }  const user = await getUser(1, true); \/*{     name: string;     last_name?: string | null | undefined; }*\/ console.log(user.last_name);<\/code><\/pre>\n<h2>Join<\/h2>\n<p>\u0414\u043b\u044f \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f join \u0435\u0441\u0442\u044c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u043d\u0430\u0431\u043e\u0440 \u043c\u0435\u0442\u043e\u0434\u043e\u0432: <code>innerJoin<\/code>, <code>leftJoin<\/code>, <code>rightJoin<\/code>, <code>fullJoin<\/code>.<\/p>\n<pre><code class=\"typescript\">const result = await db.selectFrom('user as u')   .innerJoin('order as o', 'u.id', 'o.user_id')   .select([ 'u.id', 'u.name', 'o.status', 'o.amount'])   .where('o.status', '=', 'paid')   .execute();  \/\/ [{ id: 1, name: '\u0418\u0432\u0430\u043d', status: 'paid', amount: 546 }] console.log(result);<\/code><\/pre>\n<p>\u041c\u0435\u0442\u043e\u0434 <code>select<\/code> \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0432\u044b\u0437\u044b\u0432\u0430\u0442\u044c \u043f\u043e\u0441\u043b\u0435 \u0432\u0441\u0435\u0445 join, \u0447\u0442\u043e\u0431\u044b \u0441\u043a\u043e\u043c\u043f\u0438\u043b\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043a\u043e\u0434 \u0438 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0449\u0438\u0439 \u0430\u0432\u0442\u043e\u043a\u043e\u043c\u043f\u043b\u0438\u0442 \u0434\u043b\u044f \u043a\u043e\u043b\u043e\u043d\u043e\u043a \u0442\u0430\u0431\u043b\u0438\u0446. <\/p>\n<p>\u0412\u043d\u0443\u0442\u0440\u044c \u043c\u0435\u0442\u043e\u0434\u0430 join \u043c\u043e\u0436\u043d\u043e \u043f\u0435\u0440\u0435\u0434\u0430\u0442\u044c \u0432\u0442\u043e\u0440\u044b\u043c \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u043c \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u0434\u043b\u044f \u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d\u0438\u044f \u0431\u043e\u043b\u0435\u0435 \u0441\u043b\u043e\u0436\u043d\u044b\u0445 \u0443\u0441\u043b\u043e\u0432\u0438\u0439 \u043e\u0431\u044a\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u044f:    <\/p>\n<pre><code class=\"typescript\">const result = await db.selectFrom('user as u')   .innerJoin('order as o', (join) =>     join       .onRef('u.id', '=', 'o.user_id')       .on('o.status', '=', 'paid')   )   .select([ 'u.id', 'u.name', 'o.status', 'o.amount'])   .where('o.status', '=', 'paid')   .execute();  \/\/ [{ id: 1, name: '\u0418\u0432\u0430\u043d', status: 'paid', amount: 546 }] console.log(result);<\/code><\/pre>\n<p>\u0414\u0430\u043d\u043d\u044b\u0439 \u0437\u0430\u043f\u0440\u043e\u0441 \u0430\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u0435\u043d \u0437\u0430\u043f\u0440\u043e\u0441\u0443, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043d\u0430\u043f\u0438\u0441\u0430\u043d \u0440\u0430\u043d\u0435\u0435, \u043d\u043e \u043e\u0442\u043b\u0438\u0447\u0438\u0435 \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e \u0443\u0441\u043b\u043e\u0432\u0438\u0435, \u0447\u0442\u043e \u043f\u043b\u0430\u0442\u0435\u0436\u0438 \u0434\u043e\u043b\u0436\u043d\u044b \u0438\u043c\u0435\u0442\u044c \u0441\u0442\u0430\u0442\u0443\u0441 <code>paid<\/code> \u0431\u044b\u043b\u043e \u043f\u0435\u0440\u0435\u043d\u0435\u0441\u0435\u043d\u043e \u0438\u0437 <code>where<\/code> \u0432\u043d\u0443\u0442\u0440\u044c \u0443\u0441\u043b\u043e\u0432\u0438\u044f <code>join on<\/code>.  <code>onRef<\/code> \u0437\u0434\u0435\u0441\u044c \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0430\u043d\u0430\u043b\u043e\u0433\u043e\u043c <code>whereRef<\/code>, \u0430 \u0438\u043c\u0435\u043d\u043d\u043e \u0447\u0442\u043e\u0431\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0432 \u0443\u0441\u043b\u043e\u0432\u0438\u0438 \u043a\u043e\u043b\u043e\u043d\u043a\u0438 \u0438\u0437 \u0434\u0440\u0443\u0433\u0438\u0445 \u0442\u0430\u0431\u043b\u0438\u0446, \u0430 <code>on<\/code> \u043f\u0440\u043e\u0441\u0442\u043e \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440\u043e\u043c <code>ON<\/code>.<\/p>\n<p>\u0411\u044b\u0432\u0430\u044e\u0442 \u0441\u0438\u0442\u0443\u0430\u0446\u0438\u0438, \u043a\u043e\u0433\u0434\u0430 join \u0442\u0430\u0431\u043b\u0438\u0446\u044b \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u0434\u0432\u0430\u0436\u0434\u044b \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u044b \u0432 \u0437\u0430\u043f\u0440\u043e\u0441, \u043a\u0430\u043a \u043f\u0440\u0430\u0432\u0438\u043b\u043e \u044d\u0442\u043e \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u0432 \u0437\u0430\u043f\u0440\u043e\u0441\u0430\u0445 \u0441 \u0443\u0441\u043b\u043e\u0432\u0438\u044f\u043c\u0438:<\/p>\n<pre><code class=\"typescript\">async function getUser(   id: number,   withOrderAmount: boolean,   withOrderStatus: boolean ) {   return await db     .selectFrom('user')     .selectAll('user')     .$if(withOrderAmount, (qb) =>       qb         .innerJoin('order as o', 'user.id', 'o.user_id')         .select('o.amount as orderAmount')     )     .$if(withOrderStatus, (qb) =>       qb         .innerJoin('order as o', 'user.id', 'o.user_id')         .select('o.status as orderStatus')     )     .where('user.id', '=', id)     .executeTakeFirst() }  \/\/ \u041e\u0428\u0418\u0411\u041a\u0410: inner join \u0442\u0430\u0431\u043b\u0438\u0446\u044b order \u0431\u0443\u0434\u0435\u0442 \u0434\u0432\u0430\u0436\u0434\u044b \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d const result = await getUser(1, true, true);<\/code><\/pre>\n<p>\u0418 \u0442\u0443\u0442 \u043d\u0430 \u043f\u043e\u043c\u043e\u0449\u044c \u043f\u0440\u0438\u0445\u043e\u0434\u0438\u0442 \u0432\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u044b\u0439 \u043f\u043b\u0430\u0433\u0438\u043d \u0432 kysely <code>DeduplicateJoinsPlugin<\/code>. \u041f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u0435\u0433\u043e \u043c\u043e\u0436\u043d\u043e \u0433\u043b\u043e\u0431\u0430\u043b\u044c\u043d\u043e (\u043d\u0435 \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0443\u044e, \u0438\u0431\u043e \u0435\u0441\u043b\u0438 \u0432 \u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u0435\u0441\u0442\u044c \u0441\u043b\u043e\u0436\u043d\u044b\u0435 sql \u0437\u0430\u043f\u0440\u043e\u0441\u044b c \u043f\u043e\u0434\u0437\u0430\u043f\u0440\u043e\u0441\u0430\u043c\u0438, \u0442\u043e \u043e\u043d \u043c\u043e\u0436\u0435\u0442 <a href=\"https:\/\/kysely.dev\/docs\/recipes\/deduplicate-joins\" rel=\"noopener noreferrer nofollow\">\u043d\u0435\u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e \u043e\u0442\u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c<\/a>):<\/p>\n<pre><code class=\"typescript\">import { Kysely, DeduplicateJoinsPlugin } from 'kysely';  const db = new Kysely&lt;Database>({   dialect,   plugins: [ new DeduplicateJoinsPlugin() ] });<\/code><\/pre>\n<p>\u0438\u043b\u0438 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e \u0434\u043b\u044f \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e\u0433\u043e \u0437\u0430\u043f\u0440\u043e\u0441\u0430:<\/p>\n<pre><code class=\"typescript\">import { DeduplicateJoinsPlugin } from 'kysely';  async function getUserDeduplicateJoin(   id: number,   withOrderAmount: boolean,   withOrderStatus: boolean ) {   return await db     \/\/ \u041f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u0435\u043c \u043f\u043b\u0430\u0433\u0438\u043d     .withPlugin(new DeduplicateJoinsPlugin())     .selectFrom('user')     .selectAll('user')     .$if(withOrderAmount, (qb) =>       qb         .innerJoin('order as o', 'user.id', 'o.user_id')         .select('o.amount as orderAmount')     )     .$if(withOrderStatus, (qb) =>       qb         .innerJoin('order as o', 'user.id', 'o.user_id')         .select('o.status as orderStatus')     )     .where('user.id', '=', id)     .executeTakeFirst() }  const result = await getUser(1, true, true); \/*{     id: 1,     name: '\u0418\u0432\u0430\u043d',     gender: 'man',     last_name: '\u0418\u0432\u0430\u043d\u043e\u0432',     created_at: 2023-09-07T07:38:49.000Z,     orderAmount: 235325,     orderStatus: 'pending' }*\/ console.log(result);<\/code><\/pre>\n<h2>SubQuery<\/h2>\n<p>\u0412 \u043f\u0440\u0438\u043c\u0435\u0440\u0430\u0445 \u0432\u044b\u0448\u0435 \u043c\u044b \u0443\u0436\u0435 \u0441\u0442\u0430\u043b\u043a\u0438\u0432\u0430\u043b\u0438\u0441\u044c \u0441 \u043f\u043e\u0434\u0437\u0430\u043f\u0440\u043e\u0441\u0430\u043c\u0438, \u0437\u0434\u0435\u0441\u044c \u043f\u043e\u043a\u0430\u0436\u0443 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e  \u043f\u0440\u0438\u043c\u0435\u0440\u043e\u0432, \u043a\u0430\u043a \u043f\u0438\u0441\u0430\u0442\u044c \u043f\u043e\u0434\u0437\u0430\u043f\u0440\u043e\u0441\u044b \u0434\u043b\u044f insert\/update\/join.<\/p>\n<p>Insert \u0441 \u043f\u043e\u0434\u0437\u0430\u043f\u0440\u043e\u0441\u043e\u043c:<\/p>\n<pre><code class=\"typescript\">const result = await db.insertInto('user')   .columns(['name', 'gender'])   .expression((eb) => eb     .selectFrom('order')     .select((eb) => [       eb.val('\u0421\u0430\u0448\u0430').as('name'),       eb.case().when('order.status', '=', 'paid').then('man').else('woman').end().as('gender'),      ]).limit(1)   )   .executeTakeFirst();  console.log(result.insertId); \/\/ 4 <\/code><\/pre>\n<p>\u0421 \u043f\u043e\u0434\u0437\u0430\u043f\u0440\u043e\u0441\u0430\u043c\u0438 \u0442\u0438\u043f\u0438\u0437\u0430\u0446\u0438\u044f \u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0441\u044f \u043d\u0435\u043c\u043d\u043e\u0436\u043a\u043e \u0441\u043b\u0430\u0431\u0435\u0435. \u0417\u0430\u043a\u043b\u044e\u0447\u0430\u0435\u0442\u0441\u044f \u044d\u0442\u043e \u0432 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u043c, \u0435\u0441\u043b\u0438 \u044f \u0432\u0435\u0440\u043d\u0443 3 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0438\u0437 \u043f\u043e\u0434\u0437\u0430\u043f\u0440\u043e\u0441\u0430, \u0430 \u043d\u0435 2 \u043a\u0430\u043a \u043e\u0436\u0438\u0434\u0430\u0435\u0442 insert, \u0442\u043e TypeScript \u0431\u0443\u0434\u0435\u0442 \u043c\u043e\u043b\u0447\u0430\u0442\u044c \u043e\u0431 \u043e\u0448\u0438\u0431\u043a\u0435. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u043d\u0430 \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0435 \u044f \u0441\u0442\u0430\u0440\u0430\u044e\u0441\u044c \u043d\u0435 \u0443\u0432\u043b\u0435\u043a\u0430\u0442\u044c\u0441\u044f \u0441 \u043f\u043e\u0434\u0437\u0430\u043f\u0440\u043e\u0441\u0430\u043c\u0438, \u0438\u0445 \u0438 \u0447\u0438\u0442\u0430\u0442\u044c \u0442\u044f\u0436\u0435\u043b\u0435\u0435, \u0438 \u0442\u0438\u043f\u0438\u0437\u0430\u0446\u0438\u044f \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043d\u0435 \u0432\u0441\u0435\u043e\u0431\u044a\u0435\u043c\u043b\u044e\u0449\u0430\u044f. <\/p>\n<p>Update c \u043f\u043e\u0434\u0437\u0430\u043f\u0440\u043e\u0441\u043e\u043c:<\/p>\n<pre><code class=\"typescript\">const result = await db.updateTable('user')   .set((eb) =>     ({       gender: eb         .selectFrom('order')         .select((e) => [           e.case()             .when('order.status', '=', 'paid')             .then('man')             .else('woman')             .end().as('gender')              as AliasedExpression&lt;'man' | 'woman' | null, 'gender'>          ]).limit(1)     })   )   .where('user.id', '=', 1)   .executeTakeFirst();    console.log(result.numChangedRows); \/\/ 1<\/code><\/pre>\n<p>\u0414\u043b\u044f join \u043f\u043e\u0434\u0445\u043e\u0434 \u0430\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u043d\u044b\u0439 \u0441 select:<\/p>\n<pre><code class=\"typescript\">const result = await db.selectFrom('user as u')   .innerJoin(     (eb) => eb       .selectFrom('order as o')       .select(['user_id as userId', 'status'])       .where('status', '=', 'paid')       .as('paid_orders'),     (join) => join       .onRef('paid_orders.userId', '=', 'u.id'),     )   .selectAll('paid_orders')   .execute();    \/\/ [ { userId: 1, status: 'paid' } ]   console.log(result);<\/code><\/pre>\n<h2>Raw sql \u0438 JSON type<\/h2>\n<p>\u0415\u0441\u043b\u0438 \u043d\u0435 \u0445\u0432\u0430\u0442\u0430\u0435\u0442 \u0433\u0438\u0431\u043a\u043e\u0441\u0442\u0438 \u0434\u043b\u044f \u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d\u0438\u044f \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432, \u0432\u0441\u0435\u0433\u0434\u0430 \u0435\u0441\u0442\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u00ab\u0441\u044b\u0440\u043e\u0439\u00bb \u0437\u0430\u043f\u0440\u043e\u0441:<\/p>\n<pre><code class=\"typescript\">import { sql } from 'kysely';  \/\/ \u041f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u00ab\u0441\u044b\u0440\u043e\u0439\u00bb \u0437\u0430\u043f\u0440\u043e\u0441 const id = 1; const result = await sql&lt;User[]>`select * from user where id = ${id}`   .execute(db);  \/\/ \u0427\u0430\u0441\u0442\u0438\u0447\u043d\u043e \u00ab\u0441\u044b\u0440\u043e\u0439\u00bb \u0437\u0430\u043f\u0440\u043e\u0441 const result = await db   .selectFrom('user')   .select(sql&lt;string>`concat(name, ' ', last_name)`.as('full_name'))   .execute(); \/\/ [ \/\/   { full_name: '\u0418\u0432\u0430\u043d \u0418\u0432\u0430\u043d\u043e\u0432' }, \/\/   { full_name: '\u0410\u043b\u0435\u043d\u0430 \u041f\u0435\u0442\u0440\u043e\u0432\u0430' }, \/\/   { full_name: null }, \/\/   { full_name: null } \/\/ ] console.log(result);<\/code><\/pre>\n<p>\u0421\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u0440\u0435\u043b\u044f\u0446\u0438\u043e\u043d\u043d\u044b\u0435 \u0411\u0414 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u044e\u0442 \u0442\u0438\u043f \u043a\u043e\u043b\u043e\u043d\u043a\u0438 json, \u0447\u0442\u043e \u0431\u044b\u0432\u0430\u0435\u0442 \u043e\u0447\u0435\u043d\u044c \u0443\u0434\u043e\u0431\u043d\u043e \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0434\u0430\u043d\u043d\u044b\u043c\u0438 \u0432 \u0441\u0442\u0438\u043b\u0435 NoSQL.  \u0412 kysely \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0443 json \u0442\u0438\u043f\u0430 \u043c\u043e\u0436\u043d\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c c \u043f\u043e\u043c\u043e\u0449\u044c\u044e  \u0445\u044d\u043b\u043f\u0435\u0440\u0430 <code>sql<\/code> (\u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0434\u043b\u044f \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438 \u00ab\u0441\u044b\u0440\u043e\u0433\u043e\u00bb sql \u043a\u043e\u0434\u0430). <\/p>\n<p>\u0412\u043d\u0430\u0447\u0430\u043b\u0435 \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u0432 \u043d\u0430\u0448\u0443 \u0441\u0445\u0435\u043c\u0443 \u043f\u043e\u043b\u0435 <code>settings<\/code> \u0434\u043b\u044f \u0442\u0430\u0431\u043b\u0438\u0446\u044b <code>user<\/code>:<\/p>\n<pre><code class=\"typescript\">\/\/ schema.ts  import { ColumnType, Generated } from 'kysely';  \/\/ ...  export interface UserTable {   id: Generated&lt;number>;   name: string;   gender: 'man' | 'woman' | null;   last_name: string | null;   \/\/ json column   settings: {     theme?: 'dark' | 'light';     pushNotification: boolean;   } | null,    created_at: ColumnType&lt;Date, string | Date | undefined, never> }  \/\/ ...<\/code><\/pre>\n<p>\u0417\u0430\u0442\u0435\u043c \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u0434\u043b\u044f \u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 json \u0434\u043b\u044f \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e\u0439 \u0411\u0414: <\/p>\n<pre><code class=\"typescript\">import { RawBuilder, sql } from 'kysely';  function jsonSerialize&lt;T>(value: T): RawBuilder&lt;T> {   \/\/ MySQL   return sql`${JSON.stringify(value)}`;   \/\/ PostgreSQL   \/\/ return sql`CAST(${JSON.stringify(value)} AS JSONB)`; }<\/code><\/pre>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043c\u043e\u0436\u043d\u043e \u043f\u0438\u0441\u0430\u0442\u044c \u0438 \u0447\u0438\u0442\u0430\u0442\u044c json \u043a\u043e\u043b\u043e\u043d\u043a\u0443:<\/p>\n<pre><code class=\"typescript\">const result = await db.insertInto('user').values({   name: '\u041e\u043b\u0435\u0433',   settings: jsonSerialize({     theme: 'light',     pushNotification: false,   }) }).executeTakeFirst();  \/\/ MySQL const result = await db   .selectFrom('user')   .selectAll()   .where((eb) =>     eb(sql`settings->\"$.theme\"`, '=', 'light')   )   .execute(); \/*[{     id: 58,     name: '\u041e\u043b\u0435\u0433',     gender: null,     last_name: null,     settings: { theme: 'light', pushNotification: false },     created_at: 2023-09-09T17:25:31.000Z }]*\/ console.log(result);  \/\/ PostgreSQL const result = await db   .selectFrom('user')   .selectAll()   .where(     'settings',     '@>',     jsonSerialize({       theme: 'light',       pushNotification: false,     })   )   .execute();<\/code><\/pre>\n<h2>\u0422\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u0438<\/h2>\n<p>\u041f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0430 \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u0439 \u0438\u043c\u0435\u0435\u0442\u0441\u044f, \u0435\u0441\u0442\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0432\u044b\u0441\u0442\u0430\u0432\u043b\u044f\u0442\u044c \u0443\u0440\u043e\u0432\u0435\u043d\u044c \u0438\u0437\u043e\u043b\u044f\u0446\u0438\u0438 \u0434\u043b\u044f \u043d\u0435\u0435:<\/p>\n<pre><code class=\"typescript\">await db.transaction().setIsolationLevel('repeatable read').execute(async (trx) => {   await trx.insertInto('user')     .values({       name: '\u0410\u043b\u0435\u043d\u0430',       last_name: '\u041f\u043e\u043f\u043e\u0432\u0430',     })     .executeTakeFirst();    const result = await trx     \/\/ \u043a\u043e\u0433\u0434\u0430 \u043d\u0430\u0434\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c select \u0431\u0435\u0437 from, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, SELECT LAST_INSERT_ID();     .selectNoFrom(({ fn }) => [fn.agg&lt;number>('LAST_INSERT_ID').as('userId')])     .executeTakeFirst();   const userId = result?.userId!;    return await trx.insertInto('order')     .values({       user_id: userId,       amount: 102,       status: 'pending',     })     .executeTakeFirst()   });<\/code><\/pre>\n<p>\u0415\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0435, \u043d\u0435 \u0445\u0432\u0430\u0442\u0430\u0435\u0442 \u043c\u0435\u0442\u043e\u0434\u0430 \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u0438 \u0432\u043d\u0435 \u043a\u043e\u043b\u0431\u044d\u043a \u0444\u0443\u043d\u043a\u0446\u0438\u0438. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043a\u0430\u043a \u0432 knex <code>const trx = await knex.transaction();<\/code>, \u0430 \u0434\u043b\u044f \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u044f \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u0438 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u0432\u0440\u0443\u0447\u043d\u0443\u044e \u0432\u044b\u0437\u044b\u0432\u0430\u043b\u0438\u0441\u044c \u0431\u044b <code>await trx.commit();<\/code>\u0438\u043b\u0438 <code>await trx.rollback();<\/code>. \u041d\u043e \u0432 \u0446\u0435\u043b\u043e\u043c \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043c\u043e\u0436\u043d\u043e \u0441\u0430\u043c\u043e\u0441\u0442\u043e\u044f\u0442\u0435\u043b\u044c\u043d\u043e \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0444\u0443\u043d\u043a\u0446\u0438\u044e-\u043e\u0431\u0435\u0440\u0442\u043a\u0443:<\/p>\n<pre><code class=\"typescript\">import { Kysely, Transaction } from 'kysely'; import { Database } from '.\/schema';  async function begin(   db: Kysely&lt;Database>,    isolationLevel?: 'read uncommitted' | 'read committed' | 'repeatable read' | 'serializable' ) {   return new Promise&lt;{      trx: Transaction&lt;Database>,     commit(): void;     rollback(): void   }>((resolve) => {     let trxBuilder = db.transaction();     if (isolationLevel) {       trxBuilder = trxBuilder.setIsolationLevel(isolationLevel);     }          \/\/ \u041d\u0435 \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u043c await     trxBuilder.execute((trx) => {       const p = new Promise&lt;void>((commit, rollback) => {         resolve({           trx,           commit: () => commit(),           rollback: () => { rollback(new Error('Rollback')); },         });       });       return p;     }).catch(err => {       \/\/ \u041d\u0438\u0447\u0435\u0433\u043e \u043d\u0435 \u0434\u0435\u043b\u0430\u0435\u043c \u043f\u0440\u043e\u0441\u0442\u043e \u043f\u0440\u043e\u0433\u043b\u0430\u0442\u044b\u0432\u0430\u0435\u043c \u043e\u0448\u0438\u0431\u043a\u0443 \u043e\u0442 \u0432\u044b\u0437\u043e\u0432\u0430 rollback      });   }); }<\/code><\/pre>\n<p><a href=\"https:\/\/github.com\/kysely-org\/kysely\/issues\/257#issuecomment-1676079354\" rel=\"noopener noreferrer nofollow\">\u041f\u0440\u0438\u043c\u0435\u0440 \u0442\u0430\u043a\u043e\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u0438-\u043e\u0431\u0435\u0440\u0442\u043a\u0438 \u043e\u0442 \u0430\u0432\u0442\u043e\u0440\u0430 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438.<\/a><\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u0438 \u043c\u043e\u0436\u043d\u043e \u0432\u043d\u0435 \u043a\u043e\u043b\u0431\u044d\u043a \u0444\u0443\u043d\u043a\u0446\u0438\u0438:<\/p>\n<pre><code class=\"typescript\">const { trx, commit, rollback } = await begin(db);   try {     await trx.insertInto('user')       .values({         name: '\u0410\u0433\u043b\u0430\u044f',         last_name: '\u0415\u0440\u043c\u0430\u043a\u043e\u0432\u0430',       })       .executeTakeFirst();      const result = await trx       .selectNoFrom(({ fn }) => [         fn.agg&lt;number>('LAST_INSERT_ID').as('userId')       ]).executeTakeFirst();     const userId = result?.userId!;      await trx.insertInto('order')       .values({         user_id: userId,         amount: 589,         status: 'pending',       })       .executeTakeFirst();      commit();   } catch (err) {     console.log(err);     rollback();   }<\/code><\/pre>\n<h2>\u041c\u0438\u0433\u0440\u0430\u0446\u0438\u0438<\/h2>\n<p>Kysely \u043d\u0435 \u0438\u043c\u0435\u0435\u0442 cli \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u0430 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u044f\u043c\u0438. \u042d\u0442\u043e \u0441\u0434\u0435\u043b\u0430\u043d\u043e \u043d\u0430\u043c\u0435\u0440\u0435\u043d\u043d\u043e, \u043e\u043d\u0438 \u043d\u0435 \u0445\u043e\u0442\u0435\u043b\u0438 \u0437\u0430\u0432\u044f\u0437\u044b\u0432\u0430\u0442\u044c\u0441\u044f \u043d\u0430 typescript \u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0442\u043e\u0440, \u0442\u0430\u043a \u043a\u0430\u043a \u043e\u043d\u0438 \u043f\u043e\u0437\u0438\u0446\u0438\u043e\u043d\u0438\u0440\u0443\u044e\u0442 \u0441\u0435\u0431\u044f \u043a\u0430\u043a query builder, \u0438 \u043f\u0440\u0438 \u044d\u0442\u043e\u043c \u0445\u043e\u0442\u0435\u043b\u0438 \u0434\u0430\u0442\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044e \u0441\u0430\u043c\u043e\u0441\u0442\u043e\u044f\u0442\u0435\u043b\u044c\u043d\u043e \u0440\u0435\u0448\u0430\u0442\u044c \u0432 \u043a\u0430\u043a\u043e\u043c \u0432\u0438\u0434\u0435 \u043e\u043d\u0438 \u0431\u0443\u0434\u0443\u0442 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u0438, \u043a\u0430\u043a .js \u0444\u0430\u0439\u043b\u044b \u0438\u043b\u0438 \u043a\u0430\u043a .ts. \u041d\u043e \u0432 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438 \u0435\u0441\u0442\u044c \u043f\u0440\u043e\u0441\u0442\u043e\u0439 \u043f\u0440\u0438\u043c\u0435\u0440, \u043a\u0430\u043a \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c <a href=\"https:\/\/kysely.dev\/docs\/migrations\" rel=\"noopener noreferrer nofollow\">\u0441\u043a\u0440\u0438\u043f\u0442 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u044f\u043c\u0438<\/a>.<\/p>\n<p>\u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u043d\u0430\u043f\u0438\u0448\u0435\u043c cli \u0441\u043a\u0440\u0438\u043f\u0442 \u0434\u043b\u044f \u043f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u044f\/\u043e\u0442\u043a\u0430\u0442\u0430 \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u0439: <\/p>\n<pre><code class=\"typescript\">\/\/ migration-cli.ts  \/\/ \u041c\u043e\u0434\u0443\u043b\u044c \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u0430\u043c\u0438 \u043a\u043e\u043c\u0430\u043d\u0434\u043d\u043e\u0439 \u0441\u0442\u0440\u043e\u043a\u0438 import { program, InvalidArgumentError } from 'commander';  import * as path from 'node:path'; import fs from 'node:fs\/promises';  import db from '.\/db'; import { Migrator, FileMigrationProvider } from 'kysely';   const migrator = new Migrator({   db,   provider: new FileMigrationProvider({     fs,     path,     \/\/ \u0410\u0431\u0441\u043e\u043b\u044e\u0442\u043d\u044b\u0439 \u043f\u0443\u0442\u044c \u043a \u043f\u0430\u043f\u043a\u0435 \u0441 \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u044f\u043c\u0438     migrationFolder: path.join(__dirname, 'migrations'),   }), });  \/\/ \u0424\u0443\u043d\u043a\u0446\u0438\u044f \u0434\u043b\u044f \u043f\u0440\u0438\u043c\u0435\u043d\u0438\u044f \u0432\u0441\u0435\u0445 \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u0439 async function migrateToLatest() {   const { error, results } = await migrator.migrateToLatest();    results?.forEach((it) => {     if (it.status === 'Success') {       console.log(`migration \"${it.migrationName}\" was executed successfully`);     } else if (it.status === 'Error') {       console.error(`failed to execute migration \"${it.migrationName}\"`);     }   });    if (error) {     console.error('failed to migrate');     console.error(error);     process.exit(1);   }    await db.destroy(); }  \/\/ \u0424\u0443\u043d\u043a\u0446\u0438\u044f \u0434\u043b\u044f \u043e\u0442\u043a\u0430\u0442\u0430 \u043e\u0434\u043d\u043e\u0439 \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u0438 async function migrateDown() {   const { error, results } = await migrator.migrateDown();    results?.forEach((it) => {     if (it.status === 'Success') {       console.log(`migration \"${it.migrationName}\" was rollbacked successfully`);     } else if (it.status === 'Error') {       console.error(`failed to execute migration \"${it.migrationName}\"`);     }   });    if (error) {     console.error('failed to migrate');     console.error(error);     process.exit(1)   } }  const getNumber = (value) => {   const parsedValue = parseInt(value, 10);   if (isNaN(parsedValue)) { throw new InvalidArgumentError('Not a number'); }   return parsedValue; }  program   .description('CLI for apply\/rollback migration schema of database')   .option('-d, --down &lt;number>', 'transaction rollback', getNumber)   .option('-up-all, --up-all', 'all transaction apply')   ; program.parse();  const opts = program.opts();  void async function () {   \/\/ \u043f\u0440\u0438\u043c\u0435\u043d\u0438\u0442\u044c \u0432\u0441\u0435    if (opts.upAll) {     await migrateToLatest();   \/\/ \u043e\u0442\u043a\u0430\u0442\u0438\u0442\u044c n-\u043e\u0435 \u043a\u043e\u043b-\u0432\u043e \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u0439   } else if (opts.down) {     for await (const _ of new Array(opts.down)) {       await migrateDown();     }     await db.destroy();   } }();<\/code><\/pre>\n<p>\u0417\u0430\u0442\u0435\u043c \u0441\u043e\u0437\u0434\u0430\u0435\u043c \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u044e \u0434\u043b\u044f \u0442\u0430\u0431\u043b\u0438\u0446\u044b <code>user<\/code>:<\/p>\n<pre><code class=\"typescript\">\/\/ migrations\/20230909214556_user.ts  import { Kysely, sql } from 'kysely';  export async function up(db: Kysely&lt;any>): Promise&lt;void> {   await db.schema     .createTable('user')     .addColumn('id', 'int unsigned' as any, (col) =>        col.primaryKey().autoIncrement()     )     .addColumn('name', 'varchar(255)', (col) => col.notNull())     .addColumn('gender', 'enum(\"man\", \"woman\")' as any)     .addColumn('last_name', 'varchar(255)')     .addColumn('settings', 'json')     .addColumn('created_at', 'datetime', (col) =>       col.defaultTo(         sql`CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP`).notNull()     )     .execute()    await db.schema     .createIndex('i_name')     .on('user')     .column('name')     .execute() }  export async function down(db: Kysely&lt;any>): Promise&lt;void> {   await db.schema.dropTable('user').execute(); }<\/code><\/pre>\n<p>\u0415\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u0430\u044f \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0430, \u0432\u043d\u0443\u0442\u0440\u0438 \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u0439 \u0442\u0438\u043f\u0438\u0437\u0430\u0446\u0438\u044f \u043a\u043e\u043b\u043e\u043d\u043e\u043a MySQL \u0441\u0434\u0435\u043b\u0430\u043d\u0430 \u0441\u043b\u0430\u0431\u043e  (\u043d\u0435 \u0432\u0441\u0435 \u0442\u0438\u043f\u044b \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u044b), \u043f\u0440\u0438\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u043f\u0438\u0441\u0430\u0442\u044c \u043c\u0435\u0441\u0442\u0430\u043c\u0438 <code>any<\/code>. \u041d\u043e \u0432 PostgreSQL \u0438 SQLite \u0441 \u044d\u0442\u0438\u043c \u043f\u0440\u043e\u0431\u043b\u0435\u043c \u043c\u0435\u043d\u044c\u0448\u0435.<\/p>\n<p>\u0417\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u043c \u043d\u0430\u0448 \u0441\u043a\u0440\u0438\u043f\u0442:<\/p>\n<pre><code class=\"bash\"># \u041f\u0440\u0438\u043c\u0435\u043d\u0438\u0442\u044c \u0432\u0441\u0435 \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u0438 Mitya:kysely dmitrijd$ npx tsx src\/migration-cli.ts --up-all migration \"20230909214556_user\" was executed successfully  # \u041e\u0442\u043a\u0430\u0442\u0438\u0442\u044c \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u044e\u044e \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u044e Mitya:kysely dmitrijd$ npx tsx src\/migration-cli.ts --down=1 migration \"20230909214556_user\" was rollbacked successfully<\/code><\/pre>\n<h2>\u0421\u0445\u0435\u043c\u0430<\/h2>\n<p>\u0411\u044b\u0432\u0430\u044e\u0442 \u0441\u043b\u0443\u0447\u0430\u0438, \u043a\u043e\u0433\u0434\u0430 \u0432 \u0437\u0430\u043f\u0440\u043e\u0441\u0430\u0445 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0440\u0430\u0437\u043d\u044b\u0435 \u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445 (MySQL) \u0438\u043b\u0438 \u0441\u0445\u0435\u043c\u044b (PostgreSQL). \u042d\u0442\u043e \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u0441\u0432\u044f\u0437\u0430\u043d\u043e \u0441 \u0442\u0435\u043c, \u0447\u0442\u043e \u0443 \u0432\u0430\u0441 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439, \u0438 \u043a\u0430\u0436\u0434\u043e\u0435 \u0434\u043e\u043b\u0436\u043d\u043e \u0438\u043c\u0435\u0442\u044c \u0441\u0432\u043e\u0439 namespace \u0432 \u0411\u0414, \u0438\u043b\u0438 \u0443 \u0432\u0430\u0441, \u043a \u043f\u0440\u0438\u043c\u0435\u0440\u0443, \u0448\u0430\u0440\u0434\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435, \u0438 \u0443 \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u043a\u043b\u0438\u0435\u043d\u0442\u0430 \u0441\u0432\u043e\u0439 namespace \u0432 \u0411\u0414. \u041a \u0441\u0447\u0430\u0441\u0442\u044c\u044e, \u0432 kysely \u043e\u0431 \u044d\u0442\u043e\u043c \u0443\u0436\u0435 \u043f\u043e\u0434\u0443\u043c\u0430\u043b\u0438. <\/p>\n<p>\u0414\u043e\u043f\u0443\u0441\u0442\u0438\u043c \u0443 \u043d\u0430\u0441 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0438 \u043b\u0435\u0436\u0430\u0442 \u0432 \u0431\u0430\u0437\u0435 \u0434\u0430\u043d\u043d\u044b\u0445\/\u0441\u0445\u0435\u043c\u0435 <code>admin<\/code>, \u0430 \u0437\u0430\u043a\u0430\u0437\u044b \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u0432 <code>shop<\/code>. \u0422\u043e\u0433\u0434\u0430 \u043d\u0430\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043f\u0440\u0435\u0444\u0438\u043a\u0441\u044b \u0434\u043b\u044f \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0439 \u0442\u0430\u0431\u043b\u0438\u0446 \u0432 <code>schema.ts<\/code> \u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u044d\u0442\u0438 \u043f\u0440\u0435\u0444\u0438\u043a\u0441\u044b \u0432 \u0441\u0430\u043c\u0438\u0445 \u0437\u0430\u043f\u0440\u043e\u0441\u0430\u0445: <\/p>\n<pre><code class=\"typescript\"> export interface Database {   'admin.user': UserTable;   'shop.order': OrderTable; }  const user = await db   .selectFrom('admin.user')   .select(['id', 'name', 'last_name'])   .executeTakeFirst(); \/\/ { id: 1, name: '\u0413\u0440\u0438\u0433\u043e\u0440\u0438\u0439', last_name: '\u0413\u043b\u0430\u0434\u043a\u043e\u0432' } console.log(user);  const orders = await db   .selectFrom('shop.order')   .select(['id', 'status', 'amount'])   .where('id', '=', user?.id!)   .execute(); \/\/ [{ id: 1, status: 'pending', amount: 235325 }] console.log(orders);<\/code><\/pre>\n<p>\u0414\u0440\u0443\u0433\u043e\u0439 \u0432\u0430\u0440\u0438\u0430\u043d\u0442: \u043d\u0430\u0448\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0438 \u0438 \u0437\u0430\u043a\u0430\u0437\u044b \u0436\u0438\u0432\u0443\u0442 \u0432 \u043e\u0434\u043d\u043e\u0439 \u0431\u0430\u0437\u0435 \u0434\u0430\u043d\u043d\u044b\u0445\/\u0441\u0445\u0435\u043c\u0435, \u0430 \u0443 \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u043c\u0430\u0433\u0430\u0437\u0438\u043d\u0430 \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u043b\u044c\u043d\u0430\u044f \u0431\u0430\u0437\u0430\/\u0441\u0445\u0435\u043c\u0430. \u0422\u043e\u0433\u0434\u0430 \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u043f\u0440\u043e\u0441\u0442\u043e \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0439 \u043f\u0440\u0435\u0444\u0438\u043a\u0441 \u0432 \u0441\u0430\u043c\u043e\u043c \u0437\u0430\u043f\u0440\u043e\u0441\u0435 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043c\u0435\u0442\u043e\u0434\u0430 <code>withSchema<\/code>:<\/p>\n<pre><code class=\"typescript\">const result = await db   .withSchema('shard1')   .selectFrom('user')   .innerJoin('order', 'user.id', 'order.user_id')   .select([     'user.id', 'user.name', 'user.last_name', 'order.status', 'order.amount'   ])   .where('order.status', '=', 'paid')   .execute(); \/*[     {       id: 1,       name: '\u041d\u0438\u043a\u0438\u0442\u0430',       last_name: '\u0411\u043b\u0438\u043d\u0441\u043a\u0438\u0439',       status: 'paid',       amount: 1546     } ]*\/ console.log(result);  const result2 = await db   .withSchema('shard2')   .selectFrom('user')   .innerJoin('order', 'user.id', 'order.user_id')   .select([     'user.id', 'user.name', 'user.last_name', 'order.status', 'order.amount'   ])   .where('order.status', '=', 'paid')   .execute(); \/*[     {       id: 1,       name: '\u041c\u0430\u0448\u0430',       last_name: '\u0415\u0433\u043e\u0440\u043e\u0432\u0430',       status: 'paid',       amount: 546     } ]*\/ console.log(result2);<\/code><\/pre>\n<p><a href=\"https:\/\/kysely.dev\/docs\/recipes\/schemas\" rel=\"noopener noreferrer nofollow\">\u041f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435 \u043e\u0431 \u0443\u043a\u0430\u0437\u0430\u043d\u0438\u0438 \u0441\u0445\u0435\u043c\u044b\/\u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445 \u0434\u043b\u044f \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432<\/a> <\/p>\n<h2>\u0418\u0442\u043e\u0433<\/h2>\n<p>Kysely \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u044b\u0439 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 sql \u0437\u0430\u043f\u0440\u043e\u0441\u0430\u043c\u0438 \u0432 JavaScript.  <\/p>\n<p>\u041d\u0430\u0440\u044f\u0434\u0443 \u0441 \u0447\u0438\u0441\u0442\u044b\u043c\u0438 sql \u0437\u0430\u043f\u0440\u043e\u0441\u0430\u043c\u0438 \u044f \u0434\u0430\u0432\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e sql \u0431\u0438\u043b\u0434\u0435\u0440\u044b \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0411\u0414. \u0414\u043e\u043b\u0433\u043e\u0435 \u0432\u0440\u0435\u043c\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b\u0441\u044f Knex.js (\u0441\u043e\u0432\u0441\u0435\u043c \u0434\u0430\u0432\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b Squel.js, \u043d\u043e \u043e\u043d \u0443\u0441\u0442\u0430\u0440\u0435\u043b \u0438 \u0431\u043e\u043b\u044c\u0448\u0435 \u043d\u0435 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442\u0441\u044f), \u043d\u043e \u0438\u0437-\u0437\u0430 \u0442\u043e\u0433\u043e, \u0447\u0442\u043e Knex \u0438\u0437\u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e \u043d\u0430\u043f\u0438\u0441\u0430\u043d \u043d\u0430 js, \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0430 TypeScript \u0443 \u043d\u0435\u0433\u043e \u0434\u0430\u043b\u0435\u043a\u043e \u043d\u0435 \u0441\u0430\u043c\u0430\u044f \u043b\u0443\u0447\u0448\u0430\u044f.   <\/p>\n<p>\u041b\u0438\u0447\u043d\u043e \u0434\u043b\u044f \u0441\u0435\u0431\u044f \u044f \u043e\u0442\u043a\u0440\u044b\u043b Kysely \u0433\u0434\u0435-\u0442\u043e \u0433\u043e\u0434\u0430 2 \u043d\u0430\u0437\u0430\u0434 \u0438 \u0432\u043e\u0442 \u0443\u0436\u0435 \u0433\u043e\u0434 \u043e\u043d \u0432 \u043f\u0440\u043e\u0434\u0430\u043a\u0448\u0435\u043d\u0435, \u0438 \u043a\u0430\u043a\u0438\u0445-\u0442\u043e \u0433\u043b\u043e\u0431\u0430\u043b\u044c\u043d\u044b\u0445 \u043f\u0440\u043e\u0431\u043b\u0435\u043c \u043d\u0435 \u0441\u043e\u0437\u0434\u0430\u043b, \u0430 \u0443\u0434\u043e\u0431\u0441\u0442\u0432\u0430 \u0438 \u043d\u0430\u0434\u0435\u0436\u043d\u043e\u0441\u0442\u0438 \u0434\u043e\u0431\u0430\u0432\u0438\u043b.<\/p>\n<\/p>\n<\/div>\n<\/div>\n<\/div>\n<p><!----><!----><\/div>\n<p><!----><!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/759206\/\"> https:\/\/habr.com\/ru\/articles\/759206\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p><strong>Kysely.js <\/strong>\u2013 \u044d\u0442\u043e \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430, \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u044e\u0449\u0430\u044f \u043f\u0438\u0441\u0430\u0442\u044c \u0442\u0438\u043f\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 SQL \u0437\u0430\u043f\u0440\u043e\u0441\u044b. \u0411\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 \u0434\u0435\u043b\u0430\u0435\u0442 \u0440\u0430\u0431\u043e\u0442\u0443 \u0441 SQL \u0432 \u0432\u0430\u0448\u0435\u043c \u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u0431\u043e\u043b\u0435\u0435 \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0439, \u0438\u0437\u0431\u0430\u0432\u043b\u044f\u044f \u043e\u0442 \u0442\u0430\u043a\u0438\u0445 \u043e\u0448\u0438\u0431\u043e\u043a \u043a\u0430\u043a \u043e\u043f\u0435\u0447\u0430\u0442\u043a\u0438 \u0432 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u044f\u0445 \u043a\u043e\u043b\u043e\u043d\u043e\u043a \u0438\u043b\u0438 \u0442\u0430\u0431\u043b\u0438\u0446 \u0438 \u043d\u0435\u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 SQL \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440\u043e\u0432 \u0432 \u043a\u043e\u0434\u0435 (\u043a\u043e\u0434 \u043d\u0435 \u0441\u043a\u043e\u043c\u043f\u0438\u043b\u0438\u0440\u0443\u0435\u0442\u0441\u044f). \u041a\u043e \u0432\u0441\u0435\u043c\u0443 \u043f\u0440\u043e\u0447\u0435\u043c\u0443 \u043e\u043d\u0430 \u0434\u0435\u043b\u0430\u0435\u0442 \u0440\u0430\u0431\u043e\u0442\u0443 \u0441 SQL \u0431\u043e\u043b\u0435\u0435 \u0443\u0434\u043e\u0431\u043d\u043e\u0439, \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u044f \u043f\u0440\u0438 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u0430\u0432\u0442\u043e\u0434\u043e\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u0434\u043b\u044f \u0442\u0430\u0431\u043b\u0438\u0446, \u043a\u043e\u043b\u043e\u043d\u043e\u043a, \u0430\u043b\u0438\u0430\u0441\u043e\u0432 \u0438 \u0434\u0440\u0443\u0433\u0438\u0445 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0435\u0439. Kysely \u0438\u043c\u0435\u0435\u0442 \u043d\u0435\u0437\u043d\u0430\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u0441\u043b\u043e\u0439 \u0430\u0431\u0441\u0442\u0440\u0430\u043a\u0446\u0438\u0438 \u043d\u0430\u0434 SQL \u0434\u043b\u044f \u0442\u043e\u0433\u043e \u0447\u0442\u043e\u0431\u044b \u043c\u043e\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0432\u0441\u0435\u0439 \u043c\u043e\u0449\u044c\u044e SQL \u0438 \u043f\u0440\u0438 \u044d\u0442\u043e\u043c \u043d\u0435 \u0438\u0437\u0443\u0447\u0430\u0442\u044c \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u043e \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0435\u0439. \u0411\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442 MySQL, PostgreSQL, SQLite, PlanetScale, D3, SurrealDB \u0438 \u0434\u0440\u0443\u0433\u0438\u0435.<\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043f\u043e\u0433\u0440\u0443\u0437\u0438\u043c\u0441\u044f \u0432 \u043d\u0430\u0448 \u043a\u0438\u0441\u0435\u043b\u044c ?.<\/p>\n<h2>\u0421\u0445\u0435\u043c\u0430 \u0411\u0414<\/h2>\n<p>\u0423\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043c \u0441\u0430\u043c \u043c\u043e\u0434\u0443\u043b\u044c:<\/p>\n<pre><code class=\"bash\">npm i kysely -S<\/code><\/pre>\n<p>\u0417\u0430\u0442\u0435\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u0434\u0438\u0430\u043b\u0435\u043a\u0442. \u0412 \u043d\u0430\u0448\u0438\u0445 \u043f\u0440\u0438\u043c\u0435\u0440\u0430\u0445 \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0441 MySQL. \u041d\u043e \u0435\u0441\u0442\u044c \u043e\u0444\u0438\u0446\u0438\u0430\u043b\u044c\u043d\u0430\u044f \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0430 PostgreSQL \u0438 SQLite:<\/p>\n<pre><code class=\"bash\"># MySQL npm i mysql2 -S   # PostgreSQL # npm install pg -S   # SQLite # npm install better-sqlite3<\/code><\/pre>\n<p><a href=\"https:\/\/kysely.dev\/docs\/dialects\" rel=\"noopener noreferrer nofollow\">\u0421\u043f\u0438\u0441\u043e\u043a \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u0445 \u0434\u0438\u0430\u043b\u0435\u043a\u0442\u043e\u0432<\/a>. \u041f\u043e\u0441\u043b\u0435 \u044d\u0442\u043e\u0433\u043e \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0437\u0430\u0434\u0435\u043a\u043b\u0430\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0441\u0445\u0435\u043c\u0443 \u043d\u0430\u0448\u0435\u0439 \u0431\u0430\u0437\u044b \u0438 \u0442\u0430\u0431\u043b\u0438\u0446:<\/p>\n<pre><code class=\"typescript\">\/\/ schema.ts  import { ColumnType, Generated, Insertable, Selectable, Updateable } from 'kysely';  export interface UserTable {   id: Generated&lt;number>;   name: string;   gender: 'man' | 'woman' | null;   last_name: string | null;   created_at: ColumnType&lt;Date, string | Date | undefined, never> }  export type User = Selectable&lt;UserTable> export type NewUser = Insertable&lt;UserTable> export type UserUpdate = Updateable&lt;UserTable>  export interface OrderTable {   id: Generated&lt;number>;   user_id: number;   amount: number;   status: 'pending' | 'approved' | 'canceled' | 'paid';   created_at: ColumnType&lt;Date, string | undefined, never>;   updated_at: ColumnType&lt;Date, string | undefined, Date>; }  export type Order = Selectable&lt;OrderTable> export type NewOrder = Insertable&lt;OrderTable> export type OrderUpdate = Updateable&lt;OrderTable>  export interface Database {   user: UserTable;   order: OrderTable; } <\/code><\/pre>\n<p><code>Generated<\/code> \u044d\u0442\u043e \u0442\u0438\u043f, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u0442\u044c \u0434\u043b\u044f \u043a\u043e\u043b\u043e\u043d\u043e\u043a, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0433\u0435\u043d\u0435\u0440\u0438\u0442 \u0441\u0430\u043c\u0430 \u0431\u0430\u0437\u0430 \u0434\u0430\u043d\u043d\u044b\u0445, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043f\u043e\u043b\u0435 \u0441 \u0430\u0432\u0442\u043e\u0438\u043d\u043a\u0440\u0435\u043c\u0435\u043d\u0442\u043e\u043c. \u0418 \u0442\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c \u043f\u0440\u0438 update\/insert \u044d\u0442\u043e \u043f\u043e\u043b\u0435 \u0441\u0442\u0430\u043d\u0435\u0442 \u043e\u043f\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u044b\u043c. <\/p>\n<p>\u0415\u0441\u043b\u0438 \u043f\u043e\u043b\u0435 \u0432 \u0411\u0414 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c <code>null<\/code>, \u0442\u043e \u043d\u0435 \u043d\u0430\u0434\u043e \u0434\u0435\u043b\u0430\u0442\u044c \u0435\u0433\u043e \u043e\u043f\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u044b\u043c (<code>last_name?<\/code>).  Kysely \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0441\u0434\u0435\u043b\u0430\u0435\u0442 \u044d\u0442\u043e \u0437\u0430 \u0432\u0430\u0441.<\/p>\n<p>C \u043f\u043e\u043c\u043e\u0449\u044c\u044e <code>ColumnType<\/code> \u043c\u043e\u0436\u043d\u043e \u0443\u043a\u0430\u0437\u0430\u0442\u044c \u0440\u0430\u0437\u043d\u044b\u0435 \u0442\u0438\u043f\u044b \u0434\u043b\u044f \u043a\u043e\u043b\u043e\u043d\u043e\u043a \u0432 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u0442\u043e\u0433\u043e \u0434\u0435\u043b\u0430\u0435\u043c \u043c\u044b select, insert \u0438\u043b\u0438 update. \u0422\u0438\u043f  <code>ColumnType&lt;SelectType, InsertType, UpdateType><\/code> \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 \u043d\u0430 \u0432\u0445\u043e\u0434 3 \u0434\u0436\u0435\u043d\u0435\u0440\u0438\u043a \u0442\u0438\u043f\u0430 \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0442\u0438\u043f\u0430 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e. \u042d\u0442\u043e \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u0443\u0434\u043e\u0431\u043d\u043e, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0434\u043b\u044f \u043a\u043e\u043b\u043e\u043d\u043e\u043a \u0441 \u0442\u0438\u043f\u043e\u043c <code>datetime<\/code> \u0438\u043b\u0438 <code>timestamp<\/code>.  \u0414\u043b\u044f \u0442\u0430\u0431\u043b\u0438\u0446\u044b <code>user<\/code> \u043c\u044b \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u043b\u0438, \u0447\u0442\u043e \u043a\u043e\u043b\u043e\u043d\u043a\u0430 <code>created_at<\/code> \u0434\u043b\u044f <code>select<\/code> \u0431\u0443\u0434\u0435\u0442 \u0438\u043c\u0435\u0442\u044c \u0442\u0438\u043f <code>Date<\/code>, \u0434\u043b\u044f <code>insert<\/code> \u043e\u043d\u0430 \u0431\u0443\u0434\u0435\u0442 \u043e\u043f\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0439 \u0438 \u0431\u0443\u0434\u0435\u0442 \u0438\u043c\u0435\u0442\u044c \u0442\u0438\u043f <code>Date<\/code> \u0438\u043b\u0438 <code>string<\/code> (\u0432\u0440\u0435\u043c\u044f \u0432 \u0444\u043e\u0440\u043c\u0430\u0442\u0435 \u0441\u0442\u0440\u043e\u043a\u0438), \u0430 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u044f<code>update<\/code>\u043d\u0430\u0434 \u043d\u0435\u0439 \u0431\u0443\u0434\u0435\u0442 \u0437\u0430\u043f\u0440\u0435\u0449\u0435\u043d\u0430 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0442\u0438\u043f\u0430 <code>never<\/code>.<\/p>\n<p>\u0412\u0430\u043c \u043c\u043e\u0436\u0435\u0442 \u043f\u043e\u0442\u0440\u0435\u0431\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043d\u0430\u043f\u0440\u044f\u043c\u0443\u044e \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u044b \u0442\u0430\u0431\u043b\u0438\u0446 \u0432\u0430\u0448\u0435\u0439 \u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445. \u041d\u0435 \u0441\u0442\u043e\u0438\u0442 \u044d\u0442\u043e\u0433\u043e \u0434\u0435\u043b\u0430\u0442\u044c, kysely \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0442\u0438\u043f\u044b \u043e\u0431\u0435\u0440\u0442\u043a\u0438 <code>Selectable<\/code>, <code>Insertable<\/code>, <code>Updateable<\/code>\u0434\u043b\u044f \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0445 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0439. \u041e\u043d\u0438 \u0433\u0430\u0440\u0430\u043d\u0442\u0438\u0440\u0443\u044e\u0442, \u0447\u0442\u043e \u0431\u0443\u0434\u0443\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u044b\u0435 \u0442\u0438\u043f\u044b \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0442\u0438\u043f\u0430 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0439.<\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u043a \u0411\u0414:<\/p>\n<pre><code class=\"typescript\">\/\/ db.ts  \/\/ \u0421\u0445\u0435\u043c\u0430 \u0411\u0414 import { Database } from '.\/schema'  \/\/ do not use 'mysql2\/promises'! import * as mysql from 'mysql2'  import { Kysely, MysqlDialect } from 'kysely'  const dialect = new MysqlDialect({   pool: mysql.createPool({     database: 'test',     host: 'localhost',     user: 'test',     password: 'test',     port: 3306,     connectionLimit: 10,   }) })   const db = new Kysely&lt;Database>({   dialect, });  export default db;  <\/code><\/pre>\n<p>\u041c\u044b \u0441\u043e\u0437\u0434\u0430\u0435\u043c \u0438\u043d\u0441\u0442\u0430\u043d\u0441 \u0411\u0414, \u043f\u0435\u0440\u0435\u0434\u0430\u0432 \u0434\u0438\u0430\u043b\u0435\u043a\u0442, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0441\u0445\u0435\u043c\u0443 \u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445 \u043a\u0430\u043a \u0434\u0436\u0435\u043d\u0435\u0440\u0438\u043a \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 \u0434\u043b\u044f \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e\u0439 \u0442\u0438\u043f\u0438\u0437\u0430\u0446\u0438\u0438.<\/p>\n<p>\u041f\u0440\u0438\u043c\u0435\u0440 user repository c kysely:<\/p>\n<pre><code class=\"typescript\">import { Kysely } from 'kysely'; import { Database, User, NewUser, UserUpdate } from '.\/schema';  class UserRepo {   constructor(private readonly db: Kysely&lt;Database>) {}    async getAll() {     return await this.db       .selectFrom('user')       .select(['id', 'name'])       .execute();   }    async getById(id: number) {     return await this.db       .selectFrom('user')       .select(['id', 'name'])       .where('id', '=', id)       .executeTakeFirst()     ;   }    async search(params: Partial&lt;User>) {     return await this.db       .selectFrom('user')       .select([ 'id', 'name', 'last_name' ])       .where((eb) => eb.and(params)).executeTakeFirst();   }    async create(data: NewUser) {     const { insertId } = await this.db       .insertInto('user')       .values(data)       .executeTakeFirst();          if (!insertId) {       throw new Error(`Not found id ${insertId}`);     }     return Number(insertId);   }    async updateById(id: number, data: UserUpdate) {     return await this.db       .updateTable('user')       .set(data)       .where('id', '=', id)       .execute();   }    async delete(id: number) {     return await this.db       .deleteFrom('user')       .where('id', '=', id)       .execute();   } }   const userRepo = new UserRepo(db); const userId = await userRepo.create({   name: '\u041e\u043b\u0435\u0433',   last_name: '\u0418\u0432\u0430\u043d\u043e\u0432',   gender: 'man', });  const users = await userRepo.getAll(); \/\/ [ { id: 2, name: '\u041e\u043b\u0435\u0433' } ]   console.log(users);  const user = await userRepo.getById(userId); \/\/ { id: 2, name: '\u041e\u043b\u0435\u0433' } console.log(user);  await userRepo.updateById(userId, { last_name: '' });  const foundedUser = await userRepo.search({ name: '\u041e\u043b\u0435\u0433', last_name: '' }); \/\/ { id: 2, name: '\u041e\u043b\u0435\u0433', last_name: '' } console.log(foundedUser);<\/code><\/pre>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435 \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 kysely.<\/p>\n<h2>Insert\/Update\/Delete<\/h2>\n<p>\u0412\u0441\u0442\u0430\u0432\u043a\u0430:<\/p>\n<pre><code class=\"typescript\">const result = await db.insertInto('user').values({   name: '\u0418\u0432\u0430\u043d',   last_name: '\u0418\u0432\u0430\u043d\u043e\u0432',   gender: 'man',   created_at: new Date().toISOString(), }).executeTakeFirst();    console.log({ userId: result.insertId }); <\/code><\/pre>\n<p>\u041c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u0430\u044f \u0432\u0441\u0442\u0430\u0432\u043a\u0430:<\/p>\n<pre><code class=\"typescript\">const result = await db.insertInto('user').values([{   name: '\u0418\u0432\u0430\u043d',   last_name: '\u0418\u0432\u0430\u043d\u043e\u0432',   gender: 'man',   created_at: new Date(), }, {   name: '\u0410\u043b\u0435\u043d\u0430',   last_name: '\u041f\u0435\u0442\u0440\u043e\u0432\u0430',   gender: 'woman',   created_at: new Date(), }]).executeTakeFirstOrThrow();    console.log(result.numInsertedOrUpdatedRows); \/\/ 2<\/code><\/pre>\n<p>\u0414\u043b\u044f \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442\u0441\u044f \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u043c\u0435\u0442\u043e\u0434\u044b: <code>execute<\/code> (\u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u043c\u0430\u0441\u0441\u0438\u0432 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439), <code>executeTakeFirst<\/code> (\u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u043f\u0435\u0440\u0432\u043e\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435), <code>executeTakeFirstOrThrow<\/code> (\u0430\u043d\u0430\u043b\u043e\u0433 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0435\u0433\u043e \u043c\u0435\u0442\u043e\u0434\u0430, \u043d\u043e \u0431\u0440\u043e\u0441\u0430\u044e\u0449\u0438\u0439 \u043e\u0448\u0438\u0431\u043a\u0443, \u0435\u0441\u043b\u0438 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d).<\/p>\n<p>\u0418\u043c\u0435\u0435\u0442\u0441\u044f \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0430 \u0411\u0414 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0433\u043e \u0441\u0438\u043d\u0442\u0430\u043a\u0441\u0438\u0441\u0430:<\/p>\n<pre><code class=\"typescript\">\/\/ Only MySQL: \u0438\u0433\u043d\u043e\u0440\u0438\u043c \u043e\u0448\u0438\u0431\u043a\u0443 \u043f\u0440\u0438 \u0432\u0441\u0442\u0430\u0432\u043a\u0435 \u0432 \u0442\u0430\u0431\u043b\u0438\u0446\u0443 \u0434\u0443\u0431\u043b\u0438\u043a\u0430\u0442\u0430 const result = await db.insertInto('user').ignore().values({   id: 2,   name: '\u0410\u043b\u0435\u043d\u0430',   last_name: '\u041f\u0435\u0442\u0440\u043e\u0432\u0430',   gender: 'woman',   created_at: new Date(), }).executeTakeFirst();    console.log(result.numInsertedOrUpdatedRows); \/\/ 0   \/\/ Only MySQL: \u0432 \u0441\u043b\u0443\u0447\u0430\u0435 \u043e\u0448\u0438\u0431\u043a\u0438 \u0434\u0443\u0431\u043b\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043f\u0440\u0438 \u0432\u0441\u0442\u0430\u0432\u043a\u0435,  \/\/ \u0442\u043e last_name \u0434\u0435\u043b\u0430\u0435\u043c \u043f\u0443\u0441\u0442\u044b\u043c const result = await db.insertInto('user').values({   id: 2,   name: '\u0410\u043b\u0435\u043d\u0430',   last_name: '\u041f\u0435\u0442\u0440\u043e\u0432\u0430',   gender: 'woman',   created_at: new Date(), }).onDuplicateKeyUpdate({ last_name: '' }).executeTakeFirst();  console.log(result.numInsertedOrUpdatedRows); \/\/ 2   \/\/ Only PostgreSQL: \u0432 \u0441\u043b\u0443\u0447\u0430\u0435 \u043e\u0448\u0438\u0431\u043a\u0438 \u0434\u0443\u0431\u043b\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043f\u0440\u0438 \u0432\u0441\u0442\u0430\u0432\u043a\u0435,  \/\/ \u0442\u043e last_name \u0434\u0435\u043b\u0430\u0435\u043c \u043f\u0443\u0441\u0442\u044b\u043c const result = await db.insertInto('user').values({   id: 2,   name: '\u0410\u043b\u0435\u043d\u0430',   last_name: '\u041f\u0435\u0442\u0440\u043e\u0432\u0430',   gender: 'woman',   \u0441reated_at: new Date(), }).onConflict((oc) =>      oc.column('id').doUpdateSet({ last_name: '' }) ).executeTakeFirst();  console.log(result.numInsertedOrUpdatedRows); \/\/ 2  \/\/ Only PostgreSQL: \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u043a\u043e\u043b\u043e\u043d\u043e\u043a, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0431\u044b\u043b\u0438 \u0432\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u044b   const result = await db.insertInto('user').values({   name: '\u0410\u043b\u0435\u043d\u0430',   last_name: '\u041f\u0435\u0442\u0440\u043e\u0432\u0430',   gender: 'woman',   created_at: new Date(), }).returning([ 'id', 'name' ]).executeTakeFirst();  console.log(result); \/\/ { id: 3, name: '\u0410\u043b\u0435\u043d\u0430' }<\/code><\/pre>\n<p>\u041e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435:<\/p>\n<pre><code class=\"typescript\">const result = await db   .updateTable('user')   .set({     last_name: '\u0418\u0432\u0430\u043d\u043e\u0432\u0430'   })   .where('id', '=', 2)   .executeTakeFirst()  console.log(result.numUpdatedRows) \/\/ 1<\/code><\/pre>\n<p>\u0423\u0434\u0430\u043b\u0435\u043d\u0438\u0435:<\/p>\n<pre><code class=\"typescript\">const result = await db   .deleteFrom('user')   .where('user.id', '=', 1).executeTakeFirst();  console.log(result.numDeletedRows); \/\/ 1<\/code><\/pre>\n<h2>Select<\/h2>\n<p>\u0412\u044b\u0431\u043e\u0440\u043a\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c alias:<\/p>\n<pre><code class=\"typescript\">const users = await db   .selectFrom('user')   .select(['id', 'user.name as name', 'created_at as createdAt'])   .where('gender', '!=', 'man')   .execute();  \/\/ [{ id: 2, name: '\u0410\u043b\u0435\u043d\u0430', createdAt: 2023-09-07T07:38:49.000Z }] console.log(users); <\/code><\/pre>\n<p>\u0412\u044b\u0431\u043e\u0440\u043a\u0430 \u043e\u0434\u043d\u043e\u0439 \u0441\u0442\u0440\u043e\u043a\u0438 \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c <code>limit<\/code> \u0438 <code>order by<\/code> :<\/p>\n<pre><code class=\"typescript\">const user = await db   .selectFrom('user')   .select(['id', 'user.name as name', 'created_at as createdAt'])   .where('gender', '!=', 'man')   .orderBy('id', 'desc')   .limit(1)   .executeTakeFirst();  \/\/ { id: 2, name: '\u0410\u043b\u0435\u043d\u0430', createdAt: 2023-09-07T07:38:49.000Z } console.log(user); <\/code><\/pre>\n<p>\u0420\u0430\u0437\u0443\u043c\u0435\u0435\u0442\u0441\u044f \u0435\u0441\u0442\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0434\u0435\u043b\u0430\u0442\u044c \u043f\u043e\u0434\u0437\u0430\u043f\u0440\u043e\u0441\u044b, \u0438 \u0445\u043e\u0442\u044f kysely \u043d\u0435 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f ORM, \u043e\u043d \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0443\u044e \u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e \u0434\u0430\u043d\u043d\u044b\u0445 \u0432 \u043e\u0431\u044a\u0435\u043a\u0442 \u0438\u043b\u0438 \u043c\u0430\u0441\u0441\u0438\u0432:<\/p>\n<pre><code class=\"typescript\">\/\/ mysql import { jsonObjectFrom, jsonArrayFrom } from 'kysely\/helpers\/mysql' \/\/ postgres \/\/ import { jsonObjectFrom, jsonArrayFrom } from 'kysely\/helpers\/postgres'  \/\/ \u041f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0432\u0441\u0435\u0445 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 \u0432\u043c\u0435\u0441\u0442\u0435 \u0441 \u043e\u043f\u043b\u0430\u0447\u0435\u043d\u043d\u044b\u043c \u0437\u0430\u043a\u0430\u0437\u043e\u043c const result = await db   .selectFrom('user')   \/\/ \u043f\u043e\u0434\u0437\u0430\u043f\u0440\u043e\u0441   .select((eb) => [     'id',     jsonObjectFrom(       eb.selectFrom('order')         .select(['order.id as orderId', 'order.amount'])         .whereRef('order.user_id', '=', 'user.id')         .where('order.status', '=', 'paid')         .where('order.amount', '>', 100)         .limit(1)     ).as('paid_order')   ])   .execute();  \/* [   { id: 1, paid_order: { amount: 546, orderId: 2 } },   { id: 2, paid_order: null } ] *\/ console.log(result);  \/\/ \u041f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0432\u0441\u0435\u0445 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 \u0432\u043c\u0435\u0441\u0442\u0435 \u0441 \u043e\u043f\u043b\u0430\u0447\u0435\u043d\u043d\u044b\u043c\u0438 \u0437\u0430\u043a\u0430\u0437\u0430\u043c\u0438 const result = await db   .selectFrom('user')   \/\/ \u043f\u043e\u0434\u0437\u0430\u043f\u0440\u043e\u0441   .select((eb) => [     'id',     jsonArrayFrom(<\/code><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-354126","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/354126","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=354126"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/354126\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=354126"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=354126"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=354126"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}