DBFlute-1.1のReferrerメソッド微調整

DBFlute-1.1でこうなる、最終段階!

今日は、
ExistsReferrer や LoadReferrer など、
Referrer系のインターフェース微調整のお話。

後ろの List がなくなる

ずばり、メソッド名が...

1.0.x  : existsPurchaseList()
1.1から : existsPurchase()

後ろの List がなくなります。
List<Member> memberList = memberBhv.selectList(cb -> {
    cb.setupSelect_MemberStatus();
    cb.query().existsPurchase(purchaseCB -> {
        cb.query().existsPurchasePayment(paymentCB -> {
            ...
        });
    });
});
memberBhv.loadPurchase(memberList, purchaseCB -> {
    purchaseCB.query()...
}
もともと List って、one-to-many の
many を表すキーワードでした。
自動生成されたコードの中でリレーションを識別するもの。
極端な話、相互参照しているテーブルがあったら、
many-to-one の Purchase と、
one-to-many の Purchase が混在します。
そのときの識別として必要なのです。

ですが、ExistsReferrer や LoadReferrer など、
ConditionBean や検索の識別としては、それはほとんど不要です。

exists... や load... と言えば自動的に many とわかる

厳密には exists には AsOne がいますが、
1.1.x からは互換オプションになっていますし、
そちらは AsOne 付くので、重複は相当少ないはず。
(AsOneっていうテーブル名があったらややこしいですが...)

きっかけは、Lambda。
余計な宣言が減った分、メソッド名の視認性が求められると感じました。
テーブル名と混じって後ろにListと入っていると、
何のテーブルを exists しているのかをパッと見づらいなと。
そもそも SQL でも List は付きませんし...
ということで、このようにさせて頂きました。

もちろん、

isCompatibleReferrerCBMethodIdentityNameListSuffix

で戻せます。

Entity の get はそのまま

Entity の getPurchaseList() はそのままです。
こっちは、List を get したり set したりするので、
getPurchase() で List が戻ってくるのは無しだなと。

もともと、複数形にしたら?とよく言われますが、
その辞書の作成にコストがかかりますし、
英語の分、規則的ではなくなるので、
複数を表す用語としてベタにListにしています。

今回、検索のオペレーションをするような箇所で、
Listを排除しましたが、リレーションを識別する
プロパティ名としては List が付くことには変わりません。

複数FKなどのときに、
PurchaseByMyIdList
PurchaseByMyId
と、場所によって表現がズレちゃうのでいやだなとは思いましたが...

よく使われる場面での視認性を優先しました。

InScopeReferrer はオプションに

InScopeReferrer は ExistsReferrer のオプションに。
厳密には、InScopeReferrer というのは無くなります。
List<Member> memberList = memberBhv.selectList(cb -> {
    cb.setupSelect_MemberStatus();
    cb.query().existsPurchase(purchaseCB -> {
        cb.useInScopeSubQuery();
        cb.query().existsPurchasePayment(paymentCB -> {
            ...
        });
    });
});
InScopeReferrer と ExistsReferrer は、
どちらを選んでも検索結果が変わりません。
SQLに対する命令が変わるだけです。

DBFluteでは、通常は ExistsReferrer を
使ってもらうことをメインにしています。

そちらの方がパフォーマンスに優れた場面が多い
と考えていて、意味的にしっくりくるからです。
ですが、状況によっては、InScope で
やった方がよい場面もあると思われるので、
InScopeも選択できるようになっていました。

そう、ここは手段と目的がちょっと混在していました。
「子テーブルの存在を確認する」という目的に対して、
Exists と InScope という手段があるのですが、
その手段を選ぶ感じになっていました。
ただ、Existsは目的と一致する手段でもありました。

ExistsReferrer という目的の機能に対して、
デフォルトでは、相関サブクエリの exists 句で実現し、
InScopeのサブクエリ (InScopeSubQuery) という
手段で実現するオプションがある、そんな感じに。

これにより、コンパイルスピードの向上が見込まれます。
あまり使われない機能に対して、出力されるコード量が
多かった機能でありました。
なので、意味上のリファクタリングの話も合わせて、
これを機に整理整頓しました。

で、こっちは戻すオプションがありません。
バッサリいきました。
使っている箇所は少ないと想定しているので、
もし、移行でコンパイルエラーになったら、
existsに直して、
cb.useInScopeSubQuery();
と書いてくれればOKです。

なかなかキリがないですが...

とまあ、やっぱり Lambda とか、
いろいろと互換を崩してやっていると...

「ここまでやったら、もうこれもこうしちゃいたい」

ってのが出てきちゃいますが、キリがないですね。
コンパイルの互換に対して、
精神的な互換にはとても気をつかいます。

互換が崩れても喜んでもらえる変更であればOKですが、
そうでないことをやると、大切なものを失う可能性があります。

cb.select_MemberStatus();
cb.query().orderMemberName_Desc();

こいつらは今日、妄想していた案ですが、
「せっとあっぷせれくと」っていう、独特の響きが
開発現場の会話でスムーズに流れることを考えると、
ここはそのままがいいかなと。
selectWith_...ではたいして変わってない。
ここは精神的な互換の崩すインパクトがでかい。

addOrderBy は打ちづらい。
orderMemberName_Desc() なら補完しやすい。

cb.query().orderMemberName_Desc();
cb.query().orderBirthdate_Desc();

ただ、addしてる感がなくなってしまうのと、
その精神的な互換を崩すまでの価値があるかというと、
OrderByの登場回数を考えると、そんなんでもないかも。

query()とやっているからには、
絞り込み条件とパッと見で区別がしやすい方がよく、
意外にそのおおげさな addOrderBy が目印になる。
あと、addで補完が先頭に出てくるので、
これで order by ができることが知ってもらいやすい。

addOrder_MemberName_Desc();

うーん、中途半端だなぁ...
B を打たなくていいのはうれしいけど。

中途半端であれば、そこは「まんま」を貫いた方が
いいだろう。。。でも、変えるなら今しかない。。。
なんて頭をぐるぐる、ぷはーーー

でも、今の Java だと、いくら Java8 でも、
ちょっとこの辺が限界かなっていうのもあります。
理想のインターフェースを考えたら、
いまはまだ中途半端な改善しかできないなと。
コンパイル気にしないのであれば、
もっと大それた改善ができるのは今も想像できていますが、
まだそれはできないなぁと。
なので、それはまた未来かなと。

ということで、このブログを書いてる時点では、
「取得・絞り込み・ソート」の三つの指定は、
とりあえず「そのまんま」という感じです。

猶予は、もう一、二週間くらいしかないでしょうから、
そこ以外のところも含めて、いろいろと悩みたいと。