DEV Community

Zastinian
Zastinian

Posted on

Hedystia 2.0: A New Type-Safe ORM for TypeScript with Multi-Database Support

Introducing @hedystia/db

We just released Hedystia 2.0, which introduces @hedystia/db — a brand-new database ORM that combines the best of Drizzle and TypeORM:

  • Drizzle-like schema definition — Functional, composable, no decorators
  • TypeORM-like query API — Intuitive db.users.find() syntax
  • One schema, multiple databases — MySQL, SQLite, and File storage

Quick Start

bun add @hedystia/db
Enter fullscreen mode Exit fullscreen mode

Define Your Schema

import { table, d } from "@hedystia/db";

export const users = table("users", {
  id: d.integer().primaryKey().autoIncrement(),
  name: d.varchar(255).notNull(),
  email: d.varchar(255).unique(),
  age: d.integer().default(0),
  active: d.boolean().default(true),
  bio: d.text().nullable(),
  createdAt: d.datetime(),
});

export const posts = table("posts", {
  id: d.integer().primaryKey().autoIncrement(),
  userId: d.integer().references(() => users.id, {
    onDelete: "CASCADE",
  }),
  title: d.varchar(255).notNull(),
  content: d.text(),
});
Enter fullscreen mode Exit fullscreen mode

12 column types supported: integer, bigint, varchar, char, text, boolean, json, datetime, timestamp, decimal, float, and blob.

Connect to Any Database

The same schema works across all supported databases:

import { database } from "@hedystia/db";

// SQLite
const db = database({
  schemas: [users, posts],
  database: "sqlite",
  connection: { filename: "./data.db" },
  syncSchemas: true,
  cache: true,
});

// MySQL
const db = database({
  schemas: [users, posts],
  database: "mysql",
  connection: {
    host: "localhost",
    user: "root",
    password: "password",
    database: "myapp",
  },
  syncSchemas: true,
  cache: true,
});

// File-based (JSON) — no driver needed
const db = database({
  schemas: [users, posts],
  database: "file",
  connection: { directory: "./data" },
  syncSchemas: true,
  cache: true,
});
Enter fullscreen mode Exit fullscreen mode

Intuitive Query API

No more verbose query builders. Access your tables directly:

await db.initialize();

// Insert
const user = await db.users.insert({
  name: "Alice",
  email: "alice@example.com",
  age: 25,
});

// Find with conditions
const adults = await db.users.find({
  where: { age: { gte: 18 } },
  orderBy: { name: "asc" },
  take: 10,
});

// Complex queries with OR/AND
const results = await db.users.find({
  where: {
    OR: [
      { name: { like: "%alice%" } },
      { age: { between: [25, 35] } },
    ],
  },
});

// Relations with eager loading
const usersWithPosts = await db.users.find({
  with: { posts: true },
});

// Upsert
await db.users.upsert({
  where: { email: "alice@example.com" },
  create: { name: "Alice", email: "alice@example.com" },
  update: { age: 26 },
});
Enter fullscreen mode Exit fullscreen mode

Full query API: find, findMany, findFirst, insert, insertMany, update, delete, count, exists, upsert, and truncate.

Smart Caching

Built-in cache with adaptive TTL and automatic invalidation:

const db = database({
  schemas: [users],
  database: "sqlite",
  connection: { filename: "./data.db" },
  cache: {
    enabled: true,
    ttl: 60000,       // Base TTL: 60 seconds
    maxTtl: 300000,   // Max TTL: 5 minutes
    maxEntries: 10000,
  },
});
Enter fullscreen mode Exit fullscreen mode
  • Entity cache — Individual rows cached by primary key
  • Query cache — Full query results cached by stable key
  • Auto-invalidation — Mutations automatically invalidate affected caches
  • Adaptive TTL — Frequently accessed data stays cached longer: baseTTL × (1 + log₂(hitCount + 1))

In our benchmarks: 8x speedup on repeated find() queries and 2.5x on count().

Migration System

Schema sync for development:

const db = database({
  schemas: [users, posts],
  database: "sqlite",
  connection: { filename: "./data.db" },
  syncSchemas: true, // Auto-creates tables and adds missing columns
});
Enter fullscreen mode Exit fullscreen mode

Programmatic migrations for production:

import { migration } from "@hedystia/db";

const addAgeColumn = migration("add_age_column", {
  async up({ schema }) {
    await schema.addColumn("users", "age", {
      name: "age",
      type: "integer",
      primaryKey: false,
      autoIncrement: false,
      notNull: false,
      unique: false,
      defaultValue: 0,
    });
  },
  async down({ schema }) {
    await schema.dropColumn("users", "age");
  },
});
Enter fullscreen mode Exit fullscreen mode

CLI support:

bunx @hedystia/db migration create create_users --path src/database/migrations
bunx @hedystia/db schema create users --path src/database/schemas
Enter fullscreen mode Exit fullscreen mode

Why @hedystia/db?

Feature @hedystia/db Drizzle TypeORM Prisma
Schema definition Functional Functional Decorators DSL file
Query API db.table.find() SQL-like builder Repository pattern Generated client
Type safety Full inference Full inference Partial Generated types
Multi-DB from one schema Partial
Built-in caching ✅ Adaptive
File-based storage
Zero config start ✅ syncSchemas

Get Started

bun add @hedystia/db
Enter fullscreen mode Exit fullscreen mode

📖 Full documentation: https://docs.hedystia.com/db/start
📝 Blog post: https://docs.hedystia.com/blog/2.0
⭐ GitHub: https://github.com/Hedystia/Hedystia

Top comments (0)