Skip to content

Commit

Permalink
Basic comparison operators
Browse files Browse the repository at this point in the history
  • Loading branch information
danieljharvey committed Nov 13, 2023
1 parent 20b917b commit 4d72910
Show file tree
Hide file tree
Showing 5 changed files with 1,919 additions and 2,593 deletions.
117 changes: 103 additions & 14 deletions crates/ndc-sqlserver/src/configuration/version1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ use tiberius::Query;

const TABLE_CONFIGURATION_QUERY: &str = include_str!("table_configuration.sql");

const TYPES_QUERY: &str = "SELECT name FROM sys.types FOR JSON PATH";

const CURRENT_VERSION: u32 = 1;

/// User configuration.
Expand Down Expand Up @@ -100,28 +102,39 @@ async fn create_mssql_pool(
bb8::Pool::builder().max_size(2).build(mgr).await
}

/// Construct the deployment configuration by introspecting the database.
pub async fn configure(
configuration: &RawConfiguration,
) -> Result<RawConfiguration, connector::UpdateConfigurationError> {
let mssql_pool = create_mssql_pool(configuration).await.unwrap();

async fn select_first_row(
mssql_pool: &bb8::Pool<bb8_tiberius::ConnectionManager>,
query: &str,
) -> tiberius::Row {
let mut connection = mssql_pool.get().await.unwrap();

// let's do a query to check everything is ok
let select = Query::new(TABLE_CONFIGURATION_QUERY);
let select = Query::new(query);

// go!
let stream = select.query(&mut connection).await.unwrap();

// Nothing is fetched, the first result set starts.
let row = stream.into_row().await.unwrap().unwrap();

row
}

/// Construct the deployment configuration by introspecting the database.
pub async fn configure(
configuration: &RawConfiguration,
) -> Result<RawConfiguration, connector::UpdateConfigurationError> {
let mssql_pool = create_mssql_pool(configuration).await.unwrap();

let tables_row = select_first_row(&mssql_pool, TABLE_CONFIGURATION_QUERY).await;

let decoded: Vec<introspection::IntrospectionTable> =
serde_json::from_str(row.get(0).unwrap()).unwrap();
serde_json::from_str(tables_row.get(0).unwrap()).unwrap();

let mut metadata = query_engine_metadata::metadata::Metadata::default();

metadata.comparison_operators = get_comparison_operators(&mssql_pool).await;

metadata.tables = get_tables_info(decoded);

metadata.native_queries = configuration.metadata.native_queries.clone();
Expand All @@ -133,6 +146,31 @@ pub async fn configure(
})
}

#[derive(Deserialize, Debug)]
struct TypeItem {
name: database::ScalarType,
}

// we lookup all types in sys.types, then use our hardcoded ideas about each one to attach
// comparison operators
async fn get_comparison_operators(
mssql_pool: &bb8::Pool<bb8_tiberius::ConnectionManager>,
) -> database::ComparisonOperators {
let types_row = select_first_row(mssql_pool, TYPES_QUERY).await;

let decoded: Vec<TypeItem> = serde_json::from_str(types_row.get(0).unwrap()).unwrap();

let mut comparison_operators = BTreeMap::new();

for type_name in decoded {
comparison_operators.insert(
type_name.name.clone(),
get_comparison_operators_for_type(type_name.name),
);
}
database::ComparisonOperators(comparison_operators)
}

// we hard code these, essentially
// we look up available types in `sys.types` but hard code their behaviour by looking them up below
// categories taken from https://learn.microsoft.com/en-us/sql/t-sql/data-types/data-types-transact-sql
Expand All @@ -159,26 +197,77 @@ fn get_comparison_operators_for_type(
"smalldatetime",
"time",
];
let _character_strings = vec!["char", "text", "varchar"];
let _unicode_character_strings = vec!["nchar", "ntext", "nvarchar"];
let character_strings = vec!["char", "text", "varchar"];
let unicode_character_strings = vec!["nchar", "ntext", "nvarchar"];
let _binary_strings = vec!["binary", "image", "varbinary"];
let cannot_compare = vec!["text", "ntext", "image"]; // https://learn.microsoft.com/en-us/sql/t-sql/language-elements/comparison-operators-transact-sql?view=sql-server-ver16

let mut comparison_operators = BTreeMap::new();

// some things cannot be compared
if !cannot_compare.contains(&type_name.0.as_str()) {
// in ndc-spec, all things can be `==`
comparison_operators.insert(
"_eq".to_string(),
database::ComparisonOperator {
operator_name: "=".to_string(),
argument_type: type_name.clone(),
},
);

// include LIKE and NOT LIKE for string-ish types
if character_strings.contains(&type_name.0.as_str())
|| unicode_character_strings.contains(&type_name.0.as_str())
{
comparison_operators.insert(
"_like".to_string(),
database::ComparisonOperator {
operator_name: "LIKE".to_string(),
argument_type: type_name.clone(),
},
);
comparison_operators.insert(
"_eq".to_string(),
"_nlike".to_string(),
database::ComparisonOperator {
operator_name: "=".to_string(),
operator_name: "NOT LIKE".to_string(),
argument_type: type_name.clone(),
},
);
}

// some things cannot be compared
if !cannot_compare.contains(&type_name.0.as_str()) {
comparison_operators.insert(
"_neq".to_string(),
database::ComparisonOperator {
operator_name: "!=".to_string(),
argument_type: type_name.clone(),
},
);
comparison_operators.insert(
"_lt".to_string(),
database::ComparisonOperator {
operator_name: "<".to_string(),
argument_type: type_name.clone(),
},
);
comparison_operators.insert(
"_gt".to_string(),
database::ComparisonOperator {
operator_name: ">".to_string(),
argument_type: type_name.clone(),
},
);

comparison_operators.insert(
"_gte".to_string(),
database::ComparisonOperator {
operator_name: ">=".to_string(),
argument_type: type_name.clone(),
},
);
comparison_operators.insert(
"_lte".to_string(),
database::ComparisonOperator {
operator_name: "<=".to_string(),
argument_type: type_name,
},
);
Expand Down
Loading

0 comments on commit 4d72910

Please sign in to comment.