1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
#[derive(Debug, elephantry_derive::Entity)]
#[entity(internal)]
pub struct Schema {
pub name: String,
pub oid: crate::pq::Oid,
pub relations: String,
pub comment: String,
}
pub fn database(connection: &crate::Connection) -> Vec<Schema> {
connection
.query(
r#"
select
n.nspname as "name",
n.oid as "oid",
count(c) as "relations",
d.description as "comment"
from pg_catalog.pg_namespace n
left join pg_catalog.pg_description d on n.oid = d.objoid
left join pg_catalog.pg_class c on
c.relnamespace = n.oid and c.relkind in ('r', 'v')
where n.nspname !~ '^pg' and n.nspname <> 'information_schema'
group by 1, 2, 4
order by 1;
"#,
&[],
)
.unwrap()
.collect()
}
#[derive(Debug, elephantry_derive::Entity)]
#[entity(internal)]
pub struct Relation {
pub name: String,
pub ty: String,
pub oid: crate::pq::Oid,
pub comment: Option<String>,
}
pub fn schema(connection: &crate::Connection, schema: &str) -> Vec<Relation> {
connection
.query(
r#"
with schema as(
select
s.oid as oid
from
pg_catalog.pg_namespace s
where s.nspname = $1
)
select
cl.relname as "name",
case
when cl.relkind = 'r' then 'table'
when cl.relkind = 'v' then 'view'
when cl.relkind = 'm' then 'materialized view'
when cl.relkind = 'f' then 'foreign table'
else 'other'
end as "ty",
cl.oid as "oid",
des.description as "comment"
from
pg_catalog.pg_class cl
left join pg_catalog.pg_description des on
cl.oid = des.objoid and des.objsubid = 0
join schema on schema.oid = cl.relnamespace
where relkind in ('r', 'v', 'm', 'f')
order by name asc;
"#,
&[&schema],
)
.unwrap()
.collect()
}
#[derive(Debug, elephantry_derive::Entity)]
#[entity(internal)]
pub struct Column {
pub is_primary: bool,
pub name: String,
pub oid: crate::pq::Oid,
pub ty: String,
pub default: Option<String>,
pub is_notnull: bool,
pub comment: Option<String>,
}
pub fn relation(
connection: &crate::Connection,
schema: &str,
relation: &str,
) -> Vec<Column> {
connection
.query(
r#"
with relation as(
select
c.oid as oid
from
pg_catalog.pg_class c
left join pg_catalog.pg_namespace n on n.oid = c.relnamespace
where
n.nspname = $1
and c.relname = $2
)
select
att.attnum = any(ind.indkey) as "is_primary",
att.attname as "name",
typ.oid as "oid",
case
when name.nspname = 'pg_catalog' then typ.typname
else format('%s.%s', name.nspname, typ.typname)
end as "ty",
pg_catalog.pg_get_expr(def.adbin, def.adrelid) as "default",
att.attnotnull as "is_notnull",
dsc.description as "comment"
from
pg_catalog.pg_attribute att
join relation on att.attrelid = relation.oid
join pg_catalog.pg_type typ on att.atttypid = typ.oid
join pg_catalog.pg_class cla on att.attrelid = cla.oid
join pg_catalog.pg_namespace clns on cla.relnamespace = clns.oid
left join pg_catalog.pg_description dsc on cla.oid = dsc.objoid and att.attnum = dsc.objsubid
left join pg_catalog.pg_attrdef def on att.attrelid = def.adrelid and att.attnum = def.adnum
left join pg_catalog.pg_index ind on cla.oid = ind.indrelid and ind.indisprimary
left join pg_catalog.pg_namespace name on typ.typnamespace = name.oid
where
att.attnum > 0
and not att.attisdropped
order by
att.attnum
"#,
&[&schema, &relation],
)
.unwrap()
.collect()
}