はじめに

データベースの内容を一覧するときに、検索結果を適用するという仕組みを一切プログラムを書かずに実現するために、ボタンやテキストフィールド、あるいは一般的なノードに対して機能を割り当てるという考え方を導入しました。要素のdata-im属性を利用して、ローカルコンテキスト(名前は「_」)に特別なキー名でバインドすることで、機能が割り当てられます。今の所、検索ページを作るための以下のものが利用できます。抽象的に記述してもわかりにくいと思いますので、具体的なタグのテキストともに紹介します。

検索条件の付加

テキストフィールドを「_@condition:....」のローカルコンテキストへバインドさせると、そのテキストフィールドに入れた文字列が検索条件になります。また、Enterキーで、コンテキストの更新が実行されます。

<input type="text" data-im="_@condition:postalcode:f3,f7,f8,f9:*match*">

@以降は、コロン(:)で4つのセクションに分かれます。

  • 第1セクション(例:condition):この文字列
  • 第2セクション(例:postalcode):コンテキスト名
  • 第3セクション(例:f3,f7):フィールド名。複数の指定も可能
  • 第4セクション(例:*match*):演算子

最初の2つはいいとして、3つ目のフィールドは半角のカンマで区切って複数指定も可能です。複数指定をすると、それぞれのフィールドに対して同じ値の検索条件をORで与えます。なお、FileMakerのフィールド名に含まれる「::」は、「;;」に置き換えて指定します。4つ目の演算子は、一般的なものに加えて「*match」「match*」「*match*」の3つが用意されています。データベースエンジンに関わらずに、部分一致や前方一致などをこの演算子で記述します。

上記のテキストフィールドに、例えば「新宿」と入れてEnterキーを押すと、以下の検索条件がコンテキストに付加されて、再度検索を行い、そのコンテキストのエンクロージャー内が更新されます。

(f3 LIKE '%新宿%' OR f7 LIKE '%新宿%' OR f8 LIKE '%新宿%' OR f9 LIKE '%新宿%')

表示件数の制御

以下のポップアップメニューを選択すると、レコードの表示件数をポップアップの選択肢で指定でき、選択と同時にコンテキストが更新されます。「limitnumber」が決められた名前で、コロンより後にはコンテキスト名を記述します。changeイベントにより、コンテキストの更新します。

<select type="text" data-im="_@limitnumber:postalcode">...</select>

コンテキストの更新ボタン(検索ボタン)

以下のボタンをクリックすると、指定したコンテキストが更新されます。つまり、「検索」ボタンとして機能するということです。「update」が決められた名前で、コロンより後にはコンテキスト名を記述します。clickイベントにより、コンテキストの更新します。

<button data-im="_@update:postalcode">search</button>

並べ替えフィールドの指定

以下のSPANタグ内の▲をクリックすると、f3フィールドの昇順で並べ替えを行います。同一のコンテキストに対する「addorder」の機能を持った要素は連動します。たとえば「f3で昇順」の後に「f9の降順」を選択すると、「f9の降順」を最優先とし、続くキーとして「f3で昇順」を設定します。最後に設定した条件が最優先になるようになっています。このバインドはclickイベントに対応しており、クリックすれば指定したコンテキストが更新されます。

<span style="cursor: pointer" data-im="_@addorder:postalcode:f3:asc">▲</span>

@以降は、コロン(:)で4つのセクションに分かれます。

  • 第1セクション(例:addorder):この文字列
  • 第2セクション(例:postalcode):コンテキスト名
  • 第3セクション(例:f3):フィールド名。1つのみ
  • 第4セクション(例:asc):昇順ならasc、降順ならdesc

複数の検索条件に対する演算子

この項目の記述は、Ver.10の途中から実装した機能です。あるコンテキストtesttableに対して、以下のような3つの検索用テキストフィールドを用意したとします。ちょっと複雑ですが、これによって、どんなWHERE句が生成されるのかを具体的に紹介します。

まず、既定の状態では次のように、ローカルコンテキストを利用した検索条件などからWHERE句を生成します。このコンテキストは、num1 > 0 という検索条件をコンテキストに設定しているので、まず、それらの検索条件(つまり、ローカルコンテキストではない条件)があって、続いてANDで繋がれ、その後にローカルコンテキストによる条件が並びます。既定値では、ローカルコンテキストの検索条件は全てORで結ばれます。ローカルコンテキストによる条件の前の演算子は必ずANDになります。

SELECT * FROM `testtable` WHERE ((`num1` > 0)) 
    AND ( ((`vc1` LIKE '%test word%' OR `vc2` LIKE '%test word%' OR `vc3` LIKE '%test word%') 
         OR (`num1` >= 10) 
         OR (`num2` <= 99)))

ここでカスタマイズ可能な演算子を「OP1」「OP2」で記述すると、次のようになります。OP1は、フィールドをカンマで書き並べた場合のそれぞれの条件を結合する演算子です。一方、OP2は、異なるローカルコンテキストの値ごとに生成される条件を結合する演算子です。

SELECT * FROM `testtable` WHERE ((`num1` > 0)) 
    AND ( ((`vc1` LIKE '%test word%' OP1 `vc2` LIKE '%test word%' OP1  `vc3` LIKE '%test word%') 
         OP2  (`num1` >= 10) 
         OP2  (`num2` <= 99)))

OP1、OP2については既定値ではORですが、プロパティへの設定で演算子をANDに切り替えることもできます。INTERMediator.lcConditionsOP1AND、あるいはINTERMediator.lcConditionsOP2ANDというプロパティに対してtrueを代入することで、それぞれ、OP1とOP2の演算子をANDに切り替えることができます。プロパティへの設定は、例えば、ページ生成前に呼びされるdoBeforeConstructメソッド等に記述します。

INTERMediator.lcConditionsOP3ANDは、さらに検索条件の値に半角あるいは全角のスペースがあれば、それで区切って複数の検索条件を生成することができます。例えば、次のようにプロパティを設定したとします。

INTERMediatorOnPage.doBeforeConstruct = function () {
        INTERMediatorLog.suppressDebugMessageOnPage = true
        INTERMediator.lcConditionsOP1AND = false;
        INTERMediator.lcConditionsOP2AND = true;
        INTERMediator.lcConditionsOP3AND = true;
      }

この時、3つ目の検索条件は「test word」だったので、「test」と「word」でそれぞれで検索する条件を生成して、それらは、OP1、つまりORで検索条件を生成します。ここでのtestによる検索条件と、wordによる検索条件を結ぶ演算子はORになっていますが、INTERMediator.lcConditionsOP3ANDに代入する値を文字列の'and'にすれば、ORではなくANDで演算します。なお、INTERMediator.lcConditionsOP2ANDについてもtrueにしているので、num1 >= 10などの検索条件との結合演算子はANDが設定されています。

SELECT * FROM `testtable` WHERE ((`num1` > 0))
    AND ( (((`vc1` LIKE '%test%' OR `vc2` LIKE '%test%' OR `vc3` LIKE '%test%') 
             OR (`vc1` LIKE '%word%' OR `vc2` LIKE '%word%' OR `vc3` LIKE '%word%')) 
         AND (`num1` >= 10) 
         AND (`num2` <= 99)))

改めて、OP1、OP2、OP3の関係がわかりやすいSQL文を記述しておきます。

SELECT * FROM `testtable` WHERE ((`num1` > 0)) 
    AND ( (((`vc1` LIKE '%test%' OP1  `vc2` LIKE '%test%' OP1  `vc3` LIKE '%test%') 
             OP3  (`vc1` LIKE '%word%' OP1  `vc2` LIKE '%word%' OP1  `vc3` LIKE '%word%')) 
         OP2  (`num1` >= 10) 
         OP2  (`num2` <= 99)))

INTERMediator.lcConditionsOP1ANDとINTERMediator.lcConditionsOP2ANDについては、trueかfalseを入力しますが、規定値がfalseになっているので、trueにしたい場合だけ代入することでも構いません。INTERMediator.lcConditionsOP3ANDは前の2つのプロパティと異なり、false/true/'and'の3つの値のどれかです。trueの場合は単語分割するというフラグになっているので、この時のOP3演算子はORにはなります。OP3演算子をANDにしたい場合は、文字列の'AND'を指定します。

なお、Ver.7でINTERMediator.alwaysAddOperationExchangeを導入し、これにより、前述の説明のOP2をANDにするという機能を実装しました。Ver.10での改訂時に、INTERMediator.alwaysAddOperationExchangeが設定されていれば、INTERMediator.lcConditionsOP2ANDをtrueにするようにして、互換性を保っています。