検索条件を出す
検索欄に並べる条件と、比較のしかた(等値・部分一致・範囲)。
検索欄に並べる条件は search.filters に書く。並べた順に画面に出る。
page:
type: search
id: product_search
title: 商品照会
repository: productRepository
search:
layout: { columns: 3 }
filters:
- { field: name, label: 商品名, type: text, operator: contains }
- field: category
label: カテゴリ
type: select
operator: equals
options:
- { value: food, label: 食品 }
- { value: drink, label: 飲料 }field がデータ側の項目名、type が入力欄の種類、operator が比較のしかた。
operator を省くと部分一致になる
既定は contains。名前や住所を探す欄はそれでいいが、コードや区分を探す欄では意図と違う。「A001」で検索したら「A0012」も出てくる。コードや選択肢は equals を明示する。
日付や金額の範囲は between、複数選択で絞るなら in。
- { field: orderDate, label: 受注日, type: date, operator: between }
- { field: status, label: 状態, type: select, operator: in, options: [...] }検索でしか使えない演算子、条件でしか使えない演算子
operator は検索条件(filters)と表示条件(visibleWhen / enabledWhen)の両方に出てくるが、使える演算子が違う。
| 検索条件 | 表示条件 | |
|---|---|---|
between startsWith endsWith | 使える | 使えない |
isEmpty isNotEmpty | 使えない | 使える |
値を2つ取る(between)ものは入力欄が2つ必要なので検索専用、値を取らない(isEmpty)ものは検索欄として置き場がないので条件専用、と考えると覚えやすい。
検索条件を組み立てるのは Framework、実行するのは Repository
入力された値は「項目・演算子・値」の組として Repository へ渡る。それを SQL や API のクエリにするのは Repository 側。バックエンド(Java / TypeScript)には同じ組を受け取ってクエリを組む道具が用意されている。
select には options が要る
select radio multiSelect は options を書かないと選ぶものが無い。値はデータに入る値、ラベルは画面に出る文字。マスタにある選択肢は optionsSource で引く(選択肢の連動)。
最初から絞って始める(defaultValue)
「一覧は既定で在籍者だけ」「今月の受注から」のように、開いたときから絞ってある画面は defaultValue で書く。検索欄がその値で埋まって始まり、最初の一覧もその条件で読む(欄だけ埋まって一覧は全件、にはならない)。利用者は外せる。
search:
filters:
- { field: employmentStatus, label: 在籍, type: select, operator: equals, defaultValue: active,
options: [{ value: active, label: 在籍 }, { value: retired, label: 退職 }] }
- { field: orderDate, label: 受注日, type: date, operator: between, defaultValue: $thisMonth }日付は相対の語で書ける。開いた日で解く。
| 語 | 意味 |
|---|---|
$today | 今日 |
$startOfMonth / $endOfMonth | 今月の1日 / 末日 |
$startOfYear / $endOfYear | 今年の1月1日 / 12月31日 |
$thisMonth / $thisYear | 範囲(between)だけ。今月・今年のはじめからおわりまで |
範囲は [from, to] でも書ける([$startOfMonth, $today]、片方は null でよい)。形の合わない書き方(範囲の語を範囲でない条件に書いた、など)は既定値が付かないので、npx -p @hatake-fw/api hatake validate が言う。
画面から外させない条件(fixed)
「取消は刷らない」「退職者は出さない」のように、利用者に外させたくない決めごとは fixed に書く。画面には出ない。
search:
filters: [ … ]
fixed:
- { field: cancelled, operator: notEquals, value: true }足すのは**サーバの buildQuery(TS / Java)**で、毎回の問い合わせに必ず付く。画面は送ってこないので、API を直接叩いても外せない。Repository を自分で直接実装した Flutter アプリ(buildQuery を通らない)は、同じ条件を自分で当てる。
どこに書くか
filters は search の中。ページ直下に書いても効かない(下の「よくある間違い」参照)。search を持てるのは crud master search dashboard report の5種別で、form や detail には検索欄という概念がない。
書けるキー
| キー | 書く場所 | 型 | 必須 | 既定値 | 有効なページ種別 | 説明 |
|---|---|---|---|---|---|---|
search | crudPage | object → search | 任意 | — | crud | The search area: filters plus their layout. |
search | dashboardPage | object → search | 任意 | — | dashboard | Filters applied to every card's query. |
search | masterPage | object → search | 任意 | — | master | The search area: filters plus their layout. |
search | reportPage | object → search | 任意 | — | report | Output conditions, passed to the repository as filters. |
search | searchPage | object → search | 任意 | — | search | The search area: filters plus their layout. |
filters | dashboardItem | object → dashboardItem.filters | 任意 | — | dashboard | Fixed filter values merged into the query. |
filters | search | array → filter | 任意 | — | crud dashboard master report search | — |
operator | condition | string (equals / notEquals / gt / gte / lt / lte / contains / in / isEmpty / isNotEmpty ほか) | 任意 | — | crud dashboard detail form master report search wizard | Built-ins: equals, notEquals, gt, gte, lt, lte, contains, in, isEmpty, isNotEmpty. |
operator | filter | string (equals / notEquals / contains / startsWith / endsWith / gt / gte / lt / lte / between / in ほか) | 任意 | "contains" | crud dashboard master report search | Match operator (open string). Built-ins: equals, notEquals, contains, startsWith, endsWith, gt, gte, lt, lte, between, in. |
operator | fixedCondition | string | 任意 | "equals" | crud dashboard master report search | Match operator (same open vocabulary as a filter's operator). |
options | field | array → option | 任意 | — | crud dashboard detail form master report search wizard | — |
options | filter | array → option | 任意 | — | crud dashboard master report search | Options for select-style filters. |
options | vocabulary | array → option | 必須 | — | すべて | — |
layout | dashboardPage | object → layout | 任意 | — | dashboard | Card grid width. Defaults to 2 columns. |
layout | search | object → layout | 任意 | — | crud dashboard master report search | — |
layout | section | object → layout | 任意 | — | crud detail form master | — |
layout | wizardStep | object → layout | 任意 | — | wizard | — |
defaultValue | field | `string | number | boolean | null` | 任意 |
defaultValue | filter | any (active / $today / $startOfMonth,$today / $thisMonth ほか) | 任意 | — | crud dashboard master report search | Initial value of this filter (the first list is loaded with it too; the user can clear it). A between filter takes [from, to]. Dates may use relative words resolved on the client's today: $today, $startOfMonth, $endOfMonth, $startOfYear, $endOfYear, and for between only $thisMonth / $thisYear (a whole range). Not applied by the server. |
fixed | search | array → fixedCondition | 任意 | — | crud dashboard master report search | Conditions always applied to this page's query and not shown on screen. The server's buildQuery (TS / Java) adds them to every query, so the screen cannot remove them. A Flutter app that implements Repository directly (no buildQuery) must apply them itself. |
この表は spec/reference.json から生成している(JSON Schema が正)。手元では npx -p @hatake-fw/api hatake reference <キー名> で同じものが引ける。
近い例
例は丸ごと写して直すのが一番速い。以下は CI で検証済み(そのまま動く形)。
| ファイル | 種別 | 画面 | どういうときに使うか |
|---|---|---|---|
customer_master.yaml | crud | 顧客マスタ | 検索して一覧に出して、その場で登録・修正・削除まで面倒を見る画面が欲しい |
product_search.yaml | search | 商品照会 | 検索して一覧を見るだけ(登録も更新もさせない)画面が欲しい |
customer_form.yaml | form | 顧客入力 | 一覧を持たない単票の入力画面が欲しい(新規と編集を1枚で) |
customer_wizard.yaml | wizard | 顧客登録 | 項目が多いので入力をステップに分けて、1ステップずつ検証したい |
sales_dashboard.yaml | dashboard | 売上ダッシュボード | 件数・金額・グラフのカードを並べて、まず数字を見せたい |
order_lines.yaml | app | 受注明細 | 受注番号だけでは1件に決まらない表を出したい(明細・履歴・年度別の実績) |
よくある間違い
ページ直下に filters を書く
なぜ駄目か 検索条件は search の持ち物。ページ直下の filters は無い(ダッシュボードのカードの filters は「固定の絞り込み値」で別物)。
こう直す search.filters に入れる。
page:
type: search
id: order_search
title: 受注照会
repository: orderRepository
filters:
- { field: status, label: 状態 }page:
type: search
id: order_search
title: 受注照会
repository: orderRepository
search:
filters:
- { field: status, label: 状態 }spec/pitfalls.json から生成。各項目は CI で検証済み(間違いは本当に落ち、正しい方は本当に通る)。手元では npx -p @hatake-fw/api hatake pitfalls <キー名>。
実物を見る
デモアプリの「受注照会」がこれを使っている。 デモを開く