Skip to content

Repository files navigation

drizzle-cubrid

Drizzle ORM dialect for the CUBRID database — TypeScript-first, type-safe schema definition and query builder for Node.js.

🇰🇷 한국어 · 🇺🇸 English

npm version node version ci workflow coverage license GitHub stars


Why drizzle-cubrid?

Drizzle ORM is a modern TypeScript ORM with a SQL-like query API, zero dependencies, and first-class type inference. Until now, there was no Drizzle dialect for CUBRID.

drizzle-cubrid bridges that gap:

  • Type-safe queries — Full TypeScript inference from schema to query results
  • Drizzle query APIselect(), insert(), update(), delete() with the familiar Drizzle chain syntax
  • CUBRID-specific typesSET, MULTISET, SEQUENCE, MONETARY as native column builders
  • Transactions with savepoints — Nested transaction support via CUBRID savepoints
  • Relations — Drizzle relational query API (db.query.users.findMany({ with: { posts: true } }))
  • 99%+ test coverage — 52 offline tests, no database required for CI

Architecture

flowchart TD
    A[Application] --> B[Drizzle ORM]
    B --> C[drizzle-cubrid dialect<br/>CubridDialect]
    C --> D[cubrid-client]
    D --> E[CUBRID Server]
Loading

Installation

npm install drizzle-cubrid drizzle-orm cubrid-client
Package Purpose
drizzle-cubrid CUBRID dialect for Drizzle (this package)
drizzle-orm Drizzle ORM core
cubrid-client TypeScript CUBRID driver

Requirements: Node.js 18+, CUBRID 10.2+

Quick Start

1. Define Your Schema

// schema.ts
import { cubridTable, int, varchar, timestamp } from "drizzle-cubrid";

export const users = cubridTable("users", {
  id: int("id").primaryKey().autoincrement(),
  name: varchar("name", { length: 100 }).notNull(),
  email: varchar("email", { length: 200 }).notNull().unique(),
  created_at: timestamp("created_at").defaultNow(),
});

2. Connect and Query

// app.ts
import { createClient } from "cubrid-client";
import { drizzle } from "drizzle-cubrid";
import { eq } from "drizzle-cubrid";
import { users } from "./schema";

const client = createClient({
  host: "localhost",
  port: 33000,
  database: "demodb",
  user: "dba",
});

const db = drizzle(client);

// Insert
await db.insert(users).values({
  name: "Alice",
  email: "alice@example.com",
});

// Select with type-safe results
const allUsers = await db.select().from(users);
// allUsers: { id: number; name: string; email: string; created_at: Date | null }[]

// Where clause
const alice = await db
  .select()
  .from(users)
  .where(eq(users.name, "Alice"));

// Update
await db
  .update(users)
  .set({ name: "Alicia" })
  .where(eq(users.id, 1));

// Delete
await db.delete(users).where(eq(users.id, 1));

// Close connection
await client.close();

CUBRID-Specific Column Types

Beyond standard SQL types, CUBRID has collection types and a monetary type:

import { cubridTable, int, varchar } from "drizzle-cubrid";
import { cubridSet, cubridMultiset, cubridSequence, monetary } from "drizzle-cubrid";

export const products = cubridTable("products", {
  id: int("id").primaryKey().autoincrement(),
  name: varchar("name", { length: 100 }),

  // SET — unordered unique values → SET(VARCHAR(50))
  tags: cubridSet("tags", { element: varchar("tag_item", { length: 50 }) }),

  // MULTISET — unordered, allows duplicates → MULTISET(VARCHAR(50))
  categories: cubridMultiset("categories", { element: varchar("category_item", { length: 50 }) }),

  // SEQUENCE — ordered, allows duplicates → SEQUENCE(INTEGER)
  rankings: cubridSequence("rankings", { element: int("rank_item") }),

  // MONETARY — CUBRID native monetary type → MONETARY
  price: monetary("price"),
});
// Insert with collection values
await db.insert(products).values({
  name: "Widget",
  tags: ["sale", "new"],           // string[] → SET
  categories: ["electronics"],     // string[] → MULTISET
  rankings: ["1", "3", "5"],       // string[] → SEQUENCE
});

// Select — collections return string[]
const rows = await db.select().from(products);
console.log(rows[0].tags); // ["sale", "new"]

Transactions

Automatic (Recommended)

await db.transaction(async (tx) => {
  await tx.insert(users).values({ name: "Alice", email: "a@example.com" });
  await tx.insert(users).values({ name: "Bob", email: "b@example.com" });
  // Auto-committed on success, auto-rolled back on error
});

Nested Transactions (Savepoints)

await db.transaction(async (tx) => {
  await tx.insert(users).values({ name: "Alice", email: "a@example.com" });

  try {
    await tx.transaction(async (tx2) => {
      // SAVEPOINT sp1
      await tx2.insert(users).values({ name: "Bob", email: "b@example.com" });
      throw new Error("rollback inner only");
      // ROLLBACK TO SAVEPOINT sp1
    });
  } catch {
    // Inner rolled back, outer continues
  }

  await tx.insert(users).values({ name: "Charlie", email: "c@example.com" });
  // Alice + Charlie committed, Bob rolled back
});

Relations

import { cubridTable, int, varchar } from "drizzle-cubrid";
import { relations } from "drizzle-orm";

export const users = cubridTable("users", {
  id: int("id").primaryKey().autoincrement(),
  name: varchar("name", { length: 100 }).notNull(),
});

export const posts = cubridTable("posts", {
  id: int("id").primaryKey().autoincrement(),
  title: varchar("title", { length: 200 }).notNull(),
  author_id: int("author_id").notNull(),
});

export const usersRelations = relations(users, ({ many }) => ({
  posts: many(posts),
}));

export const postsRelations = relations(posts, ({ one }) => ({
  author: one(users, {
    fields: [posts.author_id],
    references: [users.id],
  }),
}));
import * as schema from "./schema";

const db = drizzle(client, { schema, mode: "default" });

const usersWithPosts = await db.query.users.findMany({
  with: { posts: true },
});

Error Handling

Errors propagate from cubrid-client with structured error types:

import { ConnectionError, QueryError, TransactionError } from "cubrid-client";

try {
  await db.select().from(users);
} catch (error) {
  if (error instanceof QueryError) {
    console.error("Query failed:", error.message);
    console.error("Cause:", error.cause);
  }
}

CUBRID Limitations

Feature Status Notes
INSERT ... RETURNING ❌ Not supported Use separate SELECT after INSERT
Streaming / iterators ❌ Not supported Use LIMIT/OFFSET for pagination
JSON columns ❌ Not supported Use VARCHAR with manual serialization
Native BOOLEAN ❌ Not supported Mapped to SMALLINT (0/1)
Sequences ❌ Not supported Use AUTO_INCREMENT

Documentation

Document Description
Schema Guide Column types, CUBRID types, relations, custom types
Queries Guide SELECT, INSERT, UPDATE, DELETE, joins, aggregations, raw SQL
Troubleshooting Common errors, TypeScript issues, performance tips
Migration Example Drizzle Kit config, schema, and CUBRID migration notes

Development

git clone https://github.com/cubrid-labs/drizzle-cubrid.git
cd drizzle-cubrid
npm install
npm run build        # TypeScript compilation
npm run check        # Lint + type-check + test
npm test             # Run tests

Ecosystem

Package Description
cubrid-client TypeScript CUBRID driver
drizzle-cubrid Drizzle ORM dialect (this package)

Roadmap

See ROADMAP.md for this project's direction and next milestones.

For the ecosystem-wide view, see the CUBRID Labs Ecosystem Roadmap and Project Board.

License

MIT — see LICENSE.

Releases

Packages

Contributors

Languages