Skip to content

Commit

Permalink
add a subcommand stored-procedures to the update command
Browse files Browse the repository at this point in the history
  • Loading branch information
codingkarthik committed Sep 16, 2024
1 parent 368b38f commit 5503842
Show file tree
Hide file tree
Showing 8 changed files with 181 additions and 88 deletions.
24 changes: 21 additions & 3 deletions crates/cli/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,14 @@ pub struct Context<Env: Environment> {
pub environment: Env,
}

#[derive(Debug, Clone, Subcommand)]
pub enum UpdateCommand {
StoredProcedures {
#[arg(long)]
r#override: bool,
},
}

/// The command invoked by the user.
#[derive(Debug, Clone, Subcommand)]
pub enum Command {
Expand All @@ -30,7 +38,10 @@ pub enum Command {
with_metadata: bool,
},
/// Update the configuration by introspecting the database, using the configuration options.
Update,
Update {

Check warning on line 41 in crates/cli/src/lib.rs

View workflow job for this annotation

GitHub Actions / cargo fmt

Diff in /home/runner/work/ndc-sqlserver/ndc-sqlserver/crates/cli/src/lib.rs
#[command(subcommand)]
subcommand: Option<UpdateCommand>,
}
}

/// The set of errors that can go wrong _in addition to_ generic I/O or parsing errors.
Expand All @@ -44,7 +55,8 @@ pub enum Error {
pub async fn run(command: Command, context: Context<impl Environment>) -> anyhow::Result<()> {

Check warning on line 55 in crates/cli/src/lib.rs

View workflow job for this annotation

GitHub Actions / cargo fmt

Diff in /home/runner/work/ndc-sqlserver/ndc-sqlserver/crates/cli/src/lib.rs
match command {
Command::Initialize { with_metadata } => initialize(with_metadata, context).await?,
Command::Update => update(context).await?,
Command::Update { subcommand } => update(context, subcommand).await?

};
Ok(())
}
Expand Down Expand Up @@ -130,7 +142,7 @@ async fn initialize(with_metadata: bool, context: Context<impl Environment>) ->
/// Update the configuration in the current directory by introspecting the database.

Check warning on line 142 in crates/cli/src/lib.rs

View workflow job for this annotation

GitHub Actions / cargo fmt

Diff in /home/runner/work/ndc-sqlserver/ndc-sqlserver/crates/cli/src/lib.rs
///
/// This expects a configuration with a valid connection URI.
async fn update(context: Context<impl Environment>) -> anyhow::Result<()> {
async fn update(context: Context<impl Environment>, subcommand: Option<UpdateCommand>) -> anyhow::Result<()> {
// It is possible to change the file in the middle of introspection.
// We want to detect this scenario and retry, or fail if we are unable to.
// We do that with a few attempts.
Expand All @@ -144,10 +156,16 @@ async fn update(context: Context<impl Environment>) -> anyhow::Result<()> {
read_config_file_contents(&configuration_file_path).await?;
serde_json::from_str(&configuration_file_contents)?

Check warning on line 157 in crates/cli/src/lib.rs

View workflow job for this annotation

GitHub Actions / cargo fmt

Diff in /home/runner/work/ndc-sqlserver/ndc-sqlserver/crates/cli/src/lib.rs
};
let stored_procs_config = subcommand.clone().map(|sub_cmd| match sub_cmd {
UpdateCommand::StoredProcedures { r#override } => configuration::version1::StoredProceduresConfigurationOptions {
overwrite_existing_stored_procedures: r#override,
},
});
let output = configuration::configure(
&configuration_file_path,
&raw_configuration,
&context.environment,
stored_procs_config,
)
.await?;

Expand Down
2 changes: 1 addition & 1 deletion crates/cli/tests/update_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ async fn test_update_configuration() -> anyhow::Result<()> {
environment,

Check warning on line 39 in crates/cli/tests/update_tests.rs

View workflow job for this annotation

GitHub Actions / cargo fmt

Diff in /home/runner/work/ndc-sqlserver/ndc-sqlserver/crates/cli/tests/update_tests.rs
release_version: None,
};
run(Command::Update, context).await?;
run(Command::Update {subcommand: None}, context).await?;

let configuration_file_path = dir.path().join("configuration.json");
assert!(configuration_file_path.exists());
Expand Down
5 changes: 5 additions & 0 deletions crates/configuration/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,9 @@ pub enum Error {

#[error("Error creating connection pool while introspecting the database: {0}")]
ConnectionPoolError(#[from] bb8_tiberius::Error),

// error while parsing stored procedure introspection

Check warning on line 37 in crates/configuration/src/error.rs

View workflow job for this annotation

GitHub Actions / cargo fmt

Diff in /home/runner/work/ndc-sqlserver/ndc-sqlserver/crates/configuration/src/error.rs
#[error("Error parsing stored procedure introspection: {0}")]
StoredProcedureIntrospectionError(serde_json::Error),

}
59 changes: 52 additions & 7 deletions crates/configuration/src/version1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,11 @@ pub struct RawConfiguration {
pub metadata: query_engine_metadata::metadata::Metadata,
}

#[derive(Debug, PartialEq, Eq, Deserialize, Serialize, JsonSchema, Clone)]
pub struct StoredProceduresConfigurationOptions {
pub overwrite_existing_stored_procedures: bool,
}

impl RawConfiguration {
pub fn empty() -> Self {
Self {
Expand All @@ -78,6 +83,7 @@ impl RawConfiguration {
}

Check warning on line 83 in crates/configuration/src/version1.rs

View workflow job for this annotation

GitHub Actions / cargo fmt

Diff in /home/runner/work/ndc-sqlserver/ndc-sqlserver/crates/configuration/src/version1.rs
}


/// User configuration, elaborated from a 'RawConfiguration'.
#[derive(Debug, PartialEq, Eq, Deserialize, Serialize, JsonSchema)]
pub struct Configuration {
Expand Down Expand Up @@ -166,11 +172,55 @@ async fn select_first_row(
stream.into_row().await.unwrap().unwrap()
}

// get_stored_procedures fetches the stored procedures from the database and returns them as a
// vector of introspection::IntrospectStoredProcedure.
async fn configure_stored_procedures(
mssql_pool: &bb8::Pool<bb8_tiberius::ConnectionManager>,
existing_stored_procedures: StoredProcedures,
config_options: Option<StoredProceduresConfigurationOptions>,
) -> Result<StoredProcedures, Error> {

Check warning on line 181 in crates/configuration/src/version1.rs

View workflow job for this annotation

GitHub Actions / cargo fmt

Diff in /home/runner/work/ndc-sqlserver/ndc-sqlserver/crates/configuration/src/version1.rs
match config_options {
Some(config_options) => {
let stored_procedures_row =
select_first_row(&mssql_pool, STORED_PROCS_CONFIGURATION_QUERY).await;
let introspected_stored_procedures: Vec<introspection::IntrospectStoredProcedure> =
serde_json::from_str(stored_procedures_row.get(0).unwrap()).map_err(Error::StoredProcedureIntrospectionError)?;
let new_stored_procedures = get_stored_procedures(introspected_stored_procedures);

// traverse the new stored procedures and add them to the existing stored procedures
let mut merged_stored_procedures = existing_stored_procedures.0.clone();
for (name, stored_procedure) in new_stored_procedures.0 {
// check if the stored procedure already exists
if merged_stored_procedures.contains_key(&name) {
if config_options.overwrite_existing_stored_procedures {
merged_stored_procedures.insert(name, stored_procedure);
} else {
// do not overwrite the existing stored procedure
continue;
}

} else {
merged_stored_procedures.insert(name, stored_procedure);
}

}

Ok(StoredProcedures(merged_stored_procedures))

}
None => Ok(existing_stored_procedures)
}

}



/// Construct the deployment configuration by introspecting the database.
pub async fn configure(
file_path: &std::path::Path,
configuration: &RawConfiguration,
environment: impl Environment,
stored_procedure_configuration_options: Option<StoredProceduresConfigurationOptions>,
) -> Result<RawConfiguration, Error> {
let connection_string = match &configuration.mssql_connection_string {
uri::ConnectionUri(Secret::Plain(s)) => s.to_owned(),
Expand Down Expand Up @@ -205,13 +255,8 @@ pub async fn configure(

Check warning on line 255 in crates/configuration/src/version1.rs

View workflow job for this annotation

GitHub Actions / cargo fmt

Diff in /home/runner/work/ndc-sqlserver/ndc-sqlserver/crates/configuration/src/version1.rs
metadata.aggregate_functions = get_aggregate_functions(&type_names);

let stored_procedures_row =
select_first_row(&mssql_pool, STORED_PROCS_CONFIGURATION_QUERY).await;

let stored_procedures: Vec<introspection::IntrospectStoredProcedure> =
serde_json::from_str(stored_procedures_row.get(0).unwrap()).unwrap();

metadata.stored_procedures = get_stored_procedures(stored_procedures);
metadata.stored_procedures =
configure_stored_procedures(&mssql_pool, configuration.metadata.stored_procedures.clone(), stored_procedure_configuration_options).await?;

Ok(RawConfiguration {
version: 1,
Expand Down
3 changes: 3 additions & 0 deletions crates/ndc-sqlserver/src/connector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,9 @@ impl<Env: Environment + Send + Sync> connector::ConnectorSetup for SQLServerSetu
configuration::Error::ConnectionPoolError(inner) => {
connector::ParseError::Other(inner.into())
}
configuration::Error::StoredProcedureIntrospectionError(inner) => {
connector::ParseError::Other(inner.into())
}
})
}

Expand Down
4 changes: 2 additions & 2 deletions crates/ndc-sqlserver/tests/configuration_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ pub async fn configure_is_idempotent(
)]);
let file_path = PathBuf::new();

let mut actual = configuration::configure(&file_path, &args, environment)
let mut actual = configuration::configure(&file_path, &args, environment, None)
.await
.expect("configuration::configure");

Expand Down Expand Up @@ -92,7 +92,7 @@ pub async fn configure_initial_configuration_is_unchanged(
let environment = HashMap::from([(connection_uri_variable, connection_string.into())]);
let file_path = PathBuf::new();

configuration::configure(&file_path, &args, environment)
configuration::configure(&file_path, &args, environment, None)
.await
.expect("configuration::configure")
}
Expand Down
136 changes: 79 additions & 57 deletions static/configuration.json
Original file line number Diff line number Diff line change
Expand Up @@ -843,63 +843,6 @@
"description": null
}
},
"storedProcedures": {
"GetCustomerDetailsWithTotalPurchases": {
"name": "GetCustomerDetailsWithTotalPurchases",
"schema": "dbo",
"arguments": {
"CustomerId": {
"name": "CustomerId",
"type": "int",
"nullable": "nullable",
"isOutput": false,
"description": null
},
"Phone": {
"name": "Phone",
"type": "varchar",
"nullable": "nullable",
"isOutput": false,
"description": null
}
},
"returns": {
"CustomerId": {
"name": "CustomerId",
"type": "int",
"nullable": "nonNullable",
"description": null
},
"Phone": {
"name": "Phone",
"type": "varchar",
"nullable": "nonNullable",
"description": null
},
"TotalPurchases": {
"name": "TotalPurchases",
"type": "int",
"nullable": "nonNullable",
"description": null
}
},
"description": null
},
"ReturnOne": {
"name": "ReturnOne",
"schema": "dbo",
"arguments": {},
"returns": {
"result": {
"name": "result",
"type": "int",
"description": null,
"nullable": "nullable"
}
},
"description": null
}
},
"aggregateFunctions": {
"bigint": {
"APPROX_COUNT_DISTINCT": {
Expand Down Expand Up @@ -2763,6 +2706,85 @@
"operatorKind": "custom"
}
}
},
"storedProcedures": {
"GetArtistsByName1": {
"name": "GetArtistsByName1",
"schema": "dbo",
"arguments": {
"Name": {
"name": "Name",
"type": "varchar",
"nullable": "nullable",
"isOutput": false,
"description": null
},
"blah": {
"name": "blah",
"type": "varchar",
"nullable": "nullable",
"isOutput": false,
"description": null
}
},
"returns": {
"Artist": {
"name": "Artist",
"type": "varchar",
"nullable": "nonNullable",
"description": null
}
},
"description": null
},
"GetCustomerDetailsWithTotalPurchases": {
"name": "GetCustomerDetailsWithTotalPurchases",
"schema": "dbo",
"arguments": {
"CustomerId": {
"name": "CustomerId",
"type": "int",
"nullable": "nullable",
"isOutput": false,
"description": null
},
"Phone": {
"name": "Phone",
"type": "varchar",
"nullable": "nonNullable",
"isOutput": false,
"description": null
}
},
"returns": {
"CustomerId": {
"name": "CustomerId",
"type": "int",
"nullable": "nonNullable",
"description": null
},
"Phone": {
"name": "Phone",
"type": "varchar",
"nullable": "nonNullable",
"description": null
},
"TotalPurchases": {
"name": "TotalPurchases",
"type": "int",
"nullable": "nonNullable",
"description": null
}
},
"description": null
},
"ReturnOne": {
"name": "ReturnOne",
"schema": "dbo",
"arguments": {},
"returns": null,
"description": null
}
}
}
}
36 changes: 18 additions & 18 deletions static/tests/configuration.json
Original file line number Diff line number Diff line change
Expand Up @@ -2728,24 +2728,24 @@
}
},
"returns": {
"CustomerId": {
"name": "CustomerId",
"type": "int",
"nullable": "nonNullable",
"description": null
},
"Phone": {
"name": "Phone",
"type": "varchar",
"nullable": "nonNullable",
"description": null
},
"TotalPurchases": {
"name": "TotalPurchases",
"type": "int",
"nullable": "nonNullable",
"description": null
}
"CustomerId": {
"name": "CustomerId",
"type": "int",
"nullable": "nonNullable",
"description": null
},
"Phone": {
"name": "Phone",
"type": "varchar",
"nullable": "nonNullable",
"description": null
},
"TotalPurchases": {
"name": "TotalPurchases",
"type": "int",
"nullable": "nonNullable",
"description": null
}
},
"description": null
},
Expand Down

0 comments on commit 5503842

Please sign in to comment.