リレーション
KosameはhasMany/belongsToによるリレーション機能を提供しています。 リレーションではJOIN句を使わず、IN句によるバッチクエリでリレーション先を取得する設計になっています。
リレーションの繋ぎ方
hasMany()
hasMany()リレーションでは多の方を表します。 使い方としてimport { hasMany } from "kosame";とhasMany()をインポートし使います。 hasMany()の引数には対象のModelクラスを返す関数とforeignKey/localKeyを書きます。 foreignKeyは必ず書く必要がありlocalKeyは省略することができます。省略する場合には親テーブルの主キーが使われます。
static relations = { posts: hasMany(() => Post, { foreignKey: "authorId" }) };belongsTo()
belongsTo()リレーションでは単の方を表します。 使い方としてimport { belongsTo } from "kosame";とbelongsTo()をインポートし使います。 belongsTo()の引数には対象のModelクラスを返す関数とforeignKey/targetKeyを書きます。 foreignKeyは必ず書く必要がありtargetKeyは省略することができます。省略する場合にはターゲットテーブルの主キーが使われます。
static relations = { author: belongsTo(() => User, { foreignKey: "authorId" }) };include
includeはfind()で取得する際にリレーション先も一緒に取得したい場合に使用します。 includeはfind()の引数にstatic relationsで定義したリレーションのキー名を配列で渡して使います。 includeに渡したキー名は、そのまま返ってきたインスタンスのプロパティ名になります。hasMany()経由の場合は配列、belongsTo()経由の場合は単一のインスタンス(無ければundefined)が入ります。
const user = await context.users.find(id, { include: ["posts"] });既知の制限
ネスト
includeではリレーションをネストして取得することはできません。 userがどのpostにcommentしたかをわかるようにするシステムなどはネストするため注意が必要です。
複合キー未対応
複数カラムをまとめて主キー/外部キーとして扱うテーブルには対応していません。
SoftDeletableとの関係
リレーション先でSoftDeletableを使用した場合、hasMany/belongsToどちらも自動でソフトデリート済みの行を除外します。 find()でのwithDeletedに相当するオプトアウト手段は無いです。
JOINを使わない理由
KosameのリレーションではJOINを使いません。 なぜ使わないのか?IN句を使うことでfan-out問題が原理的に起きません。N+1問題も回避できるためこちらの方が安全という設計的判断によるものです。 そしてDrizzleのrelations()に依存せずに済むので、JOINは使われていないのです。
