문서 탐색 열기
R2D1 / 문서

시작하기

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.