Oracle APEX で 調整さんのマネをしてみる

最近、ローコード開発、ノーコード開発に興味を持っていますが、下記記事が気になりました。

[誰も話題にしないノーコードの制約](https://recruit.gmo.jp/engineer/jisedai/blog/no-code-restriction/)
「ノーコードの大きな壁にぶち当たった。。」

大きなテーマとして掲げられているのが、ノーコードルールのデメリットとして挙げられている、「できないことがわからない」ということかと思います。
そこで思ったこと。できるできないという観点は正しい？できることがわかったら次のステップに進める？

## Oracle APEX ならできるかな

Oracle APEXはノーコードではありません。と思っています。少なくとも、全くコードを書けないと言って良い[Glide](https://www.glideapps.com/)などとは違います。けどGlideだって、スプレッドシート側でいかにFunctionを駆使するか、みたいな面もあるので、それはコードではないのか、という気もします。結局相対的な概念でしょう。
話を戻して、Oracle APEX で下記のように調整さんのマネをするのは、ノーコード・ローコードでしょうか、がっつりコードでしょうか。

### 画面の作成

以下、試行錯誤して作った後に振り返りながら書いているので、細かいところは不正確かもしれません。ゆるく読んでください。

Oracle Cloud にサインインして、ATP（メニュー > Oracle Database > Autonomous Transaction Processing）を開きます。
以前作ったものが時間が経って停止していたので、起動しました。全く新規の場合はDBを作成します。
DBを開いて、ツール タブ > Oracle Application Express でOracle APEXに入ります。

アプリケーション・ビルダー > 作成 > 新規アプリケーション
でアプリケーションを作成します。

<img width="400" alt="スクリーンショット 2020-07-11 10.27.43.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/77307/3fe9e1f2-fe9e-921a-2e8d-0561e6943950.png">

外観を作るのは楽しいので、いろいろ試してみるのが良いと思います。
この辺は、[前の記事](https://qiita.com/JQinglong/items/abcf1cab6543aaa58000)もどうぞ。
<img width="400" alt="スクリーンショット 2020-07-11 10.30.20.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/77307/18c804d5-bb24-c1bf-188c-4945076ee2ce.png">

フォームページを作るためには表が必要なので表が必要なので、そのまま、アプリケーションの作成を行います。
とりあえず、真っ白なページは出来上がります。

<img width="400" alt="スクリーンショット 2020-07-11 10.37.45.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/77307/d9c52cbd-b4f0-d196-088e-93367fec4b30.png">
<img width="400" alt="スクリーンショット 2020-07-11 10.39.06.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/77307/d3d6246a-276e-b447-ab05-125b5144bb0e.png">

表を作ります。
SQLワークショップ > ユーティリティ > オブジェクトの作成 > 表
（表明はeventじゃなくてeventsがよかったな・・・）

<img width="400" alt="スクリーンショット 2020-07-11 11.37.18.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/77307/667fea71-9456-1f80-231c-07e5dfc8d5af.png">

<img width="400" alt="スクリーンショット 2020-07-11 11.44.37.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/77307/37b769a1-f0f4-549e-f538-da1ff7c9237a.png">

途中は割愛。出欠入力の方もテーブルは作ったけど割愛。

表を作ったら、それに基づくフォームを追加します。

ページ・デザイナからフォーム追加です。

<img width="400" alt="スクリーンショット 2020-07-11 12.20.19.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/77307/09848018-726a-fe15-c9b5-0054647e5101.png">

ここまではノーコードで異論ないと思います。

### 画面操作

上記フォーム追加で追加できるのは、表の定義に従って自動的に選定されたコントロールなので、これをカスタマイズします。
EVENT_IDや、CREATED_DATEは画面で入力するのではなく、データ登録時に自動更新したいので、非表示にします。CSSクラスに「u-VisuallyHidden」を指定することで非表示になりました。

<img width="400" alt="スクリーンショット 2020-07-14 21.11.31.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/77307/6195d44e-58b7-dd76-2e3b-2804c04ce074.png">

いよいよ本題です。
調整さんでは、カレンダーをクリックして、候補日時を追加していけます。テキストエリアに、 選択した日付に「19:00」が付加され、改行されて、複数行追加していくことができます。
これを実現してみます。
が、当然これはノーコードの範囲を超えます。これを「できないこと」と判断して、要件から外すのも一つの方針だと思います。が、個人的には、これは「できること」に入って欲しいなと思います。APEXはこの程度のことには対応可能な仕組みが用意されています。

まず、「日付ピッカー」アイテムを追加します。

<img width="320" alt="スクリーンショット 2020-07-14 21.18.38.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/77307/20397b57-ed9d-156b-9287-845f26bb93b2.png">

そして、これの変更時にイベントが発生するように、動的アクションを追加します。
日付ピッカーのカレンダーをクリックすると、テキストボックスに日付が値としてセットされますので、この値が変更されたというイベントを拾います。
<img width="400" alt="スクリーンショット 2020-07-14 21.21.12.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/77307/f2332695-a9bd-b7bb-9e74-345b5285a89f.png">

さらにそのイベントが発生した場合の処理として、「JavaScriptの実行」アクションを追加します。
<img width="400" alt="スクリーンショット 2020-07-14 21.24.44.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/77307/485383f8-8bc1-be83-8083-a0a95add6dee.png">

JavaScriptの記述は下記の通りです。

```js:
if($v('P1_DATETIMES')) {
    $s('P1_DATETIMES', $v('P1_DATETIMES') + '\n' +  $v('P1_NEW') + ' 19:00');
}  else {
    $s('P1_DATETIMES', $v('P1_NEW') + ' 19:00');
}
```

これを書くとなるとノーコードではないですかね。ローコードの範囲内ですかね。

日付ピッカーのテキストボックスは不要なので、非表示にしておきます。

### データ登録

では、この画面で入力した値を、DBに登録します。

１回の操作で二つの表にデータ登録を行います。もちろん、APIを用意すればそちらでいかようにもできるわけですが、ローコードという話とは関係なくなってしまうので、ローコードツールを活用する方法で行きます。
ここがAPEXならではですが、「PL/SQLコードの実行」という動的アクションを指定することができます。

ですので、まず、ファンクション（最初プロシージャを作りましたが、生成したEVENT_IDを受け取る必要があると思い、ファンクションに変更しました）を作ります。

```sql:
create or replace function "CREATEEVENT"
(p_event_name IN VARCHAR2,
p_memo IN VARCHAR2,
p_datetimes IN VARCHAR2) return number
is
    v_eventid PLS_INTEGER;
    v_pos PLS_INTEGER;
    v_pos_next PLS_INTEGER;
    v_datetime VARCHAR2(32767);
begin
    v_pos := 1;

    -- event
    insert into event(event_name, memo, created_date)
    values(p_event_name, p_memo, SYSDATE())
    returning event_id into v_eventid;

    -- event_date
    DBMS_OUTPUT.PUT_LINE(length(p_datetimes));

    if (length(p_datetimes) > 0 ) then
        v_pos := 1;
        while (v_pos <= length(p_datetimes) ) loop
            v_pos_next := instr ( p_datetimes, CHR(10), v_pos + 1 );
            if v_pos_next = 0 then
                v_pos_next := length(p_datetimes);
            end if;
            v_datetime := substr(p_datetimes, v_pos, v_pos_next - v_pos + 1);

            insert into event_date(event_id, event_datetime)
            values(v_eventid, v_datetime);

            v_pos := v_pos_next + 1;
        end loop;
    end if;
    
    return v_eventid;
end;
```

さすがにこれを書くのはノーコードではないですかね？ローコードの範囲内ですかね。

EVENTの登録はそのまますれば良いですが、EVENT_DATEの方は、改行（¥n で結合したので、CHR(10) で分割します）で日時を切り出して、それをループして複数行登録します。
それだけのことをするのですから、ノーコードだろうがなんだろうが、この程度の処理にはなるわけです。（久しぶりにOracleストアド書きました。拙いところがありましたらすみません・・・）
なんらかのビジュアルな組み立てツールで処理を作ろうが、SQLを書こうが、やること（考えること）は同じだと思います。

さらに、このファンクションを呼び出す処理を書きます。
動的アクションを下記のように書きます。

```sql:
begin
    return createEvent(:P1_EVENT_NAME, :P1_MEMO, :p1_DATETIMES);
end;
```

<img width="400" alt="スクリーンショット 2020-07-14 21.45.19.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/77307/0356d74a-05e5-9d00-41ff-e1152b2cba90.png">

これでデータが登録されました。

と、さりげなく書きましたが、DBへの接続云々が完全に隠されていて、書かなければならないところだけ書くという仕組みになっており、一から作る生産性という意味ではかなり高いレベルになっていると思います。
そういう意味では、非常にローコードだなという感じは受けています。

### 結果表示ページ

ここは、調べきれなかったので、仮実装。
ページの作成で、新しいページを追加し、レポート > クラシックレポート を選択しました。
SQLを指定しますが、いったん、

```sql:
select event_datetime, 0 as A, 0 as B, 0 as C from event_date
```

としておきます。
そして、本当は、作成ページのファンクション呼び出しの戻り値のEVENT_IDを渡してあげたいのですが、そしてそれはできそうなのですが、調べきれなかったので、下記のようにしておきます。

```sql:
select event_datetime, 0 as A, 0 as B, 0 as C from event_date
where EVENT_ID = (select max(EVENT_ID) from EVENT)
```

一見それっぽい動きにはなりました。
<img width="400" alt="スクリーンショット 2020-07-14 23.32.36.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/77307/1ddfa171-3a26-820b-0d8f-f260fb4b580b.png">

<img width="320" alt="スクリーンショット 2020-07-14 23.33.27.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/77307/c5a8dedf-afbd-c7c1-35ee-8a628f3141ed.png">

もう少し調べれば、ちゃんと作れると思います。なので、ローコードツールであるOracle APEXで、調整さん作成は「できないこと」ではないと思います。出欠入力機能も同様にできると思います。

## まとめ

何を書きたかったかというと、できるできないって非常に相対的ですよね。
やればできるとして、やりたいかとか、やって良いかという問題もあります。
組織としてメンテしていけるのかとか、この環境がいつまで使えるのかとか。
なので、このサービスを使わないと判断した場合の移行パスが見えていることの方が重要かなと思うのです。
OutSystemsなんかは、それに対する一つの答えをくれているのかなと思います。
https://www.bluememe.jp/outsystems/product/product-nolockin.html
Oracle APEXは厳しいかな・・・
そんなことを考えながらいろいろ作ってみています。