[ODC]JavaScript要素にObject型として渡した値の詳細を確認する (主に基本データ型)

OutSystems 11のExtensionと違い、ODCのExternal Logicには（ドキュメントによると）Object型を渡せない。
その代わりに、クライアントサイドでJavaScript要素にObject型を渡すことで代替できないか検討してみた。

ただ、検討していくと、Listにするとだいぶ複雑な構造になってしまうことがわかった。そこで、この記事では基本データ型、シンプルなRecord、階層になっていないStruct,単独のEndityを対象にし、Listの構造は別の機会に考える。


# 環境情報
ODC Studio(Version 1.3.8)

# 確認方法
## JavaScriptでの型を調べる
typeofにInput Parameterを渡して、JavaScript上の型を取得する。

## プロトタイプ名を調べる
Input Parameterのプロトタイプ（\_\_proto\_\_）のconstructor.nameから、プロトタイプ名を取得する。

## Listの場合の各レコードの型を調べる
この項目は、元々Listの場合の構造を調べたくて検討していた。
ただ、Listの場合構造が複雑すぎる事がわかり、この記事ではListを扱わないことにしたので意味がなくなった。
一応残してあるが、Input Parameterの_recordTypeでListの各要素の情報が得られる。

## サンプルコード
以下のJavaScriptコードを配置したJavaScript要素のInput Parameter (Object型）にToObject Built-in Functionを使って渡す。

``` js
function printObjectInfo(obj) {
    console.log("typeof: " + typeof(obj) + ", " + 
                "__proto__.constructor.name: " + obj.__proto__.constructor.name + ", " +
                "_recordType: " + (obj._recordType ? obj._recordType.name : "値無し"));
}
printObjectInfo($parameters.BinaryDataVar);
```

# 確認結果の整理

| データの種類 | 型(JavaScript) | プロトタイプ名 | List各要素の型 | 備考 |
|:-:|:-:|:-:|:-:|:-|
| Binary Data  | object | As | 値無し | _contentにBASE64エンコードされたバイナリデータが含まれる  |
| Boolean  | boolean | Boolean | 値無し |   |
| Currency  | object | Ai | 値無し | toNumber()やtoString()で値を取り出せる。internalValue.dには配列（第1要素が整数部、第2要素は小数部）  |
| Date  | object | Ns | 値無し | date.toISOString()など文字列として値を取得できる関数がいくつかある |
| DateTime  | object | Ns | 値無し | date.toISOString()など文字列として値を取得できる関数がいくつかある  |
| Decimal  | object | Ai | 値無し | toNumber()やtoString()で値を取り出せる。internalValue.dには配列（第1要素が整数部、第2要素は小数部）  |
| Email  | string | String | 値無し |   |
| Integer  | number | Number | 値無し |   |
| Long Integer  | object | os | 値無し | toNumber()やtoString()で値を取り出せる。toNumberなら精度に注意  |
| Text  | string | String | 値無し |   |
| Time  | object | Ns | 値無し | date.toISOString()など文字列として値を取得できる関数がいくつかある  |
| Record | object | RC_3e4f2ae63348195d56955f5c0b2d83c4Inner | 値無し | プロトタイプの戦闘にRCがつく。data._にデータが含まれる  |
| Structure：シンプル | object | ST_e6a2a95c83d67816ffdf3e9ef49ad3cdStructureInner | 値無し | プロトタイプの先頭にSTがつく。data._にデータが含まれる  |
| Entity：単独・１レコード | object | RC_4c040c61147b77ac977cee1a165ffad1Inner | 値無し | プロトタイプの先頭にRCがつく。data._.\<Entity名\>._にデータが含まれる  |

- Boolean, Email, Integer, TextはJavaScriptの対応する型が使われる
- その他の型については、独自と思われるプロトタイプを使っている
    - バイナリ：As
    - 数値：Ai
    - 数値の中でLong Integer：os
    - 日時：Ns

# Binary Data型
_contentにバイナリデータが含まれる (BASE64形式）。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332987/cf7b3301-fb4d-50d4-f88b-ccb95b2b0869.png)

Binary Dataと判定するのに使えそうなのは、プロトタイプ名=Asか、持っている関数か。

# 数値型
## Currency、Decimal型
internalValue.dには配列（第1要素が整数部、第2要素は小数部）で値が入っているようだ。しかし、toNumber()を呼ぶことで実際の値を取り出せるようなのでそのほうが良さそう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332987/e8a9fd61-ec33-688c-a1cd-432c92876520.png)

```
$parameters.CurrencyVar.toNumber()
123.45
$parameters.CurrencyVar.toString()
'123.45'
```

Currency, Decimal型のいずれかと判断するには、プロトタイプ=Aiが使えそう。ただし、CurrencyとDecimalのどちらであるかを正確には判断できない。

## Long Integer型
Long Integer型のinternalValueにhigh/lowで持っている。長い数値をこういう組み合わせで表現する方法があるらしい。しかし、toString()やtoNumber()で値を抜き出すのが良さそう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332987/f714a52a-1382-bc80-d050-9928a1ca3418.png)

例として、「5645245584135987412」という値をToObjectをしてJavaScript要素に渡したものに対してtoNumberとtoStringを試したもの。toNumberだとNumber型の精度の関係かもとの値がそのまま取れるとは限らないようだ。

```
$parameters.LongIntegerVar.toNumber()
5645245584135987000
$parameters.LongIntegerVar.toString()
'5645245584135987412'
```

Long Integer型と判定するには、プロトタイプ=osが使えそうだが、名前が「os」だとうっかりOutSystems内の別のライブラリとかで使われているかもしれない。internalValue.lowやinternalValue.highがあることも合わせて確認したほうがいいかも。

# 日時型
Date, Date TIme, Time型の場合、dateプロパティが値と各種の関数を持っている。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332987/fb2a59f0-f461-694e-1eb8-709383ced537.png)

ただ、以下のように、元の型がDate, Date Time, Time型のいずれであっても、関数を呼んだ結果が同じになる。
```
$parameters.DateVar.toString()
'2023-12-30T15:00:00.000Z'
$parameters.DateTimeTest.toString()
'2023-12-30T15:22:36.202Z'
$parameters.TimeVar.toString()
'1899-12-31T16:23:45.000Z'
```
「Date, Date TIme, Time型のいずれかであるか」はプロトタイプがNsであることで判定できる。
ただ、各種プロパティを見る限り、その中のどれであるかを判別するのは難しそう。


# Record

以下のRecord型のLocal Variableを作成して確認。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332987/7fc6ce20-a923-dd85-657d-8e76ae2ac980.png)

- プロトタイプの先頭は「RC」で始まる
- 渡したデータはdata._の下にオブジェクトとして渡されている
- RecordのAttributeは、名前の先頭を小文字にした上で、「Attr」をつけた名前のプロパティに設定される（OutSystems上で「Text」の属性は「textAttr」プロパティにマッピングされる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332987/c0000e76-a3fd-dafa-8b8e-f238b6cf5b57.png)
- プロトタイプのconstructor.Attributesに各Attribute情報を持っている。その中にdataTypeというものがある。少なくとも基本データ型に対応する値は決まっていそうだが、ドキュメントは見つからない
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332987/cde44493-8cd7-ef9a-8232-10b28409b697.png)

# Struct
- プロトタイプの先頭は「ST」で始まる
- データや属性情報についてはRecordと同じ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332987/7ef3e8fd-650a-6e28-4105-2842b34972fb.png)


# Entity
- プロトタイプの戦闘は「RC」で始まる
- 渡したデータはdata._.\<Entity名\>._の下にオブジェクトとして渡されている
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332987/5d9681c8-27f7-3535-34ff-8399a42e4102.png)
- Entityの場合は、プロトタイプのconstructor.Attributesの配列要素にcomplexTypeプロパティに定義が含まれる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332987/dd0f485c-ebab-2306-a540-63ec03c5e311.png)


# 参考：O11のExtensionの場合の調査結果
[ExtensionのC#コードに渡ってくるデータの型について](https://qiita.com/jyunji_watanabe/items/624aeba2e1293ae0f7e8)