Skip to content

Commit 0ba5470

Browse files
draft: query columns type
1 parent e3bc0c2 commit 0ba5470

File tree

6 files changed

+175
-0
lines changed

6 files changed

+175
-0
lines changed
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
use crate::{
2+
builder::CompletionBuilder, context::CompletionContext, relevance::CompletionRelevanceData,
3+
CompletionItem, CompletionItemKind,
4+
};
5+
6+
pub fn complete_functions(ctx: &CompletionContext, builder: &mut CompletionBuilder) {
7+
let available_functions = &ctx.schema_cache.functions;
8+
9+
for foo in available_functions {
10+
let item = CompletionItem {
11+
label: foo.name.clone(),
12+
score: CompletionRelevanceData::Function(foo).get_score(ctx),
13+
description: format!("Schema: {}", foo.schema),
14+
preselected: false,
15+
kind: CompletionItemKind::Function,
16+
};
17+
18+
builder.add_item(item);
19+
}
20+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1+
mod columns;
12
mod functions;
23
mod tables;
34

5+
pub use columns::*;
46
pub use functions::*;
57
pub use tables::*;

crates/pg_schema_cache/src/columns.rs

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
use crate::schema_cache::SchemaCacheItem;
2+
3+
enum ColumnClassKind {
4+
OrdinaryTable,
5+
View,
6+
MaterializedView,
7+
ForeignTable,
8+
PartitionedTable,
9+
}
10+
11+
impl From<&str> for ColumnClassKind {
12+
fn from(value: &str) -> Self {
13+
match value {
14+
"r" => ColumnClassKind::OrdinaryTable,
15+
"v" => ColumnClassKind::View,
16+
"m" => ColumnClassKind::MaterializedView,
17+
"f" => ColumnClassKind::ForeignTable,
18+
"p" => ColumnClassKind::PartitionedTable,
19+
_ => panic!(
20+
"Columns belonging to a class with pg_class.relkind = '{}' should be filtered out in the query.",
21+
value
22+
),
23+
}
24+
}
25+
}
26+
27+
impl From<String> for ColumnClassKind {
28+
fn from(value: String) -> Self {
29+
ColumnClassKind::from(value.as_str())
30+
}
31+
}
32+
33+
#[derive(Debug, Clone, PartialEq, Eq)]
34+
pub struct Column {
35+
pub name: String,
36+
37+
pub table_name: String,
38+
pub table_oid: i64,
39+
40+
/// What type of class does this column belong to?
41+
pub class_kind: bool,
42+
43+
pub schema_name: String,
44+
pub type_id: i64,
45+
// pub is_nullable: bool,
46+
// pub is_primary_key: bool,
47+
48+
// pub default_value: Option<String>,
49+
50+
// pub varchar_length: Option<i32>,
51+
52+
// /// None if the column is not a foreign key.
53+
// pub foreign_key: Option<ForeignKeyReference>,
54+
55+
// pub comment: Option<String>,
56+
}
57+
58+
#[derive(Debug, Clone, PartialEq, Eq)]
59+
pub struct ForeignKeyReference {
60+
pub schema: Option<String>,
61+
pub table: String,
62+
pub column: String,
63+
}
64+
65+
impl SchemaCacheItem for Column {
66+
type Item = Column;
67+
68+
async fn load(pool: &sqlx::PgPool) -> Result<Vec<Self::Item>, sqlx::Error> {
69+
sqlx::query_file_as!(Column, "src/queries/columns.sql")
70+
.fetch_all(pool)
71+
.await
72+
}
73+
}

crates/pg_schema_cache/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
33
#![allow(dead_code)]
44

5+
mod columns;
56
mod functions;
67
mod schema_cache;
78
mod schemas;
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
select
2+
tbl.schemaname as schema,
3+
tbl.tablename as table,
4+
tbl.quoted_name,
5+
tbl.is_table,
6+
json_agg(a) as columns
7+
from
8+
(
9+
select
10+
n.nspname as schemaname,
11+
c.relname as tablename,
12+
(
13+
quote_ident(n.nspname) || '.' || quote_ident(c.relname)
14+
) as quoted_name,
15+
true as is_table
16+
from
17+
pg_catalog.pg_class c
18+
join pg_catalog.pg_namespace n on n.oid = c.relnamespace
19+
where
20+
c.relkind = 'r'
21+
and n.nspname != 'pg_toast'
22+
and n.nspname not like 'pg_temp_%'
23+
and n.nspname not like 'pg_toast_temp_%'
24+
and has_schema_privilege(n.oid, 'USAGE') = true
25+
and has_table_privilege(
26+
quote_ident(n.nspname) || '.' || quote_ident(c.relname),
27+
'SELECT, INSERT, UPDATE, DELETE, TRUNCATE, REFERENCES, TRIGGER'
28+
) = true
29+
union
30+
all
31+
select
32+
n.nspname as schemaname,
33+
c.relname as tablename,
34+
(
35+
quote_ident(n.nspname) || '.' || quote_ident(c.relname)
36+
) as quoted_name,
37+
false as is_table
38+
from
39+
pg_catalog.pg_class c
40+
join pg_catalog.pg_namespace n on n.oid = c.relnamespace
41+
where
42+
c.relkind in ('v', 'm')
43+
and n.nspname != 'pg_toast'
44+
and n.nspname not like 'pg_temp_%'
45+
and n.nspname not like 'pg_toast_temp_%'
46+
and has_schema_privilege(n.oid, 'USAGE') = true
47+
and has_table_privilege(
48+
quote_ident(n.nspname) || '.' || quote_ident(c.relname),
49+
'SELECT, INSERT, UPDATE, DELETE, TRUNCATE, REFERENCES, TRIGGER'
50+
) = true
51+
) as tbl
52+
left join (
53+
select
54+
attrelid,
55+
attname,
56+
format_type(atttypid, atttypmod) as data_type,
57+
attnum,
58+
attisdropped
59+
from
60+
pg_attribute
61+
) as a on (
62+
a.attrelid = tbl.quoted_name :: regclass
63+
and a.attnum > 0
64+
and not a.attisdropped
65+
and has_column_privilege(
66+
tbl.quoted_name,
67+
a.attname,
68+
'SELECT, INSERT, UPDATE, REFERENCES'
69+
)
70+
)
71+
group by
72+
schemaname,
73+
tablename,
74+
quoted_name,
75+
is_table;

crates/pg_schema_cache/src/schema_cache.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,10 @@ impl SchemaCache {
5858
.find(|t| t.name == name && schema.is_none() || Some(t.schema.as_str()) == schema)
5959
}
6060

61+
pub fn find_type_by_id(&self, type_id: i64) -> Option<&PostgresType> {
62+
self.types.iter().find(|t| t.id == type_id)
63+
}
64+
6165
pub fn find_types(&self, name: &str, schema: Option<&str>) -> Vec<&PostgresType> {
6266
self.types
6367
.iter()

0 commit comments

Comments
 (0)