Database Orm Expert logo

Database Orm Expert

Community
roedyrustam
database-orm-expert

Unified database ORM, schema migrations, edge DBs, and Supabase CLI / Database ORM terpadu, migrasi skema, edge DB, dan Supabase CLI.

Overview

Publisherroedyrustam
Repositoryvibes-plug
Skill namedatabase-orm-expert
Stars
117
Forks
27
Bundled files
Instructions only
LicenseMIT
Links
  • Markdown instructions

    A SKILL.md file the model loads on demand, so it only costs tokens when a request actually matches.

  • Works with any LLM

    AI skills are plain Markdown, not provider-specific code, so this works with GPT, Claude, Gemini, Grok, or a local model.

  • Self-contained

    Everything the model needs lives in the instructions — no extra files to sync.

  • Open source

    Published by roedyrustam on GitHub. Read the source before you install it.

Installation

Install the Database Orm Expert AI skill in TypingMind to use it with any LLM, or drop it into another agent that reads SKILL.md.

1

Install in TypingMind

TypingMind installs a skill straight from its GitHub folder — it reads SKILL.md, bundles the resource files, and stores the result locally.

  1. Open the app and go to Plugins → Skills.
  2. Choose "Install from GitHub".
  3. Paste the skill folder URL below and confirm.
    https://github.com/roedyrustam/vibes-plug/tree/main/skills/database-orm-expert
  4. Enable the skill in any chat where you want it available.
Plugins → Skills → Add skill → From GitHub URL, then paste the folder URL and press Continue.
2

Install in another agent

Any agent that reads the Agent Skills format can use this skill — copy the folder into that agent's skills directory.

Claude Code — .claude/skills
git clone --depth 1 https://github.com/roedyrustam/vibes-plug.git /tmp/vibes-plug
mkdir -p .claude/skills
cp -r /tmp/vibes-plug/skills/database-orm-expert .claude/skills/database-orm-expert
Restart Claude Code after copying so it picks up the new skill.

Use it in TypingMind

Enable Database Orm Expert in any TypingMind chat and the model takes it from there. Its name and description sit in the system prompt, and the moment a request matches, the model loads the full instructions itself — you never invoke it by hand, and it costs no tokens until it is actually used.

The model loads Database Orm Expert on its own as soon as a request matches it.

Works with any AI model

AI skills are plain Markdown instructions rather than provider-specific code, so Database Orm Expert is not tied to the model it was written for. Install it once in TypingMind and use it with GPT-5, Claude, Gemini, Grok, DeepSeek, Mistral, Llama, or a local model you run yourself — all on your own API keys.

  • Loaded only when it is needed

    The system prompt carries just the name and description. The instructions are fetched on the first matching request, so an idle skill costs nothing.

  • Switch models mid-chat

    Because the skill is instructions rather than code, changing model does not break it — the next model reads the same SKILL.md.

Skill instructions

This is the SKILL.md content the model loads. Read it before installing — a skill is instructions your model will follow.

Unified Database & ORM Expert (2026 Production Edition)

English | Bahasa Indonesia


English

Orchestration & Integration

Connects and orchestrates with domain skills:

  • Backend & Runtimes: js-backend-expert, python-programming-expert, go-programming-expert, and rust-programming-expert for integrating Drizzle ORM, Prisma 6, SQLx, and SQLAlchemy/SQLModel.
  • FinTech & SaaS: saas-billing, saas-multi-tenant, double-entry-ledger-fintech-expert, and doku-payment-gateway for strict atomic database transactions (SELECT ... FOR UPDATE), distributed locks, tenant isolation via RLS, and SNAP BI idempotent records.
  • AI & Vectors: vector-db-rag-expert for pgvector 0.8+ HNSW indexing and high-dimensional cosine similarity embeddings.
  • Security & Cloud: supabase-security-expert, fga-rebac-authorization-expert, ci-cd-devops-architect, and cloud-hosting-expert for automated migration pipelines, blue-green deployments, and pooler infrastructure.
  • Master Orchestrators: brainstorming and zero-to-prod-orchestrator (Phase 3: Schema & Database Architecture).

Description

Production-grade guide for relational schema design, ORM selection, zero-downtime Expand-and-Contract migrations, pessimistic concurrency locking, query optimization, and edge serverless database drivers. Covers Drizzle ORM v0.39+, Prisma 6 (TypedSQL & Relation Joins), Supabase CLI, and Edge Databases (Neon Serverless Postgres, Cloudflare D1, Turso libSQL, Upstash Redis).

Trigger Conditions

  • Designing or migrating a production schema (blue-green, Expand-and-Contract).
  • Choosing between Drizzle ORM, Prisma 6, Kysely, or SQLx.
  • Writing complex queries with joins, cursor pagination, or atomic row locks.
  • Optimizing slow queries, missing FK indexes, or N+1 problems.
  • Building edge-compatible serverless database connections (HTTP/WebSocket poolers).
  • Executing Supabase CLI migrations and Row-Level Security (RLS) policies.

Core ORM & Query Strategies

ORM Selection Matrix (2026)
CriteriaDrizzle ORM (v0.39+)Prisma 6Kysely
Type SafetySQL-first, zero-codegen TypeScript inferenceSchema-first (schema.prisma) + TypedSQLPure type-safe SQL query builder
Cold Start & BundleUltra-lightweight (<35KB, zero binary)Wasm/Rust query compiler (~1.5MB)Minimal (<20KB)
Relational Queriesdb.query.table.findMany({ with }) (Single SQL join)relationLoadStrategy: "join"Explicit .innerJoin()
Edge RuntimeNative (Cloudflare Workers, Vercel Edge, Bun)Native via @prisma/adapter-neon / D1Native
Migrationsdrizzle-kit generate & drizzle-kit migrateprisma migrate dev / deployCustom migration runner

Recommendation: Prefer Drizzle ORM for edge-first apps, Hono/Bun backends, and performance-critical systems. Choose Prisma 6 for teams preferring declarative .prisma modeling and TypedSQL.


1. Drizzle ORM v0.39+ Production Schema & Atomic Locking

Always index foreign keys explicitly, enforce TIMESTAMPTZ, and use FOR UPDATE row locks on financial or inventory mutations.

typescript
// src/db/schema.ts
import { pgTable, uuid, varchar, bigint, timestamp, index, uniqueIndex } from 'drizzle-orm/pg-core';
import { relations, sql } from 'drizzle-orm';

export const tenants = pgTable('tenants', {
  id: uuid('id').defaultRandom().primaryKey(),
  slug: varchar('slug', { length: 64 }).notNull(),
  createdAt: timestamp('created_at', { withTimezone: true }).defaultNow().notNull(),
}, (t) => [
  uniqueIndex('idx_tenants_slug').on(t.slug),
]);

export const wallets = pgTable('wallets', {
  id: uuid('id').defaultRandom().primaryKey(),
  tenantId: uuid('tenant_id').notNull().references(() => tenants.id, { onDelete: 'restrict' }),
  currency: varchar('currency', { length: 3 }).notNull().default('IDR'),
  balanceMinor: bigint('balance_minor', { mode: 'bigint' }).notNull().default(0n),
  version: bigint('version', { mode: 'number' }).notNull().default(1),
  updatedAt: timestamp('updated_at', { withTimezone: true }).defaultNow().notNull(),
}, (t) => [
  index('idx_wallets_tenant_id').on(t.tenantId),
]);

export const paymentIdempotency = pgTable('payment_idempotency', {
  idempotencyKey: varchar('idempotency_key', { length: 128 }).primaryKey(),
  walletId: uuid('wallet_id').notNull().references(() => wallets.id, { onDelete: 'cascade' }),
  amountMinor: bigint('amount_minor', { mode: 'bigint' }).notNull(),
  status: varchar('status', { length: 24 }).notNull(),
  createdAt: timestamp('created_at', { withTimezone: true }).defaultNow().notNull(),
}, (t) => [
  index('idx_payment_idempotency_wallet').on(t.walletId),
]);

export const walletsRelations = relations(wallets, ({ one }) => ({
  tenant: one(tenants, { fields: [wallets.tenantId], references: [tenants.id] }),
}));
typescript
// src/db/mutations/debit-wallet.ts
import { eq, sql } from 'drizzle-orm';
import { db } from '../client';
import { wallets, paymentIdempotency } from '../schema';

export async function debitWalletAtomic(input: {
  walletId: string;
  amountMinor: bigint;
  idempotencyKey: string;
}) {
  if (input.amountMinor <= 0n) {
    throw new Error('Debit amount must be strictly positive');
  }

  return await db.transaction(async (tx) => {
    // 1. Check idempotency key first
    const [existing] = await tx
      .select()
      .from(paymentIdempotency)
      .where(eq(paymentIdempotency.idempotencyKey, input.idempotencyKey))
      .limit(1);

    if (existing) {
      return { status: 'ALREADY_PROCESSED' as const, record: existing };
    }

    // 2. Acquire pessimistic row-level lock (SELECT ... FOR UPDATE)
    const [wallet] = await tx
      .select()
      .from(wallets)
      .where(eq(wallets.id, input.walletId))
      .for('update');

    if (!wallet) {
      throw new Error(`Wallet ${input.walletId} not found`);
    }
    if (wallet.balanceMinor < input.amountMinor) {
      throw new Error('Insufficient wallet balance');
    }

    // 3. Deduct balance and increment optimistic version
    const [updatedWallet] = await tx
      .update(wallets)
      .set({
        balanceMinor: sql`${wallets.balanceMinor} - ${input.amountMinor}`,
        version: sql`${wallets.version} + 1`,
        updatedAt: new Date(),
      })
      .where(eq(wallets.id, input.walletId))
      .returning();

    // 4. Record idempotency lock in same transaction
    const [record] = await tx
      .insert(paymentIdempotency)
      .values({
        idempotencyKey: input.idempotencyKey,
        walletId: input.walletId,
        amountMinor: input.amountMinor,
        status: 'COMPLETED',
      })
      .returning();

    return { status: 'COMPLETED' as const, wallet: updatedWallet, record };
  }, {
    isolationLevel: 'read committed',
  });
}

2. Keyset (Cursor) Pagination Pattern

Never use OFFSET on tables exceeding 50,000 rows (OFFSET 100000 forces Postgres to scan and discard 100,000 rows). Always use composite (createdAt, id) keyset cursors:

typescript
import { and, desc, eq, lt, or } from 'drizzle-orm';
import { db } from './client';
import { wallets } from './schema';

export async function listWalletsCursor(params: {
  tenantId: string;
  limit?: number;
  cursor?: { updatedAt: Date; id: string };
}) {
  const limit = Math.min(params.limit ?? 25, 100);

  const cursorFilter = params.cursor
    ? or(
        lt(wallets.updatedAt, params.cursor.updatedAt),
        and(eq(wallets.updatedAt, params.cursor.updatedAt), lt(wallets.id, params.cursor.id))
      )
    : undefined;

  const rows = await db
    .select()
    .from(wallets)
    .where(and(eq(wallets.tenantId, params.tenantId), cursorFilter))
    .orderBy(desc(wallets.updatedAt), desc(wallets.id))
    .limit(limit + 1);

  const hasNextPage = rows.length > limit;
  const items = hasNextPage ? rows.slice(0, limit) : rows;
  const lastItem = items[items.length - 1];

  return {
    items,
    nextCursor: hasNextPage && lastItem
      ? { updatedAt: lastItem.updatedAt, id: lastItem.id }
      : null,
  };
}

Zero-Downtime Migrations (Expand and Contract Protocol)

Never execute breaking DDL changes (DROP COLUMN, RENAME COLUMN, or locking ALTER TABLE ... ADD COLUMN ... NOT NULL without default) in a single release while old application containers are still serving traffic.

  1. Phase 1 (Expand): Add nullable column or new table; create indexes using CREATE INDEX CONCURRENTLY to avoid blocking writes.
  2. Phase 2 (Dual-Write): Update application code to write to both old and new columns; read from old with fallback.
  3. Phase 3 (Chunked Backfill): Backfill historical rows in small batches (LIMIT 2000) with FOR UPDATE SKIP LOCKED to avoid replication lag and table locks.
  4. Phase 4 (Cutover Read & Contract): Switch reads to the new column, remove dual-write code, and validate constraints using NOT VALID followed by VALIDATE CONSTRAINT.
sql
-- Safe Zero-Lock Constraint & Concurrent Index Migration
ALTER TABLE wallets ADD COLUMN IF NOT EXISTS ledger_account_id UUID;

CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_wallets_ledger_account_id
  ON wallets (ledger_account_id);

-- Add foreign key without locking existing writes (Postgres 14+)
ALTER TABLE wallets
  ADD CONSTRAINT fk_wallets_ledger_account
  FOREIGN KEY (ledger_account_id) REFERENCES accounts(id) NOT VALID;

-- Validate constraint using ShareUpdateExclusiveLock (does not block reads/writes)
ALTER TABLE wallets VALIDATE CONSTRAINT fk_wallets_ledger_account;

Edge & Serverless Drivers + Cache-Aside

typescript
import { neon } from '@neondatabase/serverless';
import { drizzle } from 'drizzle-orm/neon-http';
import { Redis } from '@upstash/redis';
import * as schema from './schema';

const sqlClient = neon(process.env.DATABASE_URL!);
export const edgeDb = drizzle(sqlClient, { schema });

const redis = new Redis({
  url: process.env.UPSTASH_REDIS_REST_URL!,
  token: process.env.UPSTASH_REDIS_REST_TOKEN!,
});

export async function getTenantCached(slug: string) {
  const cacheKey = `tenant:v1:${slug}`;
  const cached = await redis.get<typeof schema.tenants.$inferSelect>(cacheKey);
  if (cached) return cached;

  const tenant = await edgeDb.query.tenants.findFirst({
    where: (t, { eq }) => eq(t.slug, slug),
  });

  if (tenant) {
    await redis.set(cacheKey, tenant, { ex: 900 });
  }
  return tenant ?? null;
}

Verification Checklist

  • Every foreign key column has a corresponding B-Tree index (idx_<table>_<fk>).
  • Financial balances and monetary quantities use BIGINT minor units (cents/sen) or NUMERIC(19,4), never FLOAT/REAL.
  • Multi-tenant tables enforce Row-Level Security (ALTER TABLE ... ENABLE ROW LEVEL SECURITY) and tenant ID predicates.
  • Production migrations never run prisma db push or drizzle-kit push; versioned SQL files are audited via vibes db:eval.
  • High-concurrency state transitions use SELECT ... FOR UPDATE or optimistic version increments.

Sovereign Execution, Token Efficiency & Invariants

DimensionSovereign Mandate & Deterministic Contract
Frontier Model CascadeMedium / High (Gemini 4 Argon, GPT-5.6 Sol Medium, Claude Sonnet 5.5 High)
Availability FallbackGemini 4 Argon/Pro -> Gemini 3.8 Flash; Claude Opus 5.5 -> Claude Opus 4.6 (Zero unhandled missing-model errors)
KV-Cache & Token ProtocolPin static instructions & schemas at prompt prefix (kv-cache-prefix-optimizer); pass surgical CONTEXT_MAP.md slices (<250 tokens/call) during Swarm Fan-Out
SaaT CLI & MCP DispatchCLI: vibes skill exec database-orm-expert <audit|eval|verify|generate|blueprint> / MCP: vibes_skill_dispatch, vibes_eval_sql, vibes_verify_invariants, vibes_verify_gate
NFR & Anti-Slop InvariantsP99 Query Latency < 15ms, 100% Row Level Security (RLS) coverage on multi-tenant tables, explicit B-Tree indexes on all Foreign Keys; 100% complete zero-placeholder output verified via node scripts/check-anti-slop.js --strict


Bahasa Indonesia

Integrasi Orkestrasi

Terhubung dan mengorkestrasi bersama skill domain:

  • Backend & Runtime: js-backend-expert, python-programming-expert, go-programming-expert, dan rust-programming-expert untuk integrasi Drizzle ORM, Prisma 6, SQLx, dan SQLAlchemy/SQLModel.
  • FinTech & SaaS: saas-billing, saas-multi-tenant, double-entry-ledger-fintech-expert, dan doku-payment-gateway untuk transaksi database atomik yang ketat (SELECT ... FOR UPDATE), distributed lock, isolasi tenant via RLS, dan pencatatan idempoten SNAP BI.
  • AI & Vektor: vector-db-rag-expert untuk pengindeksan pgvector 0.8+ HNSW dan pencarian embedding kesamaan kosinus dimensi tinggi.
  • Keamanan & Cloud: supabase-security-expert, fga-rebac-authorization-expert, ci-cd-devops-architect, dan cloud-hosting-expert untuk pipeline deployment migrasi otomatis, blue-green, dan infrastruktur connection pooler.
  • Orkestrator Utama: brainstorming dan zero-to-prod-orchestrator (Fase 3: Arsitektur Skema & Database).

Deskripsi

Panduan kelas produksi untuk perancangan skema relasional, pemilihan ORM, migrasi tanpa downtime (Expand-and-Contract), penguncian konkurensi pesimistis, optimasi query, dan driver database serverless edge (Drizzle ORM v0.39+, Prisma 6, Supabase CLI, Neon, Cloudflare D1, Turso, Upstash).

Strategi Inti ORM & Query

  1. Drizzle ORM direkomendasikan untuk aplikasi edge dan performa tinggi (<35KB, tanpa biner), sedangkan Prisma 6 untuk alur deklaratif schema.prisma dan TypedSQL.
  2. Indeks Foreign Key: Selalu buat indeks eksplisit pada setiap kolom foreign key dan kolom filter WHERE / ORDER BY.
  3. Keyset (Cursor) Pagination: Gunakan kursor komposit (updated_at, id) dan hindari OFFSET pada tabel skala besar.
  4. Transaksi & Kunci Baris Atomik: Gunakan SELECT ... FOR UPDATE di dalam transaksi database untuk mencegah kondisi balapan (race condition) pada pemotongan saldo atau stok.

Migrasi Tanpa Downtime (Expand and Contract)

  • Fase 1 (Expand): Tambahkan kolom baru bersifat nullable dan gunakan CREATE INDEX CONCURRENTLY.
  • Fase 2 (Dual-Write): Tulis ke kolom lama dan baru secara bersamaan.
  • Fase 3 (Chunked Backfill): Lakukan backfill data secara bertahap (LIMIT 2000) menggunakan antrean latar belakang.
  • Fase 4 (Contract): Pindahkan pembacaan ke kolom baru, validasi constraint dengan NOT VALID + VALIDATE CONSTRAINT, lalu hapus kode lama.

Daftar Periksa Verifikasi (Checklist)

  • Setiap kolom foreign key memiliki indeks B-Tree eksplisit.
  • Nilai uang/saldo menggunakan BIGINT satuan terkecil (sen/rupiah utuh) atau NUMERIC(19,4), bukan FLOAT.
  • Tabel multi-tenant mengaktifkan Row-Level Security (RLS).
  • Migrasi produksi menggunakan file SQL terversi dan diuji dengan vibes db:eval.

Matriks Eksekusi Berdaulat, Efisiensi Token & Invarian

DimensiMandat Berdaulat & Kontrak Deterministik
Kaskade Model FrontierMedium / High (Gemini 4 Argon, GPT-5.6 Sol Medium, Claude Sonnet 5.5 High)
Invarian Fallback KetersediaanGemini 4 Argon/Pro -> Gemini 3.8 Flash; Claude Opus 5.5 -> Claude Opus 4.6 (Bebas gagal saat model belum tersedia/kuota penuh)
Protokol Hemat Token & KV-CacheKunci instruksi & skema statis di prefix awal (kv-cache-prefix-optimizer); kirim potongan CONTEXT_MAP.md (<250 token/panggilan) saat Fan-Out
Eksekusi SaaT CLI & MCPCLI: vibes skill exec database-orm-expert <audit|eval|verify|generate|blueprint> / MCP: vibes_skill_dispatch, vibes_eval_sql, vibes_verify_invariants, vibes_verify_gate
Invarian NFR & Anti-SlopLatensi Query P99 < 15ms, cakupan Row Level Security (RLS) 100% pada tabel multi-tenant, indeks B-Tree eksplisit pada seluruh Foreign Key; kode 100% tuntas tanpa placeholder diverifikasi melalui node scripts/check-anti-slop.js --strict

Frequently asked questions

What does the Database Orm Expert AI skill do?

Unified database ORM, schema migrations, edge DBs, and Supabase CLI / Database ORM terpadu, migrasi skema, edge DB, dan Supabase CLI.

Why use Database Orm Expert on TypingMind?

Because you install it once and use it with any model. Database Orm Expert is plain Markdown rather than provider-specific code, so the same skill runs on GPT-5, Claude, Gemini, Grok, or a local model — and you can switch model mid-chat without it breaking. TypingMind runs on your own API keys, so you pay providers directly instead of a per-seat subscription, and your skills and chats stay in your own storage.

How do I install Database Orm Expert in TypingMind?

Open Plugins → Skills → Install from GitHub in TypingMind and paste https://github.com/roedyrustam/vibes-plug/tree/main/skills/database-orm-expert. TypingMind reads its SKILL.md and installs it as a skill you can enable per chat.

Which AI models can use Database Orm Expert?

Any model you connect in TypingMind. AI skills are plain Markdown instructions rather than provider-specific code, so GPT, Claude, Gemini, Grok, and local models can all load this skill when a request matches it.

How many AI models can I use with Database Orm Expert?

As many as you like. As long as a model supports skills, you can use Database Orm Expert with it — GPT, Claude, Gemini, Grok, DeepSeek, Mistral, Llama and more — all on TypingMind with your own API keys.

Is the Database Orm Expert AI skill free?

Yes. It is published on GitHub by roedyrustam under the MIT license. You only pay your own AI provider for the tokens you use.

What are AI skills?

An AI skill is a reusable instruction bundle that teaches an AI model how to do one specific task. It follows the open Agent Skills format: a SKILL.md file with a name and description, plus any scripts, templates or reference files the model may need. The model reads the instructions only when your request matches the skill, so an installed skill costs nothing until it is used.

How are AI skills different from plugins or MCP servers?

A plugin or MCP server gives a model new tools to call — code that runs somewhere and returns a result. An AI skill gives the model knowledge and process instead: how to approach a task, which steps to follow, what good output looks like. Skills are plain Markdown, so they need no server, no API key and no runtime, and they work with any model.

View all

Set up your own AI workspace now

Get notified about new features and future giveaways by subscribing to our newsletter 👇