billSDK
Adapters

Drizzle

Database adapter for Drizzle ORM

Setup

import { drizzleAdapter } from "@billsdk/drizzle-adapter";

database: drizzleAdapter(db, {
  schema,
  provider: "pg", // "pg" | "mysql" | "sqlite"
})

Schema (PostgreSQL)

db/schema.ts
import { integer, jsonb, pgTable, text, timestamp, uuid } from "drizzle-orm/pg-core";

export const customer = pgTable("customer", {
  id: uuid("id").primaryKey().defaultRandom(),
  externalId: text("external_id").unique(),
  email: text("email").notNull(),
  name: text("name"),
  providerCustomerId: text("provider_customer_id"),
  metadata: jsonb("metadata"),
  createdAt: timestamp("created_at").defaultNow().notNull(),
  updatedAt: timestamp("updated_at").defaultNow().notNull(),
});

export const subscription = pgTable("subscription", {
  id: uuid("id").primaryKey().defaultRandom(),
  customerId: uuid("customer_id").references(() => customer.id, { onDelete: "cascade" }).notNull(),
  planCode: text("plan_code").notNull(),
  interval: text("interval").default("monthly").notNull(),
  status: text("status").default("active").notNull(),
  providerSubscriptionId: text("provider_subscription_id"),
  providerCheckoutSessionId: text("provider_checkout_session_id"),
  currentPeriodStart: timestamp("current_period_start").defaultNow().notNull(),
  currentPeriodEnd: timestamp("current_period_end").notNull(),
  canceledAt: timestamp("canceled_at"),
  cancelAt: timestamp("cancel_at"),
  trialStart: timestamp("trial_start"),
  trialEnd: timestamp("trial_end"),
  scheduledPlanCode: text("scheduled_plan_code"),
  scheduledInterval: text("scheduled_interval"),
  metadata: jsonb("metadata"),
  createdAt: timestamp("created_at").defaultNow().notNull(),
  updatedAt: timestamp("updated_at").defaultNow().notNull(),
});

export const payment = pgTable("payment", {
  id: uuid("id").primaryKey().defaultRandom(),
  customerId: uuid("customer_id").references(() => customer.id).notNull(),
  subscriptionId: uuid("subscription_id"),
  type: text("type").notNull(), // "subscription" | "renewal" | "upgrade" | "refund"
  status: text("status").notNull(), // "pending" | "succeeded" | "failed" | "refunded"
  amount: integer("amount").notNull(),
  currency: text("currency").default("usd").notNull(),
  providerPaymentId: text("provider_payment_id"),
  refundedAmount: integer("refunded_amount"),
  metadata: jsonb("metadata"),
  createdAt: timestamp("created_at").defaultNow().notNull(),
  updatedAt: timestamp("updated_at").defaultNow().notNull(),
});

For MySQL/SQLite, adapt the types accordingly.

Migrations

npx drizzle-kit push

On this page