Drizzle ์ฟผ๋ฆฌ + CRUD

This guide assumes familiarity with:

Drizzle์€ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋ฅผ ์ฟผ๋ฆฌํ•˜๋Š” ์—ฌ๋Ÿฌ ๊ฐ€์ง€ ๋ฐฉ๋ฒ•์„ ์ œ๊ณตํ•˜๋ฉฐ, ๋‹ค์Œ ํ”„๋กœ์ ํŠธ์—์„œ ์–ด๋–ค ๊ฒƒ์„ ์‚ฌ์šฉํ• ์ง€ ๊ฒฐ์ •ํ•˜๋Š” ๊ฒƒ์€ ์—ฌ๋Ÿฌ๋ถ„์—๊ฒŒ ๋‹ฌ๋ ค ์žˆ์Šต๋‹ˆ๋‹ค. SQL๊ณผ ์œ ์‚ฌํ•œ ๊ตฌ๋ฌธ ๋˜๋Š” ๊ด€๊ณ„ํ˜• ๊ตฌ๋ฌธ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํ™•์ธํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค:

์™œ SQL๊ณผ ์œ ์‚ฌํ•œ๊ฐ€?


SQL์„ ์•Œ๋ฉด Drizzle์„ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋‹ค๋ฅธ ORM๊ณผ ๋ฐ์ดํ„ฐ ํ”„๋ ˆ์ž„์›Œํฌ๋Š” SQL์—์„œ ๋ฒ—์–ด๋‚˜๊ฑฐ๋‚˜ ์ถ”์ƒํ™”ํ•˜๋Š” ๊ฒฝํ–ฅ์ด ์žˆ์–ด ์ด์ค‘ ํ•™์Šต ๊ณก์„ ์ด ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค: SQL๊ณผ ํ”„๋ ˆ์ž„์›Œํฌ์˜ API๋ฅผ ๋ชจ๋‘ ๋ฐฐ์›Œ์•ผ ํ•ฉ๋‹ˆ๋‹ค.

Drizzle์€ ์ •๋ฐ˜๋Œ€์ž…๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๋Š” SQL์„ ์ˆ˜์šฉํ•˜๊ณ  Drizzle์„ ํ•ต์‹ฌ์ ์œผ๋กœ SQL๊ณผ ์œ ์‚ฌํ•˜๊ฒŒ ๋งŒ๋“ค์—ˆ๊ธฐ ๋•Œ๋ฌธ์— ํ•™์Šต ๊ณก์„ ์ด ๊ฑฐ์˜ ์—†๊ณ  SQL์˜ ๋ชจ๋“  ๊ธฐ๋Šฅ์— ์™„์ „ํžˆ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

// ๋ฐ์ดํ„ฐ์— ์ ‘๊ทผ
await db
  .select()
	.from(posts)
	.leftJoin(comments, eq(posts.id, comments.post_id))
	.where(eq(posts.id, 10))
SELECT *
FROM posts
LEFT JOIN comments ON posts.id = comments.post_id
WHERE posts.id = 10

SQL๊ณผ ์œ ์‚ฌํ•œ ๊ตฌ๋ฌธ์„ ์‚ฌ์šฉํ•˜๋ฉด ์ˆœ์ˆ˜ SQL๋กœ ํ•  ์ˆ˜ ์žˆ๋Š” ๋งŽ์€ ์ž‘์—…์„ ๋ณต์ œํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, Drizzle์ด ๋ฌด์—‡์„ ํ•  ๊ฒƒ์ด๊ณ  ์–ด๋–ค ์ฟผ๋ฆฌ๊ฐ€ ์ƒ์„ฑ๋ ์ง€ ์ •ํ™•ํžˆ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. select, insert, update, delete๋ฅผ ํฌํ•จํ•œ ๊ด‘๋ฒ”์œ„ํ•œ ์ฟผ๋ฆฌ๋ฅผ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ๋ณ„์นญ, WITH ์ ˆ, ํ•˜์œ„ ์ฟผ๋ฆฌ, prepared statement ๋“ฑ๋„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋” ๋งŽ์€ ์˜ˆ์ œ๋ฅผ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค

insert
update
delete
await db.insert(users).values({ email: 'user@gmail.com' })
INSERT INTO users (email) VALUES ('user@gmail.com')

์™œ SQL๊ณผ ์œ ์‚ฌํ•˜์ง€ ์•Š์€๊ฐ€?

์šฐ๋ฆฌ๋Š” ํ•ญ์ƒ ์™„๋ฒฝํ•˜๊ฒŒ ๊ท ํ˜• ์žกํžŒ ์†”๋ฃจ์…˜์„ ์ถ”๊ตฌํ•ฉ๋‹ˆ๋‹ค. SQL๊ณผ ์œ ์‚ฌํ•œ ์ฟผ๋ฆฌ๊ฐ€ ๋ชจ๋“  ์š”๊ตฌ ์‚ฌํ•ญ์˜ 100%๋ฅผ ์ถฉ์กฑํ•˜์ง€๋งŒ, ๋ฐ์ดํ„ฐ๋ฅผ ๋” ํšจ์œจ์ ์œผ๋กœ ์ฟผ๋ฆฌํ•  ์ˆ˜ ์žˆ๋Š” ํŠน์ • ์ผ๋ฐ˜์ ์ธ ์‹œ๋‚˜๋ฆฌ์˜ค๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

์šฐ๋ฆฌ๋Š” ์กฐ์ธ์ด๋‚˜ ๋ฐ์ดํ„ฐ ๋งคํ•‘์— ๋Œ€ํ•ด ๊ฑฑ์ •ํ•˜์ง€ ์•Š๊ณ ๋„ ๊ฐ€์žฅ ํŽธ๋ฆฌํ•˜๊ณ  ์„ฑ๋Šฅ์ด ์šฐ์ˆ˜ํ•œ ๋ฐฉ์‹์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—์„œ ๊ด€๊ณ„ํ˜• ์ค‘์ฒฉ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ๋„๋ก Queries API๋ฅผ ๊ตฌ์ถ•ํ–ˆ์Šต๋‹ˆ๋‹ค.

Drizzle์€ ํ•ญ์ƒ ์ •ํ™•ํžˆ ํ•˜๋‚˜์˜ SQL ์ฟผ๋ฆฌ๋ฅผ ์ถœ๋ ฅํ•ฉ๋‹ˆ๋‹ค. ์„œ๋ฒ„๋ฆฌ์Šค ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์™€ ํ•จ๊ป˜ ์ž์œ ๋กญ๊ฒŒ ์‚ฌ์šฉํ•˜๊ณ , ์„ฑ๋Šฅ์ด๋‚˜ ์™•๋ณต ๋น„์šฉ์— ๋Œ€ํ•ด ๊ฑฑ์ •ํ•  ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค!

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

๊ณ ๊ธ‰

Drizzle์„ ์‚ฌ์šฉํ•˜๋ฉด ์›ํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ์ฟผ๋ฆฌ๋ฅผ ๊ตฌ์„ฑํ•˜๊ณ  ๋ถ„ํ• ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ฉ”์ธ ์ฟผ๋ฆฌ์™€ ๋…๋ฆฝ์ ์œผ๋กœ ํ•„ํ„ฐ๋ฅผ ๊ตฌ์„ฑํ•˜๊ฑฐ๋‚˜, ํ•˜์œ„ ์ฟผ๋ฆฌ๋‚˜ ์กฐ๊ฑด๋ฌธ์„ ๋ถ„๋ฆฌํ•˜๋Š” ๋“ฑ ๋‹ค์–‘ํ•œ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ช‡ ๊ฐ€์ง€ ๊ณ ๊ธ‰ ์˜ˆ์ œ๋ฅผ ํ™•์ธํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค:

WHERE ๋ฌธ์„ ๊ตฌ์„ฑํ•œ ๋‹ค์Œ ์ฟผ๋ฆฌ์—์„œ ์‚ฌ์šฉ

async function getProductsBy({
  name,
  category,
  maxPrice,
}: {
  name?: string;
  category?: string;
  maxPrice?: string;
}) {
  const filters: SQL[] = [];

  if (name) filters.push(ilike(products.name, name));
  if (category) filters.push(eq(products.category, category));
  if (maxPrice) filters.push(lte(products.price, maxPrice));

  return db
    .select()
    .from(products)
    .where(and(...filters));
}

ํ•˜์œ„ ์ฟผ๋ฆฌ๋ฅผ ๋‹ค๋ฅธ ๋ณ€์ˆ˜๋กœ ๋ถ„๋ฆฌํ•œ ๋‹ค์Œ ๋ฉ”์ธ ์ฟผ๋ฆฌ์—์„œ ์‚ฌ์šฉ

const subquery = db
	.select()
	.from(internalStaff)
	.leftJoin(customUser, eq(internalStaff.userId, customUser.id))
	.as('internal_staff');

const mainQuery = await db
	.select()
	.from(ticket)
	.leftJoin(subquery, eq(subquery.internal_staff.userId, ticket.staffId));

๋‹ค์Œ์€?


์ฒ˜์Œ๋ถ€ํ„ฐ ๋๊นŒ์ง€

Migrations