TypeScript / ORM / Database

    ORM TypeScript 2024

    Kysely (query builder), MikroORM (Data Mapper), Drizzle (SQL-like), Prisma i TypeORM — porównanie.

    Kysely
    SQL Builder
    MikroORM
    Data Mapper
    Drizzle
    SQL-like
    Prisma
    Schema-first

    6 bibliotek ORM — podejście i kiedy wybrać

    Prisma, Drizzle, Kysely, MikroORM, TypeORM i Sequelize — podejście, bundle i zastosowanie.

    ORM Podejście Bundle Kiedy
    Prisma Schema-first, generowany klient Duży Standard — najlepszy DX, typesafety
    Drizzle ORM TypeScript schema, SQL-like Mały Edge, serverless, SQL control, performance
    Kysely Query Builder (nie ORM) Bardzo mały Złożone SQL, pełna kontrola, bez abstrakcji
    MikroORM Data Mapper, Unit of Work Średni Złożony domain, migracja z TypeORM
    TypeORM Active Record / Data Mapper Duży Legacy — preferuj Prisma/Drizzle dla nowych
    Sequelize Active Record (JS-first) Duży Stary JS projekt — rozważ migrację

    Często zadawane pytania

    Kysely — type-safe SQL query builder dla TypeScript?

    Kysely: Sami Koskimäki. SQL query builder. Nie ORM. TypeScript-first. Pełna typizacja zapytań. Instalacja: npm install kysely pg. Dialekty: PostgreSQL, MySQL, SQLite, MSSQL. Konfiguracja: import {Kysely, PostgresDialect} from 'kysely'. const db = new Kysely({dialect: new PostgresDialect({pool})}).withTables(). Interface DB: interface Database { users: UsersTable. posts: PostsTable }. type UsersTable = {id: Generated number. name: string. email: string. created_at: Generated Date}. Użycie: const users = await db.selectFrom('users').select(['id', 'name', 'email']).where('id', '=', userId).execute(). Type-safe: VS Code autocomplete dla nazw kolumn i tabel. Błąd kompilacji przy pomyłce. Join: await db.selectFrom('users').leftJoin('posts', 'posts.user_id', 'users.id').select(['users.name', 'posts.title']).execute(). Insert: await db.insertInto('users').values({name, email}).returning('id').executeTakeFirst(). Update: await db.updateTable('users').set({name}).where('id', '=', id).execute(). Transaction: await db.transaction().execute(async (trx) => { await trx.insertInto(...). await trx.updateTable(...) }). Migration: Kysely nie ma własnych migracji. Użyj: umzug, db-migrate lub manualne. sql template: sql`SELECT ${sql.raw(colName)} FROM users`. Escape automatyczny. Kiedy Kysely: chcesz SQL kontrolę. Bez ORM magic. Type safety krytyczna. Złożone JOIN-y.

    MikroORM — TypeScript-first ORM z Data Mapper pattern?

    MikroORM: Martin Adámek. Data Mapper pattern. Unit of Work. TypeScript-first. Alternatywa dla TypeORM. Instalacja: npm install @mikro-orm/core @mikro-orm/postgresql. Konfiguracja: await MikroORM.init({entities: ['./src/entities/*.ts'], dbName: 'mydb', type: 'postgresql'}). Entity: import {Entity, Property, PrimaryKey} from '@mikro-orm/core'. @Entity() export class User { @PrimaryKey() id!: number. @Property() name!: string. @Property({unique: true}) email!: string. @Property({onCreate: () => new Date()}) createdAt!: Date }. EntityManager: const em = orm.em.fork(). const user = em.create(User, {name, email}). await em.persistAndFlush(user). Znajdowanie: const users = await em.find(User, {name: {$like: '%Jan%'}}). const user = await em.findOne(User, {email}). Relacje: @ManyToOne(() => User, user => user.posts) author!: User. @OneToMany(() => Post, post => post.author) posts = new Collection this. Populate: await em.find(User, {}, {populate: ['posts']}). Lazy by default. Unit of Work: śledzi zmiany. user.name = 'Nowe'. await em.flush() — auto UPDATE. Nie musisz wywołać update(). QueryBuilder: em.createQueryBuilder(User).where({name}).orderBy({id: 'DESC'}).getResultList(). Migrations: npx mikro-orm migration:create. npx mikro-orm migration:up. Schema sync: npx mikro-orm schema:update --run. MikroORM vs TypeORM: TypeORM starszy, Active Record. MikroORM nowszy, Data Mapper, lepszy TypeScript. Kiedy MikroORM: TypeORM migration. Złożony domain model. Unit of Work potrzebny.

    TypeORM vs Prisma vs Drizzle — który ORM wybrać w 2024?

    Prisma (lider 2024): generuje klienta z schema.prisma. DX najlepszy. Type safety przez generowanie. Instrukcja: schema.prisma definiuje modele. npx prisma generate. PrismaClient automatycznie typed. Ograniczenia: N+1 łatwy. Duże migracje skomplikowane. Bundle size. Drizzle (rosnący): SQL-like syntax w TypeScript. Lekki. Szybki. bun add drizzle-orm pg. Schema: const users = pgTable('users', {id: serial('id').primaryKey(), name: varchar('name', {length: 255})}). const result = await db.select().from(users).where(eq(users.id, userId)). Drizzle-kit: migracje. Drizzle advantages: bliżej SQL. Serverless friendly. Edge-compatible. TypeORM (legacy): Active Record lub Data Mapper. Dekorator-based. Starszy. TypeScript support gorszy. Wiele problemów z migracjami. Używaj Prisma lub Drizzle dla nowych projektów. Sequelize: JavaScript-first. TypeScript możliwy. Starszy. Mniej polecany 2024. Porównanie DX: Prisma: schema.prisma --generate -> TypeScript. Drizzle: TypeScript schema -> SQL. Kysely: interfaces -> SQL. TypeORM: decorators -> SQL. MikroORM: decorators + Data Mapper -> SQL. Wybór 2024: standardowy projekt -> Prisma. Performance + edge -> Drizzle. SQL control -> Kysely. Complex domain -> MikroORM. Legacy -> TypeORM (rozważ migrację).

    Drizzle ORM advanced — migrations, relations i Drizzle Studio?

    Drizzle Schema: import {pgTable, serial, varchar, integer, timestamp, boolean} from 'drizzle-orm/pg-core'. const users = pgTable('users', {id: serial('id').primaryKey(), name: varchar('name', {length: 255}).notNull(), email: varchar('email', {length: 255}).notNull().unique(), role: varchar('role').$type().default('user'), createdAt: timestamp('created_at').defaultNow()}). Relations: const posts = pgTable('posts', {userId: integer('user_id').references(() => users.id)}). export const usersRelations = relations(users, ({many}) => ({posts: many(posts)})). Queries z relations: const usersWithPosts = await db.query.users.findMany({with: {posts: true}}). Filtry: where(and(eq(users.role, 'admin'), gt(users.id, 10))). Transakcje: await db.transaction(async (tx) => { const user = await tx.insert(users).values({name}).returning(). await tx.insert(posts).values({userId: user[0].id, title}) }). Drizzle-kit migracje: npx drizzle-kit generate -- generuje SQL. npx drizzle-kit migrate -- wykonaj. npx drizzle-kit push -- dev sync bez migracji. npx drizzle-kit studio -- GUI. Drizzle Studio: web UI dla bazy. Przeglądaj, edytuj dane. localhost:4983. CRUD w UI. Config: drizzle.config.ts: import {defineConfig} from 'drizzle-kit'. export default defineConfig({schema: './src/db/schema.ts', out: './drizzle', dialect: 'postgresql', dbCredentials: {url: process.env.DATABASE_URL!}}). Edge: Drizzle + Neon HTTP: import {neon} from '@neondatabase/serverless'. import {drizzle} from 'drizzle-orm/neon-http'. const db = drizzle(neon(DATABASE_URL)). Cloudflare Workers ready.

    Bazy danych TypeScript — connection pooling, migrations i best practices?

    Connection Pooling: pg Pool: import {Pool} from 'pg'. const pool = new Pool({connectionString: DATABASE_URL, max: 20, idleTimeoutMillis: 30000}). Prisma: DATABASE_URL z ?connection_limit=10. PgBouncer: proxy pooler. Serverless: problem — nowe połączenie per request. Neon: HTTP mode (bezpołączeniowy). Supabase: pooler wbudowany. PlanetScale: serverless MySQL. Migrations best practices: nie modyfikuj starych migracji. Additive first (add nullable column). Backfill data. Make NOT NULL. Remove old column. Zero-downtime: Blue-green deployment. Feature flags dla schema changes. Expand-Contract pattern. Indexes: CREATE INDEX CONCURRENTLY — bez lock. Partial indexes: WHERE deleted_at IS NULL. Composite: kolejność kolumn ważna. EXPLAIN ANALYZE przed deployem. TypeScript schema validation: zod + db schema. Zod schema == db schema. parse przed insert. Nie ufaj typom ORM na wejściu. Connection per request (Serverless): Prisma + Accelerate. Drizzle + Neon HTTP. PrismaClient singleton: const prismaClientSingleton = () => new PrismaClient(). declare global {var prisma: undefined | ReturnType typeof prismaClientSingleton}. export const db = globalThis.prisma ?? prismaClientSingleton(). if (process.env.NODE_ENV !== 'production') globalThis.prisma = db. Soft delete: deletedAt timestamp. Paranoid mode (Sequelize). Drizzle: where(isNull(users.deletedAt)). Audit logging: createdAt, updatedAt, createdBy, updatedBy. Triggers lub aplikacja. Row-level Security: Supabase RLS. PostgreSQL policies.

    Czytaj dalej

    Powiązane artykuły

    Kontakt

    Skontaktuj się z nami

    Porozmawiajmy o Twoim projekcie. Bezpłatna wycena w ciągu 24 godzin.

    Wyślij zapytanie

    Bezpłatna wycena w 24h
    Bez zobowiązań
    Indywidualne podejście
    Ekspresowa realizacja

    Telefon

    +48 790 814 814

    Pon-Pt: 9:00 - 18:00

    Email

    adam@fotz.pl

    Odpowiadamy w ciągu 24h

    Adres

    Plac Wolności 16

    61-739 Poznań

    Godziny pracy

    Pon - Pt9:00 - 18:00
    Sob - NdzZamknięte

    Wolisz porozmawiać?

    Zadzwoń teraz i porozmawiaj z naszym specjalistą o Twoim projekcie.

    Zadzwoń teraz