Files
apollinare-catering-software/docs/packages/PLJSON_HELPER.md
2025-12-17 13:02:12 +01:00

476 lines
15 KiB
Markdown

# PLJSON_HELPER
## Package Specification
```sql
package pljson_helper as
/* Example:
set serveroutput on;
declare
v_a json;
v_b json;
begin
v_a := json('{a:1, b:{a:null}, e:false}');
v_b := json('{c:3, e:{}, b:{b:2}}');
json_helper.merge(v_a, v_b).print(false);
end;
--
{"a":1,"b":{"a":null,"b":2},"e":{},"c":3}
*/
-- Recursive merge
-- Courtesy of Matt Nolan - edited by Jonas Krogsboell
function merge(p_a_json pljson, p_b_json pljson) return pljson;
-- Join two lists
-- json_helper.join(json_list('[1,2,3]'),json_list('[4,5,6]')) -> [1,2,3,4,5,6]
function join(p_a_list pljson_list, p_b_list pljson_list) return pljson_list;
-- keep only specific keys in json object
-- json_helper.keep(json('{a:1,b:2,c:3,d:4,e:5,f:6}'),json_list('["a","f","c"]')) -> {"a":1,"f":6,"c":3}
function keep(p_json pljson, p_keys pljson_list) return pljson;
-- remove specific keys in json object
-- json_helper.remove(json('{a:1,b:2,c:3,d:4,e:5,f:6}'),json_list('["a","f","c"]')) -> {"b":2,"d":4,"e":5}
function remove(p_json pljson, p_keys pljson_list) return pljson;
--equals
function equals(p_v1 pljson_element, p_v2 pljson_element, exact boolean default true) return boolean;
function equals(p_v1 pljson_element, p_v2 pljson, exact boolean default true) return boolean;
function equals(p_v1 pljson_element, p_v2 pljson_list, exact boolean default true) return boolean;
function equals(p_v1 pljson_element, p_v2 number) return boolean;
/* E.I.Sarmas (github.com/dsnz) 2016-12-01 support for binary_double numbers */
function equals(p_v1 pljson_element, p_v2 binary_double) return boolean;
function equals(p_v1 pljson_element, p_v2 varchar2) return boolean;
function equals(p_v1 pljson_element, p_v2 boolean) return boolean;
function equals(p_v1 pljson_element, p_v2 clob) return boolean;
function equals(p_v1 pljson, p_v2 pljson, exact boolean default true) return boolean;
function equals(p_v1 pljson_list, p_v2 pljson_list, exact boolean default true) return boolean;
--contains json, json_value
--contains json_list, json_value
function contains(p_v1 pljson, p_v2 pljson_element, exact boolean default false) return boolean;
function contains(p_v1 pljson, p_v2 pljson, exact boolean default false) return boolean;
function contains(p_v1 pljson, p_v2 pljson_list, exact boolean default false) return boolean;
function contains(p_v1 pljson, p_v2 number, exact boolean default false) return boolean;
/* E.I.Sarmas (github.com/dsnz) 2016-12-01 support for binary_double numbers */
function contains(p_v1 pljson, p_v2 binary_double, exact boolean default false) return boolean;
function contains(p_v1 pljson, p_v2 varchar2, exact boolean default false) return boolean;
function contains(p_v1 pljson, p_v2 boolean, exact boolean default false) return boolean;
function contains(p_v1 pljson, p_v2 clob, exact boolean default false) return boolean;
function contains(p_v1 pljson_list, p_v2 pljson_element, exact boolean default false) return boolean;
function contains(p_v1 pljson_list, p_v2 pljson, exact boolean default false) return boolean;
function contains(p_v1 pljson_list, p_v2 pljson_list, exact boolean default false) return boolean;
function contains(p_v1 pljson_list, p_v2 number, exact boolean default false) return boolean;
/* E.I.Sarmas (github.com/dsnz) 2016-12-01 support for binary_double numbers */
function contains(p_v1 pljson_list, p_v2 binary_double, exact boolean default false) return boolean;
function contains(p_v1 pljson_list, p_v2 varchar2, exact boolean default false) return boolean;
function contains(p_v1 pljson_list, p_v2 boolean, exact boolean default false) return boolean;
function contains(p_v1 pljson_list, p_v2 clob, exact boolean default false) return boolean;
end pljson_helper;```
## Package Body
```sql
package body pljson_helper as
--recursive merge
function merge(p_a_json pljson, p_b_json pljson) return pljson as
l_json pljson;
l_jv pljson_element;
l_indx number;
l_recursive pljson_element;
begin
--
-- Initialize our return object
--
l_json := p_a_json;
-- loop through p_b_json
l_indx := p_b_json.json_data.first;
loop
exit when l_indx is null;
l_jv := p_b_json.json_data(l_indx);
if (l_jv.is_object) then
--recursive
l_recursive := l_json.get(l_jv.mapname);
if (l_recursive is not null and l_recursive.is_object) then
l_json.put(l_jv.mapname, merge(pljson(l_recursive), pljson(l_jv)));
else
l_json.put(l_jv.mapname, l_jv);
end if;
else
l_json.put(l_jv.mapname, l_jv);
end if;
--increment
l_indx := p_b_json.json_data.next(l_indx);
end loop;
return l_json;
end merge;
-- join two lists
function join(p_a_list pljson_list, p_b_list pljson_list) return pljson_list as
l_json_list pljson_list := p_a_list;
begin
for indx in 1 .. p_b_list.count loop
l_json_list.append(p_b_list.get(indx));
end loop;
return l_json_list;
end join;
-- keep keys.
function keep(p_json pljson, p_keys pljson_list) return pljson as
l_json pljson := pljson();
mapname varchar2(4000);
begin
for i in 1 .. p_keys.count loop
mapname := p_keys.get(i).get_string();
if (p_json.exist(mapname)) then
l_json.put(mapname, p_json.get(mapname));
end if;
end loop;
return l_json;
end keep;
-- drop keys.
function remove(p_json pljson, p_keys pljson_list) return pljson as
l_json pljson := p_json;
begin
for i in 1 .. p_keys.count loop
l_json.remove(p_keys.get(i).get_string());
end loop;
return l_json;
end remove;
--equals functions
function equals(p_v1 pljson_element, p_v2 number) return boolean as
begin
if (p_v2 is null) then
return p_v1.is_null;
end if;
if (not p_v1.is_number) then
return false;
end if;
return p_v2 = p_v1.get_number();
end;
/* E.I.Sarmas (github.com/dsnz) 2016-12-01 support for binary_double numbers */
function equals(p_v1 pljson_element, p_v2 binary_double) return boolean as
begin
if (p_v2 is null) then
return p_v1.is_null;
end if;
if (not p_v1.is_number) then
return false;
end if;
return p_v2 = p_v1.get_double();
end;
function equals(p_v1 pljson_element, p_v2 boolean) return boolean as
begin
if (p_v2 is null) then
return p_v1.is_null;
end if;
if (not p_v1.is_bool) then
return false;
end if;
return p_v2 = p_v1.get_bool();
end;
function equals(p_v1 pljson_element, p_v2 varchar2) return boolean as
begin
if (p_v2 is null) then
return (p_v1.is_null or p_v1.get_string() is null);
end if;
if (not p_v1.is_string) then
return false;
end if;
return p_v2 = p_v1.get_string();
end;
function equals(p_v1 pljson_element, p_v2 clob) return boolean as
my_clob clob;
res boolean;
begin
if (p_v2 is null) then
return p_v1.is_null;
end if;
if (not p_v1.is_string) then
return false;
end if;
/*
my_clob := empty_clob();
dbms_lob.createtemporary(my_clob, true);
p_v1.get_string(my_clob);
*/
my_clob := p_v1.get_clob();
res := dbms_lob.compare(p_v2, my_clob) = 0;
/*dbms_lob.freetemporary(my_clob);*/
return res;
end;
function equals(p_v1 pljson_element, p_v2 pljson_element, exact boolean) return boolean as
begin
if (p_v2 is null or p_v2.is_null) then
return (p_v1 is null or p_v1.is_null);
end if;
if (p_v2.is_number) then return equals(p_v1, p_v2.get_number); end if;
if (p_v2.is_bool) then return equals(p_v1, p_v2.get_bool); end if;
if (p_v2.is_object) then return equals(p_v1, pljson(p_v2), exact); end if;
if (p_v2.is_array) then return equals(p_v1, pljson_list(p_v2), exact); end if;
if (p_v2.is_string) then
if (treat(p_v2 as pljson_string).extended_str is null) then
return equals(p_v1, p_v2.get_string);
else
declare
my_clob clob; res boolean;
begin
/*
my_clob := empty_clob();
dbms_lob.createtemporary(my_clob, true);
p_v2.get_string(my_clob);
*/
my_clob := p_v2.get_clob();
res := equals(p_v1, my_clob);
/*dbms_lob.freetemporary(my_clob);*/
return res;
end;
end if;
end if;
return false; --should never happen
end;
function equals(p_v1 pljson_element, p_v2 pljson_list, exact boolean) return boolean as
cmp pljson_list;
res boolean := true;
begin
-- p_v1.print(false);
-- p_v2.print(false);
-- dbms_output.put_line('labc1'||case when exact then 'X' else 'U' end);
if (p_v2 is null) then
return p_v1.is_null;
end if;
if (not p_v1.is_array) then
return false;
end if;
-- dbms_output.put_line('labc2'||case when exact then 'X' else 'U' end);
cmp := pljson_list(p_v1);
if (cmp.count != p_v2.count and exact) then return false; end if;
-- dbms_output.put_line('labc3'||case when exact then 'X' else 'U' end);
if (exact) then
for i in 1 .. cmp.count loop
res := equals(cmp.get(i), p_v2.get(i), exact);
if (not res) then return res; end if;
end loop;
else
-- dbms_output.put_line('labc4'||case when exact then 'X' else 'U' end);
if (p_v2.count > cmp.count) then return false; end if;
-- dbms_output.put_line('labc5'||case when exact then 'X' else 'U' end);
--match sublist here!
for x in 0 .. (cmp.count-p_v2.count) loop
-- dbms_output.put_line('labc7'||x);
for i in 1 .. p_v2.count loop
res := equals(cmp.get(x+i), p_v2.get(i), exact);
if (not res) then
goto next_index;
end if;
end loop;
return true;
<<next_index>>
null;
end loop;
-- dbms_output.put_line('labc7'||case when exact then 'X' else 'U' end);
return false; --no match
end if;
return res;
end;
function equals(p_v1 pljson_element, p_v2 pljson, exact boolean) return boolean as
cmp pljson;
res boolean := true;
begin
-- p_v1.print(false);
-- p_v2.print(false);
-- dbms_output.put_line('abc1');
if (p_v2 is null) then
return p_v1.is_null;
end if;
if (not p_v1.is_object) then
return false;
end if;
cmp := pljson(p_v1);
-- dbms_output.put_line('abc2');
if (cmp.count != p_v2.count and exact) then return false; end if;
-- dbms_output.put_line('abc3');
declare
k1 pljson_list := p_v2.get_keys();
key_index number;
begin
for i in 1 .. k1.count loop
key_index := cmp.index_of(k1.get(i).get_string());
if (key_index = -1) then return false; end if;
if (exact) then
if (not equals(p_v2.get(i), cmp.get(key_index), true)) then return false; end if;
else
--non exact
declare
v1 pljson_element := cmp.get(key_index);
v2 pljson_element := p_v2.get(i);
begin
-- dbms_output.put_line('abc3 1/2');
-- v1.print(false);
-- v2.print(false);
if (v1.is_object and v2.is_object) then
if (not equals(v1, v2, false)) then return false; end if;
elsif (v1.is_array and v2.is_array) then
if (not equals(v1, v2, false)) then return false; end if;
else
if (not equals(v1, v2, true)) then return false; end if;
end if;
end;
end if;
end loop;
end;
-- dbms_output.put_line('abc4');
return true;
end;
function equals(p_v1 pljson, p_v2 pljson, exact boolean) return boolean as
begin
return equals(p_v1, p_v2, exact);
end;
function equals(p_v1 pljson_list, p_v2 pljson_list, exact boolean) return boolean as
begin
return equals(p_v1, p_v2, exact);
end;
--contain
function contains(p_v1 pljson, p_v2 pljson_element, exact boolean) return boolean as
v_values pljson_list;
begin
if (equals(p_v1, p_v2, exact)) then return true; end if;
v_values := p_v1.get_values();
for i in 1 .. v_values.count loop
declare
v_val pljson_element := v_values.get(i);
begin
if (v_val.is_object) then
if (contains(pljson(v_val), p_v2, exact)) then return true; end if;
end if;
if (v_val.is_array) then
if (contains(pljson_list(v_val), p_v2, exact)) then return true; end if;
end if;
if (equals(v_val, p_v2, exact)) then return true; end if;
end;
end loop;
return false;
end;
function contains(p_v1 pljson_list, p_v2 pljson_element, exact boolean) return boolean as
begin
if (equals(p_v1, p_v2, exact)) then return true; end if;
for i in 1 .. p_v1.count loop
declare
v_val pljson_element := p_v1.get(i);
begin
if (v_val.is_object) then
if (contains(pljson(v_val), p_v2, exact)) then return true; end if;
end if;
if (v_val.is_array) then
if (contains(pljson_list(v_val), p_v2, exact)) then return true; end if;
end if;
if (equals(v_val, p_v2, exact)) then return true; end if;
end;
end loop;
return false;
end;
function contains(p_v1 pljson, p_v2 pljson, exact boolean ) return boolean as
begin return contains(p_v1, p_v2, exact); end;
function contains(p_v1 pljson, p_v2 pljson_list, exact boolean ) return boolean as
begin return contains(p_v1, p_v2, exact); end;
function contains(p_v1 pljson, p_v2 number, exact boolean ) return boolean as begin
return contains(p_v1, pljson_number(p_v2), exact); end;
/* E.I.Sarmas (github.com/dsnz) 2016-12-01 support for binary_double numbers */
function contains(p_v1 pljson, p_v2 binary_double, exact boolean ) return boolean as begin
return contains(p_v1, pljson_number(p_v2), exact); end;
function contains(p_v1 pljson, p_v2 varchar2, exact boolean ) return boolean as begin
return contains(p_v1, pljson_string(p_v2), exact); end;
function contains(p_v1 pljson, p_v2 boolean, exact boolean ) return boolean as begin
return contains(p_v1, pljson_bool(p_v2), exact); end;
function contains(p_v1 pljson, p_v2 clob, exact boolean ) return boolean as begin
return contains(p_v1, pljson_string(p_v2), exact); end;
function contains(p_v1 pljson_list, p_v2 pljson, exact boolean ) return boolean as begin
return contains(p_v1, p_v2, exact); end;
function contains(p_v1 pljson_list, p_v2 pljson_list, exact boolean ) return boolean as begin
return contains(p_v1, p_v2, exact); end;
function contains(p_v1 pljson_list, p_v2 number, exact boolean ) return boolean as begin
return contains(p_v1, pljson_number(p_v2), exact); end;
/* E.I.Sarmas (github.com/dsnz) 2016-12-01 support for binary_double numbers */
function contains(p_v1 pljson_list, p_v2 binary_double, exact boolean ) return boolean as begin
return contains(p_v1, pljson_number(p_v2), exact); end;
function contains(p_v1 pljson_list, p_v2 varchar2, exact boolean ) return boolean as begin
return contains(p_v1, pljson_string(p_v2), exact); end;
function contains(p_v1 pljson_list, p_v2 boolean, exact boolean ) return boolean as begin
return contains(p_v1, pljson_bool(p_v2), exact); end;
function contains(p_v1 pljson_list, p_v2 clob, exact boolean ) return boolean as begin
return contains(p_v1, pljson_string(p_v2), exact); end;
end pljson_helper;```