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コードです。

declare
l_result clob;
begin
for r in (
select
id
,title
,url
,embedded_url
from table(get_gist_faceted_search_data(:APP_PAGE_ID, 'searchresults'))
fetch first 10 rows only
)
loop
l_result := l_result ||
'<b>ブログ記事:</b><a href="' || r.url || '" target="_codeview">' || r.title || '</a><br>';
l_result := l_result ||
'<script src="' || r.embedded_url || '"></script>';
end loop;
return l_result;
end;

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


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

CREATE OR REPLACE EDITIONABLE TYPE "T_GIST_ROW" as object(
id number
,title varchar2(4000)
,url varchar2(400)
,embedded_url varchar2(400)
)
/
CREATE OR REPLACE EDITIONABLE TYPE "T_GIST_TABLE" as table of t_gist_row
/
create or replace function get_gist_faceted_search_data(
p_page_id in number,
p_region_static_id in varchar2 )
return t_gist_table pipelined
is
l_region_id number;
l_context apex_exec.t_context;
type t_col_index is table of pls_integer index by varchar2(255);
l_col_index t_col_index;
---------------------------------------------------------------------------
procedure get_column_indexes( p_columns wwv_flow_t_varchar2 ) is
begin
for i in 1 .. p_columns.count loop
l_col_index( p_columns( i ) ) := apex_exec.get_column_position(
p_context => l_context,
p_column_name => p_columns( i ) );
end loop;
end get_column_indexes;
begin
-- 1. get the region ID of the Faceted Search region
select region_id
into l_region_id
from apex_application_page_regions
where application_id = v('APP_ID')
and page_id = p_page_id
and static_id = p_region_static_id;
-- 2. Get a cursor (apex_exec.t_context) for the current region data
l_context := apex_region.open_query_context(
p_page_id => p_page_id,
p_region_id => l_region_id );
get_column_indexes( wwv_flow_t_varchar2( 'ID', 'TITLE', 'URL', 'EMBEDDED_URL' ) );
while apex_exec.next_row( p_context => l_context ) loop
pipe row( t_gist_row(
apex_exec.get_varchar2( p_context => l_context, p_column_idx => l_col_index( 'ID' ) ),
apex_exec.get_varchar2( p_context => l_context, p_column_idx => l_col_index( 'TITLE' ) ),
apex_exec.get_varchar2( p_context => l_context, p_column_idx => l_col_index( 'URL' ) ),
apex_exec.get_varchar2( p_context => l_context, p_column_idx => l_col_index( 'EMBEDDED_URL' ) )
) );
end loop;
apex_exec.close( l_context );
return;
exception
when no_data_needed then
apex_exec.close( l_context );
return;
when others then
apex_exec.close( l_context );
raise;
end get_gist_faceted_search_data;
/

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

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


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

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