ラベル パイプライン表関数 の投稿を表示しています。 すべての投稿を表示
ラベル パイプライン表関数 の投稿を表示しています。 すべての投稿を表示

2023年2月8日水曜日

コード検索アプリの作成 - その2

 昨日、記事やGistから過去に書いたサンプル・コードを探すアプリケーションを作成したのですが、どうも使いにくいです。Gistに対象を絞って検索するページを作成してみました。

public gistであればgistが提供している検索を使えるのですが、今までprivate gistとして作成していたのと、private gistはpublic gistに変更できない(作り直し)ので仕方がありません。

作成したアプリの画面です。

https://apex.oracle.com/pls/apex/r/japancommunity/codesearch/code


ファセット検索とAPEX 22.2の動的コンテンツ・リージョンを組み合わせています。

少しだけ実装の解説をします。

ファセット検索は、クラシック・レポートを検索結果のリージョンとして使用している、一般的な実装です。クラシック・レポートのソースは以下です。
select
    a.id
    ,d.title
    ,d.url
    ,a.raw_url
    ,a.raw_content
    ,a.file_name
    ,a.file_ext
    ,a.embedded_url
from cds_documents d join cds_attachments a 
  on d.id = a.post_id

ファイルタイプの選択であるファセットF6_FILE_EXTは、列FILE_EXT個別値チェックボックスで選択するように構成しています。


検索ボックスのP6_SEARCHは、検索のソースを列RAW_CONTENT(これは実際のコード)に限定しています。


検索されたコードを表示するリージョンはList Gist Snippetsとして作成しました。

タイプ動的コンテンツです。ソースは以下のPL/SQLコードです。


ブログ記事に埋め込んでいるGist由来のスクリプトをscriptタグとで出力しています。


動的コンテンツからクラシック・レポートの検索結果を取得するために、パイプライン表関数get_gist_faceted_search_dataを作成しています。


一般的にはファセットが変更されたときは、リージョンをリフレッシュします。今回は<script src="..."></script>を動的コンテンツで出力しています。Gist由来のコード中でDocument.writeが使われているため、リフレッシュでの画面更新時は出力が無視されます。

そのため、ファセット変更(Facet Change)で実行されるTRUEアクションとして、ページの送信を指定しています。


以上が、今回作成したアプリケーションの説明です。

自分のために作成したアプリですが、何かの役に立てば幸いです。

2022年12月16日金曜日

カスケードLOVのソース定義について

 2つのページ・アイテムがあり、それぞれタイプがシャトルとなっています。このページ・アイテムには親子関係があり、親となるシャトルで選択した値に基づき、子のシャトルで選択できる値が決まります。

サンプル・データセットのEMP/DEPTをデータ・ソースとして使い、以下のようなページを作成します。



基本の実装



親のシャトルがP1_DEPTNOとして作成されています。表DEPTからDEPTNOを複数選択します。

LOVSQL問合せは以下になります。

select dname d, deptno r from dept


従業員を選択する子であるシャトルはP1_EMPNOとして作成されています。

LOVSQL問合せは以下になります。カスケードLOV親アイテムとしてP1_DEPTNOを指定します。親アイテムとして指定したアイテムは必ず送信されるため、送信されるアイテムに指定する必要はありません。

ページ・アイテムに複数の値が設定される場合、それぞれの値は':'(コロン)で区切られます。そのため、P1_DEPTNOの値をapex_string.splitを呼び出して分割しています。

ページ・アイテムP1_DEPTNOのシャトルで選択した部門の従業員に限り、P1_EMPNOのシャトルで選択できるようになります。


ここまでが基本の実装です。


SQLを記述できない場合



従業員の表がそれぞれ部門で分割されているケースを想定します。

create table emp_accounting as select * from emp where deptno = 10;
create table emp_research as select * from emp where deptno = 20;
create table emp_sales as select * from emp where deptno = 30;
create table emp_operations as select * from emp where deptno = 40;


部門ごとに4つの表が作られています。EMP_ACCOUNTINGEMP_RESEARCHEMP_SALESEMP_OPERATIONSです。親となるシャトルではこれらの表を選択し、子となるシャトルは選択された表から従業員を選択します。

親のシャトルのSQL問合せは以下に変わります。

select dname d, 'EMP_' || dname r from dept

ページ・アイテムP3_DEPTNOはコロンで区切られた表名を複数持ちます。


子のシャトルでは、LOVタイプSQL問合せを返すファンクション本体に変更し、SQL問合せを戻すPL/SQLファンクション本体として以下を記述します。ファンクションの評価時はページ・アイテムP3_DEPTNOはnullになります。評価に失敗するため、0行を返すダミーのSELECT文を戻しています。

カスケードLOVは基本と同じ設定になります。



動的にSELECT文を作成できない場合



動的にSQLを作る場合でも、最終的には実行可能なSELECT文が生成される必要があります。SELECT文を作るのが困難なケース(RESTサービスを呼び出すなど)では、パイプライン表関数を作成することで対応できる場合もあります。

今回の例を実装すると、以下のようになります。

作成したパイプライン表関数get_cascade_lov_sourceを使用したSQL問合せは以下になります。

select display_value, return_value from table(get_cascade_lov_source(:P2_DEPTNO))

パイプライン表関数による実装の場合、表示値と戻り値を返せばよいので実際のデータ・ソースが表である必要はありません。



カスケードLOVの親アイテムを指定できない場合



あまり無いとは思いますが、カスケードLOVの親アイテムを設定できない場合を考えてみます。

この場合、親となるページ・アイテムが変更されたときに、子となるページ・アイテムをリフレッシュする必要があります。


ページ・アイテムの変更イベントでページ・アイテムのリフレッシュを実行します。このTRUEアクションは、一般的なリフレッシュの設定です。


子アイテムのLOVSQL問合せ、または、ファンクション本体に親アイテムであるページ・アイテムがバインド変数として使用されている場合、カスケードLOVの親アイテムを指定せずに、送信するページ・アイテムを指定する方法はありません

このため、親となるページ・アイテムのセッション・ステートストレージセッションごと(永続)に切り替えます。


TRUEアクションを作成し、子であるページ・アイテムをリフレッシュする前に配置します。

アクションサーバー側のコードを実行を選択します。PL/SQLコードは不要なのでnull;とします。送信するアイテムとして親となるページ・アイテムを指定します。

セッション・ステートの定義はセッション(永続)になっているため、送信されたページ・アイテムの値はデータベースに保存されます。子アイテムのソースとなるコードが実行される際に、サーバーに保存されている値がバインド変数に割り当てられるため、親アイテムの値が反映された結果が得られます。


今回の記事は以上です。

検証に使用したアプリケーションのエクスポートを以下に置きました。
https://github.com/ujnak/apexapps/blob/master/exports/cascade-shuttle-lov-source.zip

Oracle APEXのアプリケーション作成の参考になれば幸いです。