시작하기
R2D1 설정은 두 backend 선택으로 시작하고 하나의 공통 API 경로로 이어집니다. 완전한 문서를 저장할 위치와 인덱스 필드를 저장할 위치를 선택한 뒤, 두 store로 collection facade를 구성하세요.
1. 문서 저장소 선택
DocumentStore는 완전한 직렬화 문서, 식별자 조회, 논리적 존재의 권위 있는 원본입니다. 하나를 선택하세요:
- R2 DocumentStore는 AWS SDK 비동기 클라이언트를 통해 Cloudflare R2에 문서를 저장합니다.
- Filesystem DocumentStore는 원자적 교체를 사용하는 canonical 로컬 문서를 저장합니다.
2. 인덱스 저장소 선택
IndexStore는 문서 식별자와 명시적으로 인덱싱한 필드의 재구축 가능한 projection입니다. 하나를 선택하세요:
- D1 IndexStore는 Java 비동기 HttpClient를 통해 Cloudflare D1 REST API를 사용합니다.
- JDBC IndexStore는 애플리케이션 소유 DataSource를 통해 H2, HSQLDB, 로컬 SQLite를 지원합니다.
이 선택으로 R2 + D1, R2 + JDBC, Filesystem + D1, Filesystem + JDBC 네 조합을 만들 수 있지만, 컬렉션 API가 네 개로 나뉘지는 않습니다.
3. 필요한 모듈 추가
core artifact는 공통 API와 Cloudflare R2/D1 adapter를 제공합니다:
dependencies {
implementation("dev.nexcraft:r2d1:<version>")
}애플리케이션에서 사용하는 통합 모듈만 추가하세요:
dependencies {
implementation("dev.nexcraft:r2d1-filesystem:<version>")
implementation("dev.nexcraft:r2d1-jdbc:<version>")
implementation("dev.nexcraft:r2d1-micronaut:<version>")
}JDBC driver는 애플리케이션이 제공하며 r2d1-jdbc에 포함되지 않습니다. 전체 모듈 표와 소유권 규칙은 Configuration.
4. 문서 정의
식별자로 사용할 비어 있지 않은 String member 하나에 @Id를 붙이고, 인덱스에 저장할 필드에 @Index를 붙입니다. 필터와 정렬에는 인덱싱한 필드만 사용할 수 있습니다.
import dev.nexcraft.r2d1.annotation.Document;
import dev.nexcraft.r2d1.annotation.Id;
import dev.nexcraft.r2d1.annotation.Index;
@Document("users")
public record User(
@Id String id,
@Index String country,
@Index long score,
String name) {}R2D1은 JSON library를 선택하지 않습니다. domain object를 StoredDocument로 직렬화하고 collection이 결과를 hydrate할 때 다시 역직렬화하는 DocumentCodec을 제공하세요.
5. 공통 collection API 구성
아래 예제는 두 storage 역할이 보이도록 adapter 생성을 애플리케이션에 남겨둡니다. documentStore, indexStore, documentCodec은 애플리케이션 소유 값입니다.
import dev.nexcraft.r2d1.DocumentCodec;
import dev.nexcraft.r2d1.PersistenceCollectionFactory;
import dev.nexcraft.r2d1.R2D1;
import dev.nexcraft.r2d1.R2D1Collection;
import dev.nexcraft.r2d1.spi.DocumentStore;
import dev.nexcraft.r2d1.spi.IndexStore;
DocumentStore documentStore = applicationDocumentStore;
IndexStore indexStore = applicationIndexStore;
DocumentCodec documentCodec = applicationDocumentCodec;
R2D1 database =
R2D1.builder()
.collectionFactory(
new PersistenceCollectionFactory(
documentStore, indexStore, documentCodec, indexStore::initialize))
.build();
R2D1Collection<User> users = database.collection(User.class);collection을 열면 collection metadata를 초기화하거나 검증한 뒤 collection을 반환합니다. factory는 store, codec, caller-owned execution resource의 소유권을 가져가지 않습니다.
6. put, get, delete
User user = new User("user-123", "NZ", 42, "Ada");
users.put(user);
Optional<User> stored = users.get("user-123");
users.delete("user-123");
Optional<User> absent = users.get("user-123");put은 @Id 값으로 문서를 생성하거나 교체합니다. get은 authoritative document storage를 읽고, 없는 식별자를 삭제해도 효과가 없습니다.
7. 인덱스 쿼리 실행
import dev.nexcraft.r2d1.Page;
import dev.nexcraft.r2d1.SortDirection;
Page<User> first =
users.query()
.where("country")
.eq("NZ")
.sortBy("score", SortDirection.DESC)
.limit(20)
.fetch();
if (first.nextCursor() != null) {
Page<User> second =
users.query()
.where("country")
.eq("NZ")
.sortBy("score", SortDirection.DESC)
.limit(20)
.after(first.nextCursor())
.fetch();
}cursor는 opaque 값입니다. 다음 페이지를 요청할 때 같은 filter와 sort를 유지하세요. 지원 연산자와 정렬 규칙은 Querying를, 두 store를 운영 환경에서 사용하기 전 복구 의미는 Consistency and Recovery.
