pgkiln 0.44.0 → 0.46.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.
Files changed (91) hide show
  1. package/db/migrations/102_app_computations.sql +345 -0
  2. package/db/migrations/103_shortcuts.sql +341 -0
  3. package/db/migrations/104_report_queries.sql +413 -0
  4. package/db/migrations/105_component_settings_groups.sql +367 -0
  5. package/db/migrations/106_form_designer.sql +102 -0
  6. package/db/migrations/107_app_version.sql +9 -0
  7. package/docs/apex-feature-parity.md +15 -12
  8. package/docs/guide/02-concepts.md +24 -0
  9. package/docs/guide/03-builder.md +69 -13
  10. package/docs/guide/04-pages-and-regions.md +84 -3
  11. package/docs/guide/05-items.md +14 -2
  12. package/docs/guide/06-processing.md +22 -0
  13. package/docs/guide/09-reference.md +14 -1
  14. package/docs/guide/11-from-apex.md +2 -1
  15. package/docs/guide/12-development.md +8 -2
  16. package/docs/guide/16-files.md +23 -0
  17. package/docs/guide/18-cli.md +4 -0
  18. package/examples/hr/hr_61_form_designer.sql +80 -0
  19. package/package.json +1 -1
  20. package/public/app.css +79 -2
  21. package/public/app.js +307 -35
  22. package/public/builder.css +21 -1
  23. package/public/builder.js +67 -0
  24. package/public/sw.js +2 -1
  25. package/src/app.ts +9 -1
  26. package/src/appfiles.ts +18 -2
  27. package/src/builder/advisor.ts +7 -2
  28. package/src/builder/appwizard.ts +22 -6
  29. package/src/builder/arrange.ts +33 -12
  30. package/src/builder/code-editor.ts +7 -2
  31. package/src/builder/components.ts +86 -4
  32. package/src/builder/designer.ts +44 -17
  33. package/src/builder/errors.ts +65 -0
  34. package/src/builder/form-designer.ts +229 -0
  35. package/src/builder/forms.ts +1 -1
  36. package/src/builder/locks.ts +6 -0
  37. package/src/builder/newapp.ts +2 -1
  38. package/src/builder/object-browser.ts +81 -18
  39. package/src/builder/region-help.ts +2 -0
  40. package/src/builder/region-settings.ts +2 -0
  41. package/src/builder/reporter.ts +1 -1
  42. package/src/builder/routes.ts +7 -5
  43. package/src/builder/search.ts +3 -3
  44. package/src/builder/shared.ts +41 -8
  45. package/src/builder/subscriptions.ts +30 -4
  46. package/src/builder/ui.ts +2 -0
  47. package/src/cli/replace.ts +16 -2
  48. package/src/i18n/ar.ts +62 -0
  49. package/src/i18n/cs.ts +62 -0
  50. package/src/i18n/da.ts +62 -0
  51. package/src/i18n/de.ts +62 -0
  52. package/src/i18n/el.ts +62 -0
  53. package/src/i18n/es.ts +62 -0
  54. package/src/i18n/fi.ts +62 -0
  55. package/src/i18n/fr.ts +62 -0
  56. package/src/i18n/he.ts +62 -0
  57. package/src/i18n/it.ts +62 -0
  58. package/src/i18n/ja.ts +62 -0
  59. package/src/i18n/ko.ts +62 -0
  60. package/src/i18n/nb.ts +62 -0
  61. package/src/i18n/pl.ts +62 -0
  62. package/src/i18n/pt.ts +62 -0
  63. package/src/i18n/ru.ts +62 -0
  64. package/src/i18n/sv.ts +62 -0
  65. package/src/i18n/tr.ts +62 -0
  66. package/src/i18n/uk.ts +62 -0
  67. package/src/i18n/zh.ts +62 -0
  68. package/src/i18n.ts +124 -0
  69. package/src/metadata.ts +18 -3
  70. package/src/runtime/component-settings.ts +42 -0
  71. package/src/runtime/context.ts +4 -0
  72. package/src/runtime/devbar.ts +1 -1
  73. package/src/runtime/documents.ts +29 -3
  74. package/src/runtime/engine.ts +2 -2
  75. package/src/runtime/facet-state.ts +10 -5
  76. package/src/runtime/facets.ts +29 -5
  77. package/src/runtime/form-designer.ts +676 -0
  78. package/src/runtime/grid.ts +36 -11
  79. package/src/runtime/items.ts +47 -32
  80. package/src/runtime/lists.ts +1 -1
  81. package/src/runtime/logic.ts +12 -7
  82. package/src/runtime/pdf.ts +2 -1
  83. package/src/runtime/regions.ts +8 -3
  84. package/src/runtime/render.ts +8 -3
  85. package/src/runtime/report.ts +4 -3
  86. package/src/runtime/routes.ts +7 -3
  87. package/src/runtime/shortcuts.ts +43 -0
  88. package/src/runtime/smart-filters.ts +2 -1
  89. package/src/runtime/tasks.ts +6 -3
  90. package/src/security.ts +2 -1
  91. package/src/subscriptions.ts +67 -0
@@ -0,0 +1,345 @@
1
+ -- =====================================================================
2
+ -- 102: application computations (APEX: Shared Components → Application
3
+ -- Computations)
4
+ --
5
+ -- meta.app_computation: a computation of an application item (or of a
6
+ -- page item of whichever page is shown) that runs for every page of the
7
+ -- application at a point:
8
+ -- after_authentication once, when a user signs in (after the
9
+ -- application processes "after_login")
10
+ -- before_header every page shown, before the page's own
11
+ -- computations of that point
12
+ -- after_submit every page submitted, before the page's own
13
+ -- computations of that point
14
+ -- The types, conditions, authorization and build option are those of a
15
+ -- page computation (meta.computation, migration 029).
16
+ -- export_app / import_app are redefined from 089 to carry app_computations.
17
+ -- =====================================================================
18
+ create table meta.app_computation (
19
+ id serial primary key,
20
+ app_id int not null references meta.app on delete cascade,
21
+ seq int not null default 10,
22
+ item_name text not null check (item_name ~ '^[A-Z][A-Z0-9_]*$'),
23
+ point text not null default 'before_header' check (point in ('after_authentication', 'before_header', 'after_submit')),
24
+ type text not null default 'static' check (type in ('static', 'item', 'sql_query', 'sql_expression', 'function_body')),
25
+ expression text,
26
+ condition_type text check (condition_type in ('sql', 'exists', 'not_exists', 'item_null', 'item_not_null', 'item_equals', 'item_not_equals', 'request_in')),
27
+ condition_expr text,
28
+ condition_value text,
29
+ authz text,
30
+ build_option text check (build_option ~ '^!?[A-Z][A-Z0-9_]{0,59}$'),
31
+ comments text,
32
+ check (type = 'static' or coalesce(trim(expression), '') <> ''),
33
+ check (type <> 'item' or expression ~ '^[A-Z][A-Z0-9_]*$'),
34
+ check (meta.condition_ok(condition_type, condition_expr, condition_value))
35
+ );
36
+ create index on meta.app_computation (app_id, seq);
37
+ revoke all on meta.app_computation from public;
38
+ grant select on meta.app_computation to pgkiln_runtime;
39
+ comment on table meta.app_computation is 'Application computations (102): computations of items that run for every page of the application';
40
+
41
+ -- (090) an isolated workspace's logins see their own applications' rows only
42
+ alter table meta.app_computation enable row level security;
43
+ create policy workspace on meta.app_computation
44
+ using ((select meta.isolation_off()) or app_id in (select meta.visible_apps()))
45
+ with check ((select meta.isolation_off()) or app_id in (select meta.visible_apps()));
46
+
47
+ create or replace function meta.export_app(p_alias text) returns jsonb
48
+ language sql stable set search_path = meta, pg_catalog as $$
49
+ select jsonb_build_object(
50
+ 'format', 'pgkiln/2',
51
+ -- (083) availability and build status belong to the installation
52
+ 'app', to_jsonb(a) - 'id' - 'created_at' - 'updated_at' - 'availability' - 'availability_message' - 'availability_users' - 'build_status',
53
+ 'authz_schemes', coalesce((select jsonb_agg(to_jsonb(x) - 'id' - 'app_id' order by x.name) from meta.authz_scheme x where x.app_id = a.id), '[]'),
54
+ 'app_items', coalesce((select jsonb_agg(to_jsonb(x) - 'id' - 'app_id' order by x.name) from meta.app_item x where x.app_id = a.id), '[]'),
55
+ 'app_processes', coalesce((select jsonb_agg(to_jsonb(x) - 'id' - 'app_id' order by x.seq, x.id) from meta.app_process x where x.app_id = a.id), '[]'),
56
+ 'lovs', coalesce((select jsonb_agg(to_jsonb(x) - 'id' - 'app_id' order by x.name) from meta.lov x where x.app_id = a.id), '[]'),
57
+ 'group_roles', coalesce((select jsonb_agg(to_jsonb(x) - 'app_id' order by x.group_name, x.role) from meta.app_group_role x where x.app_id = a.id), '[]'),
58
+ 'text_messages', coalesce((select jsonb_agg(to_jsonb(x) - 'app_id' order by x.name, x.language) from meta.text_message x where x.app_id = a.id), '[]'),
59
+ 'translations', coalesce((select jsonb_agg(to_jsonb(x) - 'app_id' order by x.language, x.source) from meta.translation x where x.app_id = a.id), '[]'),
60
+ 'report_layouts', coalesce((select jsonb_agg(to_jsonb(x) - 'id' - 'app_id' - 'logo' || jsonb_build_object('logo', encode(x.logo, 'base64')) order by x.name)
61
+ from meta.report_layout x where x.app_id = a.id), '[]'),
62
+ 'automations', coalesce((select jsonb_agg(to_jsonb(x) - 'id' - 'app_id' - 'next_run_at' - 'last_run_at' - 'last_status' - 'code' order by x.name)
63
+ from meta.automation x where x.app_id = a.id), '[]'),
64
+ -- (044) the actions of the automations, by automation name
65
+ 'automation_actions', coalesce((select jsonb_agg(to_jsonb(x) - 'id' - 'app_id' order by x.automation_name collate "C", x.seq, x.name collate "C")
66
+ from meta.automation_action x where x.app_id = a.id), '[]'),
67
+ 'document_templates', coalesce((select jsonb_agg(to_jsonb(x) - 'id' - 'app_id' order by x.name) from meta.document_template x where x.app_id = a.id), '[]'),
68
+ 'task_definitions', coalesce((select jsonb_agg(to_jsonb(x) - 'id' - 'app_id' order by x.name) from meta.task_definition x where x.app_id = a.id), '[]'),
69
+ 'workflow_definitions', coalesce((select jsonb_agg(to_jsonb(x) - 'id' - 'app_id' order by x.name) from meta.workflow_definition x where x.app_id = a.id), '[]'),
70
+ 'rest_modules', coalesce((select jsonb_agg(to_jsonb(x) - 'id' - 'app_id' order by x.name) from meta.rest_module x where x.app_id = a.id), '[]'),
71
+ 'template_components', coalesce((select jsonb_agg(to_jsonb(x) - 'id' - 'app_id' order by x.static_id) from meta.template_component x where x.app_id = a.id), '[]'),
72
+ 'build_options', coalesce((select jsonb_agg(to_jsonb(x) - 'id' - 'app_id' order by x.name) from meta.build_option x where x.app_id = a.id), '[]'),
73
+ -- (030) secrets never leave the installation: they are entered again after an import
74
+ -- (050) nor do the password and refresh token of the OAuth2 flows, or the token state
75
+ 'web_credentials', coalesce((select jsonb_agg(to_jsonb(x) - 'id' - 'app_id' - 'secret_enc' - 'password_enc' - 'refresh_token_enc' - 'token_refreshed_at' order by x.name)
76
+ from meta.web_credential x where x.app_id = a.id), '[]'),
77
+ -- (050) the synchronisation's state (next and last run) belongs to the installation
78
+ 'rest_sources', coalesce((select jsonb_agg(to_jsonb(x) - 'id' - 'app_id' - 'sync_next_at' - 'sync_last_at' - 'sync_last_status' order by x.name)
79
+ from meta.rest_source x where x.app_id = a.id), '[]'),
80
+ -- (041) data load definitions
81
+ 'data_load_definitions', coalesce((select jsonb_agg(to_jsonb(x) - 'id' - 'app_id' order by x.name) from meta.data_load_def x where x.app_id = a.id), '[]'),
82
+ -- (042) lists; entries keep their ids so parents can be remapped on import
83
+ 'lists', coalesce((select jsonb_agg(to_jsonb(x) - 'id' - 'app_id' order by x.name) from meta.list x where x.app_id = a.id), '[]'),
84
+ 'list_entries', coalesce((select jsonb_agg(to_jsonb(x) - 'app_id' order by x.list_name, x.parent_id nulls first, x.seq, x.id) from meta.list_entry x where x.app_id = a.id), '[]'),
85
+ -- (042) supporting objects: install, upgrade and deinstall scripts (never run on import)
86
+ 'supporting_scripts', coalesce((select jsonb_agg(to_jsonb(x) - 'id' - 'app_id' order by x.name) from meta.supporting_script x where x.app_id = a.id), '[]'),
87
+ -- (069) plug-ins (their files are static files, their templates template components)
88
+ 'plugins', coalesce((select jsonb_agg(to_jsonb(x) - 'id' - 'app_id' order by x.name) from meta.plugin x where x.app_id = a.id), '[]'),
89
+ -- (080) search configurations
90
+ 'search_configs', coalesce((select jsonb_agg(to_jsonb(x) - 'id' - 'app_id' order by x.name) from meta.search_config x where x.app_id = a.id), '[]'),
91
+ -- (081) e-mail templates
92
+ 'email_templates', coalesce((select jsonb_agg(to_jsonb(x) - 'id' - 'app_id' order by x.name) from meta.email_template x where x.app_id = a.id), '[]'),
93
+ -- (086) application settings (with their values) and dynamic translations
94
+ 'app_settings', coalesce((select jsonb_agg(to_jsonb(x) - 'id' - 'app_id' order by x.name) from meta.app_setting x where x.app_id = a.id), '[]'),
95
+ 'page_groups', coalesce((select jsonb_agg(to_jsonb(x) - 'id' - 'app_id' order by x.name) from meta.page_group x where x.app_id = a.id), '[]'),
96
+ -- (102) application computations
97
+ 'app_computations', coalesce((select jsonb_agg(to_jsonb(x) - 'id' - 'app_id' order by x.seq, x.id) from meta.app_computation x where x.app_id = a.id), '[]'),
98
+ 'dynamic_translations', coalesce((select jsonb_agg(to_jsonb(x) - 'id' - 'app_id' order by x.language, x.source collate "C") from meta.dynamic_translation x where x.app_id = a.id), '[]'),
99
+ -- (068) static application files (JavaScript, CSS, images, fonts) as base64
100
+ 'static_files', coalesce((select jsonb_agg(to_jsonb(x) - 'id' - 'app_id' - 'content' - 'updated_at' || jsonb_build_object('content', translate(encode(x.content, 'base64'), E'\n', '')) order by x.name)
101
+ from meta.static_file x where x.app_id = a.id), '[]'),
102
+ -- nav entries and regions keep their ids, so parents and references can be remapped on import
103
+ 'nav', coalesce((select jsonb_agg(to_jsonb(x) - 'app_id' order by x.parent_id nulls first, x.seq, x.id) from meta.nav_entry x where x.app_id = a.id), '[]'),
104
+ 'pages', coalesce((
105
+ select jsonb_agg(to_jsonb(p) - 'id' - 'app_id' || jsonb_build_object(
106
+ 'regions', coalesce((select jsonb_agg(to_jsonb(r) - 'page_id' order by r.seq, r.id) from meta.region r where r.page_id = p.id), '[]'),
107
+ 'items', coalesce((select jsonb_agg(to_jsonb(i) - 'id' - 'page_id' order by i.seq, i.id) from meta.item i where i.page_id = p.id), '[]'),
108
+ 'buttons', coalesce((select jsonb_agg(to_jsonb(b) - 'id' - 'page_id' order by b.seq, b.id) from meta.button b where b.page_id = p.id), '[]'),
109
+ 'dynamic_actions', coalesce((select jsonb_agg(to_jsonb(d) - 'id' - 'page_id' order by d.seq, d.id) from meta.dynamic_action d where d.page_id = p.id), '[]'),
110
+ 'validations', coalesce((select jsonb_agg(to_jsonb(v) - 'id' - 'page_id' order by v.seq, v.id) from meta.validation v where v.page_id = p.id), '[]'),
111
+ 'processes', coalesce((select jsonb_agg(to_jsonb(x) - 'id' - 'page_id' order by x.seq, x.id) from meta.process x where x.page_id = p.id), '[]'),
112
+ 'computations', coalesce((select jsonb_agg(to_jsonb(x) - 'id' - 'page_id' order by x.seq, x.id) from meta.computation x where x.page_id = p.id), '[]'),
113
+ 'branches', coalesce((select jsonb_agg(to_jsonb(x) - 'id' - 'page_id' order by x.seq, x.id) from meta.branch x where x.page_id = p.id), '[]')
114
+ ) order by p.page_no)
115
+ from meta.page p where p.app_id = a.id), '[]'))
116
+ from meta.app a
117
+ where a.alias = p_alias
118
+ $$;
119
+
120
+ -- ---------------------------------------------------------------- import
121
+ -- Same as 081, plus app_settings and dynamic_translations.
122
+
123
+ create or replace function meta.import_app(p_doc jsonb, p_alias text default null) returns int
124
+ language plpgsql set search_path = meta, pg_catalog as $$
125
+ declare
126
+ v_app_id int;
127
+ v_page_id int;
128
+ v_page jsonb;
129
+ v_e jsonb;
130
+ v_rmap jsonb;
131
+ v_nmap jsonb := '{}';
132
+ v_lmap jsonb := '{}';
133
+ v_new_id int;
134
+ begin
135
+ if p_doc->>'format' is distinct from 'pgkiln/2' then
136
+ raise exception 'unsupported export format %', coalesce(p_doc->>'format', '(none)');
137
+ end if;
138
+
139
+ insert into meta.app
140
+ select (jsonb_populate_record(null::meta.app, p_doc->'app' || jsonb_build_object(
141
+ 'id', nextval('meta.app_id_seq'),
142
+ 'alias', coalesce(p_alias, p_doc->'app'->>'alias'),
143
+ 'created_at', now(), 'updated_at', now()))).*
144
+ returning id into v_app_id;
145
+
146
+ insert into meta.authz_scheme
147
+ select (jsonb_populate_record(null::meta.authz_scheme, e || jsonb_build_object('id', nextval('meta.authz_scheme_id_seq'), 'app_id', v_app_id))).*
148
+ from jsonb_array_elements(coalesce(p_doc->'authz_schemes', '[]')) e;
149
+ insert into meta.app_item
150
+ select (jsonb_populate_record(null::meta.app_item, e || jsonb_build_object('id', nextval('meta.app_item_id_seq'), 'app_id', v_app_id))).*
151
+ from jsonb_array_elements(coalesce(p_doc->'app_items', '[]')) e;
152
+ insert into meta.app_process
153
+ select (jsonb_populate_record(null::meta.app_process, e || jsonb_build_object('id', nextval('meta.app_process_id_seq'), 'app_id', v_app_id))).*
154
+ from jsonb_array_elements(coalesce(p_doc->'app_processes', '[]')) e;
155
+ insert into meta.lov
156
+ select (jsonb_populate_record(null::meta.lov, e || jsonb_build_object('id', nextval('meta.lov_id_seq'), 'app_id', v_app_id))).*
157
+ from jsonb_array_elements(coalesce(p_doc->'lovs', '[]')) e;
158
+ insert into meta.app_group_role
159
+ select (jsonb_populate_record(null::meta.app_group_role, e || jsonb_build_object('app_id', v_app_id))).*
160
+ from jsonb_array_elements(coalesce(p_doc->'group_roles', '[]')) e;
161
+ insert into meta.text_message
162
+ select (jsonb_populate_record(null::meta.text_message, e || jsonb_build_object('app_id', v_app_id))).*
163
+ from jsonb_array_elements(coalesce(p_doc->'text_messages', '[]')) e;
164
+ insert into meta.translation
165
+ select (jsonb_populate_record(null::meta.translation, e || jsonb_build_object('app_id', v_app_id))).*
166
+ from jsonb_array_elements(coalesce(p_doc->'translations', '[]')) e;
167
+ insert into meta.report_layout
168
+ select (jsonb_populate_record(null::meta.report_layout, (e - 'logo') || jsonb_build_object(
169
+ 'id', nextval('meta.report_layout_id_seq'), 'app_id', v_app_id,
170
+ 'logo', null))).*
171
+ from jsonb_array_elements(coalesce(p_doc->'report_layouts', '[]')) e;
172
+ update meta.report_layout l
173
+ set logo = decode(e->>'logo', 'base64')
174
+ from jsonb_array_elements(coalesce(p_doc->'report_layouts', '[]')) e
175
+ where l.app_id = v_app_id and l.name = e->>'name' and e->>'logo' is not null;
176
+ -- imported automations start switched off: the copy must not run the original's jobs unasked.
177
+ -- (044) a file with actions: the automations' code is ignored; an older file: code becomes the single action
178
+ insert into meta.automation
179
+ select (jsonb_populate_record(null::meta.automation, '{"error_handling": "stop"}'::jsonb
180
+ || jsonb_strip_nulls(case when p_doc ? 'automation_actions' then e - 'code' else e end)
181
+ || jsonb_build_object('id', nextval('meta.automation_id_seq'), 'app_id', v_app_id, 'enabled', false))).*
182
+ from jsonb_array_elements(coalesce(p_doc->'automations', '[]')) e;
183
+ insert into meta.automation_action
184
+ select (jsonb_populate_record(null::meta.automation_action, '{"seq": 10}'::jsonb || jsonb_strip_nulls(e)
185
+ || jsonb_build_object('id', nextval('meta.automation_action_id_seq'), 'app_id', v_app_id))).*
186
+ from jsonb_array_elements(coalesce(p_doc->'automation_actions', '[]')) e;
187
+ insert into meta.document_template
188
+ select (jsonb_populate_record(null::meta.document_template, e || jsonb_build_object('id', nextval('meta.document_template_id_seq'), 'app_id', v_app_id))).*
189
+ from jsonb_array_elements(coalesce(p_doc->'document_templates', '[]')) e;
190
+ insert into meta.task_definition
191
+ select (jsonb_populate_record(null::meta.task_definition, e || jsonb_build_object('id', nextval('meta.task_definition_id_seq'), 'app_id', v_app_id))).*
192
+ from jsonb_array_elements(coalesce(p_doc->'task_definitions', '[]')) e;
193
+ insert into meta.workflow_definition
194
+ select (jsonb_populate_record(null::meta.workflow_definition, e || jsonb_build_object('id', nextval('meta.workflow_definition_id_seq'), 'app_id', v_app_id))).*
195
+ from jsonb_array_elements(coalesce(p_doc->'workflow_definitions', '[]')) e;
196
+ insert into meta.rest_module
197
+ select (jsonb_populate_record(null::meta.rest_module, e || jsonb_build_object('id', nextval('meta.rest_module_id_seq'), 'app_id', v_app_id))).*
198
+ from jsonb_array_elements(coalesce(p_doc->'rest_modules', '[]')) e;
199
+ -- (028) template components: regions and report columns refer to them by static id
200
+ insert into meta.template_component
201
+ select (jsonb_populate_record(null::meta.template_component, e || jsonb_build_object('id', nextval('meta.template_component_id_seq'), 'app_id', v_app_id))).*
202
+ from jsonb_array_elements(coalesce(p_doc->'template_components', '[]')) e;
203
+ -- (029) build options (components name them by name)
204
+ insert into meta.build_option
205
+ select (jsonb_populate_record(null::meta.build_option, e || jsonb_build_object('id', nextval('meta.build_option_id_seq'), 'app_id', v_app_id))).*
206
+ from jsonb_array_elements(coalesce(p_doc->'build_options', '[]')) e;
207
+ -- (030) web credentials arrive without a secret, whatever the document holds
208
+ -- (050) nor a password or refresh token
209
+ insert into meta.web_credential
210
+ select (jsonb_populate_record(null::meta.web_credential, '{"type": "basic", "valid_for": [], "grant_type": "client_credentials"}'::jsonb
211
+ || jsonb_strip_nulls(e - 'secret_enc' - 'password_enc' - 'refresh_token_enc' - 'token_refreshed_at')
212
+ || jsonb_build_object('id', nextval('meta.web_credential_id_seq'), 'app_id', v_app_id))).*
213
+ from jsonb_array_elements(coalesce(p_doc->'web_credentials', '[]')) e;
214
+ -- (050) write-back operations and synchronisation; an imported synchronisation starts switched off
215
+ insert into meta.rest_source
216
+ select (jsonb_populate_record(null::meta.rest_source, '{"method": "GET", "headers": {}, "params": [], "columns": [], "cache_seconds": 0, "timeout_s": 10, "max_rows": 1000,
217
+ "operations": {}, "key_columns": [], "sync_mode": "merge", "sync_delete": false, "sync_time_zone": "UTC"}'::jsonb
218
+ || jsonb_strip_nulls(e - 'sync_next_at' - 'sync_last_at' - 'sync_last_status')
219
+ || jsonb_build_object('id', nextval('meta.rest_source_id_seq'), 'app_id', v_app_id, 'sync_enabled', false))).*
220
+ from jsonb_array_elements(coalesce(p_doc->'rest_sources', '[]')) e;
221
+
222
+ -- (041) data load definitions (the data_load process names them)
223
+ insert into meta.data_load_def
224
+ select (jsonb_populate_record(null::meta.data_load_def, '{"format": "auto", "headers": true, "mode": "append", "skip_errors": false, "columns": []}'::jsonb
225
+ || jsonb_strip_nulls(e) || jsonb_build_object('id', nextval('meta.data_load_def_id_seq'), 'app_id', v_app_id))).*
226
+ from jsonb_array_elements(coalesce(p_doc->'data_load_definitions', '[]')) e;
227
+
228
+ -- (042) lists and their entries, supporting scripts. Entries are inserted
229
+ -- without a parent first and the parents set afterwards, so the order of
230
+ -- the entries in the document doesn't matter (a moved entry may have a
231
+ -- higher id than its children).
232
+ insert into meta.list
233
+ select (jsonb_populate_record(null::meta.list, '{"type": "static"}'::jsonb || jsonb_strip_nulls(e) || jsonb_build_object('id', nextval('meta.list_id_seq'), 'app_id', v_app_id))).*
234
+ from jsonb_array_elements(coalesce(p_doc->'lists', '[]')) e;
235
+ for v_e in select * from jsonb_array_elements(coalesce(p_doc->'list_entries', '[]')) loop
236
+ insert into meta.list_entry
237
+ select (jsonb_populate_record(null::meta.list_entry, '{"target_items": {}}'::jsonb || jsonb_strip_nulls(v_e) || jsonb_build_object(
238
+ 'id', nextval('meta.list_entry_id_seq'), 'app_id', v_app_id, 'parent_id', null))).*
239
+ returning id into v_new_id;
240
+ if v_e->>'id' is not null then
241
+ v_lmap := v_lmap || jsonb_build_object(v_e->>'id', v_new_id);
242
+ end if;
243
+ end loop;
244
+ update meta.list_entry x
245
+ set parent_id = (v_lmap->>(e->>'parent_id'))::int
246
+ from jsonb_array_elements(coalesce(p_doc->'list_entries', '[]')) e
247
+ where e->>'parent_id' is not null and v_lmap ? (e->>'parent_id') and v_lmap ? (e->>'id')
248
+ and x.id = (v_lmap->>(e->>'id'))::int;
249
+ insert into meta.supporting_script
250
+ select (jsonb_populate_record(null::meta.supporting_script, '{"kind": "install", "seq": 10, "script": ""}'::jsonb || jsonb_strip_nulls(e)
251
+ || jsonb_build_object('id', nextval('meta.supporting_script_id_seq'), 'app_id', v_app_id))).*
252
+ from jsonb_array_elements(coalesce(p_doc->'supporting_scripts', '[]')) e;
253
+
254
+ -- (069) plug-ins
255
+ insert into meta.plugin
256
+ select (jsonb_populate_record(null::meta.plugin, e || jsonb_build_object('id', nextval('meta.plugin_id_seq'), 'app_id', v_app_id))).*
257
+ from jsonb_array_elements(coalesce(p_doc->'plugins', '[]')) e;
258
+
259
+ -- (080) search configurations (search regions name them)
260
+ insert into meta.search_config
261
+ select (jsonb_populate_record(null::meta.search_config, '{"seq": 10, "source_type": "table", "searchable_columns": [], "max_results": 10}'::jsonb
262
+ || jsonb_strip_nulls(e) || jsonb_build_object('id', nextval('meta.search_config_id_seq'), 'app_id', v_app_id))).*
263
+ from jsonb_array_elements(coalesce(p_doc->'search_configs', '[]')) e;
264
+
265
+ -- (081) e-mail templates (meta.send_mail_template and the send_email process name them)
266
+ insert into meta.email_template
267
+ select (jsonb_populate_record(null::meta.email_template, e || jsonb_build_object('id', nextval('meta.email_template_id_seq'), 'app_id', v_app_id))).*
268
+ from jsonb_array_elements(coalesce(p_doc->'email_templates', '[]')) e;
269
+
270
+ -- (102) application computations
271
+ insert into meta.app_computation
272
+ select (jsonb_populate_record(null::meta.app_computation, '{"seq": 10, "point": "before_header", "type": "static"}'::jsonb || jsonb_strip_nulls(e)
273
+ || jsonb_build_object('id', nextval('meta.app_computation_id_seq'), 'app_id', v_app_id))).*
274
+ from jsonb_array_elements(coalesce(p_doc->'app_computations', '[]')) e;
275
+
276
+ -- (089) page groups
277
+ insert into meta.page_group
278
+ select (jsonb_populate_record(null::meta.page_group, e || jsonb_build_object('id', nextval('meta.page_group_id_seq'), 'app_id', v_app_id))).*
279
+ from jsonb_array_elements(coalesce(p_doc->'page_groups', '[]')) e;
280
+
281
+ -- (086) application settings and dynamic translations
282
+ insert into meta.app_setting
283
+ select (jsonb_populate_record(null::meta.app_setting, e || jsonb_build_object('id', nextval('meta.app_setting_id_seq'), 'app_id', v_app_id))).*
284
+ from jsonb_array_elements(coalesce(p_doc->'app_settings', '[]')) e;
285
+ insert into meta.dynamic_translation
286
+ select (jsonb_populate_record(null::meta.dynamic_translation, e || jsonb_build_object('id', nextval('meta.dynamic_translation_id_seq'), 'app_id', v_app_id))).*
287
+ from jsonb_array_elements(coalesce(p_doc->'dynamic_translations', '[]')) e;
288
+
289
+ -- (068) static application files
290
+ insert into meta.static_file (app_id, name, mime, content, updated_at)
291
+ select v_app_id, e->>'name', e->>'mime', decode(coalesce(e->>'content', ''), 'base64'), now()
292
+ from jsonb_array_elements(coalesce(p_doc->'static_files', '[]')) e;
293
+
294
+ for v_e in select * from jsonb_array_elements(coalesce(p_doc->'nav', '[]')) loop
295
+ insert into meta.nav_entry
296
+ select (jsonb_populate_record(null::meta.nav_entry, v_e || jsonb_build_object(
297
+ 'id', nextval('meta.nav_entry_id_seq'), 'app_id', v_app_id,
298
+ 'parent_id', v_nmap->>(v_e->>'parent_id')))).*
299
+ returning id into v_new_id;
300
+ v_nmap := v_nmap || jsonb_build_object(v_e->>'id', v_new_id);
301
+ end loop;
302
+
303
+ for v_page in select * from jsonb_array_elements(coalesce(p_doc->'pages', '[]')) loop
304
+ insert into meta.page
305
+ select (jsonb_populate_record(null::meta.page, v_page || jsonb_build_object('id', nextval('meta.page_id_seq'), 'app_id', v_app_id))).*
306
+ returning id into v_page_id;
307
+
308
+ v_rmap := '{}';
309
+ for v_e in select * from jsonb_array_elements(coalesce(v_page->'regions', '[]')) loop
310
+ insert into meta.region
311
+ select (jsonb_populate_record(null::meta.region, v_e || jsonb_build_object('id', nextval('meta.region_id_seq'), 'page_id', v_page_id))).*
312
+ returning id into v_new_id;
313
+ v_rmap := v_rmap || jsonb_build_object(v_e->>'id', v_new_id);
314
+ end loop;
315
+ -- facet and map regions point at their report region by id
316
+ update meta.region r
317
+ set config = jsonb_set(r.config, '{report}', to_jsonb((v_rmap->>(r.config->>'report'))::int))
318
+ where r.page_id = v_page_id and r.type in ('facets', 'smart_filters', 'map') and v_rmap ? (r.config->>'report');
319
+
320
+ insert into meta.item
321
+ select (jsonb_populate_record(null::meta.item, e || jsonb_build_object('id', nextval('meta.item_id_seq'), 'page_id', v_page_id, 'region_id', v_rmap->>(e->>'region_id')))).*
322
+ from jsonb_array_elements(coalesce(v_page->'items', '[]')) e;
323
+ insert into meta.button
324
+ select (jsonb_populate_record(null::meta.button, e || jsonb_build_object('id', nextval('meta.button_id_seq'), 'page_id', v_page_id, 'region_id', v_rmap->>(e->>'region_id')))).*
325
+ from jsonb_array_elements(coalesce(v_page->'buttons', '[]')) e;
326
+ insert into meta.dynamic_action
327
+ select (jsonb_populate_record(null::meta.dynamic_action, e || jsonb_build_object('id', nextval('meta.dynamic_action_id_seq'), 'page_id', v_page_id, 'affected_region_id', v_rmap->>(e->>'affected_region_id')))).*
328
+ from jsonb_array_elements(coalesce(v_page->'dynamic_actions', '[]')) e;
329
+ insert into meta.validation
330
+ select (jsonb_populate_record(null::meta.validation, e || jsonb_build_object('id', nextval('meta.validation_id_seq'), 'page_id', v_page_id))).*
331
+ from jsonb_array_elements(coalesce(v_page->'validations', '[]')) e;
332
+ insert into meta.process
333
+ select (jsonb_populate_record(null::meta.process, e || jsonb_build_object('id', nextval('meta.process_id_seq'), 'page_id', v_page_id, 'region_id', v_rmap->>(e->>'region_id')))).*
334
+ from jsonb_array_elements(coalesce(v_page->'processes', '[]')) e;
335
+ insert into meta.computation
336
+ select (jsonb_populate_record(null::meta.computation, e || jsonb_build_object('id', nextval('meta.computation_id_seq'), 'page_id', v_page_id))).*
337
+ from jsonb_array_elements(coalesce(v_page->'computations', '[]')) e;
338
+ insert into meta.branch
339
+ select (jsonb_populate_record(null::meta.branch, e || jsonb_build_object('id', nextval('meta.branch_id_seq'), 'page_id', v_page_id))).*
340
+ from jsonb_array_elements(coalesce(v_page->'branches', '[]')) e;
341
+ end loop;
342
+
343
+ return v_app_id;
344
+ end
345
+ $$;