Kysera или Kysely на стероидах: почему этот проект существует

Kysera или Kysely на стероидах: почему этот проект существует

Эта статья - не маркетинговый материал. Она не пытается убедить вас в том, что Kysera - лучшее решение для всех задач. Вместо этого здесь представлен критический анализ: какие проблемы привели к созданию Kysera, какое место он занимает среди существующих решений, и для каких случаев он действительно подходит.

Если после прочтения вы решите, что Kysera вам не нужен - это нормальный и, возможно, правильный вывод.

Ландшафт проблем

Боль разработчиков в больших проектах

Работа с базами данных в production-системах сопряжена с повторяющимися проблемами, которые не зависят от выбранного инструмента:

Архитектурные проблемы:

  • Транзакции, распределённые по нескольким сервисам или слоям
  • Soft delete, который нужно применять повсюду, но который легко забыть
  • Audit trail, требующий единообразия во всех операциях записи
  • Row-Level Security для мультитенантных приложений
  • Graceful shutdown и управление connection pool

Операционные проблемы:

  • Ошибки БД, которые сложно понять без знания кодов PostgreSQL/MySQL
  • Health checks и мониторинг состояния соединений
  • Медленные запросы, которые нужно найти и профилировать
  • Тестирование с изоляцией транзакций

Проблемы типизации:

  • Generated<T> поля, которые есть на чтение, но не на запись
  • Схемы валидации для create/update, отличающиеся от типа сущности
  • Типы ошибок, которые теряются в unknown

Как разные инструменты решают эти проблемы

Prisma

Подход: Полная абстракция. Prisma скрывает SQL за декларативной схемой и генерированным клиентом.

Сильные стороны:

  • Отличный DX для простых CRUD-операций
  • Автоматические миграции из схемы
  • Встроенные связи и вложенные запросы
  • Type-safe клиент из коробки

Слабые стороны:

  • Генерированный код - чёрный ящик
  • Сложные запросы требуют $queryRaw, теряя типизацию
  • Ограниченный контроль над SQL
  • Soft delete требует middleware, который не очевиден
  • Query engine как отдельный процесс (или WASM) добавляет overhead
  • Миграции привязаны к Prisma, сложно выйти

Философия: "Мы знаем лучше, как работать с БД. Доверьтесь абстракции."

TypeORM

Подход: Классический ORM с декораторами, Active Record или Data Mapper.

Сильные стороны:

  • Знакомые паттерны для разработчиков из мира Java/C#
  • Поддержка множества баз данных
  • Entity lifecycle management
  • Query Builder для сложных случаев

Слабые стороны:

  • Декораторы и метаданные - runtime magic
  • Identity Map создаёт неочевидное состояние
  • Lazy loading - источник N+1 проблем
  • Типизация часто теряется в сложных запросах
  • Миграции требуют синхронизации с entities

Философия: "ORM должен управлять жизненным циклом entities."

Drizzle

Подход: Типобезопасный schema-first конструктор запросов с API, похожим на ORM.

Сильные стороны:

  • Отличная типизация из схемы
  • SQL близок к поверхности
  • Легковесный (нет runtime engine)
  • Relational queries для простых JOIN'ов

Слабые стороны:

  • Схема в коде, а не в БД (требует синхронизации)
  • Меньше ecosystem/плагинов, чем у Prisma
  • Relational queries - не полноценные связи
  • Для сложных запросов всё равно нужен raw SQL

Философия: "Type safety важнее абстракции. SQL - не враг."

Knex

Подход: Query builder без претензий на ORM.

Сильные стороны:

  • Простой и понятный API
  • Миграции как код
  • Поддержка множества диалектов
  • Минимальный overhead

Слабые стороны:

  • Слабая типизация (до TypeScript-first эпохи)
  • Нет валидации
  • Нет plugin-системы
  • Каждый проект пишет свои утилиты

Философия: "Query builder - это всё, что нужно."

Kysely

Подход: Type-safe query builder для TypeScript.

Сильные стороны:

  • Полная типизация запросов
  • SQL как first-class citizen
  • Нулевой runtime overhead
  • Предсказуемый SQL output

Слабые стороны:

  • Только query builder - нет паттернов доступа к данным
  • Нет валидации
  • Нет plugin-системы
  • Нет utilities для production (health, retry, pagination)
  • Каждый проект реализует soft delete по-своему

Философия: "Type-safe SQL. Ничего больше, ничего меньше."

Позиция Kysera

Что Kysera НЕ пытается делать

Прежде чем говорить о том, что Kysera делает, важно понять, чего он намеренно избегает:

  1. Не заменяет Kysely. Kysera - надстройка над Kysely, не альтернатива. Вы всегда можете использовать Kysely напрямую.
  2. Не является ORM. Нет entity mapping, Unit of Work, Identity Map, lazy loading. Эти паттерны - источник сложности, которую Kysera отвергает.
  3. Не скрывает SQL. Запросы пишутся на Kysely, SQL остаётся видимым и предсказуемым.
  4. Не навязывает архитектуру. Repository или DAL - выбор за вами. Можно использовать оба.
  5. Не решает все проблемы. Kysera фокусируется на конкретных болях, а не на попытке стать "всем для всех".

Что Kysera делает

Kysera предоставляет инструментарий для решения повторяющихся проблем в работе с БД:

Plugin System с Query Interception

Вместо того чтобы помнить о soft delete в каждом запросе:

// Без Kysera — легко забыть const users = await db .selectFrom('users') .selectAll() .where('deleted_at', 'is', null) // Забыли? Получите удалённых пользователей .execute(); // С Kysera — применяется автоматически const executor = await createExecutor(db, [softDeletePlugin()]); const users = await executor .selectFrom('users') .selectAll() .execute(); // WHERE deleted_at IS NULL добавлено автоматически

Это работает через Proxy-based interception - тот же подход, который используют middleware в Express или interceptors в Axios.

Dual API: Repository и Functional DAL

Repository - для структурированного CRUD с валидацией:

const userRepo = orm.createRepository(createUserRepository); const user = await userRepo.create({ email: 'test@example.com', name: 'Test' }); // Валидация, типизация, плагины — всё из коробки

Functional DAL - для сложных запросов с композицией:

const getUserWithStats = createQuery(async (ctx, id: number) => { const user = await ctx.db .selectFrom('users') .selectAll() .where('id', '=', id) .executeTakeFirst(); const stats = await ctx.db .selectFrom('events') .select(sql<number>`count(*)`.as('total')) .where('user_id', '=', id) .executeTakeFirst(); return { user, stats }; });

Typed Error Handling

Вместо парсинга строк ошибок:

// Без Kysera try { await db.insertInto('users').values(data).execute(); } catch (error: unknown) { // Что это? UniqueConstraint? ForeignKey? Кто знает? if (error.message.includes('duplicate')) { /* ... */ } } // С Kysera try { await userRepo.create(data); } catch (error) { const dbError = parseDatabaseError(error, 'postgres'); if (dbError instanceof UniqueConstraintError) { // Типизированная ошибка с constraint name, table, columns } }

Production Utilities

Opt-in пакеты для production:

// Health checks const health = await checkDatabaseHealth(db, pool); // { status: 'healthy', latency: 12, poolMetrics: {...} } // Retry с exponential backoff const result = await withRetry( () => userRepo.findById(id), { maxAttempts: 3, backoff: 'exponential' } ); // Graceful shutdown await gracefulShutdown(db, { timeout: 30000, onClose: () => console.log('DB connections closed') });

Архитектурное решение: Unified Execution Layer

Ключевое архитектурное решение Kysera - KyseraExecutor. Это Proxy-обёртка над Kysely, которая:

  1. Перехватывает selectFrom, insertInto, updateTable, deleteFrom
  2. Применяет плагины к каждому запросу
  3. Пропагирует плагины в транзакции
  4. Сохраняет нулевой overhead при отсутствии плагинов
┌─────────────────────────────────────────┐ │ Application Code │ │ │ │ │ ▼ │ │ ┌─────────────────┐ │ │ │ KyseraExecutor │ ← Proxy intercepts │ │ │ (selectFrom) │ query methods │ │ └────────┬────────┘ │ │ │ │ │ ▼ │ │ ┌─────────────────┐ │ │ │ Plugin Chain │ ← Plugins modify │ │ │ (interceptors) │ query builders │ │ └────────┬────────┘ │ │ │ │ │ ▼ │ │ ┌─────────────────┐ │ │ │ Kysely │ ← Original QB │ │ └────────┬────────┘ │ │ │ │ │ ▼ │ │ Database │ └─────────────────────────────────────────┘

Это позволяет плагинам работать с обоими паттернами - Repository и DAL - без дублирования кода.

Честное сравнение

Kysera vs Prisma

Аспект │ Prisma │ Kysera ─────────────────┼───────────────────────────┼────────────────────────────── Абстракция │ Высокая (скрывает SQL) │ Низкая (SQL видим) Типизация │ Генерированная из схемы │ Из Kysely + схемы БД Soft delete │ Middleware (неочевидно) │ Plugin (явно) Сложные запросы │ `$queryRaw` (теряет типы) │ Kysely (сохраняет типы) Bundle size │ ~2MB (с engine) │ ~30KB (все пакеты) Lock-in │ Высокий │ Низкий (можно уйти на Kysely)

Когда Prisma лучше:

  • Быстрый старт с простым CRUD
  • Команда не хочет думать о SQL
  • Нужны автоматические миграции из схемы

Когда Kysera лучше:

  • Сложные запросы составляют значительную часть проекта
  • Важен контроль над SQL
  • Критичен размер bundle
  • Нужна постепенная миграция или возможность выхода

Kysera vs Drizzle

Аспект │ Drizzle │ Kysera ─────────────────────┼───────────────────┼────────────────────── Schema source │ Код (schema.ts) │ База данных Plugin system │ Нет │ Да Repository pattern │ Нет │ Опционально Error handling │ Generic │ Typed errors Production utils │ Частично │ Полный набор (opt-in)

Когда Drizzle лучше:

  • Предпочитаете schema-first подход
  • Relational queries покрывают ваши JOIN'ы
  • Не нужны плагины

Когда Kysera лучше:

  • Schema в БД (database-first)
  • Нужен soft delete, audit, RLS как plugin
  • Важны production utilities

Kysera vs "Просто Kysely"

Это самый важный вопрос: зачем Kysera, если есть Kysely?

Проблема │ Kysely │ Kysely + Kysera ─────────────────────┼───────────────────────────────┼────────────────────────────── Soft delete │ Ручной WHERE в каждом запросе │ Plugin автоматически Audit trail │ Своя реализация │ Plugin с полной историей RLS │ Ручная фильтрация │ Plugin с AsyncLocalStorage Error parsing │ `try/catch` + строки │ Typed errors Pagination │ Своя реализация │ Offset + cursor из коробки Health checks │ Своя реализация │ @kysera/infra Retry logic │ Своя реализация │ @kysera/infra Validation │ Своя интеграция │ Встроено (Zod, Valibot, etc.) Testing │ Своя изоляция │ Transaction rollback helpers

Вывод: Kysera - это кодификация best practices, которые каждая команда иначе пишет с нуля.

Критический взгляд на Kysera

Слабые стороны

1. Дополнительная абстракция

Каждый слой абстракции - это:

  • Потенциальное место для багов
  • Необходимость изучения документации
  • Зависимость от maintainer'ов

Для простых проектов overhead может не окупиться.

2. Ecosystem меньше, чем у Prisma

У Prisma - огромная экосистема: Prisma Studio, Prisma Accelerate, интеграции со всеми фреймворками. Kysera - молодой проект с меньшим сообществом.

3. Два паттерна - потенциальная путаница

Repository и DAL в одном проекте могут создать inconsistency, если команда не договорится о конвенциях.

4. Plugin dependencies

Плагины имеют порядок выполнения и зависимости. Неправильный порядок может привести к неожиданному поведению.

Когда НЕ использовать Kysera

  1. Простой CRUD-проект - Prisma или даже raw Kysely будет проще.
  2. Команда не знает SQL - Kysera не скрывает SQL, это осознанный выбор.
  3. Нужен entity lifecycle - Kysera отвергает эти паттерны. Если вам нужен Identity Map или Unit of Work - смотрите на TypeORM.
  4. Максимальный DX важнее контроля - Prisma даёт лучший out-of-the-box опыт для простых случаев.
  5. Уже есть рабочее решение - Миграция ради миграции не имеет смысла.

Для кого Kysera?

Профиль "идеального" пользователя

Kysera создан для разработчиков, которые:

  • Понимают SQL и хотят его контролировать
  • Работают над production-системами с требованиями к надёжности
  • Ценят явность над магией
  • Предпочитают композицию над наследованием
  • Хотят opt-in функциональность, а не "всё включено"
  • Используют TypeScript со strict mode

Типичные сценарии

1. Multi-tenant SaaS

RLS plugin + AsyncLocalStorage для автоматической фильтрации по tenant_id.

2. Приложения с audit requirements

Audit plugin для полной истории изменений с возможностью restore.

3. Сложные domain-driven приложения

Functional DAL для сложных запросов + Repository для CRUD.

4. Microservices с shared database patterns

Plugins как переиспользуемые пакеты между сервисами.

Философия "Start minimal, grow as needed, stay transparent"

Start minimal

Минимальная установка - только @kysera/core (8KB):

npm install kysely @kysera/core

Вы получаете error handling и pagination. Всё остальное - opt-in.

Grow as needed

По мере роста проекта добавляете то, что нужно:

# Нужен soft delete? npm install @kysera/soft-delete # Нужен audit? npm install @kysera/audit # Нужны health checks? npm install @kysera/infra

Stay transparent

Каждая операция:

  • Генерирует предсказуемый SQL
  • Может быть отлажена через @kysera/debug
  • Не имеет скрытого состояния
  • Работает в транзакциях так же, как вне их

Заключение: честная оценка

Kysera - это не революция в data access. Это эволюционное решение конкретных проблем, которые возникают при масштабировании TypeScript-проектов с реляционными базами данных.

Сильные стороны:

  • Решает реальные production-проблемы (soft delete, audit, RLS, error handling)
  • Сохраняет контроль над SQL через Kysely
  • Модульная архитектура - берёте только нужное
  • Низкий lock-in - можно уйти на чистый Kysely
  • Plugin system для переиспользования паттернов

Слабые стороны:

  • Дополнительная абстракция над Kysely
  • Меньший ecosystem, чем у Prisma
  • Требует понимания SQL
  • Молодой проект

Вердикт

Если вы:

  • Уже используете или планируете Kysely
  • Работаете над production-системой
  • Хотите плагины для cross-cutting concerns
  • Цените explicit над implicit

...то Kysera стоит рассмотреть.

Если же вам нужен максимальный DX с минимальным SQL, или вы работаете над простым проектом - Prisma или Drizzle могут подойти лучше.

Kysera не пытается быть лучшим решением для всех. Он пытается быть правильным решением для определённого класса задач.

Приложение: Ссылки для дальнейшего изучения

Kysely Documentation - фундамент, на котором построен Kysera

Kysera - быстрый старт за 5 минут