Drizzle ์ฟผ๋ฆฌ

PostgreSQL
SQLite
MySQL
SingleStore

Drizzle ORM์€ SQL ์œ„์— ์–‡์€ ํƒ€์ž… ๊ณ„์ธต์œผ๋กœ ์„ค๊ณ„๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๋Š” TypeScript์—์„œ SQL ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋ฅผ ์šด์˜ํ•˜๋Š” ์ตœ๊ณ ์˜ ๋ฐฉ๋ฒ•์„ ์„ค๊ณ„ํ–ˆ๋‹ค๊ณ  ์ง„์‹ฌ์œผ๋กœ ๋ฏฟ์œผ๋ฉฐ, ์ด๋ฅผ ๋”์šฑ ๊ฐœ์„ ํ•  ๋•Œ์ž…๋‹ˆ๋‹ค.

๊ด€๊ณ„ํ˜• ์ฟผ๋ฆฌ๋Š” ์—ฌ๋Ÿฌ ์กฐ์ธ๊ณผ ๋ณต์žกํ•œ ๋ฐ์ดํ„ฐ ๋งคํ•‘์„ ํ”ผํ•˜๋ฉด์„œ SQL ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—์„œ ์ค‘์ฒฉ๋œ ๊ด€๊ณ„ํ˜• ๋ฐ์ดํ„ฐ๋ฅผ ์ฟผ๋ฆฌํ•  ์ˆ˜ ์žˆ๋Š” ํ›Œ๋ฅญํ•œ ๊ฐœ๋ฐœ์ž ๊ฒฝํ—˜์„ ์ œ๊ณตํ•˜๊ธฐ ์œ„ํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์ด๊ฒƒ์€ ๊ธฐ์กด ์Šคํ‚ค๋งˆ ์ •์˜ ๋ฐ ์ฟผ๋ฆฌ ๋นŒ๋”์˜ ํ™•์žฅ์ž…๋‹ˆ๋‹ค. ํ•„์š”์— ๋”ฐ๋ผ ์„ ํƒ์ ์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ตœ๊ณ  ์ˆ˜์ค€์˜ ๊ฐœ๋ฐœ์ž ๊ฒฝํ—˜๊ณผ ์„ฑ๋Šฅ์„ ๋ชจ๋‘ ๋ณด์žฅํ•ฉ๋‹ˆ๋‹ค.

index.ts
schema.ts
import * as schema from './schema';
import { drizzle } from 'drizzle-orm/...';

const db = drizzle({ schema });

const result = await db.query.users.findMany({
	with: {
		posts: true			
	},
});
[{
	id: 10,
	name: "Dan",
	posts: [
		{
			id: 1,
			content: "SQL is awesome",
			authorId: 10,
		},
		{
			id: 2,
			content: "But check relational queries",
			authorId: 10,
		}
	]
}]

โš ๏ธ ์—ฌ๋Ÿฌ ํŒŒ์ผ์— SQL ์Šคํ‚ค๋งˆ๋ฅผ ์„ ์–ธํ•œ ๊ฒฝ์šฐ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค

index.ts
schema1.ts
schema2.ts
import * as schema1 from './schema1';
import * as schema2 from './schema2';
import { drizzle } from 'drizzle-orm/...';

const db = drizzle({ schema: { ...schema1, ...schema2 } });

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

๋ชจ๋“œ

Drizzle ๊ด€๊ณ„ํ˜• ์ฟผ๋ฆฌ๋Š” ํ•ญ์ƒ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—์„œ ์‹คํ–‰ํ•  ์ •ํ™•ํžˆ ํ•˜๋‚˜์˜ SQL ๋ฌธ์„ ์ƒ์„ฑํ•˜๋ฉฐ, ๋ช‡ ๊ฐ€์ง€ ์ฃผ์˜์‚ฌํ•ญ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ๋ชจ๋“  ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ๋Œ€ํ•œ ์ตœ๊ณ  ์ˆ˜์ค€์˜ ์ง€์›์„ ์ œ๊ณตํ•˜๊ธฐ ์œ„ํ•ด **๋ชจ๋“œ**๋ฅผ ๋„์ž…ํ–ˆ์Šต๋‹ˆ๋‹ค.

Drizzle ๊ด€๊ณ„ํ˜• ์ฟผ๋ฆฌ๋Š” ๋‚ด๋ถ€์ ์œผ๋กœ ํ•˜์œ„ ์ฟผ๋ฆฌ์˜ ์ธก๋ฉด ์กฐ์ธ(lateral joins)์„ ์‚ฌ์šฉํ•˜๋ฉฐ, ํ˜„์žฌ PlanetScale์€ ์ด๋ฅผ ์ง€์›ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์ผ๋ฐ˜ MySQL ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์™€ ํ•จ๊ป˜ mysql2 ๋“œ๋ผ์ด๋ฒ„๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ โ€” mode: "default"๋ฅผ ์ง€์ •ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค PlanetScale๊ณผ ํ•จ๊ป˜ mysql2 ๋“œ๋ผ์ด๋ฒ„๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ โ€” mode: "planetscale"์„ ์ง€์ •ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค

import * as schema from './schema';
import { drizzle } from "drizzle-orm/mysql2";
import mysql from "mysql2/promise";

const connection = await mysql.createConnection({
  uri: process.env.PLANETSCALE_DATABASE_URL,
});

const db = drizzle({ client: connection, schema, mode: 'planetscale' });

์ฟผ๋ฆฌํ•˜๊ธฐ

๊ด€๊ณ„ํ˜• ์ฟผ๋ฆฌ๋Š” Drizzle์˜ ์›๋ž˜ **์ฟผ๋ฆฌ ๋นŒ๋”**์˜ ํ™•์žฅ์ž…๋‹ˆ๋‹ค. ์Šคํ‚ค๋งˆ ํŒŒ์ผ์—์„œ ๋ชจ๋“  tables์™€ relations๋ฅผ drizzle() ์ดˆ๊ธฐํ™” ์‹œ ์ œ๊ณตํ•˜๊ณ  db.query API๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

drizzle ์ž„ํฌํŠธ ๊ฒฝ๋กœ๋Š” ์‚ฌ์šฉ ์ค‘์ธ **๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๋“œ๋ผ์ด๋ฒ„**์— ๋”ฐ๋ผ ๋‹ค๋ฆ…๋‹ˆ๋‹ค.

index.ts
schema.ts
import * as schema from './schema';
import { drizzle } from 'drizzle-orm/...';

const db = drizzle({ schema });

await db.query.users.findMany(...);
// if you have schema in multiple files
import * as schema1 from './schema1';
import * as schema2 from './schema2';
import { drizzle } from 'drizzle-orm/...';

const db = drizzle({ schema: { ...schema1, ...schema2 } });

await db.query.users.findMany(...);

Drizzle๋Š” .findMany() ๋ฐ .findFirst() API๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

์—ฌ๋Ÿฌ ๊ฐœ ์ฐพ๊ธฐ

const users = await db.query.users.findMany();
// result type
const result: {
	id: number;
	name: string;
	verified: boolean;
	invitedBy: number | null;
}[];

์ฒซ ๋ฒˆ์งธ ์ฐพ๊ธฐ

.findFirst()๋Š” ์ฟผ๋ฆฌ์— limit 1์„ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.

const user = await db.query.users.findFirst();
// result type
const result: {
	id: number;
	name: string;
	verified: boolean;
	invitedBy: number | null;
};

๊ด€๊ณ„ ํฌํ•จํ•˜๊ธฐ

With ์—ฐ์‚ฐ์ž๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์—ฌ๋Ÿฌ ๊ด€๋ จ ํ…Œ์ด๋ธ”์˜ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฒฐํ•ฉํ•˜๊ณ  ๊ฒฐ๊ณผ๋ฅผ ์ ์ ˆํžˆ ์ง‘๊ณ„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋Œ“๊ธ€๊ณผ ํ•จ๊ป˜ ๋ชจ๋“  ๊ฒŒ์‹œ๋ฌผ ๊ฐ€์ ธ์˜ค๊ธฐ:

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

๋Œ“๊ธ€๊ณผ ํ•จ๊ป˜ ์ฒซ ๋ฒˆ์งธ ๊ฒŒ์‹œ๋ฌผ ๊ฐ€์ ธ์˜ค๊ธฐ:

const post = await db.query.posts.findFirst({
	with: {
		comments: true,
	},
});

ํ•„์š”ํ•œ ๋งŒํผ ์ค‘์ฒฉ๋œ with ๋ฌธ์„ ์—ฐ๊ฒฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ค‘์ฒฉ๋œ with ์ฟผ๋ฆฌ์˜ ๊ฒฝ์šฐ Drizzle์€ Core Type API๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํƒ€์ž…์„ ์ถ”๋ก ํ•ฉ๋‹ˆ๋‹ค.

๊ฒŒ์‹œ๋ฌผ๊ณผ ํ•จ๊ป˜ ๋ชจ๋“  ์‚ฌ์šฉ์ž ๊ฐ€์ ธ์˜ค๊ธฐ. ๊ฐ ๊ฒŒ์‹œ๋ฌผ์—๋Š” ๋Œ“๊ธ€ ๋ชฉ๋ก์ด ํฌํ•จ๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค:

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

๋ถ€๋ถ„ ํ•„๋“œ ์„ ํƒ

columns ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—์„œ ๊ฐ€์ ธ์˜ฌ ์ปฌ๋Ÿผ์„ ํฌํ•จํ•˜๊ฑฐ๋‚˜ ์ƒ๋žตํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Drizzle์€ ์ฟผ๋ฆฌ ์ˆ˜์ค€์—์„œ ๋ถ€๋ถ„ ์„ ํƒ์„ ์ˆ˜ํ–‰ํ•˜๋ฏ€๋กœ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—์„œ ์ถ”๊ฐ€ ๋ฐ์ดํ„ฐ๊ฐ€ ์ „์†ก๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

Drizzle์€ ๋‹จ์ผ SQL ๋ฌธ์„ ์ถœ๋ ฅํ•œ๋‹ค๋Š” ์ ์„ ๊ธฐ์–ตํ•˜์„ธ์š”.

id, content๋งŒ ํฌํ•จํ•˜๊ณ  comments๋„ ํฌํ•จํ•˜๋Š” ๋ชจ๋“  ๊ฒŒ์‹œ๋ฌผ ๊ฐ€์ ธ์˜ค๊ธฐ:

const posts = await db.query.posts.findMany({
	columns: {
		id: true,
		content: true,
	},
	with: {
		comments: true,
	}
});

content ์—†์ด ๋ชจ๋“  ๊ฒŒ์‹œ๋ฌผ ๊ฐ€์ ธ์˜ค๊ธฐ:

const posts = await db.query.posts.findMany({
	columns: {
		content: false,
	},
});

true์™€ false ์„ ํƒ ์˜ต์…˜์ด ๋ชจ๋‘ ์žˆ๋Š” ๊ฒฝ์šฐ ๋ชจ๋“  false ์˜ต์…˜์€ ๋ฌด์‹œ๋ฉ๋‹ˆ๋‹ค.

name ํ•„๋“œ๋ฅผ ํฌํ•จํ•˜๊ณ  id ํ•„๋“œ๋ฅผ ์ œ์™ธํ•˜๋ฉด id ์ œ์™ธ๋Š” ์ค‘๋ณต๋ฉ๋‹ˆ๋‹ค. ์–ด์ฐจํ”ผ name์„ ์ œ์™ธํ•œ ๋ชจ๋“  ํ•„๋“œ๊ฐ€ ์ œ์™ธ๋ฉ๋‹ˆ๋‹ค.

๋™์ผํ•œ ์ฟผ๋ฆฌ์—์„œ ํ•„๋“œ ์ œ์™ธ ๋ฐ ํฌํ•จ:

const users = await db.query.users.findMany({
	columns: {
		name: true,
		id: false //ignored
	},
});
// result type
const users: {
	name: string;
};

์ค‘์ฒฉ๋œ ๊ด€๊ณ„์˜ ์ปฌ๋Ÿผ๋งŒ ํฌํ•จ:

const res = await db.query.users.findMany({
	columns: {},
	with: {
		posts: true
	}
});
// result type
const res: {
	posts: {
		id: number,
		text: string
	}
}[];

์ค‘์ฒฉ๋œ ๋ถ€๋ถ„ ํ•„๋“œ ์„ ํƒ

**๋ถ€๋ถ„ ์„ ํƒ**๊ณผ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ์ค‘์ฒฉ๋œ ๊ด€๊ณ„์˜ ์ปฌ๋Ÿผ์„ ํฌํ•จํ•˜๊ฑฐ๋‚˜ ์ œ์™ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

const posts = await db.query.posts.findMany({
	columns: {
		id: true,
		content: true,
	},
	with: {
		comments: {
			columns: {
				authorId: false
			}
		}
	}
});

์„ ํƒ ํ•„ํ„ฐ

SQL๊ณผ ์œ ์‚ฌํ•œ ์ฟผ๋ฆฌ ๋นŒ๋”์™€ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ, ๊ด€๊ณ„ํ˜• ์ฟผ๋ฆฌ API๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์—ฐ์‚ฐ์ž ๋ชฉ๋ก์œผ๋กœ ํ•„ํ„ฐ์™€ ์กฐ๊ฑด์„ ์ •์˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

drizzle-orm์—์„œ ๊ฐ€์ ธ์˜ค๊ฑฐ๋‚˜ ์ฝœ๋ฐฑ ๊ตฌ๋ฌธ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

import { eq } from 'drizzle-orm';

const users = await db.query.users.findMany({
	where: eq(users.id, 1)
})
const users = await db.query.users.findMany({
	where: (users, { eq }) => eq(users.id, 1),
})

ํŠน์ • ๋‚ ์งœ ์ด์ „์— ์ƒ์„ฑ๋œ ๋Œ“๊ธ€๊ณผ ํ•จ๊ป˜ id=1์ธ ๊ฒŒ์‹œ๋ฌผ ์ฐพ๊ธฐ:

await db.query.posts.findMany({
	where: (posts, { eq }) => (eq(posts.id, 1)),
	with: {
		comments: {
			where: (comments, { lt }) => lt(comments.createdAt, new Date()),
		},
	},
});

Limit ๋ฐ Offset

Drizzle ORM์€ ์ฟผ๋ฆฌ ๋ฐ ์ค‘์ฒฉ๋œ ์—”ํ‹ฐํ‹ฐ์— ๋Œ€ํ•œ limit ๋ฐ offset API๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

5๊ฐœ์˜ ๊ฒŒ์‹œ๋ฌผ ์ฐพ๊ธฐ:

await db.query.posts.findMany({
	limit: 5,
});

๊ฒŒ์‹œ๋ฌผ์„ ์ฐพ๊ณ  ์ตœ๋Œ€ 3๊ฐœ์˜ ๋Œ“๊ธ€ ๊ฐ€์ ธ์˜ค๊ธฐ:

await db.query.posts.findMany({
	with: {
		comments: {
			limit: 3,
		},
	},
});
IMPORTANT

offset์€ ์ตœ์ƒ์œ„ ์ฟผ๋ฆฌ์—์„œ๋งŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

await db.query.posts.findMany({
	limit: 5,
	offset: 2, // correct โœ…
	with: {
		comments: {
			offset: 3, // incorrect โŒ
			limit: 3,
		},
	},
});

5๋ฒˆ์งธ๋ถ€ํ„ฐ 10๋ฒˆ์งธ ๊ฒŒ์‹œ๋ฌผ๊นŒ์ง€์˜ ๋Œ“๊ธ€๊ณผ ํ•จ๊ป˜ ๊ฒŒ์‹œ๋ฌผ ์ฐพ๊ธฐ:

await db.query.posts.findMany({
	limit: 5,
  offset: 5,
	with: {
		comments: true,
	},
});

Order By (์ •๋ ฌ)

Drizzle์€ ๊ด€๊ณ„ํ˜• ์ฟผ๋ฆฌ ๋นŒ๋”์—์„œ ์ •๋ ฌ์„ ์œ„ํ•œ API๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

๋™์ผํ•œ ์ •๋ ฌ **core API**๋ฅผ ์‚ฌ์šฉํ•˜๊ฑฐ๋‚˜ ์ž„ํฌํŠธ ์—†์ด ์ฝœ๋ฐฑ์—์„œ order by ์—ฐ์‚ฐ์ž๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

import { desc, asc } from 'drizzle-orm';

await db.query.posts.findMany({
	orderBy: [asc(posts.id)],
});
await db.query.posts.findMany({
	orderBy: (posts, { asc }) => [asc(posts.id)],
});

asc + desc๋กœ ์ •๋ ฌ:

await db.query.posts.findMany({
	orderBy: (posts, { asc }) => [asc(posts.id)],
	with: {
		comments: {
			orderBy: (comments, { desc }) => [desc(comments.id)],
		},
	},
});

์ปค์Šคํ…€ ํ•„๋“œ ํฌํ•จ

๊ด€๊ณ„ํ˜• ์ฟผ๋ฆฌ API๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ปค์Šคํ…€ ์ถ”๊ฐ€ ํ•„๋“œ๋ฅผ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ฐ์ดํ„ฐ๋ฅผ ๊ฒ€์ƒ‰ํ•˜๊ณ  ์ถ”๊ฐ€ ํ•จ์ˆ˜๋ฅผ ์ ์šฉํ•ด์•ผ ํ•  ๋•Œ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค.

IMPORTANT

ํ˜„์žฌ extras์—์„œ๋Š” ์ง‘๊ณ„๊ฐ€ ์ง€์›๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ด๋ฅผ ์œ„ํ•ด์„œ๋Š” **core queries**๋ฅผ ์‚ฌ์šฉํ•˜์„ธ์š”.

import { sql } from 'drizzle-orm';

await db.query.users.findMany({
	extras: {
		loweredName: sql`lower(${users.name})`.as('lowered_name'),
	},
})
await db.query.users.findMany({
	extras: {
		loweredName: (users, { sql }) => sql`lower(${users.name})`.as('lowered_name'),
	},
})

ํ‚ค๋กœ์„œ lowerName์€ ๋ฐ˜ํ™˜๋œ ๊ฐ์ฒด์˜ ๋ชจ๋“  ํ•„๋“œ์— ํฌํ•จ๋ฉ๋‹ˆ๋‹ค.

IMPORTANT

.as("<name_for_column>")๋ฅผ ๋ช…์‹œ์ ์œผ๋กœ ์ง€์ •ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค

๊ทธ๋ฃน๊ณผ ํ•จ๊ป˜ ๋ชจ๋“  ์‚ฌ์šฉ์ž๋ฅผ ๊ฒ€์ƒ‰ํ•˜๋˜ fullName ํ•„๋“œ(firstName๊ณผ lastName์˜ ์—ฐ๊ฒฐ)๋ฅผ ํฌํ•จํ•˜๋ ค๋ฉด, Drizzle ๊ด€๊ณ„ํ˜• ์ฟผ๋ฆฌ ๋นŒ๋”๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋‹ค์Œ ์ฟผ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

const res = await db.query.users.findMany({
	extras: {
		fullName: sql<string>`concat(${users.name}, " ", ${users.name})`.as('full_name'),
	},
	with: {
		usersToGroups: {
			with: {
				group: true,
			},
		},
	},
});
// result type
const res: {
	id: number;
	name: string;
	verified: boolean;
	invitedBy: number | null;
	fullName: string;
	usersToGroups: {
			group: {
					id: number;
					name: string;
					description: string | null;
			};
	}[];
}[];

๋Œ“๊ธ€๊ณผ ํ•จ๊ป˜ ๋ชจ๋“  ๊ฒŒ์‹œ๋ฌผ์„ ๊ฒ€์ƒ‰ํ•˜๊ณ  ๊ฒŒ์‹œ๋ฌผ ๋‚ด์šฉ์˜ ํฌ๊ธฐ์™€ ๊ฐ ๋Œ“๊ธ€ ๋‚ด์šฉ์˜ ํฌ๊ธฐ๋ฅผ ๊ณ„์‚ฐํ•˜๋Š” ์ถ”๊ฐ€ ํ•„๋“œ๋ฅผ ์ถ”๊ฐ€ํ•˜๋ ค๋ฉด:

const res = await db.query.posts.findMany({
	extras: (table, { sql }) => ({
		contentLength: (sql<number>`length(${table.content})`).as('content_length'),
	}),
	with: {
		comments: {
			extras: {
				commentSize: sql<number>`length(${comments.content})`.as('comment_size'),
			},
		},
	},
});
// result type
const res: {
	id: number;
	createdAt: Date;
	content: string;
	authorId: number | null;
	contentLength: number;
	comments: {
			id: number;
			createdAt: Date;
			content: string;
			creator: number | null;
			postId: number | null;
			commentSize: number;
	}[];
};

์ค€๋น„๋œ ๋ฌธ(Prepared statements)

์ค€๋น„๋œ ๋ฌธ์€ ์ฟผ๋ฆฌ ์„ฑ๋Šฅ์„ ๋Œ€ํญ ํ–ฅ์ƒ์‹œํ‚ค๋„๋ก ์„ค๊ณ„๋˜์—ˆ์Šต๋‹ˆ๋‹ค โ€” ์—ฌ๊ธฐ๋ฅผ ์ฐธ์กฐํ•˜์„ธ์š”.

์ด ์„น์…˜์—์„œ๋Š” Drizzle ๊ด€๊ณ„ํ˜• ์ฟผ๋ฆฌ ๋นŒ๋”๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ”Œ๋ ˆ์ด์Šคํ™€๋”๋ฅผ ์ •์˜ํ•˜๊ณ  ์ค€๋น„๋œ ๋ฌธ์„ ์‹คํ–‰ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๋ฐฐ์šธ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

where์˜ ํ”Œ๋ ˆ์ด์Šคํ™€๋”
PostgreSQL
MySQL
SQLite
const prepared = db.query.users.findMany({
	where: ((users, { eq }) => eq(users.id, placeholder('id'))),
	with: {
		posts: {
			where: ((users, { eq }) => eq(users.id, placeholder('pid'))),
		},
	},
}).prepare('query_name');

const usersWithPosts = await prepared.execute({ id: 1 });
limit์˜ ํ”Œ๋ ˆ์ด์Šคํ™€๋”
PostgreSQL
MySQL
SQLite
const prepared = db.query.users.findMany({
	with: {
		posts: {
			limit: placeholder('limit'),
		},
	},
}).prepare('query_name');

const usersWithPosts = await prepared.execute({ limit: 1 });
offset์˜ ํ”Œ๋ ˆ์ด์Šคํ™€๋”
PostgreSQL
MySQL
SQLite
const prepared = db.query.users.findMany({
	offset: placeholder('offset'),
	with: {
		posts: true,
	},
}).prepare('query_name');

const usersWithPosts = await prepared.execute({ offset: 1 });
์—ฌ๋Ÿฌ ํ”Œ๋ ˆ์ด์Šคํ™€๋”
PostgreSQL
MySQL
SQLite
const prepared = db.query.users.findMany({
	limit: placeholder('uLimit'),
	offset: placeholder('uOffset'),
	where: ((users, { eq, or }) => or(eq(users.id, placeholder('id')), eq(users.id, 3))),
	with: {
		posts: {
			where: ((users, { eq }) => eq(users.id, placeholder('pid'))),
			limit: placeholder('pLimit'),
		},
	},
}).prepare('query_name');

const usersWithPosts = await prepared.execute({ pLimit: 1, uLimit: 3, uOffset: 1, id: 2, pid: 6 });