🗄️ 데이터베이스

EdgeDB

Graph-Relational Database

PostgreSQL을 기반으로 한 차세대 그래프-관계형 데이터베이스로, 강력한 타입 시스템과 EdgeQL 쿼리 언어를 통해 복잡한 데이터 모델링을 단순화하고, 완전한 타입 안전성을 제공합니다.

📖 상세 설명

EdgeDB는 PostgreSQL 위에 구축된 오픈소스 데이터베이스로, SQL의 복잡성을 해결하고 ORM 없이도 타입 안전한 쿼리를 작성할 수 있게 설계되었습니다. 객체 지향적인 스키마 정의와 그래프 형태의 관계 탐색을 지원하며, TypeScript, Python, Go 등에서 완전한 타입 추론을 제공합니다.

핵심 철학: "SQL의 표현력 + ORM의 편의성"

SQL의 조인 복잡성과 ORM의 N+1 문제를 동시에 해결. 스키마에서 타입을 추론하여 런타임 에러 방지.

EdgeDB 핵심 기능

🔷
EdgeQL
직관적인 쿼리 언어
📝
SDL Schema
선언적 스키마 정의
🔒
Type Safety
완전한 타입 추론
🐘
PostgreSQL 기반
검증된 안정성
🔄
Migrations
내장 마이그레이션 도구
🌐
EdgeDB Cloud
관리형 클라우드 서비스

💻 코드 예제

1. 스키마 정의 (SDL)

dbschema/default.esdl
module default { # 사용자 타입 type User { required property email -> str { constraint exclusive; # 유니크 제약 } required property name -> str; property created_at -> datetime { default := datetime_current(); } # 관계 (역방향 자동 생성) multi link posts := . str; property content -> str; required property published -> bool { default := false; } property created_at -> datetime { default := datetime_current(); } # 관계 정의 required link author -> User; multi link tags -> Tag; multi link comments := . str; property created_at -> datetime { default := datetime_current(); } required link post -> Post; required link author -> User; } # 태그 타입 type Tag { required property name -> str { constraint exclusive; } } }

2. EdgeQL 기본 쿼리

EdgeQL
# 사용자 생성 INSERT User { email := 'john@example.com', name := 'John Doe' }; # 게시글 생성 (관계 포함) INSERT Post { title := 'Getting Started with EdgeDB', content := 'EdgeDB is a next-generation database...', author := (SELECT User FILTER .email = 'john@example.com'), tags := { (INSERT Tag { name := 'database' } UNLESS CONFLICT ON .name ELSE Tag), (INSERT Tag { name := 'tutorial' } UNLESS CONFLICT ON .name ELSE Tag) } }; # 중첩 데이터 조회 (JOIN 없이!) SELECT Post { title, content, created_at, author: { name, email }, tags: { name }, comments: { content, author: { name } } ORDER BY .created_at DESC } FILTER .published = true ORDER BY .created_at DESC LIMIT 10; # 조건부 필터링 SELECT User { name, email, post_count := count(.posts), recent_post := ( SELECT .posts { title, created_at } ORDER BY .created_at DESC LIMIT 1 ) } FILTER count(.posts) > 5;

3. TypeScript 클라이언트 (타입 자동 생성)

TypeScript
import { createClient } from 'edgedb'; import e from './dbschema/edgeql-js'; // 자동 생성된 타입 const client = createClient(); // 완전한 타입 추론! async function getPublishedPosts() { const posts = await e.select(e.Post, (post) => ({ id: true, title: true, content: true, created_at: true, author: { name: true, email: true, }, tags: { name: true, }, filter: e.op(post.published, '=', true), order_by: { expression: post.created_at, direction: e.DESC, }, limit: 10, })).run(client); // posts는 완전히 타입 추론됨! // posts[0].author.name - 타입 안전 return posts; } // INSERT도 타입 안전 async function createUser(email: string, name: string) { const user = await e.insert(e.User, { email, name, }).run(client); return user; } // 복잡한 쿼리도 타입 추론 async function getUserStats(userId: string) { const result = await e.select(e.User, (user) => ({ name: true, post_count: e.count(user.posts), comment_count: e.count(user.comments), latest_post: e.select(user.posts, (post) => ({ title: true, order_by: { expression: post.created_at, direction: e.DESC }, limit: 1, })), filter_single: e.op(user.id, '=', e.uuid(userId)), })).run(client); return result; }

4. 마이그레이션

CLI 명령어
# EdgeDB 프로젝트 초기화 edgedb project init # 스키마 변경 후 마이그레이션 생성 edgedb migration create # 마이그레이션 적용 edgedb migrate # 마이그레이션 상태 확인 edgedb migration status # 타입스크립트 타입 재생성 npx @edgedb/generate edgeql-js # REPL에서 쿼리 테스트 edgedb edgedb> SELECT User { name, email }; edgedb> \q

5. 고급 쿼리 패턴

EdgeQL
# 그래프 탐색: 2단계 관계 SELECT User { name, # 내 게시글에 댓글 단 사람들 commenters := ( SELECT .posts.comments.author { name, email } ) } FILTER .name = 'John'; # 집계 및 그룹화 SELECT ( GROUP Post { title, author: { name } } BY .author ) { key: { author_name := .key.author.name }, post_count := count(.elements), titles := .elements.title }; # 재귀 쿼리 (계층 구조) # 예: 카테고리의 모든 하위 카테고리 WITH MODULE default SELECT Category { name, children: { name, children: { name } } } FILTER NOT EXISTS .parent; # 전체 텍스트 검색 (fts 모듈) SELECT Post { title, content, score := fts::score(Post) } FILTER fts::search(Post, 'edgedb tutorial') ORDER BY fts::score(Post) DESC;

💬 현업 대화 예시

풀스택 개발자
"EdgeQL 쿼리가 JSON 형태라서 중첩 데이터 가져올 때 JOIN 안 써도 돼. N+1 문제도 알아서 해결해주고."
TypeScript 개발자
"edgeql-js 쓰면 스키마에서 타입 자동 생성돼서 오타나 잘못된 필드 접근하면 컴파일 에러 나. Prisma보다 타입 추론이 더 정확해."
백엔드 개발자
"마이그레이션이 내장되어 있어서 스키마 변경할 때 따로 도구 안 써도 돼. 변경 사항 자동 감지해서 마이그레이션 파일 만들어줘."
시니어 개발자
"PostgreSQL 위에서 돌아가니까 안정성은 검증됐어. 다만 아직 생태계가 작아서 특수한 케이스에서 참고할 자료가 좀 부족해."

⚠️ 주의사항

학습 곡선

EdgeQL은 SQL과 다른 새로운 쿼리 언어입니다. SQL에 익숙한 개발자도 새로운 문법을 학습해야 합니다.

생태계 규모

PostgreSQL이나 MongoDB에 비해 커뮤니티와 서드파티 도구가 제한적입니다. 문제 발생 시 참고 자료가 부족할 수 있습니다.

호스팅 옵션

EdgeDB Cloud 외에 관리형 서비스가 제한적입니다. 셀프 호스팅 시 운영 부담이 있을 수 있습니다.

🔗 관련 용어

📚 더 배우기