Ref<T> は高レベル API の参照型です。別のエンティティを安定した行 ID または主キーから解決するための情報を持ち、table binding を通して参照先を遅延読み込みできます。
参照 trait
Section titled “参照 trait”参照される型には RefTraits<T> が必要です。AKKARADB_ENTITY はこれを生成します。
struct Author { uint64_t id; std::string name;};
AKKARADB_ENTITY(Author, id, name);参照を保存する
Section titled “参照を保存する”struct Post { uint64_t id; akkaradb::Ref<Author> author; std::string title;};
AKKARADB_ENTITY(Post, id, author, title);
authors.put({1, "Alice"});posts.put({100, akkaradb::ref<Author>(1), "Hello"});table または schema が Author の binding を持っていれば、ref は必要になった時点で遅延解決できます。
auto post = posts.get(100);auto name = post->author->name;結合は走査と検索の上にある型付き読み取りビューです。
auto rows = posts .join<&Post::author>(authors) .where([](const Post& post, const Author& author) { return author.name == "Alice"; }) .toVector();plain field 同士で join する場合は、左右両方の field を指定します。
auto rows = posts.join<&PlainPost::authorId, &Author::id>(authors).toVector();各結合行は左側の Entry と復号済みの右側エンティティを持ちます。where()、first()、any()、count()、toVector() は結合ビュー上で評価されます。
実用上の目安
Section titled “実用上の目安”owner row が primary key 変更後も同じ logical target を追跡してほしい場合は Ref<T> を使います。見えている key を保存して比較するだけなら plain foreign-key field の方が単純です。
参照フィールドには join<&RefField>(right)、通常フィールドには join<&LeftField, &RightField>(right) を使います。参照関係が多い大規模な処理では、頻繁に使う経路を明示的なインデックスやアプリケーション層の実体化ビューとして設計する方が向いています。
Ref の状態
Section titled “Ref の状態”| 状態 | 意味 |
|---|---|
| key known | id() が row-id lookup なしで返せます。 |
| row id known | rowId() が返せるか、metadata から解決できます。 |
| loaded | operator-> と operator* で値へアクセスできます。 |
| dirty | owner を保存する前に、参照先の値も保存する必要があります。 |
| attached | 遅延解決に使う table binding が利用できます。 |
完全なエンティティから Ref<T> を作ると未保存状態になります。PackedTable::put() は所有エンティティを書き込む前に未保存の参照を保存します。
主キーの変更
Section titled “主キーの変更”table は pk2row と row2pk metadata を維持するため、Ref<T> は primary key の変更を跨いでも安定します。
authors.updatePrimaryKey(1, Author{10, "Alice Cooper"});見えている主キーが変わった後でも、既存の Ref<Author> は行 ID 経由で同じ論理エンティティを解決できます。
結合の実行形
Section titled “結合の実行形”| join 形式 | 実行の形 |
|---|---|
join<&RefField>(right) | 左 table scan と右 table の row-id lookup。 |
join<&LeftField, &RightPk>(right) | 左 table scan と右 table の primary-key lookup。 |
join<&LeftField, &RightField>(right) | 左 table scan と、matching field を探すための右 table scan。 |
結合ヘルパーは Native の結合エンジン計画を作りません。テーブル走査と検索の上にあるビュー層のヘルパーです。
クエリとバイトコードの境界
Section titled “クエリとバイトコードの境界”Ref<T> の遅延解決は通常の C++ 動作です。post.author->name == "Alice" のような条件式は別テーブルへ境界をまたぐため、ローカルの生の行フィールド読み込みとして表現できません。
Clang プラグインのバイトコード書き換え経路では、Ref<T> をまたぐ PackedTable::query(lambda) は所有する HostCallBool 記述子として出力されます。通常の遅延解決は保たれますが、その条件式は生の行を直接評価できません。
BytecodeQueryView::where(lambda) では、Ref<T> をまたぐ条件は復号後フィルターとして残ります。where 記述子はバイトコードとして合成できる必要があるためです。明示的な join(...).where([](const Left&, const Right&) { ... }) は既存の二つのエンティティを受け取る条件式の意味を保ち、ローカル行バイトコードには書き換えられません。