Skip to content

Commit 79dc39b

Browse files
committed
store: Use Layout for schema information
1 parent 261bc4a commit 79dc39b

File tree

4 files changed

+79
-75
lines changed

4 files changed

+79
-75
lines changed

store/postgres/src/sql/formatter.rs

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
use sqlparser::ast::{ObjectName, Statement, TableFactor, VisitMut, VisitorMut};
22
use std::ops::ControlFlow;
33

4-
use super::Schema;
4+
use crate::relational::{Layout, SqlName};
55

66
pub struct Formatter<'a> {
77
prelude: &'a str,
8-
schema: &'a Schema,
8+
layout: &'a Layout,
99
}
1010

1111
impl<'a> Formatter<'a> {
12-
pub fn new(prelude: &'a str, schema: &'a Schema) -> Self {
13-
Self { prelude, schema }
12+
pub fn new(prelude: &'a str, layout: &'a Layout) -> Self {
13+
Self { prelude, layout }
1414
}
1515

1616
fn prepend_prefix_to_object_name_mut(&self, name: &mut ObjectName) {
@@ -20,7 +20,8 @@ impl<'a> Formatter<'a> {
2020

2121
// Ensure schema tables has quotation to match up with prelude generated cte.
2222
if let Some(table_name) = table_identifier.last_mut() {
23-
if self.schema.contains_key(&table_name.value) {
23+
let sql_name = SqlName::verbatim(table_name.to_string());
24+
if self.layout.table(&sql_name).is_some() {
2425
table_name.quote_style = Some('"');
2526
}
2627
}
@@ -52,10 +53,19 @@ impl VisitorMut for Formatter<'_> {
5253

5354
#[cfg(test)]
5455
mod test {
55-
use std::collections::HashSet;
56-
5756
use super::*;
58-
use crate::sql::constants::SQL_DIALECT;
57+
use crate::sql::{constants::SQL_DIALECT, test::make_layout};
58+
59+
const GQL: &str = "
60+
type Swap @entity {
61+
id: ID!
62+
amountIn: BigDecimal!
63+
amountOut: BigDecimal!
64+
tokenIn: Bytes!
65+
tokenOut: Bytes!
66+
}
67+
";
68+
5969
const CTE_PREFIX: &str = "WITH \"swap\" AS (
6070
SELECT
6171
id,
@@ -69,17 +79,9 @@ mod test {
6979

7080
#[test]
7181
fn format_sql() {
72-
let mut schema = Schema::new();
73-
schema.insert(
74-
"swap".to_string(),
75-
HashSet::from_iter(
76-
["id", "amount_in", "amount_out", "token_in", "token_out"]
77-
.into_iter()
78-
.map(|s| s.to_string()),
79-
),
80-
);
82+
let layout = make_layout(GQL);
8183

82-
let mut formatter = Formatter::new(CTE_PREFIX, &schema);
84+
let mut formatter = Formatter::new(CTE_PREFIX, &layout);
8385

8486
let sql = "SELECT token_in, SUM(amount_in) AS amount FROM unknown.swap GROUP BY token_in";
8587

store/postgres/src/sql/mod.rs

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,27 @@ mod formatter;
33
mod parser;
44
mod validation;
55

6-
use std::collections::{HashMap, HashSet};
6+
pub use parser::Parser;
77

8-
pub(self) type Schema = HashMap<String, HashSet<String>>; // HashMap<Table, HashSet<Column>>
8+
#[cfg(test)]
9+
mod test {
10+
use std::{collections::BTreeSet, sync::Arc};
911

10-
pub use parser::Parser;
12+
use graph::{prelude::DeploymentHash, schema::InputSchema};
13+
14+
use crate::{
15+
catalog::Catalog,
16+
primary::{make_dummy_site, Namespace},
17+
relational::Layout,
18+
};
19+
20+
pub(crate) fn make_layout(gql: &str) -> Layout {
21+
let subgraph = DeploymentHash::new("Qmasubgraph").unwrap();
22+
let schema = InputSchema::parse_latest(gql, subgraph.clone()).unwrap();
23+
let namespace = Namespace::new("sgd0815".to_string()).unwrap();
24+
let site = Arc::new(make_dummy_site(subgraph, namespace, "anet".to_string()));
25+
let catalog = Catalog::for_tests(site.clone(), BTreeSet::new()).unwrap();
26+
let layout = Layout::new(site, &schema, catalog).unwrap();
27+
layout
28+
}
29+
}

store/postgres/src/sql/parser.rs

Lines changed: 5 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -52,39 +52,23 @@ pub fn generate_table_prelude_from_layout(layout: &Layout) -> String {
5252
}
5353

5454
pub struct Parser {
55-
schema: super::Schema,
55+
layout: Arc<Layout>,
5656
prelude: String,
5757
}
5858

5959
impl Parser {
6060
pub fn new(layout: Arc<Layout>) -> Self {
61-
Self {
62-
schema: layout
63-
.tables
64-
.iter()
65-
.filter(|(entity, _)| !entity.is_poi())
66-
.map(|(_, table)| {
67-
(
68-
table.name.to_string(),
69-
table
70-
.columns
71-
.iter()
72-
.map(|column| column.name.to_string())
73-
.collect(),
74-
)
75-
})
76-
.collect(),
77-
prelude: generate_table_prelude_from_layout(&layout),
78-
}
61+
let prelude = generate_table_prelude_from_layout(&layout);
62+
Self { layout, prelude }
7963
}
8064

8165
pub fn parse_and_validate(&self, sql: &str) -> Result<String> {
8266
let mut statements = sqlparser::parser::Parser::parse_sql(&SQL_DIALECT, sql)?;
8367

84-
let mut validator = Validator::new(&self.schema);
68+
let mut validator = Validator::new(&self.layout);
8569
validator.validate_statements(&statements)?;
8670

87-
let mut formatter = Formatter::new(&self.prelude, &self.schema);
71+
let mut formatter = Formatter::new(&self.prelude, &self.layout);
8872

8973
let statement = statements
9074
.get_mut(0)

store/postgres/src/sql/validation.rs

Lines changed: 32 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@ use sqlparser::ast::{Expr, ObjectName, Query, SetExpr, Statement, TableFactor, V
22
use std::result::Result;
33
use std::{collections::HashSet, ops::ControlFlow};
44

5-
use super::{constants::ALLOWED_FUNCTIONS, Schema};
5+
use crate::relational::Layout;
6+
7+
use super::constants::ALLOWED_FUNCTIONS;
68

79
#[derive(thiserror::Error, Debug, PartialEq)]
810
pub enum Error {
@@ -17,14 +19,14 @@ pub enum Error {
1719
}
1820

1921
pub struct Validator<'a> {
20-
schema: &'a Schema,
22+
layout: &'a Layout,
2123
ctes: HashSet<String>,
2224
}
2325

2426
impl<'a> Validator<'a> {
25-
pub fn new(schema: &'a Schema) -> Self {
27+
pub fn new(layout: &'a Layout) -> Self {
2628
Self {
27-
schema,
29+
layout,
2830
ctes: Default::default(),
2931
}
3032
}
@@ -54,9 +56,9 @@ impl<'a> Validator<'a> {
5456

5557
fn validate_table_name(&mut self, name: &ObjectName) -> ControlFlow<Error> {
5658
if let Some(table_name) = name.0.last() {
57-
let table_name = table_name.to_string().to_lowercase();
58-
if !self.schema.contains_key(&table_name) && !self.ctes.contains(&table_name) {
59-
return ControlFlow::Break(Error::UnknownTable(table_name));
59+
let name = &table_name.value;
60+
if !self.layout.table(name).is_some() && !self.ctes.contains(name) {
61+
return ControlFlow::Break(Error::UnknownTable(name.to_string()));
6062
}
6163
}
6264
ControlFlow::Continue(())
@@ -114,38 +116,35 @@ impl Visitor for Validator<'_> {
114116
#[cfg(test)]
115117
mod test {
116118
use super::*;
117-
use crate::sql::constants::SQL_DIALECT;
118-
use std::collections::{HashMap, HashSet};
119+
use crate::sql::{constants::SQL_DIALECT, test::make_layout};
119120

120121
fn validate(sql: &str) -> Result<(), Error> {
121122
let statements = sqlparser::parser::Parser::parse_sql(&SQL_DIALECT, sql).unwrap();
122123

123-
let schema: Schema = HashMap::from([(
124-
"swap".to_owned(),
125-
HashSet::from([
126-
"vid".to_owned(),
127-
"block$".to_owned(),
128-
"id".to_owned(),
129-
"sender".to_owned(),
130-
"input_amount".to_owned(),
131-
"input_token".to_owned(),
132-
"amount_out".to_owned(),
133-
"output_token".to_owned(),
134-
"slippage".to_owned(),
135-
"referral_code".to_owned(),
136-
"block_number".to_owned(),
137-
"block_timestamp".to_owned(),
138-
"transaction_hash".to_owned(),
139-
]),
140-
)]);
141-
142-
let mut validator = Validator::new(&schema);
124+
const GQL: &str = "
125+
type Swap @entity {
126+
id: ID!
127+
sender: Bytes!
128+
inputAmount: BigDecimal!
129+
inputToken: Bytes!
130+
amountOut: BigDecimal!
131+
outputToken: Bytes!
132+
slippage: BigDecimal!
133+
referralCode: String
134+
blockNumber: Int!
135+
blockTimestamp: Timestamp!
136+
transactionHash: Bytes!
137+
}";
138+
139+
let layout = make_layout(GQL);
140+
141+
let mut validator = Validator::new(&layout);
143142

144143
validator.validate_statements(&statements)
145144
}
146145

147146
#[test]
148-
fn test_function_blacklisted() {
147+
fn test_function_disallowed() {
149148
let result = validate(
150149
"
151150
SELECT
@@ -161,7 +160,7 @@ mod test {
161160
}
162161

163162
#[test]
164-
fn test_table_function_blacklisted() {
163+
fn test_table_function_disallowed() {
165164
let result = validate(
166165
"
167166
SELECT
@@ -181,7 +180,7 @@ mod test {
181180
}
182181

183182
#[test]
184-
fn test_function_blacklisted_without_paranthesis() {
183+
fn test_function_disallowed_without_paranthesis() {
185184
let result = validate(
186185
"
187186
SELECT
@@ -195,7 +194,7 @@ mod test {
195194
}
196195

197196
#[test]
198-
fn test_function_whitelisted() {
197+
fn test_function_allowed() {
199198
let result = validate(
200199
"
201200
SELECT

0 commit comments

Comments
 (0)