Platioでミニアプリを作成すると、以下の様な簡単な計算をしたくなることがあります。
Platio式は、このような計算をするための仕組みです。なお、Platio式は、JavaScriptの式に良く似ていますが、JavaScriptの全ての機能を使えるわけではありません。
はじめに、いくつかの具体的な例を見てみましょう。
数値計算フィールドの値プロパティには、Platio式を指定することができます。
例えば、単価フィールド(数値)、数量フィールド(数値)、合計フィールド(数値計算)があったとします。単価フィールドのカラムIDがc9dda012
、数量フィールドのカラムIDがc48fdfa4
のとき、合計フィールドの値プロパティに、c9dda012 * c48fdfa4
を指定すると、単価と数量を掛け合わせた結果が合計フィールドに設定されることになります。
同様にテキスト生成フィールドの値プロパティにも、Platio式を指定することができます。
例えば、姓フィールド(テキスト)、名フィールド(テキスト)と、名前フィールド(テキスト生成)があった場合に、名前フィールドの値プロパティに、c14d3611 + " " + c42b023c
を指定すると、姓と名を空白文字で繋げた名前が名前フィールドに設定されることになります。ただし、c14d3611
は姓フィールドのカラムID、c42b023c
は名フィールドのカラムIDとします。
Webhookで外部のサーバーに通知を送るときには、Webhook プログラミングガイドで説明されている様に、決まったJSON形式でレコードがサーバーに送られます。しかし、他のサービスに直接接続する場合には、そのサービスが必要としている形式に変換する必要があります。Platio式を使用して、この変換を行うことができます。
例えば、以下の様な形式のJSONを受け取るサービスに接続することを考えます。
{
"subject": "<ここに件名>",
"body": "<ここに本文>"
}
subject
やbody
に、件名フィールドや本文フィールドで指定された値を設定したい場合には、以下の様な変換用のPlatio式を指定します。cff8e7af
とc80c825e
は、それぞれ件名フィールドと本文フィールドのカラムIDです。
{
"subject": cff8e7af,
"body": c80c825e
}
Webhookを使って、レコードが特定の条件を満たした時にのみ、サーバーに通知を送ることもできます。
例えば、温度フィールドの値が40度を超えたときにのみ通知を送りたい場合、条件としてc978eb40 > 40
を指定します。c978eb40
は、温度フィールドのカラムIDです。
少し複雑な数値計算フィールドを考えてみましょう。商品名と値段を一緒に選択できる複数テキスト選択フィールドがあります。選択できる値は、商品A (¥1000)
、商品B (¥500)
、商品C (¥800)
のようになっているとします。ここで、数値計算フィールドに選択された商品の合計金額を設定するには、以下の様なPlatio式を使用します。c0be75a4
は、複数テキスト選択フィールドのカラムIDです。
sum(map(c0be75a4, value => number(replace(value, /.*\(¥(\d+)\)$/, "$1"))))
Platio式を評価するときには、いくつかの引数が渡されますので、それらの引数を式の中で使用することができます。上の例では、カラムのIDを式の中で使用していましたが、これらが引数です。
フィールドの値を計算したり、Webhookの変換・条件にPlatio式を使うときには、カラムのIDを名前とする引数が渡されます。それぞれの引数の値は、そのカラムの値をPlatio式で扱いやすい様に変換した値になります。その他に、record
という名前の引数が渡されますが、この引数にはレコードのJSON表現がそのまま渡されます。
例として、テキストフィールドと複数数値選択フィールドを一つずつ持つレコードを考えます。それぞれのカラムのIDは、c63ae565
とc00bb867
とします。この場合、以下の3つの引数が渡されます。
c63ae565
Test Value
c00bb867
[10, 15, 20]
record
{
"values": {
"c63ae565": {
"type": "String",
"value": "Test Value"
},
"c00bb867": {
"type": "Array",
"value": [
{
"type": "Number",
"value": 10
},
{
"type": "Number",
"value": 15
},
{
"type": "Number",
"value": 20
}
]
}
}
}
上記の様に、カラムのIDを使った引数を使うと、扱いやすい形でレコードの値を参照することができます。例えば、record.values.c00bb867.value[1].value
の代わりにc00bb867[1]
を使用することができます。通常は、c63ae565
やc00bb867
を使用しますが、それ以上の情報を使用したい場合には、record
を使用することができます。
この例の様に、ネストしているオブジェクトの引数を参照するときには、.
を使用します。また、配列の要素を参照するには、0から始まるインデックスを、[]
内に指定します。
元の値からカラムのIDを使った引数の値にするときに、どの様な変換が行われるかについては、型と値を参照してください。
また、record
引数の形式は、Platio API
リファレンスを参照してください。また、値の形式については、型と値を参照してください。
カラムのIDで引数を参照する場合に、そのカラムに値が指定されていない場合には、その型のデフォルトの値を取得します。例えば、テキストフィールドの値が指定されていない場合には空文字列を、数値フィールドの値が指定されていない場合には0
を取得します。
各型のデフォルト値については、型と値を参照してください。
Platio式では以下の型が扱えます。各型の値が取れる値は、JavaScriptと同等です。
式に現れる値は、これらの型のいずれかの値か、null
またはundefined
になります。
以下の型にはリテラル表現があります。
JavaScriptの文字列リテラルと同様ですが、ダブルクオートで括る必要があります(シングルクオートはサポートしていません)。文字列中のエスケープの方法もJavaScriptと同様です。
"abc"
"\""
"\n"
10進の小数点表記のみが使用できます。指数部を指定した1e10
の様な表現は使用できません。
10
103.51
-435.2
JavaScriptの真偽値と同様です。
true
false
リテラルはありません。
JavaScriptの配列と同様です。スプレッド演算子を使用することができます。
[1, 2, 3]
["a", "b", "c"]
[1, 2, ...[3, 4]]
["a", "b", x] // xは配列
JavaScriptのオブジェクト同様ですが、キーがアルファベット以外を含むときにはダブルクオートで括る必要があります。スプレッド演算子を使用することができます。
{ x: 10, y: "abc" }
{ "x.y": 20 }
{ x: 10, y: "abc", ...{ z: true } }
{ x: 10, y: "abc", ...z } // zはオブジェクト
JavaScriptの正規表現と同様です。
/pattern/
/pattern/ig
null
とundefined
null
とundefined
をリテラルとして使用することができます。
以下の演算子が使用できます。
+
-
*
/
%
**
||
&&
!
==
!=
<
<=
>
>=
?:
(三項演算子)これらの演算子の動作および優先度は、以下の例外を除いてJavaScriptと同様です。
==
と!=
は、JavaScriptの===
および!==
にあたる厳密な比較を行います。**
の基数部分で単項演算子を使用できます。例えば、-2 ** 3
は、-(2 ** 3)
として扱われます。三項演算子の条件として使われたり、フィールドの条件付き表示に式を指定した場合など、値を真偽値に変換する場合には、以下のように行われます。
undefined
とnull
は、false
に変換されます。true
、空の場合にはfalse
に変換されます。0
またはNaN
の場合にはfalse
、それ以外の場合にはtrue
に変換されます。true
に変換されます。map
やfilter
などには、定義した関数を渡すことができます。
関数は、JavaScriptのアロー関数と同様の形式で定義します。例えば、map([1, 2, 3], n => n * 2)
の、n => n * 2
は引数の値を2倍する関数です。
式の中では以下の関数を呼び出すことができます。関数を呼び出すには、floor(c3ef4f5d, 2)
のように、関数名の後ろに()
で括られ,
で区切られた引数を指定します。
addDate
指定された日時・文字列・数値に、指定された時間を加えます。加える時間は、数値で2番目の引数として指定します。3番目の引数には、指定した時間の単位を指定します。指定できる単位は、
days
, hours
, minutes
,
seconds
, milliseconds
のいずれかで、それぞれ日数、時間、分、秒、ミリ秒を意味します。
日時を指定した場合、指定された時間を加え、日時を返します。単位を指定しなかった場合には、
milliseconds
が指定されたものとして扱います。
数値を指定した場合、その数値を、1970年1月1日 00:00:00
(UTC)からのミリ秒として日時型に変換した上で、指定された時間を加え、1970年1月1日
00:00:00
(UTC)からのミリ秒を数値として返します。単位を指定しなかった場合には、
milliseconds
が指定されたものとして扱います。
YYYY-MM-DD
形式の文字列を指定した場合、指定された日付に指定された時間を加え、
YYYY-MM-DD
形式の文字列を返します。単位を指定しなかった場合には、 days
が指定されたものとして扱います。
HH:mm:ss
形式の文字列を指定した場合、指定された時間に指定された時間を加え、
HH:mm:ss
形式の文字列を返します。単位を指定しなかった場合には、
milliseconds
が指定されたものとして扱います。24時間を超えた場合には、24時間で転回します。例えば、
"28:00:00"
の代わりに "04:00:00"
を返します。
addDate(parseDateTime("2021-12-08T10:34:45.000Z"), 10 * 60 * 60 * 1000)
// => 2021年12月8日 20:34:45 (UTC)を表す日時型の値
addDate(parseDateTime("2021-12-08T10:34:45.000Z"), 3, "days")
// => 2021年12月11日 10:34:45 (UTC)を表す日時型の値
addDate(1638959685000, 10 * 60 * 60 * 1000)
// => 1638995685000
addDate(1638959685000, 3, "days")
// => 1639218885000
addDate("2021-12-08", 3)
// => "2021-12-11"
addDate("2021-12-08", 4 * 24 * 60 * 60 * 1000, "milliseconds")
// => "2021-12-12"
addDate("10:34:45", 10 * 1000)
// => "10:34:55"
addDate("10:34:45", 15, "hours")
// => "01:34:55"
ceil
指定した精度で切り上げた値を返します。
ceil(10.5)
// => 11
ceil(10.513, 2)
// => 10.52
contains
文字列または配列・オブジェクトが指定された値を含んでいるかどうかを返します。
contains("abcdefg", "cde")
// => true
contains("abcdefg", "x")
// => false
contains([1, 2, 3], 3)
// => true
contains([1, 2, 3], [2, 3])
// => false
contains({ x: 1, y: 2 }, 2)
// => true
count
文字列の長さ、または、配列、オブジェクトの要素数を取得します。
count("abcdefg")
// => 7
count([1, 2, 3])
// => 3
count({ x: 1, y: 2 })
// => 2
encodeURIComponent
文字列をURIに埋め込むためにエンコード処理を行います。
encodeURIComponent("100% ABC")
// => "100%25%20ABC"
encodeURIComponent("こんにちは")
// => "%E3%81%93%E3%82%93%E3%81%AB%E3%81%A1%E3%81%AF"
escapeHtml
文字列をHTMLとしてエスケープ処理します。以下の変換が行われます。
<
-> <
>
-> >
&
-> &
"
-> "
escapeHtml("<A & B>")
// => "<A & B>"
filter
配列またはオブジェクトの各値に関数を適用し、真となる値を返した値のみを含む配列またはオブジェクトを返します。
filter([1, 2, 3], n => n % 2 == 1)
// => [1, 3]
filter({ x: 1, y: "foo", z: 300 }, v => count(string(v)) == 3)
// => { y: "foo", z: 300 }
floor
指定した精度で切り捨てた値を返します。
floor(10.5)
// => 10
floor(10.513, 2)
// => 10.51
formatDateTime
指定された日時型の値をフォーマットして文字列に変換します。フォーマットを指定しない場合には、YYYY-MM-DD'T'HH:mm:ss.SSS'Z'
でフォーマットされます。使用できるフォーマットは、Formatを参照してください。
フォーマットを指定した場合、タイムゾーンをAsia/Tokyo
のように指定することができます。タイムゾーンが指定されない場合、実行されている環境のタイムゾーンでフォーマットされます(サーバー上で実行された場合にはアプリケーションのタイムゾーン、アプリ内で実行された場合にはデバイスのタイムゾーンの指定を使用します)。
formatDateTime(parseDateTime("2018-06-30T12:30:00.000Z"))
// => "2018-06-30T12:30:00.000Z"
formatDateTime(parseDateTime("2018-06-30T12:30:00.000Z"), "YYYY/MM/DD HH:mm:ss")
// => "2018/06/30 12:30:00"
formatDateTime(parseDateTime("2018-06-30T12:30:00.000Z"), "YYYY/MM/DD HH:mm:ss", "Asia/Tokyo")
// => "2018/06/30 21:30:00"
formatNumber
指定された数値型の値をフォーマットして文字列に変換します。
二番目の引数として、以下のオプションの組み合わせを指定することができます。
useGrouping
グループ化する区切り記号を使用するかどうかを指定します。指定しない場合には、区切り記号を使用します。
minimumIntegerDigits
整数部に使用する最小桁数です。指定しない場合には、1
になります。
minimumFractionDigits
小数部に使用する最小桁数です。指定しない場合には、0
になります。
maximumFractionDigits
小数部に使用する最大桁数です。指定しない場合には、minimumFractionDigits
と3
の大きい方になります。
指定可能な値の範囲などの詳細は、Intl.NumberFormatを参照してください。
formatNumber(1234.56)
// => "1,234.56"
formatNumber(1234.56, { useGrouping: false })
// => "1234.56"
formatNumber(1234.56, { minimumIntegerDigits: 5 })
// => "01,234.56"
formatNumber(1234.56, { minimumFractionDigits: 3 })
// => "1,234.560"
formatNumber(1234.56, { maximumFractionDigits: 1 })
// => "1,234.5"
formatTime
数値、または文字列で指定された時間を、指定されたフォーマットで文字列に変換します。時間は、1日の初めからの経過時間をミリ秒単位の数値で、もしくは、HH:mm:ss
形式の文字列で指定します。使用できるフォーマットは、Formatを参照してください。
formatTime((9 * 60 + 30) * 60 * 1000, "HH:mm:ss")
// => "09:30:00"
formatTime("08:34:00", "H:mm")
// => "8:34"
formatTime("13:30:00", "Ah時mm分")
// => "午後1時30分"
map
配列またはオブジェクトの各値に関数を適用し、配列またはオブジェクトを返します。
map([1, 2, 3], n => n * 2)
// => [2, 4, 6]
map({ x: 10, y: "foo" }, v => string(v))
// => { x: "10", y: "foo" }
match
指定された文字列を正規表現にマッチさせて結果を返します。結果は、文字列の配列で返されます。最初の要素は、正規表現全体にマッチした文字列が、それ以降の要素には、正規表現中のグループにマッチした文字列が入ります。ただし、正規表現にg
フラグが指定されている場合には、正規表現全体にマッチした文字列が配列として返されます。マッチしない場合には、null
が返されます。
match("ABC", /B/)
// => ["B"]
match("ABC", /(.)B/)
// => ["AB", "A"]
match("ABCBA", /(.)B/g)
// => ["AB", "CB"]
match("ABC", /X/g)
// => null
number
引数を数値に変換します。
number("10.5")
// => 10.5
number(true)
// => 1
number(parseDateTime("2018-06-30T12:30:00.000Z"))
// => 1530361800000
number("abc")
// => NaN
parseDate
文字列を渡すと、YYYY-MM-DD
形式でフォーマットされた文字列を、指定されたタイムゾーンで日時型に変換します。タイムゾーンが指定されない場合、実行されている環境のタイムゾーンで変換されます(サーバー上で実行された場合にはアプリケーションのタイムゾーン、アプリ内で実行された場合にはデバイスのタイムゾーンの指定を使用します)。
parseDate("2018-06-30")
// => 2018年6月30日 00:00:00 (UTC)を表す日時型の値
parseDate("2018-06-30", "Asia/Tokyo")
// => 2018年6月29日 15:00:00 (UTC)を表す日時方の値
parseDate("2018/06/30")
// => undefined
parseDateTime
文字列を渡すと、YYYY-MM-DD'T'HH:mm:ss.SSS'Z'
形式でフォーマットされた文字列を日時型に変換します。数値を渡すと、1970年1月1日
00:00:00 (UTC)からのミリ秒として日時型に変換します。
parseDateTime("2018-06-30T12:30:00.000Z")
// => 2018年6月30日 12:30:00 (UTC)を表す日時型の値
parseDateTime(1530361800000)
// => 2018年6月30日 12:30:00 (UTC)を表す日時型の値
parseDateTime("2018/06/30 12:30:00")
// => undefined
parseTime
文字列を渡すと、HH:mm:ss
形式でフォーマットされた時間をミリ秒単位で数値に変換します。
parseTime("09:00:00")
// => 32400000
parseTime("9:00:00")
// => undefined
quote
引数を""
で括ります。"
と\
は\
でエスケープされます。引数が文字列以外の場合には、文字列に変換されます。
quote("abc")
// => "\"abc\""
quote("a\"b\\c")
// => "\"a\\\"b\\\\c\""
quote(10.5)
// => "10.5"
quote(true)
// => "true"
quote([1, 2, 3])
// => "1,2,3"
quote({ x: 1 })
// => "[object Object]"
reduce
配列またはオブジェクトの各値に関数を適用して畳み込みます。
reduce([1, 2, 3], (a, n) => a + n, 0)
// => 6
reduce({ x: 10, y: "foo" }, (a, v) => a + v, "")
// => "10foo"
replace
指定された文字列が指定された正規表現にマッチした部分を、指定された文字列で置き換えます。正規表現にマッチしない場合には、元の文字列が返されます。
正規表現にg
フラグが指定されていない場合には、最初にマッチした文字列が置き換えられます。g
フラグが指定されている場合には、マッチした全ての文字列が置き換えられます。
replace("ABC", /B/, "XYZ")
// => "AXYZC"
replace("ABC", /X/, "PQR")
// => "ABC"
replace("ABC", /^(.)/, "$1X")
// => "AXBC"
replace("A B C", / /g, "")
// => "ABC"
round
指定した精度で四捨五入した値を返します。
round(10.5)
// => 11
round(10.513, 2)
// => 10.51
sort
配列をソートします。配列以外を渡すと、undefined
を返します。
比較関数を渡さなかった場合、配列の全ての要素が数値の場合には数値として、それ以外の場合には要素を文字列に変換した上で大小が比較され、ソートされます。
比較関数を渡す場合には、比較関数に渡された一番目の引数の値が二番目の引数よりも前に位置する場合には負の値を、一番目の引数の値が二番目の引数よりも後ろに位置する場合には正の値を、元の順序を保持する場合には0
を返すようにします。
sort([51, 9, 10, 9])
// => [9, 9, 10, 51]
sort(["51", "9", "10", "9"])
// => ["10", "51", "9", "9"]
sort(["abc", "d", "ef", "ghi"], (lhs, rhs) => count(lhs) - count(rhs))
// => ["d", "ef", "abc", "ghi"]
string
引数を文字列に変換します。
string("abc")
// => "abc"
string(10.5)
// => "10.5"
string(true)
// => "true"
string([1, 2, 3])
// => "1,2,3"
string({ x: 1 })
// => "[object Object]"
substring
文字列から、指定された位置、長さの文字列を取得します。位置や長さは文字単位で指定します。
位置は、0ベースのインデックスで、0以上の整数を指定する事ができます。整数以外や負の整数を指定するとundefined
を、文字列の長さより大きい値を指定すると、空文字列を返します。
長さは、0以上の整数を指定する事ができます。整数以外や負の整数を指定するとundefined
を返します。位置と長さの合計が文字列の長さより大きい場合には、文字列の最後までを返します。
substring("abc123", 0, 2)
// => "ab"
substring("abc123", 2, 10)
// => "c123"
substring("abc123", 10, 2)
// => ""
sum
配列内の数値の合計を計算します。
sum([1, 2, 3, 4, 5])
// => 15
toLowerCase
文字列を小文字に変換します。
toLowerCase("ABCabc123")
// => "abcabc123"
toLowerCase("ABCabc123")
// => "abcabc123"
toUpperCase
文字列を大文字に変換します。
toUpperCase("ABCabc123")
// => "ABCABC123"
toUpperCase("ABCabc123")
// => "ABCABC123"
Platio式は、JavaScriptと似ていますが、一部異なる部分があります。また、JavaScriptの全ての機能が使えるわけではありません。ここでは、JavaScriptと異なる部分のいくつかを挙げます。ここで挙げた以外にも違いはありますので注意してください。
Platio式は、式のみが使用でき、文は使用できません。例えば、10 + 5; "test"
はPlatio式では不正な式になります。また、文を必要とする、for
,
if
, while
などの制御構文は使用できません。
Platio式では、文字列のリテラルは、ダブルクオートで("
)で括ります。シングルクオート('
)は使用できません。例えば、"test"
は正しい式ですが、'test'
は不正な式です。
オブジェクトや配列の要素を.
で区切った名前で参照できるのは、引数を参照する場合のみです。例えば、record
が引数の時に、record.values.c7faa419.value
は正しい式ですが、{ key: "value" }.key
は不正な式です。引数以外のオブジェクトの値を参照するには、{ key: "value" }["key"]
の様にキーを[]
内に指定します。
undefined
やnull
のプロパティの参照JavaScriptでは、undefined
やnull
のプロパティを参照しようとするとエラーになりますが、Platio式ではundefined
になります。例えば、cb3bbfb0
というカラムIDのフィールドに値が設定されていない時、record.values.cb3bbfb0.value
はundefined
になります。
Platio式の==
と!=
は厳密な比較です。JavaScriptの===
と!==
にあたります。
Platio式では、オブジェクトのメソッドを呼び出すことはできません。例えば、date.getTime()
は不正な式です。
Platio式では、関数は全てアロー関数の構文を使用して定義します。例えば、map([1, 2], n => n * 2)
は正しい式ですが、map([1, 2], function(n) { return n * 2 })
は不正な式です。
NaN
とInfinite
Platio式を評価した結果がNaN
,
Infinite
または-Infinite
になった場合、undefined
に変換されます。