pgkiln 0.74.0 → 0.75.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/db/migrations/142_json_sources.sql +426 -0
- package/docs/apex-feature-parity.md +5 -5
- package/docs/guide/03-builder.md +15 -0
- package/docs/guide/04-pages-and-regions.md +1 -0
- package/docs/guide/12-development.md +11 -0
- package/docs/guide/19-rest-data-sources.md +108 -1
- package/examples/hr/hr_77_json_sources.sql +174 -0
- package/package.json +1 -1
- package/src/app.ts +5 -0
- package/src/builder/document-view.ts +117 -0
- package/src/builder/i18n/de.ts +1 -0
- package/src/builder/i18n/en.ts +1 -0
- package/src/builder/i18n/es.ts +1 -0
- package/src/builder/i18n/fr.ts +1 -0
- package/src/builder/i18n/it.ts +1 -0
- package/src/builder/i18n/ja.ts +1 -0
- package/src/builder/i18n/ko.ts +1 -0
- package/src/builder/i18n/nl.ts +1 -0
- package/src/builder/i18n/pt.ts +1 -0
- package/src/builder/i18n/zh-cn.ts +1 -0
- package/src/builder/i18n/zh-tw.ts +1 -0
- package/src/builder/json-sources.ts +395 -0
- package/src/builder/object-actions.ts +1 -0
- package/src/builder/report-settings.ts +9 -0
- package/src/builder/shared.ts +1 -1
- package/src/builder/table-editor.ts +1 -0
- package/src/builder/websources.ts +6 -3
- package/src/json-sources.ts +365 -0
- package/src/runtime/report.ts +3 -1
|
@@ -0,0 +1,426 @@
|
|
|
1
|
+
-- Sprint 142 (AP-8): JSON sources and document views (APEX: Shared Components → JSON Sources, JSON Duality Views).
|
|
2
|
+
--
|
|
3
|
+
-- meta.app.json_sources an application's JSON sources, a JSON list exported with the application (like
|
|
4
|
+
-- vector_providers, migration 136). A source names a table, its key and a jsonb column
|
|
5
|
+
-- (a column of a relational table, or the one document column of a table of documents)
|
|
6
|
+
-- and a data profile: columns at paths in the document, and arrays of objects (or of
|
|
7
|
+
-- values) with columns of their own. The builder (Shared Components → JSON sources)
|
|
8
|
+
-- proposes the profile from sample rows and creates views from it in the application's
|
|
9
|
+
-- schema; regions, REST and MCP use those views like tables.
|
|
10
|
+
--
|
|
11
|
+
-- The views are ordinary schema objects, made by the builder with the developer's connection and recorded in the
|
|
12
|
+
-- Change Log (like Table Properties › Add full-text search, migration 135). They are security_invoker (the
|
|
13
|
+
-- table's row level security and grants apply to whoever reads them) and get INSTEAD OF triggers that call the
|
|
14
|
+
-- functions below, with the source's description as the trigger argument:
|
|
15
|
+
--
|
|
16
|
+
-- meta.json_source_write() a source's view: an UPDATE changes only the paths whose values changed, in one
|
|
17
|
+
-- UPDATE of the table row (meta.jsonb_patch), so keys the profile doesn't know about
|
|
18
|
+
-- stay; an INSERT or DELETE adds or removes the table row only when the source says
|
|
19
|
+
-- so (a table of documents), else it is refused.
|
|
20
|
+
-- meta.json_array_write() an array's view (one row per element, keyed by the element's contents): UPDATE
|
|
21
|
+
-- patches one element, INSERT appends one, DELETE removes one, each in one UPDATE of
|
|
22
|
+
-- the table row (meta.jsonb_array_change). An element that changed meanwhile is not
|
|
23
|
+
-- found and the statement fails, so nothing is overwritten.
|
|
24
|
+
-- meta.json_document_write() a document view (SQL Workshop › Table Properties › Document view: APEX's JSON
|
|
25
|
+
-- Duality View): a table row and its child rows (foreign keys) as one jsonb document;
|
|
26
|
+
-- writing the document updates the row, upserts the children it lists and deletes the
|
|
27
|
+
-- children it leaves out.
|
|
28
|
+
--
|
|
29
|
+
-- All of them are SECURITY INVOKER with search_path pg_catalog: they write as the role that writes the view, so its
|
|
30
|
+
-- grants and the table's row level security apply; identifiers from the trigger argument are quoted (format %I).
|
|
31
|
+
|
|
32
|
+
alter table meta.app add column json_sources jsonb not null default '[]'
|
|
33
|
+
check (jsonb_typeof(json_sources) = 'array');
|
|
34
|
+
comment on column meta.app.json_sources is 'JSON sources (142): a jsonb column described by a data profile, presented as updatable views; exported with the application';
|
|
35
|
+
|
|
36
|
+
-- an export made before 142 has no json_sources
|
|
37
|
+
create or replace function meta.app_ai_default() returns trigger
|
|
38
|
+
language plpgsql set search_path = pg_catalog as $$
|
|
39
|
+
begin
|
|
40
|
+
new.ai_tools := coalesce(new.ai_tools, '[]');
|
|
41
|
+
new.ai_agents := coalesce(new.ai_agents, '[]');
|
|
42
|
+
new.vector_providers := coalesce(new.vector_providers, '[]');
|
|
43
|
+
new.json_sources := coalesce(new.json_sources, '[]');
|
|
44
|
+
return new;
|
|
45
|
+
end $$;
|
|
46
|
+
|
|
47
|
+
-- ---------------------------------------------------------------- reading values
|
|
48
|
+
|
|
49
|
+
-- Whether a text reads as a value of a type (integer, numeric, date …): a document with a wrong value shows NULL
|
|
50
|
+
-- in that column instead of failing the whole view. pg_input_is_valid on PostgreSQL 16 and later.
|
|
51
|
+
do $do$
|
|
52
|
+
begin
|
|
53
|
+
if current_setting('server_version_num')::int >= 160000 then
|
|
54
|
+
execute $f$
|
|
55
|
+
create function meta.input_ok(p_value text, p_type text) returns boolean
|
|
56
|
+
language sql stable parallel safe set search_path = pg_catalog as
|
|
57
|
+
$$ select p_value is null or pg_input_is_valid(p_value, p_type) $$$f$;
|
|
58
|
+
else
|
|
59
|
+
execute $f$
|
|
60
|
+
create function meta.input_ok(p_value text, p_type text) returns boolean
|
|
61
|
+
language plpgsql stable parallel safe set search_path = pg_catalog as $$
|
|
62
|
+
begin
|
|
63
|
+
if p_value is null then
|
|
64
|
+
return true;
|
|
65
|
+
end if;
|
|
66
|
+
execute format('select %L::%s', p_value, p_type::regtype);
|
|
67
|
+
return true;
|
|
68
|
+
exception when others then
|
|
69
|
+
return false;
|
|
70
|
+
end $$$f$;
|
|
71
|
+
end if;
|
|
72
|
+
end
|
|
73
|
+
$do$;
|
|
74
|
+
|
|
75
|
+
-- ---------------------------------------------------------------- changing documents
|
|
76
|
+
|
|
77
|
+
-- Set a value at a path of keys, making the objects on the way (jsonb_set only makes the last key).
|
|
78
|
+
create function meta.jsonb_put(p_doc jsonb, p_path text[], p_value jsonb) returns jsonb
|
|
79
|
+
language plpgsql immutable parallel safe set search_path = pg_catalog as $$
|
|
80
|
+
declare
|
|
81
|
+
d jsonb := p_doc;
|
|
82
|
+
i int;
|
|
83
|
+
begin
|
|
84
|
+
if coalesce(cardinality(p_path), 0) = 0 then
|
|
85
|
+
return p_value;
|
|
86
|
+
end if;
|
|
87
|
+
if d is null or jsonb_typeof(d) <> 'object' then
|
|
88
|
+
d := '{}';
|
|
89
|
+
end if;
|
|
90
|
+
for i in 1 .. cardinality(p_path) - 1 loop
|
|
91
|
+
if jsonb_typeof(d #> p_path[1:i]) is distinct from 'object' then
|
|
92
|
+
d := jsonb_set(d, p_path[1:i], '{}', true);
|
|
93
|
+
end if;
|
|
94
|
+
end loop;
|
|
95
|
+
return jsonb_set(d, p_path, p_value, true);
|
|
96
|
+
end $$;
|
|
97
|
+
|
|
98
|
+
-- Apply changes [{"p": [keys], "v": value}] to a document: a value is set at its path, a null (or JSON null)
|
|
99
|
+
-- removes the key. Keys the changes don't name stay as they are.
|
|
100
|
+
create function meta.jsonb_patch(p_doc jsonb, p_changes jsonb) returns jsonb
|
|
101
|
+
language plpgsql immutable parallel safe set search_path = pg_catalog as $$
|
|
102
|
+
declare
|
|
103
|
+
d jsonb := p_doc;
|
|
104
|
+
c jsonb;
|
|
105
|
+
p text[];
|
|
106
|
+
begin
|
|
107
|
+
for c in select x from jsonb_array_elements(coalesce(p_changes, '[]')) x loop
|
|
108
|
+
p := array(select jsonb_array_elements_text(c->'p'));
|
|
109
|
+
if c->'v' is null or jsonb_typeof(c->'v') = 'null' then
|
|
110
|
+
if cardinality(p) = 0 then
|
|
111
|
+
d := null;
|
|
112
|
+
elsif d is not null then
|
|
113
|
+
d := d #- p;
|
|
114
|
+
end if;
|
|
115
|
+
else
|
|
116
|
+
d := meta.jsonb_put(d, p, c->'v');
|
|
117
|
+
end if;
|
|
118
|
+
end loop;
|
|
119
|
+
return d;
|
|
120
|
+
end $$;
|
|
121
|
+
|
|
122
|
+
-- The key of each element of an array as the array views show it: the md5 of the element's text and its
|
|
123
|
+
-- occurrence among equal elements (1, 2 …), so a key stays the same when other elements are added or removed.
|
|
124
|
+
create function meta.jsonb_element_keys(p_array jsonb)
|
|
125
|
+
returns table (idx int, key text)
|
|
126
|
+
language sql immutable parallel safe set search_path = pg_catalog as $$
|
|
127
|
+
select (x.ord - 1)::int, md5(x.e::text) || '.' || row_number() over (partition by md5(x.e::text) order by x.ord)
|
|
128
|
+
from jsonb_array_elements(case when jsonb_typeof(p_array) = 'array' then p_array else '[]' end) with ordinality x(e, ord)
|
|
129
|
+
$$;
|
|
130
|
+
|
|
131
|
+
-- Change one element of the array at p_path: 'update' patches the element with the given key, 'delete' removes
|
|
132
|
+
-- it, 'insert' appends a new element made of the changes. An element that is not there (changed or removed
|
|
133
|
+
-- meanwhile) raises an error.
|
|
134
|
+
create function meta.jsonb_array_change(p_doc jsonb, p_path text[], p_op text, p_key text, p_changes jsonb) returns jsonb
|
|
135
|
+
language plpgsql immutable set search_path = pg_catalog as $$
|
|
136
|
+
declare
|
|
137
|
+
arr jsonb := p_doc #> p_path;
|
|
138
|
+
i int;
|
|
139
|
+
e jsonb;
|
|
140
|
+
begin
|
|
141
|
+
if arr is null or jsonb_typeof(arr) <> 'array' then
|
|
142
|
+
arr := '[]';
|
|
143
|
+
end if;
|
|
144
|
+
if p_op = 'insert' then
|
|
145
|
+
arr := arr || jsonb_build_array(coalesce(meta.jsonb_patch('{}', p_changes), 'null'));
|
|
146
|
+
else
|
|
147
|
+
select k.idx into i from meta.jsonb_element_keys(arr) k where k.key = p_key;
|
|
148
|
+
if i is null then
|
|
149
|
+
raise exception 'The element % of % is no longer there: someone changed the document meanwhile. Reload and try again.',
|
|
150
|
+
p_key, array_to_string(p_path, '.') using errcode = '40001';
|
|
151
|
+
end if;
|
|
152
|
+
if p_op = 'delete' then
|
|
153
|
+
arr := arr - i;
|
|
154
|
+
elsif p_op = 'update' then
|
|
155
|
+
e := arr -> i;
|
|
156
|
+
if jsonb_typeof(e) <> 'object' and exists (select from jsonb_array_elements(p_changes) c where jsonb_array_length(c->'p') > 0) then
|
|
157
|
+
e := '{}';
|
|
158
|
+
end if;
|
|
159
|
+
arr := jsonb_set(arr, array[i::text], coalesce(meta.jsonb_patch(e, p_changes), 'null'));
|
|
160
|
+
else
|
|
161
|
+
raise exception 'meta.jsonb_array_change: unknown operation %', p_op;
|
|
162
|
+
end if;
|
|
163
|
+
end if;
|
|
164
|
+
return meta.jsonb_put(p_doc, p_path, arr);
|
|
165
|
+
end $$;
|
|
166
|
+
|
|
167
|
+
-- The WHERE condition on a table's key columns, with the values from $1 (a jsonb row): typed by the table's row type.
|
|
168
|
+
create function meta.json_key_where(p_schema text, p_table text, p_key jsonb, p_alias text default 't', p_param int default 1) returns text
|
|
169
|
+
language sql immutable set search_path = pg_catalog as $$
|
|
170
|
+
select string_agg(format('%I.%I = (jsonb_populate_record(null::%I.%I, $%s)).%I', p_alias, k, p_schema, p_table, p_param, k), ' and ')
|
|
171
|
+
from jsonb_array_elements_text(p_key) k
|
|
172
|
+
$$;
|
|
173
|
+
|
|
174
|
+
-- The changes of the profile's columns between two rows of a view (to_jsonb(old), to_jsonb(new)).
|
|
175
|
+
create function meta.json_column_changes(p_columns jsonb, p_old jsonb, p_new jsonb) returns jsonb
|
|
176
|
+
language sql immutable parallel safe set search_path = pg_catalog as $$
|
|
177
|
+
select coalesce(jsonb_agg(jsonb_build_object('p', c->'path', 'v', p_new -> (c->>'name'))), '[]')
|
|
178
|
+
from jsonb_array_elements(p_columns) c
|
|
179
|
+
where coalesce(c->>'readonly', 'false') <> 'true'
|
|
180
|
+
and (p_old is null or (p_new -> (c->>'name')) is distinct from (p_old -> (c->>'name')))
|
|
181
|
+
and (p_old is not null or jsonb_typeof(p_new -> (c->>'name')) is distinct from 'null')
|
|
182
|
+
$$;
|
|
183
|
+
|
|
184
|
+
-- INSTEAD OF trigger of a JSON source's view. Argument: {"schema", "table", "key": [columns], "column",
|
|
185
|
+
-- "columns": [{"name", "path"}], "rows": true|false, "name"}.
|
|
186
|
+
create function meta.json_source_write() returns trigger
|
|
187
|
+
language plpgsql security invoker set search_path = pg_catalog as $$
|
|
188
|
+
declare
|
|
189
|
+
s jsonb := tg_argv[0]::jsonb;
|
|
190
|
+
o jsonb := case when tg_op <> 'INSERT' then to_jsonb(old) end;
|
|
191
|
+
n jsonb := case when tg_op <> 'DELETE' then to_jsonb(new) end;
|
|
192
|
+
k text;
|
|
193
|
+
ch jsonb;
|
|
194
|
+
cnt int;
|
|
195
|
+
cols text := '';
|
|
196
|
+
vals text := '';
|
|
197
|
+
r jsonb;
|
|
198
|
+
begin
|
|
199
|
+
if tg_op = 'UPDATE' then
|
|
200
|
+
for k in select jsonb_array_elements_text(s->'key') loop
|
|
201
|
+
if (n->k) is distinct from (o->k) then
|
|
202
|
+
raise exception 'JSON source %: the key column % is not changed through the view', s->>'name', k;
|
|
203
|
+
end if;
|
|
204
|
+
end loop;
|
|
205
|
+
ch := meta.json_column_changes(s->'columns', o, n);
|
|
206
|
+
if jsonb_array_length(ch) > 0 then
|
|
207
|
+
execute format('update %I.%I t set %I = meta.jsonb_patch(t.%I, $2) where %s',
|
|
208
|
+
s->>'schema', s->>'table', s->>'column', s->>'column', meta.json_key_where(s->>'schema', s->>'table', s->'key'))
|
|
209
|
+
using o, ch;
|
|
210
|
+
get diagnostics cnt = row_count;
|
|
211
|
+
if cnt = 0 then
|
|
212
|
+
return null;
|
|
213
|
+
end if;
|
|
214
|
+
end if;
|
|
215
|
+
return new;
|
|
216
|
+
end if;
|
|
217
|
+
if coalesce(s->>'rows', 'false') <> 'true' then
|
|
218
|
+
raise exception 'JSON source % changes the documents of existing rows of %.%: % through its view is not allowed',
|
|
219
|
+
s->>'name', s->>'schema', s->>'table', lower(tg_op) using errcode = '42501';
|
|
220
|
+
end if;
|
|
221
|
+
if tg_op = 'DELETE' then
|
|
222
|
+
execute format('delete from %I.%I t where %s', s->>'schema', s->>'table', meta.json_key_where(s->>'schema', s->>'table', s->'key')) using o;
|
|
223
|
+
get diagnostics cnt = row_count;
|
|
224
|
+
return case when cnt = 0 then null else old end;
|
|
225
|
+
end if;
|
|
226
|
+
-- INSERT: the key columns given (others take their defaults) and the document made of the given values
|
|
227
|
+
for k in select jsonb_array_elements_text(s->'key') loop
|
|
228
|
+
if jsonb_typeof(n->k) is distinct from 'null' and (n->k) is not null then
|
|
229
|
+
cols := cols || format('%I, ', k);
|
|
230
|
+
vals := vals || format('(jsonb_populate_record(null::%I.%I, $1)).%I, ', s->>'schema', s->>'table', k);
|
|
231
|
+
end if;
|
|
232
|
+
end loop;
|
|
233
|
+
execute format('insert into %I.%I as t (%s%I) values (%s$2) returning to_jsonb(t)',
|
|
234
|
+
s->>'schema', s->>'table', cols, s->>'column', vals)
|
|
235
|
+
into r using n, coalesce(meta.jsonb_patch('{}', meta.json_column_changes(s->'columns', null, n)), '{}');
|
|
236
|
+
new := jsonb_populate_record(new, r);
|
|
237
|
+
return new;
|
|
238
|
+
end $$;
|
|
239
|
+
|
|
240
|
+
-- INSTEAD OF trigger of an array's view. Argument: {"schema", "table", "key": [the table's key columns, also
|
|
241
|
+
-- columns of the view], "column", "array": [path], "columns": [{"name", "path"}], "row_key", "position", "name"}.
|
|
242
|
+
create function meta.json_array_write() returns trigger
|
|
243
|
+
language plpgsql security invoker set search_path = pg_catalog as $$
|
|
244
|
+
declare
|
|
245
|
+
s jsonb := tg_argv[0]::jsonb;
|
|
246
|
+
o jsonb := case when tg_op <> 'INSERT' then to_jsonb(old) end;
|
|
247
|
+
n jsonb := case when tg_op <> 'DELETE' then to_jsonb(new) end;
|
|
248
|
+
rk text := coalesce(s->>'row_key', 'row_key');
|
|
249
|
+
k text;
|
|
250
|
+
ch jsonb;
|
|
251
|
+
e jsonb;
|
|
252
|
+
doc jsonb;
|
|
253
|
+
cnt int;
|
|
254
|
+
arr text[] := array(select jsonb_array_elements_text(s->'array'));
|
|
255
|
+
begin
|
|
256
|
+
if tg_op = 'UPDATE' then
|
|
257
|
+
for k in select jsonb_array_elements_text(s->'key') loop
|
|
258
|
+
if (n->k) is distinct from (o->k) then
|
|
259
|
+
raise exception 'JSON source %: an element does not move to another row (column %)', s->>'name', k;
|
|
260
|
+
end if;
|
|
261
|
+
end loop;
|
|
262
|
+
ch := meta.json_column_changes(s->'columns', o, n);
|
|
263
|
+
if jsonb_array_length(ch) = 0 then
|
|
264
|
+
return new;
|
|
265
|
+
end if;
|
|
266
|
+
elsif tg_op = 'INSERT' then
|
|
267
|
+
for k in select jsonb_array_elements_text(s->'key') loop
|
|
268
|
+
if n->k is null or jsonb_typeof(n->k) = 'null' then
|
|
269
|
+
raise exception 'JSON source %: a new element needs the row it belongs to (column %)', s->>'name', k using errcode = '23502';
|
|
270
|
+
end if;
|
|
271
|
+
end loop;
|
|
272
|
+
ch := meta.json_column_changes(s->'columns', null, n);
|
|
273
|
+
end if;
|
|
274
|
+
execute format('update %I.%I t set %I = meta.jsonb_array_change(t.%I, $2, $3, $4, $5) where %s returning t.%I',
|
|
275
|
+
s->>'schema', s->>'table', s->>'column', s->>'column', meta.json_key_where(s->>'schema', s->>'table', s->'key'), s->>'column')
|
|
276
|
+
into doc using coalesce(o, n), arr, lower(tg_op), o->>rk, ch;
|
|
277
|
+
get diagnostics cnt = row_count;
|
|
278
|
+
if cnt = 0 then
|
|
279
|
+
return null;
|
|
280
|
+
end if;
|
|
281
|
+
if tg_op = 'DELETE' then
|
|
282
|
+
return old;
|
|
283
|
+
end if;
|
|
284
|
+
-- a new element: its key and position as the view now shows them (the last one)
|
|
285
|
+
if tg_op = 'INSERT' then
|
|
286
|
+
select jsonb_build_object(rk, k3.key, coalesce(s->>'position', 'position'), k3.idx + 1) into e
|
|
287
|
+
from meta.jsonb_element_keys(doc #> arr) k3
|
|
288
|
+
order by k3.idx desc limit 1;
|
|
289
|
+
new := jsonb_populate_record(new, e);
|
|
290
|
+
end if;
|
|
291
|
+
return new;
|
|
292
|
+
end $$;
|
|
293
|
+
|
|
294
|
+
-- INSTEAD OF trigger of a document view. Argument: {"schema", "table", "key": [columns], "document": "doc",
|
|
295
|
+
-- "children": [{"name", "schema", "table", "key": [columns], "fk": [[child column, parent column], …]}]}.
|
|
296
|
+
create function meta.json_document_write() returns trigger
|
|
297
|
+
language plpgsql security invoker set search_path = pg_catalog as $$
|
|
298
|
+
declare
|
|
299
|
+
s jsonb := tg_argv[0]::jsonb;
|
|
300
|
+
dcol text := coalesce(s->>'document', 'doc');
|
|
301
|
+
o jsonb := case when tg_op <> 'INSERT' then to_jsonb(old) end;
|
|
302
|
+
d jsonb := case when tg_op <> 'DELETE' then to_jsonb(new) -> dcol end;
|
|
303
|
+
pk jsonb; -- the parent row's key columns and values
|
|
304
|
+
ch jsonb;
|
|
305
|
+
c jsonb;
|
|
306
|
+
e jsonb;
|
|
307
|
+
row_ jsonb;
|
|
308
|
+
kept jsonb[];
|
|
309
|
+
cols text[];
|
|
310
|
+
sets text;
|
|
311
|
+
ins text;
|
|
312
|
+
fkw text;
|
|
313
|
+
k text;
|
|
314
|
+
cnt int;
|
|
315
|
+
childnames text[] := array(select x->>'name' from jsonb_array_elements(coalesce(s->'children', '[]')) x);
|
|
316
|
+
begin
|
|
317
|
+
if tg_op <> 'DELETE' and (d is null or jsonb_typeof(d) <> 'object') then
|
|
318
|
+
raise exception 'The document of %.% is a JSON object', s->>'schema', s->>'table' using errcode = '22023';
|
|
319
|
+
end if;
|
|
320
|
+
-- the parent row
|
|
321
|
+
if tg_op = 'DELETE' then
|
|
322
|
+
pk := (select jsonb_object_agg(k2, o->k2) from jsonb_array_elements_text(s->'key') k2);
|
|
323
|
+
elsif tg_op = 'UPDATE' then
|
|
324
|
+
pk := (select jsonb_object_agg(k2, o->k2) from jsonb_array_elements_text(s->'key') k2);
|
|
325
|
+
for k in select jsonb_array_elements_text(s->'key') loop
|
|
326
|
+
if d ? k and (d->k) is distinct from (o->k) and (d->>k) is distinct from (o->>k) then
|
|
327
|
+
raise exception 'The key column % of %.% is not changed through its document', k, s->>'schema', s->>'table';
|
|
328
|
+
end if;
|
|
329
|
+
end loop;
|
|
330
|
+
cols := array(
|
|
331
|
+
select a.attname::text from pg_attribute a
|
|
332
|
+
where a.attrelid = format('%I.%I', s->>'schema', s->>'table')::regclass and a.attnum > 0 and not a.attisdropped
|
|
333
|
+
and a.attgenerated = '' and a.attidentity <> 'a' and d ? a.attname
|
|
334
|
+
and a.attname <> all (array(select jsonb_array_elements_text(s->'key'))) and a.attname <> all (childnames));
|
|
335
|
+
if cardinality(cols) > 0 then
|
|
336
|
+
select string_agg(format('%I = r.%I', x, x), ', ') into sets from unnest(cols) x;
|
|
337
|
+
execute format('update %I.%I t set %s from jsonb_populate_record(null::%I.%I, $2) r where %s',
|
|
338
|
+
s->>'schema', s->>'table', sets, s->>'schema', s->>'table', meta.json_key_where(s->>'schema', s->>'table', s->'key'))
|
|
339
|
+
using pk, d;
|
|
340
|
+
get diagnostics cnt = row_count;
|
|
341
|
+
if cnt = 0 then
|
|
342
|
+
return null;
|
|
343
|
+
end if;
|
|
344
|
+
end if;
|
|
345
|
+
else
|
|
346
|
+
cols := array(
|
|
347
|
+
select a.attname::text from pg_attribute a
|
|
348
|
+
where a.attrelid = format('%I.%I', s->>'schema', s->>'table')::regclass and a.attnum > 0 and not a.attisdropped
|
|
349
|
+
and a.attgenerated = '' and a.attidentity <> 'a' and d ? a.attname and jsonb_typeof(d->a.attname) <> 'null'
|
|
350
|
+
and a.attname <> all (childnames));
|
|
351
|
+
select string_agg(format('%I', x), ', '), string_agg(format('r.%I', x), ', ') into sets, ins from unnest(cols) x;
|
|
352
|
+
if sets is null then
|
|
353
|
+
execute format('insert into %I.%I as t default values returning to_jsonb(t)', s->>'schema', s->>'table') into row_;
|
|
354
|
+
else
|
|
355
|
+
execute format('insert into %I.%I as t (%s) select %s from jsonb_populate_record(null::%I.%I, $1) r returning to_jsonb(t)',
|
|
356
|
+
s->>'schema', s->>'table', sets, ins, s->>'schema', s->>'table')
|
|
357
|
+
into row_ using d;
|
|
358
|
+
end if;
|
|
359
|
+
pk := (select jsonb_object_agg(k2, row_->k2) from jsonb_array_elements_text(s->'key') k2);
|
|
360
|
+
end if;
|
|
361
|
+
|
|
362
|
+
-- the children
|
|
363
|
+
for c in select x from jsonb_array_elements(coalesce(s->'children', '[]')) x loop
|
|
364
|
+
select string_agg(format('x.%I = (jsonb_populate_record(null::%I.%I, $1)).%I', f->>0, s->>'schema', s->>'table', f->>1), ' and ')
|
|
365
|
+
into fkw from jsonb_array_elements(c->'fk') f;
|
|
366
|
+
if tg_op = 'DELETE' then
|
|
367
|
+
execute format('delete from %I.%I x where %s', c->>'schema', c->>'table', fkw) using pk;
|
|
368
|
+
continue;
|
|
369
|
+
end if;
|
|
370
|
+
if not (d ? (c->>'name')) then
|
|
371
|
+
continue;
|
|
372
|
+
end if;
|
|
373
|
+
if jsonb_typeof(d->(c->>'name')) <> 'array' then
|
|
374
|
+
raise exception 'In the document of %.%, % is an array', s->>'schema', s->>'table', c->>'name' using errcode = '22023';
|
|
375
|
+
end if;
|
|
376
|
+
kept := '{}';
|
|
377
|
+
for e in select x from jsonb_array_elements(d->(c->>'name')) x loop
|
|
378
|
+
if jsonb_typeof(e) <> 'object' then
|
|
379
|
+
raise exception 'In the document of %.%, the elements of % are objects', s->>'schema', s->>'table', c->>'name' using errcode = '22023';
|
|
380
|
+
end if;
|
|
381
|
+
-- the foreign key columns come from the parent
|
|
382
|
+
e := e || (select jsonb_object_agg(f->>0, pk->(f->>1)) from jsonb_array_elements(c->'fk') f);
|
|
383
|
+
row_ := null;
|
|
384
|
+
if not exists (select from jsonb_array_elements_text(c->'key') k2 where e->k2 is null or jsonb_typeof(e->k2) = 'null') then
|
|
385
|
+
cols := array(
|
|
386
|
+
select a.attname::text from pg_attribute a
|
|
387
|
+
where a.attrelid = format('%I.%I', c->>'schema', c->>'table')::regclass and a.attnum > 0 and not a.attisdropped
|
|
388
|
+
and a.attgenerated = '' and a.attidentity <> 'a' and e ? a.attname
|
|
389
|
+
and a.attname <> all (array(select jsonb_array_elements_text(c->'key'))));
|
|
390
|
+
select string_agg(format('%I = r.%I', x, x), ', ') into sets from unnest(cols) x;
|
|
391
|
+
execute format('update %I.%I x set %s from jsonb_populate_record(null::%I.%I, $2) r where %s and %s returning to_jsonb(x)',
|
|
392
|
+
c->>'schema', c->>'table', coalesce(sets, format('%I = x.%I', c->'key'->>0, c->'key'->>0)), c->>'schema', c->>'table',
|
|
393
|
+
fkw, meta.json_key_where(c->>'schema', c->>'table', c->'key', 'x', 2))
|
|
394
|
+
into row_ using pk, e;
|
|
395
|
+
end if;
|
|
396
|
+
if row_ is null then
|
|
397
|
+
cols := array(
|
|
398
|
+
select a.attname::text from pg_attribute a
|
|
399
|
+
where a.attrelid = format('%I.%I', c->>'schema', c->>'table')::regclass and a.attnum > 0 and not a.attisdropped
|
|
400
|
+
and a.attgenerated = '' and a.attidentity <> 'a' and e ? a.attname and jsonb_typeof(e->a.attname) <> 'null');
|
|
401
|
+
select string_agg(format('%I', x), ', '), string_agg(format('r.%I', x), ', ') into sets, ins from unnest(cols) x;
|
|
402
|
+
execute format('insert into %I.%I as x (%s) select %s from jsonb_populate_record(null::%I.%I, $1) r returning to_jsonb(x)',
|
|
403
|
+
c->>'schema', c->>'table', sets, ins, c->>'schema', c->>'table')
|
|
404
|
+
into row_ using e;
|
|
405
|
+
end if;
|
|
406
|
+
kept := kept || (select jsonb_object_agg(k2, row_->k2) from jsonb_array_elements_text(c->'key') k2);
|
|
407
|
+
end loop;
|
|
408
|
+
-- the children the document leaves out
|
|
409
|
+
execute format('delete from %I.%I x where %s and not ((select jsonb_object_agg(k, to_jsonb(x)->k) from jsonb_array_elements_text($3) k) = any ($2))',
|
|
410
|
+
c->>'schema', c->>'table', fkw)
|
|
411
|
+
using pk, kept, c->'key';
|
|
412
|
+
end loop;
|
|
413
|
+
|
|
414
|
+
if tg_op = 'DELETE' then
|
|
415
|
+
execute format('delete from %I.%I t where %s', s->>'schema', s->>'table', meta.json_key_where(s->>'schema', s->>'table', s->'key')) using pk;
|
|
416
|
+
get diagnostics cnt = row_count;
|
|
417
|
+
return case when cnt = 0 then null else old end;
|
|
418
|
+
end if;
|
|
419
|
+
new := jsonb_populate_record(new, pk);
|
|
420
|
+
return new;
|
|
421
|
+
end $$;
|
|
422
|
+
|
|
423
|
+
grant execute on function meta.input_ok(text, text), meta.jsonb_put(jsonb, text[], jsonb), meta.jsonb_patch(jsonb, jsonb),
|
|
424
|
+
meta.jsonb_element_keys(jsonb), meta.jsonb_array_change(jsonb, text[], text, text, jsonb),
|
|
425
|
+
meta.json_key_where(text, text, jsonb, text, int), meta.json_column_changes(jsonb, jsonb, jsonb),
|
|
426
|
+
meta.json_source_write(), meta.json_array_write(), meta.json_document_write() to public;
|
|
@@ -7,7 +7,7 @@ open item and open an issue or pull request; see [CONTRIBUTING.md](../CONTRIBUTI
|
|
|
7
7
|
Legend: ✅ available · 🟡 partial (see notes) · ❌ not yet · ➖ not planned (a deliberate choice,
|
|
8
8
|
or better served by the PostgreSQL ecosystem; see the notes and [extensions](guide/15-extensions.md))
|
|
9
9
|
|
|
10
|
-
Last reviewed: 2026-11-04 against **APEX 26.2** (sprint 141: static workspace files (`#WORKSPACE_FILES#`), remote servers for REST data sources, catalogs and AI services (an environment variable per environment), and workspace-level web credentials (AP-7); sprint 140: the items Shuttle (ordered), Select One and Select Many, the regions Classic Report (report templates, pagination types), Breadcrumb and Help Text with a page help text, and a [mapping of every APEX item and region type](#item-and-region-types-one-by-one) (AP-4); sprint 139: OpenTelemetry, traces with a span per SQL statement, web call, AI request and tool call, logs, metrics and `/metrics` for Prometheus, browser spans relayed by pgkiln, per workspace off or its own collector (AP-6); sprint 138: an application's Utilities tab with a dashboard, database object dependencies, change history per component, Upgrade application, UI defaults (APEX's Attribute Dictionary), application and page checksums and an icon browser (AP-5); sprint 137: Create page as a grid of page types with previews, the page types interactive report, smart filters, search page, data loading, tree, timeline, media list, content row, comments, dashboard, wizard, unified task list and workflow console, a Feature tab with nine features that install once, and Create page as copy with shared components mapped or copied (AP-3); sprint 136: vector providers (an AI service with an embedding model or a SQL function), `meta.embed`, *Add vector column* in Table Properties with an HNSW index and a queue that keeps embeddings current, search types vector and hybrid (reciprocal rank fusion with full-text) and a Retrieve (RAG) tool for AI agents, all as the app's role through RLS, on pgvector (AP-1); sprint 135: full-text search configurations, APEX's Oracle Text search type on PostgreSQL full-text search with stemming, ranking, highlights, *Did you mean* and *Add full-text search* in Table Properties (AP-2); sprint 134: the builder also in Italiano, 中文 (简体), 中文 (繁體), 日本語 and 한국어, APEX's ten builder languages plus Nederlands (SEC-5); sprints 121, 123–125: the builder in Deutsch, English, Español, Français, Nederlands and Português, step by step: the frame, sign-in, Workspace home, App Builder, Page Designer menus, the SQL Workshop's home, SQL Worksheet, Object Browser and Table Properties, Shared Components, application settings, users, identity providers, developers and workspaces (WS-7); sprint 122: *Ask in your own words* sets faceted search and smart filter facets, smart filters read a typed phrase (WS-5), and Sample Maps, Sample Approvals, Sample Data Loading and Sample Files in the App Gallery (WS-8); sprint 120: the App Gallery's single-topic sample apps (charts, cards, calendar, interactive grids, dynamic actions, reporting), the UX Pattern Catalog and a Utility Apps tab with Lookup Lists, Release Notes and Announcements (WS-8); sprint 119: data security per table, a roles × columns matrix and masked values per application role in a masking view, the same identity for pages, AI tools, REST, AutoREST and MCP (WS-13); sprint 118: Administration → Mail queue with delivery per hour and per workspace, the slowest provider calls and failures with Retry and Purge, a workspace's own mail service, and workspace network access lists that narrow the installation's allow-list (WS-9); sprint 117: Pillar Light and Pillar Dark navigation appearances with a header strip, clearer navigation tree states, subtle colour utilities, RTL; sprint 116: the comparison moved from 26.1 to 26.2, with a section for the 26.2 workspace items WS-1 … WS-13 and OCI managed identities; the App Builder list with Updated by, working copies and the lock; `pgkiln import --only`, a file-level import; stale rows on facet menus and blueprints fixed; sprint 115: popup LOVs that load on scroll, Wait Popup dynamic actions and dynamic actions on menu entries; sprint 114: Workflow 26.2 with custom task outcomes, task events and notifications, Send E-Mail and draft steps, migrating running instances and the diagram as SVG / PNG; sprint 113: Team Development with issues, labels, milestones, templates, a board and a set-up wizard; sprint 112: AI interactive reports with chips, Undo, computed columns and a phrase parser that needs no AI service; sprint 111: AI Agents with tools as a shared component, a Navigate tool with checksummed URLs, Gemini and OpenAI-compatible services; sprint 110: Data Reporter as a workspace tool with datasets, reporting applications, editors and viewers, published reports with stable URLs and pins; sprint 109: the Workspace home above the App Builder and SQL Workshop, with a summary, top applications, users and developers, and an optional release check; sprint 108: the code editor's syntax colours in the builder's light and dark themes, read-only SQL highlighted, the Data Modeler in dark mode; sprint 107: a transaction mode in the SQL Worksheet with Commit and Rollback; DA-18: JavaScript (MLE) not planned, plv8 where installed; sprint 106: the change log of DDL change sets with Flyway, Liquibase and SQL downloads; sprint 104: RESTful Services modules, templates and handlers with PL/pgSQL and media handlers, privileges, OpenAPI and Try it; sprint 103: Schema Export / Import with pg_dump and pg_restore; sprint 102: the SQL Monitor with live sessions, Top SQL and a statement's plan; sprint 101: Scheduling of pg_cron jobs with a schedule builder, run now and run history; sprint 100: RESTful Services, tables and views published as REST endpoints with paging, filters, keys and OpenAPI; sprint 99: Administration → Database Users for PostgreSQL roles; sprint 98: the Data Modeler with relational diagrams, DDL and a data dictionary; sprint 97: charts of a query in the worksheet, saved charts and their dashboard; sprint 96: the SQL Workshop's Launchpad with pins and tool groups, the builder's search with Ctrl+K; sprint 95: Table Properties: create, edit or copy a table in a form with a DDL preview and Apply in one transaction; sprint 94: an object's menu with Open in a panel, Quick DDL, Add index / trigger / policy and Drop with dependents; sprint 93: worksheets saved as SQL Scripts with tabs and a Files list, Format, Convert case, find and replace, bind and substitution variables; sprint 92: the worksheet's Query Result with sort, value dialog, copy and downloads, plans as a tree with the slowest step and misestimates, SQL History with status, search and run again; sprint 91: the SQL Worksheet like Database Actions' SQL: navigator, Run Statement at the cursor and Run Script with a log per statement, Explain Plan, Autotrace, notices, history, Run as an application role; sprint 90: Comment Out in the page designer, gallery labels in title case; sprint 89: the Object Browser's schema, one row of tabs, blank NULLs, Modify column; sprint 88: home cards with colour bands and round icons, the hero on the page background, a page footer with the version and Back to top; sprint 87: the Create Application wizard reloads the page list for a schema, RLS badges, the alias from the name; sprint 86: the page designer by page number, HTML error pages in the builder; sprint 85: the Form Designer, beyond APEX; sprint 84: the date picker, facet menus; sprint 83: Component Settings and Component Groups; sprint 82: Report Queries; sprint 81: Application Computations and Shortcuts in Shared Components; sprint 80: the master grid's first row selected when the page opens and after a search; grid cells as text with their format mask until edited, with cell navigation by arrow keys, Enter, F2 and Escape; sprint 79: generated dashboards with sums, donuts and lines, leaving out charts that say nothing; applications open in their own light or dark mode until the user chooses, per application; a user menu with Appearance and Sign in when signed out; the developer toolbar's App and Page texts and debug state; the report search's column scope in the magnifier; sprint 78: generated faceted search reports with one column per foreign key, the faceted search's total row count, Show all and Yes/No values, one search field, friendly headings and number formats in generated grids and master-detail pages, friendly names in the Create Application wizard's page list; sprint 77: the Page Designer's layout and tree by display position, button positions, the tree's context menu with Duplicate and Copy to other page, Show Common / Show All, Go to group and the Template Options dialog; display positions, button positions and side-column page templates at runtime; sprint 76: the interactive report's menus and pagination, date items in the date format; sprint 75: the SQL Workshop's Object Browser and tabs; sprint 74: the builder's information architecture: Shared Components grid, Settings tabs, application home search and tasks; sprint 73: the Create Application wizard on one page with page types and features; sprint 72: the runtime chrome compared with APEX 26.2's: the developer toolbar, the Iris look, the navigation bar's Help menu and Install button; sprint 71: generated applications compared with APEX 26.2's: labels, foreign key names in reports, file columns, format masks, the Home page and the dashboard; sprint 70: treemap, sunburst and timeline charts; sprint 69: dragging tasks on a Gantt chart; sprint 68: the Data Reporter's welcome page, Find my workspace; sprint 67: REST source catalogs from OpenAPI documents, a workspace's export and import (two rows added); sprint 66: a blueprint from an existing application; sprint 65: facet charts; sprint 64: approval vacation rules and expiration policies; sprint 63: range, box plot and stock charts; sprint 62: workspace preferences (SQL Workshop and RESTful services per workspace), extension links, Manage backups across applications, SQL Workshop utilities with object reports, About Database and a database monitor; sprint 61: the builder's screens compared with APEX 26.1: the workspace sign-in page, the Administration menu with workspace message, environment banner and utilization, the SQL Workshop home, the App Gallery, application groups and cross application reports (four rows added); sprint 60: isolated workspaces with their own database logins, row-level security on pgkiln's tables and workspace database roles, workspace administrators; sprint 59: the Page Designer's help pane, Quick edit from the developer toolbar; sprint 58: page groups; sprint 57: region templates hero, title bar, buttons container, inline dialog and drawer, wizard with wizard progress, the carousel; sprint 56: Generate DDL and Schema Comparison in the SQL Workshop, `pgkiln ddl` and `pgkiln compare`; sprint 55: an editable login page with a Login region and the Minimal page template, Forgot password through the application's mail service; sprint 54: interactive grid views, the single row view, group by and chart; sprint 53: application settings, user preferences and items kept per user, dynamic translations, `meta.data_export` and data export downloads, display image and geocoded address items; sprint 52: every dynamic action event and action, Ajax callbacks, an error handling function, the session timeout warning; sprint 51: checked imports, application backups, availability and Run only, feedback, type-specific attribute help; sprint 50: lost update detection, warn on unsaved changes, the URL and search regions with search configurations, the developer toolbar with a session state viewer, and e-mail through SMTP with OAuth2, Microsoft Graph, Amazon SES and HTTP APIs; import checks, application availability, property help and e-mail compared again; 2026-10-06: pgkiln 0.31.0, in progress: static application files and the Execute JavaScript dynamic action; region, item, dynamic action and process plug-ins; conditional and dynamic theme styles; XML and Excel in `meta.parse_data`, zips in SQL, `meta.v_boolean`; file items in S3-compatible object storage; map layers by the visible area and as vector tiles; a graphical query builder; tenants for workflows and tasks; application files as YAML and region static IDs; Lucide icons and icon modifiers; PWA push notifications; 0.30.0: 136 icons and an icon picker; an axe-core accessibility audit; cropping pictures; session sharing between applications; twenty-two built-in languages; 0.29.0: workspaces; the Iris base style; drawers; built-in template components including the metric card; Theme Roller dark-mode colours, live preview and template options on items and report columns; report selection across pages; instance settings; fourteen built-in languages; 0.28.0: AI with Claude and OpenAI; 0.27.0: Data Reporter; sample data generator; create application from several sheets, pasted data or existing tables; 0.26.0: working copies with a three-way merge; theme, library and boilerplate applications with subscriptions; 0.25.0: Gantt, pyramid and polar charts; map layers, clustering and server-side spatial filters; REST data sources that write back from forms and grids and synchronise into tables, OAuth2 password and refresh-token grants; debug messages per request and an install/upgrade log; `meta.web_request()` and `meta.parse_data()`; Theme Roller style variants and template options; 0.24.0: automations with several actions, error handling per row and runs from SQL; invoke-API workflow steps; Unload Data in the Data Workshop; create page wizards for cards, calendar, chart, map, faceted search, form and master-detail; create an application from a file; 0.23.0: interactive grid aggregates, frozen/moved/resized columns, layouts and saved grid reports, master-detail, row actions and copy/paste; download processes, execution chains in the background, workflow processes, branches to a function's URL or another app, the Dialog Closed event; number format masks, automatic time zone, runtime messages in German, French and Spanish; SQL scripts, Quick SQL, a query builder, XML loading and data load definitions; custom authentication, lists, page and application locks with developer comments, supporting objects; 0.22.0: keyset paging, report PDFs and REST collections streamed from a cursor, database-account authentication; 0.21.0: HTTP-header authentication behind a reverse proxy; 0.20.0: a popup list of values with server-side search; 0.19.0: row-range pagination, maximum row counts and row limits, lazy loading and caching of regions, streamed CSV/Excel downloads; 0.18.0: calendar week/day/list views with drag and drop, bubble/gauge/funnel/radar charts and drill-down, smart filters, a region display selector and more facet types, computations, conditional branches, build options, menu buttons, REST data sources and web credentials, rich text/Markdown, rating, combobox, date range and QR code items; 0.17.0: an App Builder home, workspace dashboard and utilities like APEX's; 0.16.0: a Page Designer with drag-and-drop layout, a code editor with autocomplete, template components and plug-ins, parallel branches and versions of workflows, the `pgkiln` command line with one file per component; 0.15.0: drop and paste files, heat maps, filtering a report by the map area; 0.14.0: stacked, combo, scatter and pie charts, several files per upload item; 0.13.0: map and tree regions; 0.12.0: REST modules in the builder; 0.11.0: workflows and Progressive Web Apps; 0.10.0: LDAP, SAML, "Keep me signed in", document templates, JSON loading, approvals and the task list; pgkiln installs no application, HR is an example).
|
|
10
|
+
Last reviewed: 2026-11-04 against **APEX 26.2** (sprint 142: JSON sources with a data profile and updatable views whose arrays are rows, document views of a table with its children (APEX's duality views), JSON path columns in reports (AP-8); sprint 141: static workspace files (`#WORKSPACE_FILES#`), remote servers for REST data sources, catalogs and AI services (an environment variable per environment), and workspace-level web credentials (AP-7); sprint 140: the items Shuttle (ordered), Select One and Select Many, the regions Classic Report (report templates, pagination types), Breadcrumb and Help Text with a page help text, and a [mapping of every APEX item and region type](#item-and-region-types-one-by-one) (AP-4); sprint 139: OpenTelemetry, traces with a span per SQL statement, web call, AI request and tool call, logs, metrics and `/metrics` for Prometheus, browser spans relayed by pgkiln, per workspace off or its own collector (AP-6); sprint 138: an application's Utilities tab with a dashboard, database object dependencies, change history per component, Upgrade application, UI defaults (APEX's Attribute Dictionary), application and page checksums and an icon browser (AP-5); sprint 137: Create page as a grid of page types with previews, the page types interactive report, smart filters, search page, data loading, tree, timeline, media list, content row, comments, dashboard, wizard, unified task list and workflow console, a Feature tab with nine features that install once, and Create page as copy with shared components mapped or copied (AP-3); sprint 136: vector providers (an AI service with an embedding model or a SQL function), `meta.embed`, *Add vector column* in Table Properties with an HNSW index and a queue that keeps embeddings current, search types vector and hybrid (reciprocal rank fusion with full-text) and a Retrieve (RAG) tool for AI agents, all as the app's role through RLS, on pgvector (AP-1); sprint 135: full-text search configurations, APEX's Oracle Text search type on PostgreSQL full-text search with stemming, ranking, highlights, *Did you mean* and *Add full-text search* in Table Properties (AP-2); sprint 134: the builder also in Italiano, 中文 (简体), 中文 (繁體), 日本語 and 한국어, APEX's ten builder languages plus Nederlands (SEC-5); sprints 121, 123–125: the builder in Deutsch, English, Español, Français, Nederlands and Português, step by step: the frame, sign-in, Workspace home, App Builder, Page Designer menus, the SQL Workshop's home, SQL Worksheet, Object Browser and Table Properties, Shared Components, application settings, users, identity providers, developers and workspaces (WS-7); sprint 122: *Ask in your own words* sets faceted search and smart filter facets, smart filters read a typed phrase (WS-5), and Sample Maps, Sample Approvals, Sample Data Loading and Sample Files in the App Gallery (WS-8); sprint 120: the App Gallery's single-topic sample apps (charts, cards, calendar, interactive grids, dynamic actions, reporting), the UX Pattern Catalog and a Utility Apps tab with Lookup Lists, Release Notes and Announcements (WS-8); sprint 119: data security per table, a roles × columns matrix and masked values per application role in a masking view, the same identity for pages, AI tools, REST, AutoREST and MCP (WS-13); sprint 118: Administration → Mail queue with delivery per hour and per workspace, the slowest provider calls and failures with Retry and Purge, a workspace's own mail service, and workspace network access lists that narrow the installation's allow-list (WS-9); sprint 117: Pillar Light and Pillar Dark navigation appearances with a header strip, clearer navigation tree states, subtle colour utilities, RTL; sprint 116: the comparison moved from 26.1 to 26.2, with a section for the 26.2 workspace items WS-1 … WS-13 and OCI managed identities; the App Builder list with Updated by, working copies and the lock; `pgkiln import --only`, a file-level import; stale rows on facet menus and blueprints fixed; sprint 115: popup LOVs that load on scroll, Wait Popup dynamic actions and dynamic actions on menu entries; sprint 114: Workflow 26.2 with custom task outcomes, task events and notifications, Send E-Mail and draft steps, migrating running instances and the diagram as SVG / PNG; sprint 113: Team Development with issues, labels, milestones, templates, a board and a set-up wizard; sprint 112: AI interactive reports with chips, Undo, computed columns and a phrase parser that needs no AI service; sprint 111: AI Agents with tools as a shared component, a Navigate tool with checksummed URLs, Gemini and OpenAI-compatible services; sprint 110: Data Reporter as a workspace tool with datasets, reporting applications, editors and viewers, published reports with stable URLs and pins; sprint 109: the Workspace home above the App Builder and SQL Workshop, with a summary, top applications, users and developers, and an optional release check; sprint 108: the code editor's syntax colours in the builder's light and dark themes, read-only SQL highlighted, the Data Modeler in dark mode; sprint 107: a transaction mode in the SQL Worksheet with Commit and Rollback; DA-18: JavaScript (MLE) not planned, plv8 where installed; sprint 106: the change log of DDL change sets with Flyway, Liquibase and SQL downloads; sprint 104: RESTful Services modules, templates and handlers with PL/pgSQL and media handlers, privileges, OpenAPI and Try it; sprint 103: Schema Export / Import with pg_dump and pg_restore; sprint 102: the SQL Monitor with live sessions, Top SQL and a statement's plan; sprint 101: Scheduling of pg_cron jobs with a schedule builder, run now and run history; sprint 100: RESTful Services, tables and views published as REST endpoints with paging, filters, keys and OpenAPI; sprint 99: Administration → Database Users for PostgreSQL roles; sprint 98: the Data Modeler with relational diagrams, DDL and a data dictionary; sprint 97: charts of a query in the worksheet, saved charts and their dashboard; sprint 96: the SQL Workshop's Launchpad with pins and tool groups, the builder's search with Ctrl+K; sprint 95: Table Properties: create, edit or copy a table in a form with a DDL preview and Apply in one transaction; sprint 94: an object's menu with Open in a panel, Quick DDL, Add index / trigger / policy and Drop with dependents; sprint 93: worksheets saved as SQL Scripts with tabs and a Files list, Format, Convert case, find and replace, bind and substitution variables; sprint 92: the worksheet's Query Result with sort, value dialog, copy and downloads, plans as a tree with the slowest step and misestimates, SQL History with status, search and run again; sprint 91: the SQL Worksheet like Database Actions' SQL: navigator, Run Statement at the cursor and Run Script with a log per statement, Explain Plan, Autotrace, notices, history, Run as an application role; sprint 90: Comment Out in the page designer, gallery labels in title case; sprint 89: the Object Browser's schema, one row of tabs, blank NULLs, Modify column; sprint 88: home cards with colour bands and round icons, the hero on the page background, a page footer with the version and Back to top; sprint 87: the Create Application wizard reloads the page list for a schema, RLS badges, the alias from the name; sprint 86: the page designer by page number, HTML error pages in the builder; sprint 85: the Form Designer, beyond APEX; sprint 84: the date picker, facet menus; sprint 83: Component Settings and Component Groups; sprint 82: Report Queries; sprint 81: Application Computations and Shortcuts in Shared Components; sprint 80: the master grid's first row selected when the page opens and after a search; grid cells as text with their format mask until edited, with cell navigation by arrow keys, Enter, F2 and Escape; sprint 79: generated dashboards with sums, donuts and lines, leaving out charts that say nothing; applications open in their own light or dark mode until the user chooses, per application; a user menu with Appearance and Sign in when signed out; the developer toolbar's App and Page texts and debug state; the report search's column scope in the magnifier; sprint 78: generated faceted search reports with one column per foreign key, the faceted search's total row count, Show all and Yes/No values, one search field, friendly headings and number formats in generated grids and master-detail pages, friendly names in the Create Application wizard's page list; sprint 77: the Page Designer's layout and tree by display position, button positions, the tree's context menu with Duplicate and Copy to other page, Show Common / Show All, Go to group and the Template Options dialog; display positions, button positions and side-column page templates at runtime; sprint 76: the interactive report's menus and pagination, date items in the date format; sprint 75: the SQL Workshop's Object Browser and tabs; sprint 74: the builder's information architecture: Shared Components grid, Settings tabs, application home search and tasks; sprint 73: the Create Application wizard on one page with page types and features; sprint 72: the runtime chrome compared with APEX 26.2's: the developer toolbar, the Iris look, the navigation bar's Help menu and Install button; sprint 71: generated applications compared with APEX 26.2's: labels, foreign key names in reports, file columns, format masks, the Home page and the dashboard; sprint 70: treemap, sunburst and timeline charts; sprint 69: dragging tasks on a Gantt chart; sprint 68: the Data Reporter's welcome page, Find my workspace; sprint 67: REST source catalogs from OpenAPI documents, a workspace's export and import (two rows added); sprint 66: a blueprint from an existing application; sprint 65: facet charts; sprint 64: approval vacation rules and expiration policies; sprint 63: range, box plot and stock charts; sprint 62: workspace preferences (SQL Workshop and RESTful services per workspace), extension links, Manage backups across applications, SQL Workshop utilities with object reports, About Database and a database monitor; sprint 61: the builder's screens compared with APEX 26.1: the workspace sign-in page, the Administration menu with workspace message, environment banner and utilization, the SQL Workshop home, the App Gallery, application groups and cross application reports (four rows added); sprint 60: isolated workspaces with their own database logins, row-level security on pgkiln's tables and workspace database roles, workspace administrators; sprint 59: the Page Designer's help pane, Quick edit from the developer toolbar; sprint 58: page groups; sprint 57: region templates hero, title bar, buttons container, inline dialog and drawer, wizard with wizard progress, the carousel; sprint 56: Generate DDL and Schema Comparison in the SQL Workshop, `pgkiln ddl` and `pgkiln compare`; sprint 55: an editable login page with a Login region and the Minimal page template, Forgot password through the application's mail service; sprint 54: interactive grid views, the single row view, group by and chart; sprint 53: application settings, user preferences and items kept per user, dynamic translations, `meta.data_export` and data export downloads, display image and geocoded address items; sprint 52: every dynamic action event and action, Ajax callbacks, an error handling function, the session timeout warning; sprint 51: checked imports, application backups, availability and Run only, feedback, type-specific attribute help; sprint 50: lost update detection, warn on unsaved changes, the URL and search regions with search configurations, the developer toolbar with a session state viewer, and e-mail through SMTP with OAuth2, Microsoft Graph, Amazon SES and HTTP APIs; import checks, application availability, property help and e-mail compared again; 2026-10-06: pgkiln 0.31.0, in progress: static application files and the Execute JavaScript dynamic action; region, item, dynamic action and process plug-ins; conditional and dynamic theme styles; XML and Excel in `meta.parse_data`, zips in SQL, `meta.v_boolean`; file items in S3-compatible object storage; map layers by the visible area and as vector tiles; a graphical query builder; tenants for workflows and tasks; application files as YAML and region static IDs; Lucide icons and icon modifiers; PWA push notifications; 0.30.0: 136 icons and an icon picker; an axe-core accessibility audit; cropping pictures; session sharing between applications; twenty-two built-in languages; 0.29.0: workspaces; the Iris base style; drawers; built-in template components including the metric card; Theme Roller dark-mode colours, live preview and template options on items and report columns; report selection across pages; instance settings; fourteen built-in languages; 0.28.0: AI with Claude and OpenAI; 0.27.0: Data Reporter; sample data generator; create application from several sheets, pasted data or existing tables; 0.26.0: working copies with a three-way merge; theme, library and boilerplate applications with subscriptions; 0.25.0: Gantt, pyramid and polar charts; map layers, clustering and server-side spatial filters; REST data sources that write back from forms and grids and synchronise into tables, OAuth2 password and refresh-token grants; debug messages per request and an install/upgrade log; `meta.web_request()` and `meta.parse_data()`; Theme Roller style variants and template options; 0.24.0: automations with several actions, error handling per row and runs from SQL; invoke-API workflow steps; Unload Data in the Data Workshop; create page wizards for cards, calendar, chart, map, faceted search, form and master-detail; create an application from a file; 0.23.0: interactive grid aggregates, frozen/moved/resized columns, layouts and saved grid reports, master-detail, row actions and copy/paste; download processes, execution chains in the background, workflow processes, branches to a function's URL or another app, the Dialog Closed event; number format masks, automatic time zone, runtime messages in German, French and Spanish; SQL scripts, Quick SQL, a query builder, XML loading and data load definitions; custom authentication, lists, page and application locks with developer comments, supporting objects; 0.22.0: keyset paging, report PDFs and REST collections streamed from a cursor, database-account authentication; 0.21.0: HTTP-header authentication behind a reverse proxy; 0.20.0: a popup list of values with server-side search; 0.19.0: row-range pagination, maximum row counts and row limits, lazy loading and caching of regions, streamed CSV/Excel downloads; 0.18.0: calendar week/day/list views with drag and drop, bubble/gauge/funnel/radar charts and drill-down, smart filters, a region display selector and more facet types, computations, conditional branches, build options, menu buttons, REST data sources and web credentials, rich text/Markdown, rating, combobox, date range and QR code items; 0.17.0: an App Builder home, workspace dashboard and utilities like APEX's; 0.16.0: a Page Designer with drag-and-drop layout, a code editor with autocomplete, template components and plug-ins, parallel branches and versions of workflows, the `pgkiln` command line with one file per component; 0.15.0: drop and paste files, heat maps, filtering a report by the map area; 0.14.0: stacked, combo, scatter and pie charts, several files per upload item; 0.13.0: map and tree regions; 0.12.0: REST modules in the builder; 0.11.0: workflows and Progressive Web Apps; 0.10.0: LDAP, SAML, "Keep me signed in", document templates, JSON loading, approvals and the task list; pgkiln installs no application, HR is an example).
|
|
11
11
|
|
|
12
12
|
## At a glance
|
|
13
13
|
|
|
@@ -20,11 +20,11 @@ Last reviewed: 2026-11-04 against **APEX 26.2** (sprint 141: static workspace fi
|
|
|
20
20
|
| Security | 22 | 0 | 0 | 0 | An editable login page and Forgot password; a session timeout warning; On par or stricter (CSP without `unsafe-inline`); OIDC, SAML and LDAP; header authentication behind a proxy; database accounts; custom authentication |
|
|
21
21
|
| User interface | 12 | 0 | 0 | 0 | Region templates incl. hero, inline dialog and drawer, wizard and carousel; Universal Theme-like and responsive; a Theme Roller with style variants and conditional, dynamic styles; about 1,700 icons with Font APEX-like modifiers |
|
|
22
22
|
| Globalization | 6 | 0 | 0 | 0 | One translated app like 26.1 with dynamic translations of table values; number format masks and automatic time zone; twenty-two built-in languages |
|
|
23
|
-
| Data and integration |
|
|
23
|
+
| Data and integration | 16 | 0 | 0 | 1 | Remote servers, static workspace files and workspace web credentials; REST source catalogs from OpenAPI documents; Generate DDL and schema comparison; `meta.data_export` and data export downloads (CSV, JSON, XML, HTML, Excel, PDF); e-mail through SMTP (password or OAuth2), Microsoft Graph, Amazon SES and HTTP APIs; REST APIs via PostgREST, REST data sources that write back and synchronise, web credentials with OAuth2 grants, CSV/XLSX/JSON/XML loading with saved definitions and unloading, SQL scripts and Quick SQL, report PDFs and document templates |
|
|
24
24
|
| Workflow, automation and AI | 6 | 0 | 0 | 0 | Scheduled automations with several actions and runs from SQL, approvals, a task list and workflows with parallel branches, versions and invoke-API steps; AI with Claude or OpenAI: *Generate text with AI*, an assistant region with tools, natural-language report filters and blueprints |
|
|
25
25
|
| Administration | 15 | 0 | 0 | 0 | OpenTelemetry traces, logs and metrics to the team's own monitoring and `/metrics` for Prometheus (24.2); An APEX-like sign-in with a workspace and a Workspace home; a mail queue dashboard, a workspace's own mail service and network access list (26.1 / 26.2); a workspace's components exported and imported as one file; workspace message, environment banner and utilization; isolated workspaces with their own database logins and roles, and workspace administrators; application availability and Run only, automatic backups, user feedback; a developer toolbar with a session state viewer and debug per session; Top SQL per app; debug messages per request; an install/upgrade log |
|
|
26
26
|
| APEX 26.2 workspace (WS-1 … WS-13) | 13 | 0 | 0 | 1 | Workspace home, Data Reporter as a workspace tool, Team Development, AI Agents, AI interactive reports, Workflow 26.2, the mail queue, workspace mail and network access, the 26.1 component details, the App Builder list's details, the Pillar navigation appearances and data security per table (rows, columns and masked values), the App Gallery's single-topic sample apps, UX Pattern Catalog and Utility Apps; the builder in eleven languages (APEX's ten and Nederlands) |
|
|
27
|
-
| **Total** | **
|
|
27
|
+
| **Total** | **169** | **0** | **0** | **3** | 172 APEX features compared: 98% available, none missing, 3 deliberately not planned |
|
|
28
28
|
|
|
29
29
|
(Counts are of the rows in the tables below. A review on 2026-10-06 added 18 rows for APEX features that were
|
|
30
30
|
not compared before, one on 2026-10-12 added two more (property help, application availability), and one on
|
|
@@ -280,7 +280,7 @@ review is a diff. Not counted in [At a glance](#at-a-glance): the rows above com
|
|
|
280
280
|
| SQL Workshop utilities: schema comparison, generate DDL | ✅ | (sprint 56) SQL Workshop → **DDL**: a schema's objects (types, sequences, tables, functions, views, constraints, indexes, triggers, RLS and policies, comments, grants) from the catalog, in an order that runs, unqualified so it also creates them in another schema. **Compare**: two schemas by their DDL (only in one, different, with a diff) and a change script that makes the target like the source (tables column by column; drops commented out for review). Also `pgkiln ddl`, `pgkiln compare` and the MCP tools `generate_ddl`, `compare_schemas` ([chapter 3](guide/03-builder.md#sql-workshop)). Two schemas of the same database only (APEX: also within one workspace) |
|
|
281
281
|
| Data Reporter: self-service reports for business users (26.1) | ✅ | A **Data Reporter** region ([chapter 4](guide/04-pages-and-regions.md#data_reporter-data-reporter)): the developer offers tables and views with chosen columns, labels and format masks; signed-in users pick columns, filter, group with totals (count, sum, average, minimum, maximum), sort and chart, and save reports privately or shared with the app's users. Runs as the app's role (grants and RLS apply); works without JavaScript and fits phones. (sprint 68) A **welcome page** like 26.1's: a greeting (the developer's own, or pgkiln's), the sources as cards that start a report, the user's reports latest first, shared ones, and a search. One source per report (offer a view to combine tables); no downloads from a reporter yet (sprint 110) **A workspace tool too**: App Builder → **Data Reporter** ([chapter 3](guide/03-builder.md#data-reporter-datasets-and-reporting-applications)) keeps **datasets** (tables and views of one schema with joins proposed from foreign keys, offered columns with labels, masks and descriptions, a row filter; files and the workspace export) and makes a **reporting application** on them in two clicks: viewers open published reports by a stable URL and pin them, editors build and publish, administrators moderate; every report runs as the application's SELECT-only role through RLS. |
|
|
282
282
|
| REST Source Catalogs (Workspace Utilities) | ✅ | (sprint 67) Workspace utilities → **REST Source Catalogs**: a workspace's web services with a base URL and services, from an **OpenAPI 3 / Swagger 2.0** document (file, pasted or read from a URL on the allow-list), a catalog file or by hand: parameters (under the service's own names), row selector, typed columns and write-back operations from the response schemas and collection/item paths, with notes on what can't be used. An application's *REST data sources → From a REST source catalog* makes a data source from a service, with its own web credential ([chapter 19](guide/19-rest-data-sources.md#rest-source-catalogs)). **Missing:** YAML documents (convert to JSON), APEX's built-in catalogs (e.g. Oracle Fusion) |
|
|
283
|
-
| JSON sources, duality views (24.2) |
|
|
283
|
+
| JSON sources, duality views (24.2) | ✅ | (sprint 142, AP-8) Shared Components → **JSON Sources** ([chapter 19](guide/19-rest-data-sources.md#json-sources-and-document-views)): a `jsonb` column with a data profile proposed from the documents; `security_invoker` views with a typed column per path and a view per array (stable row keys), whose triggers write only the changed paths, so unknown keys stay; forms, reports, grids, master-detail, AutoREST and MCP use them like tables; Create page makes a form with detail grids. Table Properties → **Document view**: a row and its child rows as one `jsonb` document, written back in one statement (the duality view). JSON path columns in reports |
|
|
284
284
|
| Remote Servers (Workspace Utilities): a named base URL per environment for REST data sources, catalogs and AI services | ✅ | (sprint 141, AP-7) Workspace utilities → **Remote servers** ([chapter 19](guide/19-rest-data-sources.md#remote-servers)): a static id, this installation's base URL and/or an environment variable `PGKILN_SERVER_<NAME>` that wins when set, and a default web credential. REST data sources (a server and a path), REST source catalogs and AI services name a server, so changing it moves every source at once; the resolved URL passes the allow-list, the workspace's network access list (which shows each server's host) and the address checks. In the workspace export (an existing server keeps its local URL) |
|
|
285
285
|
| Static Workspace Files (`#WORKSPACE_FILES#`), workspace-level Web Credentials | ✅ | (sprint 141, AP-7) Workspace utilities → **Static workspace files**: CSS, JavaScript, images and fonts with the static application files' types (no HTML), size limit and headers, served to each application of the workspace at `/a/<alias>/workspace-files/<name>`, loaded with `#WORKSPACE_FILES#name` and written as `#WORKSPACE_FILES#` / `#APP_FILES#` in HTML and templates ([chapter 16](guide/16-files.md#static-workspace-files)). **Web credentials** of the workspace, used by name by its applications (an application's own of the same name wins); secrets encrypted, write-only, never exported. Both in the workspace export |
|
|
286
286
|
| Remote database regions (REST Enabled SQL), database links | ➖ | Not built: regions on another database were left out of sprint 141. `postgres_fdw` or `dblink` bring another PostgreSQL database's tables into the application's own |
|
|
@@ -460,7 +460,7 @@ Sources: [APEX 26.2 new features](https://docs.oracle.com/en/database/oracle/ape
|
|
|
460
460
|
| Progressive Web App | Settings → Progressive Web App |
|
|
461
461
|
| Static Application Files, Static Workspace Files | Static Application Files; Static workspace files in Workspace utilities (sprint 141) |
|
|
462
462
|
| Report Layouts, Report Queries | The same names (Files and Reports, sprint 82): a report query is one query printed as PDF with a report layout, Excel, CSV, JSON, XML or HTML (`?doc=NAME`, document buttons); APEX's several queries for one layout: a document template's JSON columns |
|
|
463
|
-
| REST Data Sources, Web Credentials, REST Enabled SQL, Data Load Definitions | The same names (Data Sources); web credentials of the workspace and Remote Servers in Workspace utilities (sprint 141); REST Enabled SQL ➖ not planned (one database) |
|
|
463
|
+
| REST Data Sources, Web Credentials, REST Enabled SQL, Data Load Definitions, JSON Sources | The same names (Data Sources; JSON Sources since sprint 142); web credentials of the workspace and Remote Servers in Workspace utilities (sprint 141); REST Enabled SQL ➖ not planned (one database) |
|
|
464
464
|
| Workflows, Task Definitions, Automations | The same names |
|
|
465
465
|
| Text Messages, Translate, Dynamic Translations, Globalization Attributes | Translations and Text Messages, Dynamic Translations, Settings → Globalization |
|
|
466
466
|
| Map Backgrounds | ➖ Not planned per application: the installation's map tile server (`MAP_TILE_URL`) is every map's background |
|
package/docs/guide/03-builder.md
CHANGED
|
@@ -1899,6 +1899,17 @@ earns most?* and it calls the SQL tool `top_earners` as the signed-in user's rol
|
|
|
1899
1899
|
*Open BLAKE's record*, a link to the employee form (page 3) with a valid checksum, only to users who
|
|
1900
1900
|
may open that page.
|
|
1901
1901
|
|
|
1902
|
+
## JSON sources
|
|
1903
|
+
|
|
1904
|
+
(sprint 142; APEX: JSON Sources) Shared Components → Data Sources → **JSON Sources**: a `jsonb` column of one of the
|
|
1905
|
+
application's tables described by a data profile (columns at paths, arrays of objects or values), kept in
|
|
1906
|
+
`meta.app.json_sources` and exported with the application. *Propose from the data* reads up to 200 documents;
|
|
1907
|
+
**Create views** makes a `security_invoker` view with a typed column per path and a view per array (one row per
|
|
1908
|
+
element), with INSTEAD OF triggers that write only the changed paths, so keys the profile doesn't know stay in the
|
|
1909
|
+
documents; **Create page** makes a form on the view with a detail grid per array. The list shows which views are
|
|
1910
|
+
not made yet. Everything about the views, their keys and their security is in
|
|
1911
|
+
[chapter 19](19-rest-data-sources.md#json-sources-and-document-views).
|
|
1912
|
+
|
|
1902
1913
|
## Vector providers
|
|
1903
1914
|
|
|
1904
1915
|
(sprint 136; APEX: Vector Providers) A **vector provider** turns a text into an **embedding**: a list of numbers
|
|
@@ -2084,6 +2095,10 @@ the SQL Workshop's connection may use. Without JavaScript the header's field ope
|
|
|
2084
2095
|
[vector provider](#vector-providers), an HNSW index for the distance and a trigger that re-embeds a row when its
|
|
2085
2096
|
source columns change (at once with a function provider, else through the server's queue); the page shows each
|
|
2086
2097
|
vector column's progress and **Backfill**. Without pgvector it says what is missing.
|
|
2098
|
+
(sprint 142) **Document view…** (Table Properties, or the ⋯ menu): a `security_invoker` view with the table's key
|
|
2099
|
+
and a `jsonb` document per row with lists of the child tables you tick (by foreign key); writing a document
|
|
2100
|
+
updates the row, upserts the children it lists and deletes the ones it leaves out, like an APEX duality view
|
|
2101
|
+
([chapter 19](19-rest-data-sources.md#document-views-duality-views)). Preview, Apply (Change Log) or Open in the worksheet.
|
|
2087
2102
|
- (sprint 119) **Security** (the Object Browser's *Security* button on a table, *Security…* in its ⋯ menu): the
|
|
2088
2103
|
table's row level security policies, a matrix of database roles × columns with *read* and *update*, and masked
|
|
2089
2104
|
columns per application role in a masking view; Preview SQL, Apply (one transaction, recorded in the Change Log)
|
|
@@ -414,6 +414,7 @@ Attributes (most of them are also in the page designer's **Report settings** for
|
|
|
414
414
|
| `sortable` | `true` | Allow sorting (`false` keeps the query's order, e.g. for trees) |
|
|
415
415
|
| `mobile` | `"reflow"` | `"scroll"` keeps a horizontally scrolling table on phones |
|
|
416
416
|
| `hidden` | `[]` | Column names to leave out of the display (they can still be used in links). Users can't search, filter, sort, compute or aggregate on them either, also not by editing the URL |
|
|
417
|
+
| `json_columns` | none | (sprint 142) Columns read from a json or jsonb column of the source: `[{"name": "title", "column": "profile", "path": "title", "type": "text"}]`. A path is keys separated by dots, a number picks an array element (`skills.0.name`); `type` is `text` (default), `integer`, `bigint`, `numeric`, `boolean`, `date`, `timestamp`, `timestamptz` or `jsonb`, and a value that doesn't read as it is NULL. They are columns like the others (search, filters, sorting, downloads). In the report settings: *JSON path columns*, `name=column:path[:type]; …` ([chapter 19](19-rest-data-sources.md#json-path-columns-in-reports)) |
|
|
417
418
|
| `headings` | `{}` | Column headings, e.g. `{"sal": "Salary"}`; by default `hire_date` becomes "Hire Date" |
|
|
418
419
|
| `formats` | `{}` | Format masks per column, e.g. `{"sal": "FML999G990D00", "hiredate": "DD-MON-YYYY"}` (see [number formats](14-globalization.md#number-formats)) |
|
|
419
420
|
| `link` | none | Makes one column a link: `{"column": "empno", "page": 3, "items": {"P3_EMPNO": "#empno#"}}`. `#col#` is replaced by the row's value; the link carries a checksum and is hidden when the user may not open that page |
|
|
@@ -139,6 +139,10 @@ src/
|
|
|
139
139
|
wins over base_url), joinUrl, resolveSource (a REST source on a server: full URL + the server's default
|
|
140
140
|
credential; used by loadSource/fetchSource/callOperation), catalog and AI service URLs (owner pool,
|
|
141
141
|
the application's own workspace only)
|
|
142
|
+
json-sources.ts (sprint 142, AP-8) JSON sources (meta.app.json_sources): jsonSourceProblems, proposeProfile (types and
|
|
143
|
+
arrays from sample documents), jsonSourceDdl (security_invoker views with the meta.json_source_write /
|
|
144
|
+
json_array_write triggers, the table's grants), documentViewDdl (duality-view analogue, meta.json_document_write),
|
|
145
|
+
withJsonColumns / parseJsonColumns (a report's json_columns), catalog helpers (primaryKey, tableGrants, childTables)
|
|
142
146
|
datapump.ts (sprint 103, DA-16) Schema Export / Import jobs (meta.dump_job): findTools (pg_dump/pg_restore ≥ the
|
|
143
147
|
server's major), startExport (pg_dump, argument array, PGPASSWORD), readToc/parseToc (pg_restore --list),
|
|
144
148
|
startImport (pg_restore -f - run in one transaction between schema renames; data-only in FK order),
|
|
@@ -419,6 +423,11 @@ src/
|
|
|
419
423
|
vector-providers.ts (sprint 136, AP-1) Shared Components → Vector providers (/apps/:id/vector-providers: list, provider form,
|
|
420
424
|
test, delete) and Workspace utilities → Vector providers (/vector-providers: pgvector status, Create
|
|
421
425
|
extension for administrators, the workspace's providers and vector columns); pgvectorNote()
|
|
426
|
+
json-sources.ts (sprint 142, AP-8) Shared Components → JSON sources (/apps/:id/json-sources: list, source form with
|
|
427
|
+
Propose from the data, views: Create views / worksheet (Change Log), page: createSourcePage() = a form
|
|
428
|
+
on the view and a detail grid per array, delete)
|
|
429
|
+
document-view.ts (sprint 142, AP-8) Table Properties › Document view: GET/POST /sql/objects/document?o= (child tables
|
|
430
|
+
by foreign key), Preview / Apply (Change Log) / worksheet
|
|
422
431
|
telemetry.ts (sprint 139, AP-6) Workspace utilities → OpenTelemetry (/telemetry: the collector, signals, values, user,
|
|
423
432
|
browser spans, /metrics and its token, status per collector, Send a test span; administrators) and a
|
|
424
433
|
workspace's own (/workspaces/:id/telemetry: as the instance / off / own collector; its administrators)
|
|
@@ -643,6 +652,8 @@ test/
|
|
|
643
652
|
workspace-transfer.test.ts a workspace's export, import into another workspace (added, kept, replaced, all or nothing), groups, access
|
|
644
653
|
workspace-resources.test.ts (sprint 141) remote servers (checks, env var, HR's CRM moves its sources, credentials, renames, catalogs,
|
|
645
654
|
AI services, the Advisor), static workspace files styling two applications, workspace credentials, the export
|
|
655
|
+
json-sources.test.ts (sprint 142) data profiles, the views' DDL, writing through them (unknown keys stay, arrays by row_key,
|
|
656
|
+
a table of documents, document views), HR page 51 (JSON path columns, form and skills grid), the builder, export
|
|
646
657
|
tree-charts.test.ts treemap and sunburst (the hierarchy, cycles, squarify), timeline (lanes, rows, points and periods)
|
|
647
658
|
gantt-move.test.ts an editable Gantt's markup, the move route, dates, who may drag, the builder's settings
|
|
648
659
|
find-workspace.test.ts developers' addresses, builder mail, the workspaces mail, the same answer, limits
|