FileMaker Ver18でようやく搭載されたwhile関数を使ってみた

ようやくというか、今頃というか、おそらく多くの人がカスタム関数でやりくりしていた繰り返し関数が正式に搭載されましたね。
今までFileMakerで繰り返し処理はLoopスクリプトしか用意されていなかったので、本当にやっと、ようやくという気がします。
まあLoopスクリプトでも個人的には不自由していませんでしたが、関数になればフィールド定義とかでも使えるようになるので多くの方にとって朗報でしょう。

で、ざっと触ってみた感じ、正直とっつきは悪いです。他の言語みたいに直感的にわからない。JSON関数も使いこなせるまで苦労しましたが、while関数もハードルは高いなと思いました。

公式に上がっているサンプルでは実用的でないと感じたので、自分なりに解釈してみました。

##while式の公式は

`While ( [ 初期変数 ] ; 条件 ; [ ロジック ] ; 結果 )`
[] で囲まれた初期変数とロジックは複数の記述が可能です。変数のスコープもLet関数に準じているようです。

##まず一番簡単な式を

```
While ( 
i = 0;//初期変数
i <10;//終了条件
i= i+1;//計算式
i  //リターンする結果
)
```

で答えは10

ここから発展させて運用するアプリに適用させて行くわけですが、自分的にはポータルを含む伝票情報のJSON化を真っ先に思い浮かべるので、それをやってみます。

伝票画面がこのようになっていて、ポータルに伝票明細があります。典型的なやつです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/171037/78e9da92-651b-b8fe-8a3d-b463630d42ac.png)

この伝票情報をwhile関数を使ってJSON化してみました。

繰り返しを使う部分は数が変動する明細行の部分ですので、そこをwhile関数で取得します。

```
While (
[ 
//変数初期値
i=0; //カウンター
#伝票明細=JSONSetElement ( "{}";"";"";3 ); //空のオブジェクトを用意しておく　3=JSONObject
#明細行=""
];

//終了条件
i   <   Count ( 明細::明細_ID ) ;//ポータルの行数

//計算式
 [ 
i= i + 1;

#明細行 = 
JSONSetElement (#明細行 ; 
["商品ID" ; GetNthRecord ( 明細::kf_商品ID;i );1];//1=JSONString
["数量" ; GetNthRecord ( 明細::納品数;i );1];
["販売区分" ; GetNthRecord ( 明細::販売区分;i );1]
);
#伝票明細 = JSONSetElement ( #伝票明細;"明細行["& i-1 & "]";#明細行;3 ) //3=JSONObject
]

//リターンする結果
; #伝票明細
)
```

以上の式で以下のようなJSONが取得できます。（結果をJSONFormatElementsで整形しています。）

```
{
	"明細行" : 
	[
		{
			"商品ID" : "201",
			"数量" : "10",
			"販売区分" : "売上"
		},
		{
			"商品ID" : "202",
			"数量" : "20",
			"販売区分" : "売上"
		},
		{
			"商品ID" : "203",
			"数量" : "1",
			"販売区分" : "売上"
		},
		{
			"商品ID" : "204",
			"数量" : "5",
			"販売区分" : "売上"
		},
		{
			"商品ID" : "205",
			"数量" : "5",
			"販売区分" : "売上"
		}
	]
}
```

伝票ヘッダ情報から全て取得するにはLet関数と絡めて以下のように。

```
Let(
[
//伝票の固定値
#伝票ヘッダ=
JSONSetElement ( "" ; 
["伝票ID";伝票::伝票_ID ;1];
["得意先ID"; 伝票::kf_得意先ID;2];
["日付";伝票::日付 ;1];
["伝票明細";"";3]//空のオブジェクトを用意しておく

 );

//伝票の変動値
#伝票明細=
While (
[ 
//変数初期値
i=0; 
#伝票明細=JSONSetElement ( "{}";"";"";3 ); //空のオブジェクトを用意しておく
#明細行=""
];

//終了条件
i   <   Count ( 明細::明細_ID ) ;

//計算式
 [ 
i= i + 1;

#明細行 = 
JSONSetElement (#明細行 ; 
["商品ID" ; GetNthRecord ( 明細::kf_商品ID;i );1];
["数量" ; GetNthRecord ( 明細::納品数;i );1];
["販売区分" ; GetNthRecord ( 明細::販売区分;i );1]
);
#伝票明細 = JSONSetElement ( #伝票明細;"明細行["& i-1 & "]";#明細行;3 ) 
]

//リターンする結果
; #伝票明細
)

];
JSONFormatElements ( JSONSetElement ( #伝票ヘッダ ; "伝票明細" ; #伝票明細 ; 3 ))
)
```

これで以下のようなJSONで伝票情報をまるっと取得できます。

```
{
	"伝票ID" : "103",
	"伝票明細" : 
	{
		"明細行" : 
		[
			{
				"商品ID" : "201",
				"数量" : "10",
				"販売区分" : "売上"
			},
			{
				"商品ID" : "202",
				"数量" : "20",
				"販売区分" : "売上"
			},
			{
				"商品ID" : "203",
				"数量" : "1",
				"販売区分" : "売上"
			},
			{
				"商品ID" : "204",
				"数量" : "5",
				"販売区分" : "売上"
			},
			{
				"商品ID" : "205",
				"数量" : "5",
				"販売区分" : "売上"
			}
		]
	},
	"得意先ID" : 301,
	"日付" : "2018/03/15"
}
```


正直Loopスクリプトで回して取得するのとあまり記述量が変わりませんし、Loopスクリプトの方が理解しやすいです。

ただ、今まではEvalutate関数を駆使した難解な再帰計算式に頼っていた部分をだいぶ理解しやすい形で利用できるようになったと思います。

ざっと触った感じなので勘違いな部分や冗長な部分があるかもしれませんが、待望の機能ですし、実用的なサンプルがまだ乏しいので取り急ぎアップしてみました。

###5/27　追記
上記Let関数とwhile関数の組み合わせは冗長でした。while関数だけで伝票全体をまるっと取得できますね。

```
While (
[ 
//伝票の固定値（上記Let関数で記述していた部分)
#伝票=
JSONSetElement ( "" ; 
["伝票ID";伝票::伝票_ID ;1];
["得意先ID"; 伝票::kf_得意先ID;2];
["日付";伝票::日付 ;1];
["明細行";"";4]);//空の配列を用意しておく

//変動値
i=0; 
#明細行=""
];

//終了条件
i   <   Count ( 明細::明細_ID ) ;

//計算式
 [ 
i= i + 1;

#明細行 = 
JSONSetElement (#明細行 ; 
["商品ID" ; GetNthRecord ( 明細::kf_商品ID;i );1];
["数量" ; GetNthRecord ( 明細::納品数;i );1];
["販売区分" ; GetNthRecord ( 明細::販売区分;i );1]
);
#伝票 = JSONSetElement ( #伝票;"明細行["& i-1 & "]";#明細行;3 ) 
]

//リターンする結果
; JSONFormatElements  (#伝票)
)

```

letで記述していた部分をwhile関数の初期変数の中に入れてやれば良いだけでした。結果は以下に。

```
{
	"伝票ID" : "103",
	"得意先ID" : 301,
	"日付" : "2018/03/15",
	"明細行" : 
	[
		{
			"商品ID" : "201",
			"数量" : "10",
			"販売区分" : "売上"
		},
		{
			"商品ID" : "202",
			"数量" : "20",
			"販売区分" : "売上"
		},
		{
			"商品ID" : "203",
			"数量" : "1",
			"販売区分" : "売上"
		},
		{
			"商品ID" : "204",
			"数量" : "5",
			"販売区分" : "売上"
		},
		{
			"商品ID" : "205",
			"数量" : "5",
			"販売区分" : "売上"
		}
	]
}

```

まあこういう場面では素直にLoopスクリプトを回す方がデバックもできていいとは思いますが、色々いじっていると理解が深まります。

FileMakerCommunityが現状使い物にならないので（米国のコミュニティにログインできない）、おそらくあちらでは活発に議論されているネタだろうと思いつつ指を加えて見てるのもあれですのでこちらで。
それにしても社長が変わってからすぐにFileMakerCommunity上の貴重な情報源を失った（ようなもの）代償は大きいですね。1ヶ月を過ぎてもまだゴタゴタしてますし。ダメなら諦めて以前の状態に戻せばいいと思うのですがね。過去ログは宝ですよ。