Skip to content

Commit

Permalink
wip v1 insert
Browse files Browse the repository at this point in the history
  • Loading branch information
Gil Mizrahi committed Jan 15, 2024
1 parent f7f739e commit 26ca7f0
Show file tree
Hide file tree
Showing 13 changed files with 1,195 additions and 5 deletions.
67 changes: 64 additions & 3 deletions crates/connectors/ndc-postgres/src/schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use super::configuration;
use ndc_sdk::connector;
use ndc_sdk::models;
use query_engine_metadata::metadata;
use query_engine_translation::translation::mutation::{delete, generate};
use query_engine_translation::translation::mutation::{delete, generate, insert};

/// Get the connector's schema.
///
Expand Down Expand Up @@ -234,16 +234,19 @@ pub async fn get_schema(
})
.collect();

let mut more_object_types = BTreeMap::new();
let generated_procedures: Vec<models::ProcedureInfo> =
query_engine_translation::translation::mutation::generate::generate(
&metadata.tables,
&config.mutations_version,
)
.iter()
.map(|(name, mutation)| mutation_to_procedure(name, mutation))
.map(|(name, mutation)| mutation_to_procedure(name, mutation, &mut more_object_types))
.collect();

procedures.extend(generated_procedures);
println!("{:#?}", more_object_types);
object_types.extend(more_object_types);

Ok(models::SchemaResponse {
collections,
Expand Down Expand Up @@ -275,9 +278,18 @@ fn type_to_type(typ: &metadata::Type) -> models::Type {
}

/// Turn our different `Mutation` items into `ProcedureInfo`s to be output in the schema
fn mutation_to_procedure(name: &String, mutation: &generate::Mutation) -> models::ProcedureInfo {
fn mutation_to_procedure(
name: &String,
mutation: &generate::Mutation,
object_types: &mut BTreeMap<String, models::ObjectType>,
) -> models::ProcedureInfo {
match mutation {
generate::Mutation::DeleteMutation(delete) => delete_to_procedure(name, delete),
generate::Mutation::InsertMutation(insert) => {
let p = insert_to_procedure(name, insert, object_types);
println!("{:#?}", p);
p
}
}
}

Expand Down Expand Up @@ -311,3 +323,52 @@ fn delete_to_procedure(name: &String, delete: &delete::DeleteMutation) -> models
}
}
}

/// Create an ObjectType out of columns metadata.
fn make_object_type(
columns: &BTreeMap<String, metadata::database::ColumnInfo>,
) -> models::ObjectType {
let mut fields = BTreeMap::new();
for (name, column) in columns {
fields.insert(
name.clone(),
models::ObjectField {
r#type: column_to_type(column),
description: None,
},
);
}
models::ObjectType {
description: None,
fields,
}
}

/// given a `InsertMutation`, turn it into a `ProcedureInfo` to be output in the schema.
fn insert_to_procedure(
name: &String,
insert: &insert::InsertMutation,
object_types: &mut BTreeMap<String, models::ObjectType>,
) -> models::ProcedureInfo {
let mut arguments = BTreeMap::new();
let object_type = make_object_type(&insert.columns);
let object_name = format!("{name}_object").to_string();
object_types.insert(object_name.clone(), object_type);

arguments.insert(
"_object".to_string(),
models::ArgumentInfo {
argument_type: models::Type::Named { name: object_name },
description: None,
},
);

models::ProcedureInfo {
name: name.to_string(),
description: Some(insert.description.to_string()),
arguments,
result_type: models::Type::Named {
name: insert.collection_name.to_string(),
},
}
}
11 changes: 11 additions & 0 deletions crates/query-engine/sql/src/sql/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ pub struct CommonTableExpression {
pub enum CTExpr {
RawSql(Vec<RawSql>),
Delete(Delete),
Insert(Insert),
}

/// Raw SQL written by a user which is opaque to us
Expand All @@ -51,6 +52,16 @@ pub struct Select {
pub limit: Limit,
}

/// An INSERT clause
#[derive(Debug, Clone, PartialEq)]
pub struct Insert {
pub schema: SchemaName,
pub table: TableName,
pub columns: Vec<ColumnName>,
pub values: Vec<Expression>,
pub returning: Returning,
}

/// A DELETE clause
#[derive(Debug, Clone, PartialEq)]
pub struct Delete {
Expand Down
33 changes: 33 additions & 0 deletions crates/query-engine/sql/src/sql/convert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ impl CTExpr {
}
}
CTExpr::Delete(delete) => delete.to_sql(sql),
CTExpr::Insert(insert) => insert.to_sql(sql),
}
}
}
Expand Down Expand Up @@ -122,6 +123,38 @@ impl Select {
}
}

impl Insert {
pub fn to_sql(&self, sql: &mut SQL) {
sql.append_syntax("INSERT INTO ");

sql.append_identifier(&self.schema.0);
sql.append_syntax(".");
sql.append_identifier(&self.table.0);
sql.append_syntax("(");
for (index, column_name) in self.columns.iter().enumerate() {
sql.append_identifier(&column_name.0.to_string());
if index < (self.columns.len() - 1) {
sql.append_syntax(", ")
}
}
sql.append_syntax(")");

sql.append_syntax(" VALUES ");
sql.append_syntax("(");
for (index, value) in self.values.iter().enumerate() {
value.to_sql(sql);
if index < (self.values.len() - 1) {
sql.append_syntax(", ")
}
}
sql.append_syntax(")");

sql.append_syntax(" ");

self.returning.to_sql(sql);
}
}

impl Delete {
pub fn to_sql(&self, sql: &mut SQL) {
let Delete {
Expand Down
7 changes: 7 additions & 0 deletions crates/query-engine/sql/src/sql/rewrites/constant_folding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ pub fn normalize_cte(mut cte: CommonTableExpression) -> CommonTableExpression {
.collect(),
),
CTExpr::Delete(delete) => CTExpr::Delete(normalize_delete(delete)),
CTExpr::Insert(insert) => CTExpr::Insert(normalize_insert(insert)),
};
cte
}
Expand All @@ -111,6 +112,12 @@ fn normalize_delete(mut delete: Delete) -> Delete {
delete
}

/// Normalize everything in an Insert
fn normalize_insert(mut insert: Insert) -> Insert {
insert.values = insert.values.into_iter().map(normalize_expr).collect();
insert
}

/// Constant expressions folding. Remove redundant expressions.
/// This is the main work. The other parts are just trying to apply
/// this rewrite to their Expressions.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
//! Given introspection data, generate a set of standard mutation procedures
use super::delete::{generate_delete_by_unique, DeleteMutation};
use super::insert;
use super::insert::InsertMutation;
use query_engine_metadata::metadata::{database, mutations};
use std::collections::BTreeMap;

#[derive(Debug, Clone)]
pub enum Mutation {
DeleteMutation(DeleteMutation),
InsertMutation(InsertMutation),
}

/// Given our introspection data, work out all the mutations we can generate
Expand All @@ -24,6 +27,8 @@ pub fn generate(
for (name, delete_mutation) in delete_mutations {
mutations.insert(name, Mutation::DeleteMutation(delete_mutation));
}
let (name, insert_mutation) = insert::generate(collection_name, table_info);
mutations.insert(name, Mutation::InsertMutation(insert_mutation));
}
}
None => {}
Expand Down
75 changes: 75 additions & 0 deletions crates/query-engine/translation/src/translation/mutation/insert.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
//! Auto-generate insert mutations and translate them into sql ast.
use crate::translation::error::Error;
use crate::translation::query::values::translate_json_value;
use query_engine_metadata::metadata;
use query_engine_metadata::metadata::database;
use query_engine_sql::sql::ast;
use std::collections::BTreeMap;

/// A representation of an auto-generated insert mutation.
///
/// This can get us `INSERT INTO <table>(<columns>) VALUES (<values>)`.
#[derive(Debug, Clone)]
pub struct InsertMutation {
pub collection_name: String,
pub description: String,
pub schema_name: ast::SchemaName,
pub table_name: ast::TableName,
pub columns: BTreeMap<String, metadata::database::ColumnInfo>,
}

/// generate an insert mutation.
pub fn generate(
collection_name: &String,
table_info: &database::TableInfo,
) -> (String, InsertMutation) {
let name = format!("v1_insert_{collection_name}");

let description = format!("Insert into the {collection_name} table",);

let insert_mutation = InsertMutation {
collection_name: collection_name.clone(),
description,
schema_name: ast::SchemaName(table_info.schema_name.clone()),
table_name: ast::TableName(table_info.table_name.clone()),
columns: table_info.columns.clone(),
};

(name, insert_mutation)
}

/// Given the description of an insert mutation (ie, `InsertMutation`),
/// and the arguments, output the SQL AST.
pub fn translate(
// state: &mut crate::translation::helpers::State,
mutation: &InsertMutation,
arguments: BTreeMap<String, serde_json::Value>,
) -> Result<ast::Insert, Error> {
println!("{:#?}", mutation);
let insert = ast::Insert {
schema: mutation.schema_name.clone(),
table: mutation.table_name.clone(),
columns: mutation
.columns
.values()
.map(|column_info| ast::ColumnName(column_info.name.clone()))
.collect(),
values: {
let object = arguments.get("_object").unwrap(); // TODO
match object {
serde_json::Value::Object(object) => object
.iter()
.map(|(name, value)| {
let column = mutation.columns.get(name).unwrap();
translate_json_value(value, &column.r#type).unwrap()
})
.collect(),
_ => todo!(),
}
},
returning: ast::Returning::ReturningStar,
};
println!("{:#?}", insert);
Ok(insert)
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
pub mod delete;
pub mod generate;
pub mod insert;
pub mod translate;
pub use translate::translate;
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ pub fn translate(
// and failing that, try a generated mutation,
{
env.lookup_generated_mutation(&name).and_then(|mutation| {
translate_delete_mutation(&env, name, fields, arguments, mutation)
translate_mutation(&env, name, fields, arguments, mutation)
})
}
}
Expand All @@ -46,7 +46,7 @@ pub fn translate(

/// Translate a built-in delete mutation into an ExecutionPlan (SQL) to be run against the database.
/// Most of this is probably reusable for `insert`, `update` etc in future.
fn translate_delete_mutation(
fn translate_mutation(
env: &Env,
procedure_name: String,
fields: Option<IndexMap<String, ndc_sdk::models::Field>>,
Expand Down Expand Up @@ -91,6 +91,13 @@ fn translate_delete_mutation(
)?),
)
}
mutation::generate::Mutation::InsertMutation(insert) => {
let return_collection = insert.collection_name.clone();
(
return_collection,
sql::ast::CTExpr::Insert(mutation::insert::translate(&insert, arguments)?),
)
}
};

let current_table = TableNameAndReference {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"operations": [
{
"type": "procedure",
"name": "v1_insert_Artist",
"arguments": {
"_object": {
"id": 276,
"name": "Olympians"
}
},
"fields": {
"artist_id": {
"type": "column",
"column": "id"
},
"name": {
"type": "column",
"column": "name"
}
}
}
],
"collection_relationships": {}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"tables": {
"Artist": {
"schemaName": "public",
"tableName": "Artist",
"columns": {
"id": {
"name": "ArtistId",
"type": {
"scalarType": "int4"
}
},
"name": {
"name": "Name",
"type": {
"scalarType": "varchar"
}
}
}
}
}
}
Loading

0 comments on commit 26ca7f0

Please sign in to comment.