mikras_utils 0.1.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.
- checksums.yaml +7 -0
- data/.rspec +3 -0
- data/.ruby-version +1 -0
- data/Gemfile +10 -0
- data/README.md +31 -0
- data/Rakefile +8 -0
- data/acl-build +5 -0
- data/build +11 -0
- data/exe/mikras_utils +5 -0
- data/exe/mkacl +59 -0
- data/lib/mikras_utils/mkacl/analyzer.rb +46 -0
- data/lib/mikras_utils/mkacl/generator.rb +55 -0
- data/lib/mikras_utils/mkacl/generators/acl_functions.rb +208 -0
- data/lib/mikras_utils/mkacl/generators/id_functions.rb +262 -0
- data/lib/mikras_utils/mkacl/generators/insert_triggers.rb +267 -0
- data/lib/mikras_utils/mkacl/generators/role_functions.rb +72 -0
- data/lib/mikras_utils/mkacl/generators/rules.rb +80 -0
- data/lib/mikras_utils/mkacl/parser.rb +73 -0
- data/lib/mikras_utils/mkacl/spec.rb +154 -0
- data/lib/mikras_utils/mkacl.rb +18 -0
- data/lib/mikras_utils/version.rb +5 -0
- data/lib/mikras_utils.rb +6 -0
- data/sig/mikras_utils.rbs +4 -0
- data/tests/acl.fox +312 -0
- data/tests/acl.spec +135 -0
- data/tests/acl.sql +132 -0
- data/tests/acl_portal-functions.sql +94 -0
- data/tests/acl_portal-tables.sql +23 -0
- data/tests/acl_portal-views.sql +73 -0
- data/tests/agg.sql +25 -0
- data/tests/app.sql +48 -0
- data/tests/app_portal-tables.sql +138 -0
- data/tests/app_portal-triggers.sql +23 -0
- data/tests/app_portal-views.sql +203 -0
- data/tests/auth.sql +12 -0
- data/tests/auth.users.sql +5 -0
- data/tests/build +7 -0
- data/tests/final-functions.sql +28 -0
- data/tests/fox.sql +158 -0
- data/tests/initial-functions.sql +6 -0
- data/tests/meta.sql +197 -0
- data/tests/reflections.yml +5 -0
- data/tests/schemas.sql +25 -0
- data/tests/setup.sql +8 -0
- data/tests/sys_portal.sql +172 -0
- metadata +145 -0
@@ -0,0 +1,203 @@
|
|
1
|
+
\set ON_ERROR_STOP on
|
2
|
+
|
3
|
+
set search_path to app_portal;
|
4
|
+
|
5
|
+
-- Union of case_roles and event_roles
|
6
|
+
drop view if exists acl_portal.domain_roles cascade;
|
7
|
+
create view acl_portal.domain_roles as
|
8
|
+
select
|
9
|
+
id,
|
10
|
+
case_id as "domain_id",
|
11
|
+
role
|
12
|
+
from
|
13
|
+
app_portal.case_roles
|
14
|
+
|
15
|
+
union all
|
16
|
+
|
17
|
+
select
|
18
|
+
id,
|
19
|
+
event_id as "domain_id",
|
20
|
+
role
|
21
|
+
from
|
22
|
+
app_portal.event_roles
|
23
|
+
;
|
24
|
+
|
25
|
+
-- Union of case_users and event_users
|
26
|
+
drop view if exists acl_portal.domain_users cascade;
|
27
|
+
create view acl_portal.domain_users as
|
28
|
+
select
|
29
|
+
case_role_id as "domain_role_id",
|
30
|
+
user_id
|
31
|
+
from
|
32
|
+
app_portal.case_users
|
33
|
+
|
34
|
+
union all
|
35
|
+
|
36
|
+
select
|
37
|
+
event_role_id as "domain_role_id",
|
38
|
+
user_id
|
39
|
+
from
|
40
|
+
app_portal.event_users
|
41
|
+
;
|
42
|
+
|
43
|
+
-- Combines cases, case_roles, and case_users and also computes the virtual CLA
|
44
|
+
-- and CTA roles from the event ELA and ETA roles and assigns the CLA role to
|
45
|
+
-- RES users. Only ACL roles are included
|
46
|
+
drop view if exists case_role_users cascade;
|
47
|
+
create view case_role_users as
|
48
|
+
with
|
49
|
+
-- Base roles
|
50
|
+
roles as (
|
51
|
+
select
|
52
|
+
cr.case_id,
|
53
|
+
cu.user_id,
|
54
|
+
cr.id as "role_id",
|
55
|
+
cr.role
|
56
|
+
from app_portal.role_kinds rk
|
57
|
+
join app_portal.case_roles cr on cr.role = rk.kind
|
58
|
+
join app_portal.case_users cu on cu.case_role_id = cr.id
|
59
|
+
where rk.acl
|
60
|
+
),
|
61
|
+
-- RES user is also CLA
|
62
|
+
res_roles as (
|
63
|
+
select
|
64
|
+
r.case_id,
|
65
|
+
r.user_id,
|
66
|
+
cr.id as "role_id",
|
67
|
+
cr.role
|
68
|
+
from roles r
|
69
|
+
join case_roles cr on cr.case_id = r.case_id and cr.role = 'CLA'
|
70
|
+
where r.role = 'RES'
|
71
|
+
),
|
72
|
+
-- Event roles ELA and ETA are translated to CLA and CTA case roles
|
73
|
+
eta_ela_roles as (
|
74
|
+
select
|
75
|
+
e.case_id,
|
76
|
+
eu.user_id,
|
77
|
+
cr.id,
|
78
|
+
cr.role
|
79
|
+
from
|
80
|
+
events e
|
81
|
+
join event_roles er on er.event_id = e.id
|
82
|
+
join event_users eu on eu.event_role_id = er.id
|
83
|
+
join case_roles cr on
|
84
|
+
cr.case_id = e.case_id
|
85
|
+
and (
|
86
|
+
(cr.role = 'CTA' and er.role = 'ETA')
|
87
|
+
or (cr.role = 'CLA' and er.role = 'ELA')
|
88
|
+
)
|
89
|
+
where not e.closed
|
90
|
+
)
|
91
|
+
select * from roles
|
92
|
+
union
|
93
|
+
select * from res_roles
|
94
|
+
union
|
95
|
+
select * from eta_ela_roles
|
96
|
+
order by case_id, user_id -- FIXME: Yt
|
97
|
+
;
|
98
|
+
|
99
|
+
-- Combines case_role_users with event_roles and event_users. It is the set of
|
100
|
+
-- roles (case or event) that is associated with an event. Users that are no
|
101
|
+
-- longer associated with the case are excluded
|
102
|
+
drop view if exists event_role_users cascade;
|
103
|
+
create view event_role_users as
|
104
|
+
-- Roles inherited from case
|
105
|
+
select
|
106
|
+
e.id as "event_id",
|
107
|
+
cru.user_id,
|
108
|
+
cru.role_id,
|
109
|
+
cru.role
|
110
|
+
from
|
111
|
+
events e
|
112
|
+
join case_role_users cru on cru.case_id = e.case_id
|
113
|
+
where
|
114
|
+
not e.closed
|
115
|
+
|
116
|
+
union all
|
117
|
+
|
118
|
+
-- Roles from event users. KON and AKK are duplicates
|
119
|
+
select
|
120
|
+
e.id as "event_id",
|
121
|
+
eu.user_id,
|
122
|
+
er.id as "role_id",
|
123
|
+
er.role
|
124
|
+
from
|
125
|
+
events e
|
126
|
+
join event_roles er on er.event_id = e.id
|
127
|
+
join event_users eu on eu.event_role_id = er.id
|
128
|
+
where
|
129
|
+
not e.closed
|
130
|
+
|
131
|
+
order by event_id -- FIXME Yt
|
132
|
+
;
|
133
|
+
|
134
|
+
drop view if exists domain_role_users cascade;
|
135
|
+
create view domain_role_users as
|
136
|
+
select
|
137
|
+
case_id as "domain_id",
|
138
|
+
user_id,
|
139
|
+
role_id,
|
140
|
+
role
|
141
|
+
from
|
142
|
+
case_role_users
|
143
|
+
|
144
|
+
union all
|
145
|
+
|
146
|
+
select
|
147
|
+
event_id as "domain_id",
|
148
|
+
user_id,
|
149
|
+
role_id,
|
150
|
+
role
|
151
|
+
from
|
152
|
+
event_role_users
|
153
|
+
;
|
154
|
+
|
155
|
+
drop view if exists agg.domain_role_users cascade;
|
156
|
+
create view agg.domain_role_users as
|
157
|
+
select
|
158
|
+
domain_id,
|
159
|
+
user_id,
|
160
|
+
array_agg(role_id) as "role_ids",
|
161
|
+
array_agg(role) as "roles"
|
162
|
+
from
|
163
|
+
app_portal.domain_role_users
|
164
|
+
group by
|
165
|
+
domain_id,
|
166
|
+
user_id
|
167
|
+
;
|
168
|
+
|
169
|
+
drop view if exists name.domain_role_users cascade;
|
170
|
+
create view name.domain_role_users as
|
171
|
+
select
|
172
|
+
dru.domain_id,
|
173
|
+
dru.user_id,
|
174
|
+
dru.role_id,
|
175
|
+
coalesce(c.ident, e.label) as "domain",
|
176
|
+
u.rolename as "username",
|
177
|
+
dru.role
|
178
|
+
from
|
179
|
+
domain_role_users dru
|
180
|
+
join auth.roles u on u.id = dru.user_id
|
181
|
+
left join cases c on c.id = dru.domain_id
|
182
|
+
left join events e on e.id = dru.domain_id
|
183
|
+
;
|
184
|
+
|
185
|
+
drop view if exists agg_name.domain_role_users cascade;
|
186
|
+
create view agg_name.domain_role_users as
|
187
|
+
select
|
188
|
+
domain_id,
|
189
|
+
user_id,
|
190
|
+
domain,
|
191
|
+
username,
|
192
|
+
array_agg(role_id) as "role_ids",
|
193
|
+
array_agg(role) as "roles"
|
194
|
+
from
|
195
|
+
name.domain_role_users
|
196
|
+
group by
|
197
|
+
domain_id,
|
198
|
+
user_id,
|
199
|
+
domain,
|
200
|
+
username
|
201
|
+
order by domain_id, username
|
202
|
+
;
|
203
|
+
|
data/tests/auth.sql
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
\set ON_ERROR_STOP on
|
2
|
+
|
3
|
+
create table auth.roles (
|
4
|
+
id integer generated by default as identity primary key,
|
5
|
+
rolename varchar not null
|
6
|
+
);
|
7
|
+
|
8
|
+
create table auth.users (
|
9
|
+
id integer generated by default as identity primary key,
|
10
|
+
rolename varchar not null
|
11
|
+
);
|
12
|
+
|
data/tests/build
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
|
2
|
+
-- Returns an array of role IDs for the current user (from both auth and
|
3
|
+
-- app_portal). This array is matched against the relevant ACL field in the RLS
|
4
|
+
-- policies so performance is important (TODO)
|
5
|
+
drop function if exists public.current_role_ids() cascade;
|
6
|
+
create function public.current_role_ids() returns integer[] as $$
|
7
|
+
select acl_portal.select_user_acl(public.current_user_id());
|
8
|
+
$$ language sql
|
9
|
+
stable
|
10
|
+
leakproof
|
11
|
+
security definer
|
12
|
+
;
|
13
|
+
|
14
|
+
-- Returns an array of app_portal role names (kind) for the current user in the
|
15
|
+
-- given domain
|
16
|
+
drop function if exists public.current_domain_roles(integer) cascade;
|
17
|
+
create function public.current_domain_roles(_domain_id integer) returns text[] as $$
|
18
|
+
select coalesce(array_agg(dr.role), array[]::text[])
|
19
|
+
from acl_portal.domain_users du
|
20
|
+
join acl_portal.domain_roles dr on dr.id = du.domain_role_id
|
21
|
+
where du.user_id = public.current_user_id()
|
22
|
+
and dr.domain_id = _domain_id;
|
23
|
+
$$ language sql
|
24
|
+
stable
|
25
|
+
leakproof
|
26
|
+
security definer
|
27
|
+
;
|
28
|
+
|
data/tests/fox.sql
ADDED
@@ -0,0 +1,158 @@
|
|
1
|
+
\set ON_ERROR_STOP on
|
2
|
+
|
3
|
+
/*
|
4
|
+
delete from acl_portal.attach_acls;
|
5
|
+
|
6
|
+
insert into acl_portal.attach_acls (parent_table, parent_id, child_table, child_field, acls) values
|
7
|
+
('cases', 1, 'events', 'case_id', array[1]), -- case-hdj can create events on case 1
|
8
|
+
('events', 3, 'visits', 'event_id', array[16]), -- event-hdj can create visits on event 3 of case 1
|
9
|
+
('visits', 1, 'noncompliances', 'visit_id', array[16, 17]),
|
10
|
+
('visits', 2, 'noncompliances', 'visit_id', array[16, 2]),
|
11
|
+
('events', 3, 'bookings', 'event_id', array[16])
|
12
|
+
;
|
13
|
+
|
14
|
+
insert into acl_portal.attach_acls (parent_table, parent_id, child_table, child_field, acls)
|
15
|
+
select
|
16
|
+
'case_roles' as "parent_table",
|
17
|
+
id as "parent_id",
|
18
|
+
'case_users' as "child_table",
|
19
|
+
'case_role_id' as "child_id",
|
20
|
+
array[2] -- hdj
|
21
|
+
from
|
22
|
+
app_portal.case_roles
|
23
|
+
where case_id = 1
|
24
|
+
and role = 'CLA'
|
25
|
+
;
|
26
|
+
*/
|
27
|
+
|
28
|
+
delete from auth.users;
|
29
|
+
insert into auth.users select * from auth.roles;
|
30
|
+
|
31
|
+
select acl_portal.update_acls();
|
32
|
+
select acl_portal.update_user_acls();
|
33
|
+
|
34
|
+
/*
|
35
|
+
drop schema if exists acl cascade;
|
36
|
+
create schema acl;
|
37
|
+
set search_path to acl;
|
38
|
+
|
39
|
+
create view tables as
|
40
|
+
select distinct
|
41
|
+
schema_name,
|
42
|
+
table_name
|
43
|
+
from
|
44
|
+
meta.columns
|
45
|
+
where
|
46
|
+
column_name like 'acl\_%'
|
47
|
+
;
|
48
|
+
|
49
|
+
\echo ACL_TABLES
|
50
|
+
select * from tables where schema_name = 'app_portal';
|
51
|
+
|
52
|
+
-- Subset of meta.columns where both referencing and referenced tables are ACL tables
|
53
|
+
drop view if exists links cascade;
|
54
|
+
create view links as
|
55
|
+
select c.*
|
56
|
+
from tables tf
|
57
|
+
join meta.links c
|
58
|
+
on c.schema_name = tf.schema_name
|
59
|
+
and c.table_name = tf.table_name
|
60
|
+
join tables tt
|
61
|
+
on tt.schema_name = c.ref_schema_name
|
62
|
+
and tt.table_name = c.ref_table_name
|
63
|
+
;
|
64
|
+
|
65
|
+
\echo ACL_LINKS
|
66
|
+
select * from links where schema_name = 'app_portal';
|
67
|
+
|
68
|
+
-- Subset of meta.chains where first and last table are ACL tables
|
69
|
+
drop view if exists chains cascade;
|
70
|
+
create view chains as
|
71
|
+
select mc.*
|
72
|
+
from meta.chains mc
|
73
|
+
join tables src on
|
74
|
+
mc.src_schema_name = src.schema_name
|
75
|
+
and mc.src_table_name = src.table_name
|
76
|
+
join tables dst on
|
77
|
+
mc.dst_schema_name = dst.schema_name
|
78
|
+
and mc.dst_table_name = dst.table_name
|
79
|
+
;
|
80
|
+
|
81
|
+
\echo ACL_CHAINS
|
82
|
+
--select * from chains where src_schema_name = 'app_portal';
|
83
|
+
|
84
|
+
drop view if exists closures cascade;
|
85
|
+
create view closures as
|
86
|
+
select
|
87
|
+
at.schema_name,
|
88
|
+
at.table_name,
|
89
|
+
coalesce(
|
90
|
+
array_agg(ac.src_schema_name || '.' || ac.src_table_name) filter (where ac.src_schema_name is not null),
|
91
|
+
array[]::varchar[]
|
92
|
+
) as closure_uids
|
93
|
+
from
|
94
|
+
tables at
|
95
|
+
left join chains ac
|
96
|
+
on ac.dst_schema_name = at.schema_name
|
97
|
+
and ac.dst_table_name = at.table_name
|
98
|
+
group by
|
99
|
+
at.schema_name,
|
100
|
+
at.table_name
|
101
|
+
;
|
102
|
+
|
103
|
+
\echo ACL_CLOSURES
|
104
|
+
--select * from closures;
|
105
|
+
|
106
|
+
drop view if exists paths cascade;
|
107
|
+
create view paths as
|
108
|
+
with
|
109
|
+
recursive search_path as (
|
110
|
+
with edges as (
|
111
|
+
select distinct
|
112
|
+
schema_name || '.' || table_name as "from_table",
|
113
|
+
ref_schema_name || '.' || ref_table_name as "to_table",
|
114
|
+
column_name as "from_column",
|
115
|
+
ref_column_name as "to_column"
|
116
|
+
from
|
117
|
+
acl.links
|
118
|
+
)
|
119
|
+
|
120
|
+
-- Anchor member: start from the initial node
|
121
|
+
select
|
122
|
+
from_table as "start_table",
|
123
|
+
from_table,
|
124
|
+
to_table,
|
125
|
+
array[from_table] as path,
|
126
|
+
array[array[from_table || '.' || from_column, to_table || '.' || to_column]] as link,
|
127
|
+
false as cycle
|
128
|
+
from edges
|
129
|
+
|
130
|
+
union all
|
131
|
+
|
132
|
+
-- Recursive member: find the next links
|
133
|
+
select
|
134
|
+
sp.start_table,
|
135
|
+
e.from_table,
|
136
|
+
e.to_table,
|
137
|
+
sp.path || e.from_table as "path",
|
138
|
+
sp.link || array[array[e.from_table || '.' || e.from_column, e.to_table || '.' || e.to_column]] as "link",
|
139
|
+
e.from_table = any(sp.path) as "cycle"
|
140
|
+
from search_path sp
|
141
|
+
join edges e on e.from_table = sp.to_table
|
142
|
+
where not sp.cycle
|
143
|
+
)
|
144
|
+
select
|
145
|
+
start_table,
|
146
|
+
to_table as "stop_table",
|
147
|
+
path || to_table as "path",
|
148
|
+
link as "links"
|
149
|
+
from search_path
|
150
|
+
order by
|
151
|
+
start_table,
|
152
|
+
"stop_table"
|
153
|
+
;
|
154
|
+
|
155
|
+
\echo ACL_PATHS
|
156
|
+
--select * from paths;
|
157
|
+
|
158
|
+
*/
|
data/tests/meta.sql
ADDED
@@ -0,0 +1,197 @@
|
|
1
|
+
|
2
|
+
\set ON_ERROR_STOP on
|
3
|
+
|
4
|
+
drop schema if exists meta cascade;
|
5
|
+
create schema meta;
|
6
|
+
set search_path to meta;
|
7
|
+
|
8
|
+
create view schemas as
|
9
|
+
select
|
10
|
+
nspname as "schema_name"
|
11
|
+
from
|
12
|
+
pg_namespace
|
13
|
+
where nspname <> 'information_schema'
|
14
|
+
and nspname not like 'pg\_%'
|
15
|
+
and nspname not like 'fdw\_%'
|
16
|
+
and nspname not in ('pgcrypto') -- array because more libraries may come
|
17
|
+
;
|
18
|
+
|
19
|
+
create view tables as
|
20
|
+
select
|
21
|
+
relnamespace::regnamespace::varchar as "schema_name",
|
22
|
+
relname as "table_name"
|
23
|
+
from
|
24
|
+
pg_class
|
25
|
+
where
|
26
|
+
relkind = 'r'
|
27
|
+
and relnamespace::regnamespace::varchar <> 'information_schema'
|
28
|
+
and relnamespace::regnamespace::varchar not like 'pg\_%'
|
29
|
+
-- FIXME relation "fdw_webtoolpublished.publisheddata" does not exist
|
30
|
+
and relnamespace::regnamespace::varchar not like 'fdw\_%'
|
31
|
+
;
|
32
|
+
|
33
|
+
\echo META_TABLES
|
34
|
+
select *
|
35
|
+
from tables
|
36
|
+
where
|
37
|
+
schema_name = 'app_portal'
|
38
|
+
;
|
39
|
+
|
40
|
+
create view columns as
|
41
|
+
with
|
42
|
+
referencing_fields as (
|
43
|
+
select
|
44
|
+
tf.relnamespace::regnamespace::varchar as "schema_name",
|
45
|
+
tf.relname as "table_name", -- avoids qualified table name
|
46
|
+
af.attname as "column_name",
|
47
|
+
tt.relnamespace::regnamespace::varchar as "ref_schema_name",
|
48
|
+
tt.relname as "ref_table_name", -- avoids qualified table name
|
49
|
+
at.attname as "ref_column_name"
|
50
|
+
from
|
51
|
+
pg_constraint as c
|
52
|
+
join pg_attribute as af on af.attnum = any(c.conkey) and af.attrelid = c.conrelid
|
53
|
+
join pg_attribute as at on at.attnum = any(c.confkey) and at.attrelid = c.confrelid
|
54
|
+
join pg_class tf on tf.oid = c.conrelid
|
55
|
+
join pg_class tt on tt.oid = c.confrelid
|
56
|
+
where
|
57
|
+
c.contype = 'f'
|
58
|
+
order by
|
59
|
+
"schema_name",
|
60
|
+
"table_name",
|
61
|
+
"column_name"
|
62
|
+
)
|
63
|
+
select
|
64
|
+
t.schema_name,
|
65
|
+
t.table_name,
|
66
|
+
af.attname as "column_name",
|
67
|
+
at.ref_schema_name,
|
68
|
+
at.ref_table_name,
|
69
|
+
at.ref_column_name,
|
70
|
+
af.attnum as "ordinal"
|
71
|
+
from
|
72
|
+
tables t
|
73
|
+
join pg_attribute af
|
74
|
+
on af.attrelid = (schema_name || '.' || table_name)::regclass
|
75
|
+
and af.attnum > 0
|
76
|
+
left join referencing_fields at
|
77
|
+
on at.schema_name = t.schema_name
|
78
|
+
and at.table_name = t.table_name
|
79
|
+
and at.column_name = af.attname
|
80
|
+
order by
|
81
|
+
"schema_name",
|
82
|
+
"table_name",
|
83
|
+
"ordinal"
|
84
|
+
;
|
85
|
+
|
86
|
+
\echo META_COLUMNS
|
87
|
+
/*
|
88
|
+
select
|
89
|
+
schema_name, table_name, column_name,
|
90
|
+
ref_schema_name, ref_table_name, ref_column_name
|
91
|
+
from columns
|
92
|
+
where
|
93
|
+
schema_name = 'app_portal'
|
94
|
+
;
|
95
|
+
*/
|
96
|
+
|
97
|
+
create view links as
|
98
|
+
select *
|
99
|
+
from columns
|
100
|
+
where ref_table_name is not null
|
101
|
+
;
|
102
|
+
|
103
|
+
\echo META_LINKS
|
104
|
+
--select * from links;
|
105
|
+
|
106
|
+
create view chains as
|
107
|
+
with
|
108
|
+
recursive search_path as (
|
109
|
+
with
|
110
|
+
edges as (
|
111
|
+
select distinct
|
112
|
+
schema_name || '.' || table_name as "from_table",
|
113
|
+
ref_schema_name || '.' || ref_table_name as "to_table",
|
114
|
+
column_name as "from_column",
|
115
|
+
ref_column_name as "to_column"
|
116
|
+
from
|
117
|
+
links
|
118
|
+
)
|
119
|
+
|
120
|
+
-- Anchor member: src from the initial node
|
121
|
+
select
|
122
|
+
from_table as "src_table",
|
123
|
+
from_table,
|
124
|
+
to_table,
|
125
|
+
array[from_table] as path,
|
126
|
+
array[array[from_table || '.' || from_column, to_table || '.' || to_column]] as link,
|
127
|
+
false as cycle
|
128
|
+
from edges
|
129
|
+
|
130
|
+
union all
|
131
|
+
|
132
|
+
-- Recursive member: find the next links
|
133
|
+
select
|
134
|
+
sp.src_table,
|
135
|
+
e.from_table,
|
136
|
+
e.to_table,
|
137
|
+
sp.path || e.from_table as "path",
|
138
|
+
sp.link || array[array[e.from_table || '.' || e.from_column, e.to_table || '.' || e.to_column]] as "link",
|
139
|
+
e.from_table = any(sp.path) as "cycle"
|
140
|
+
from search_path sp
|
141
|
+
join edges e on e.from_table = sp.to_table
|
142
|
+
where not sp.cycle
|
143
|
+
)
|
144
|
+
select
|
145
|
+
regexp_replace(src_table, '\..*', '') as src_schema_name,
|
146
|
+
regexp_replace(src_table, '^.*\.', '') as src_table_name,
|
147
|
+
regexp_replace(to_table, '\..*', '') as dst_schema_name,
|
148
|
+
regexp_replace(to_table, '^.*\.', '') as dst_table_name,
|
149
|
+
path || to_table as "path",
|
150
|
+
link as "links"
|
151
|
+
from search_path
|
152
|
+
order by
|
153
|
+
"src_schema_name",
|
154
|
+
"src_table_name",
|
155
|
+
"dst_schema_name",
|
156
|
+
"dst_table_name"
|
157
|
+
;
|
158
|
+
|
159
|
+
\echo META_CHAINS
|
160
|
+
--select * from chains;
|
161
|
+
|
162
|
+
create view closures as
|
163
|
+
select
|
164
|
+
mt.schema_name,
|
165
|
+
mt.table_name,
|
166
|
+
coalesce(
|
167
|
+
array_agg(mc.src_schema_name || '.' || mc.src_table_name) filter (where mc.src_schema_name is not null),
|
168
|
+
array[]::varchar[]
|
169
|
+
) as closure_uids
|
170
|
+
from
|
171
|
+
tables mt
|
172
|
+
left join chains mc
|
173
|
+
on mc.dst_schema_name = mt.schema_name
|
174
|
+
and mc.dst_table_name = mt.table_name
|
175
|
+
group by
|
176
|
+
mt.schema_name,
|
177
|
+
mt.table_name
|
178
|
+
;
|
179
|
+
|
180
|
+
\echo META_CLOSURES
|
181
|
+
--select * from closures;
|
182
|
+
|
183
|
+
create view functions as
|
184
|
+
select
|
185
|
+
s.schema_name,
|
186
|
+
proname as "function_name",
|
187
|
+
string_to_array(pg_catalog.pg_get_function_identity_arguments(oid), ',') as arguments,
|
188
|
+
pg_catalog.format_type(prorettype, null) as return_type,
|
189
|
+
proconfig as "config"
|
190
|
+
from
|
191
|
+
meta.schemas s
|
192
|
+
join pg_proc p on p.pronamespace::regnamespace::varchar = s.schema_name
|
193
|
+
order by
|
194
|
+
s.schema_name,
|
195
|
+
"function_name"
|
196
|
+
;
|
197
|
+
|
data/tests/schemas.sql
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
\set ON_ERROR_STOP on
|
2
|
+
|
3
|
+
drop schema if exists app_portal cascade;
|
4
|
+
drop schema if exists acl_portal cascade;
|
5
|
+
drop schema if exists sys_portal cascade;
|
6
|
+
|
7
|
+
drop schema if exists meta cascade;
|
8
|
+
drop schema if exists acl cascade;
|
9
|
+
|
10
|
+
drop schema if exists agg cascade;
|
11
|
+
drop schema if exists name cascade;
|
12
|
+
drop schema if exists agg_name cascade;
|
13
|
+
|
14
|
+
drop schema if exists auth cascade;
|
15
|
+
|
16
|
+
create schema auth;
|
17
|
+
create schema app_portal;
|
18
|
+
create schema acl_portal;
|
19
|
+
create schema sys_portal;
|
20
|
+
create schema meta;
|
21
|
+
create schema acl;
|
22
|
+
create schema agg;
|
23
|
+
create schema name;
|
24
|
+
create schema agg_name;
|
25
|
+
|
data/tests/setup.sql
ADDED
@@ -0,0 +1,8 @@
|
|
1
|
+
|
2
|
+
grant all on schema app_portal to alt;
|
3
|
+
grant all on all tables in schema app_portal to alt;
|
4
|
+
alter table cases enable row level security;
|
5
|
+
alter table events enable row level security;
|
6
|
+
alter table visits enable row level security;
|
7
|
+
alter table noncompliances enable row level security;
|
8
|
+
|