Drizzle <> Nile
This guide assumes familiarity with:
**공식 웹사이트**에 따르면, Nile은 멀티 테넌트 앱을 위해 재설계된 PostgreSQL입니다.
공식 Nile + Drizzle 빠른 시작 및 마이그레이션 문서를 확인하세요.
Nile은 Drizzle의 모든 Postgres 드라이버와 함께 사용할 수 있으며, 아래에서는 node-postgres의 사용법을 보여드립니다.
단계 1 - 패키지 설치
npm
yarn
pnpm
bun
npm i drizzle-orm postgres
npm i -D drizzle-kit
단계 2 - 드라이버 초기화 및 쿼리 실행
// Make sure to install the 'pg' package
import { drizzle } from 'drizzle-orm/node-postgres'
const db = drizzle(process.env.NILEDB_URL);
const response = await db.select().from(...);기존 드라이버를 제공해야 하는 경우:
// Make sure to install the 'pg' package
import { drizzle } from "drizzle-orm/node-postgres";
import { Pool } from "pg";
const pool = new Pool({
connectionString: process.env.DATABASE_URL,
});
const db = drizzle({ client: pool });
const response = await db.select().from(...);가상 테넌트 데이터베이스에 연결
Nile은 가상 테넌트 데이터베이스를 제공합니다. 테넌트 컨텍스트를 설정하면 Nile은 해당 테넌트의 가상 데이터베이스로 쿼리를 전달하며, 모든 쿼리는 해당 테넌트에만 적용됩니다(즉, select * from table은 해당 테넌트의 레코드만 반환합니다).
테넌트 컨텍스트를 설정하기 위해, 트랜잭션을 실행하기 전에 적절한 테넌트 컨텍스트를 설정하는 트랜잭션으로 각 쿼리를 래핑합니다.
테넌트 ID는 단순히 래퍼에 인자로 전달할 수 있습니다:
import { drizzle } from 'drizzle-orm/node-postgres';
import { todosTable, tenants } from "./db/schema";
import { sql } from 'drizzle-orm';
import 'dotenv/config';
const db = drizzle(process.env.NILEDB_URL);
function tenantDB<T>(tenantId: string, cb: (tx: any) => T | Promise<T>): Promise<T> {
return db.transaction(async (tx) => {
if (tenantId) {
await tx.execute(sql`set local nile.tenant_id = '${sql.raw(tenantId)}'`);
}
return cb(tx);
}) as Promise<T>;
}
// In a webapp, you'll likely get it from the request path parameters or headers
const tenantId = '01943e56-16df-754f-a7b6-6234c368b400'
const response = await tenantDB(tenantId, async (tx) => {
// No need for a "where" clause here
return await tx.select().from(todosTable);
});
console.log(response);이를 지원하는 웹 프레임워크를 사용하는 경우, AsyncLocalStorage를 설정하고 미들웨어를 사용하여 테넌트 ID로 채울 수 있습니다. 이 경우 Drizzle 클라이언트 설정은 다음과 같습니다:
import { drizzle } from 'drizzle-orm/node-postgres';
import dotenv from "dotenv/config";
import { sql } from "drizzle-orm";
import { AsyncLocalStorage } from "async_hooks";
export const db = drizzle(process.env.NILEDB_URL);
export const tenantContext = new AsyncLocalStorage<string | undefined>();
export function tenantDB<T>(cb: (tx: any) => T | Promise<T>): Promise<T> {
return db.transaction(async (tx) => {
const tenantId = tenantContext.getStore();
console.log("executing query with tenant: " + tenantId);
// if there's a tenant ID, set it in the transaction context
if (tenantId) {
await tx.execute(sql`set local nile.tenant_id = '${sql.raw(tenantId)}'`);
}
return cb(tx);
}) as Promise<T>;
}그런 다음, AsyncLocalStorage를 채우도록 미들웨어를 구성하고 요청을 처리할 때 tenantDB 메서드를 사용합니다:
// Middleware to set tenant context
app.use("/api/tenants/:tenantId/*", async (c, next) => {
const tenantId = c.req.param("tenantId");
console.log("setting context to tenant: " + tenantId);
return tenantContext.run(tenantId, () => next());
});
// Route handler
app.get("/api/tenants/:tenantId/todos", async (c) => {
const todos = await tenantDB(c, async (tx) => {
return await tx
.select({
id: todoSchema.id,
tenant_id: todoSchema.tenantId,
title: todoSchema.title,
estimate: todoSchema.estimate,
})
.from(todoSchema);
});
return c.json(todos);
});