From cd0174df8d5f9711f33b2e7922654ea12b771020 Mon Sep 17 00:00:00 2001 From: Paul Ruane Date: Sun, 8 Sep 2024 01:07:08 +0100 Subject: [PATCH] chore(refactor): Refactoring project layout --- TODO.md | 2 +- src/cli/args.rs | 36 ++++ src/cli/mod.rs | 96 ++++----- src/compare/mod.rs | 253 +++++++++++------------ src/compare/report.rs | 269 ------------------------- src/compare/report/mod.rs | 24 +++ src/compare/report/privilege.rs | 16 ++ src/compare/report/property.rs | 15 ++ src/compare/report/routine.rs | 21 ++ src/compare/report/schema.rs | 27 +++ src/compare/report/sequence.rs | 19 ++ src/compare/report/table.rs | 27 +++ src/compare/report/table_column.rs | 20 ++ src/compare/report/table_constraint.rs | 18 ++ src/compare/report/table_trigger.rs | 18 ++ src/compare/report/view.rs | 15 ++ src/db/mod.rs | 74 ++++--- src/db/thing.rs | 3 +- 18 files changed, 457 insertions(+), 496 deletions(-) create mode 100644 src/cli/args.rs delete mode 100644 src/compare/report.rs create mode 100644 src/compare/report/mod.rs create mode 100644 src/compare/report/privilege.rs create mode 100644 src/compare/report/property.rs create mode 100644 src/compare/report/routine.rs create mode 100644 src/compare/report/schema.rs create mode 100644 src/compare/report/sequence.rs create mode 100644 src/compare/report/table.rs create mode 100644 src/compare/report/table_column.rs create mode 100644 src/compare/report/table_constraint.rs create mode 100644 src/compare/report/table_trigger.rs create mode 100644 src/compare/report/view.rs diff --git a/TODO.md b/TODO.md index 7b82176..1d68108 100644 --- a/TODO.md +++ b/TODO.md @@ -1 +1 @@ -* [ ] Get integration tests to snapshot database +* [ ] Split into lib and executable \ No newline at end of file diff --git a/src/cli/args.rs b/src/cli/args.rs new file mode 100644 index 0000000..9ddfa82 --- /dev/null +++ b/src/cli/args.rs @@ -0,0 +1,36 @@ +use clap::{Parser, ValueEnum}; + +#[derive(Parser, Debug)] +#[command(version, about, long_about = None)] +pub struct Args { + #[arg(short, long, short = 'l', help = "The left database URL")] + pub left: String, + + #[arg(short, long, short = 'r', help = "The right database URL")] + pub right: String, + + #[arg(short, long, required = true, short = 's', help = "Schema to compare")] + pub schema: Vec, + + #[arg(short, long, short = 'w', help = "Ignore routine whitespace differences")] + pub ignore_whitespace: bool, + + #[arg(short, long, short = 'o', help = "Ignore column ordering differences")] + pub ignore_column_ordinal: bool, + + #[arg(short, long, short = 'p', help = "Ignore privilege changes")] + pub ignore_privileges: bool, + + #[arg(short, long, short = 'v', help = "Show matches")] + pub verbose: bool, + + #[arg(short, long, short = 'c', alias = "colour", help = "Use colour", default_value = "auto")] + pub color: Colouring, +} + +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ValueEnum, Debug)] +pub enum Colouring { + Auto, + Always, + Never, +} diff --git a/src/cli/mod.rs b/src/cli/mod.rs index f491ea3..f2eca4e 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -1,20 +1,33 @@ +mod args; + use std::process; -use clap::{Parser, ValueEnum}; +use clap::{Parser}; use colored::Colorize; use postgres::Error; use crate::{compare, db}; -use crate::compare::report::PrivilegeComparison::{PrivilegeAdded, PrivilegeMaintained, PrivilegeRemoved}; -use crate::compare::report::{HasChanges, TableColumnReport, TableConstraintReport, SchemaReport, RoutineReport, SequenceReport, ViewReport, PropertyReport, PrivilegeReport, TableReport, TableTriggerReport}; -use crate::compare::report::PropertyComparison::{PropertyChanged, PropertyUnchanged}; -use crate::compare::report::RoutineComparison::{RoutineAdded, RoutineMaintained, RoutineRemoved}; -use crate::compare::report::SchemaComparison::{SchemaAdded, SchemaMaintained, SchemaMissing, SchemaRemoved}; -use crate::compare::report::SequenceComparison::{SequenceAdded, SequenceMaintained, SequenceRemoved}; -use crate::compare::report::TableColumnComparison::{ColumnAdded, ColumnMaintained, ColumnRemoved}; -use crate::compare::report::TableComparison::{TableAdded, TableMaintained, TableRemoved}; -use crate::compare::report::TableConstraintComparison::{ConstraintAdded, ConstraintMaintained, ConstraintRemoved}; -use crate::compare::report::TableTriggerComparison::{TriggerAdded, TriggerMaintained, TriggerRemoved}; -use crate::compare::report::ViewComparison::{ViewMaintained}; +use crate::cli::args::{Args, Colouring::Always, Colouring::Never}; +use crate::compare::report::{HasChanges, Report}; +use crate::compare::report::privilege::PrivilegeComparison; +use crate::compare::report::privilege::PrivilegeComparison::{PrivilegeAdded, PrivilegeMaintained, PrivilegeRemoved}; +use crate::compare::report::property::PropertyComparison; +use crate::compare::report::property::PropertyComparison::{PropertyChanged, PropertyUnchanged}; +use crate::compare::report::routine::RoutineComparison; +use crate::compare::report::routine::RoutineComparison::{RoutineAdded, RoutineMaintained, RoutineRemoved}; +use crate::compare::report::schema::SchemaComparison; +use crate::compare::report::schema::SchemaComparison::{SchemaAdded, SchemaMaintained, SchemaMissing, SchemaRemoved}; +use crate::compare::report::sequence::SequenceComparison; +use crate::compare::report::sequence::SequenceComparison::{SequenceAdded, SequenceMaintained, SequenceRemoved}; +use crate::compare::report::table::TableComparison; +use crate::compare::report::table::TableComparison::{TableAdded, TableMaintained, TableRemoved}; +use crate::compare::report::table_column::TableColumnComparison; +use crate::compare::report::table_column::TableColumnComparison::{ColumnAdded, ColumnMaintained, ColumnRemoved}; +use crate::compare::report::table_constraint::TableConstraintComparison; +use crate::compare::report::table_constraint::TableConstraintComparison::{ConstraintAdded, ConstraintMaintained, ConstraintRemoved}; +use crate::compare::report::table_trigger::TableTriggerComparison::{TriggerAdded, TriggerMaintained, TriggerRemoved}; +use crate::compare::report::table_trigger::{TableTriggerComparison}; +use crate::compare::report::view::ViewComparison; +use crate::compare::report::view::ViewComparison::ViewMaintained; const COLOUR_ADDED: colored::Color = colored::Color::Green; const COLOUR_CHANGED: colored::Color= colored::Color::Yellow; @@ -30,8 +43,8 @@ impl CLI { let args = Args::parse(); match args.color { - Colouring::Always => colored::control::set_override(true), - Colouring::Never => colored::control::set_override(false), + Always => colored::control::set_override(true), + Never => colored::control::set_override(false), _ => (), } @@ -57,7 +70,7 @@ impl CLI { process::exit(differences); } - fn render_schema_report(&self, report: SchemaReport) -> i32{ + fn render_schema_report(&self, report: Report) -> i32{ let mut differences = 0; for schema in &report.entries { @@ -104,7 +117,7 @@ impl CLI { differences } - fn render_property_report(&self, report: &PropertyReport, depth: usize) -> i32 { + fn render_property_report(&self, report: &Report, depth: usize) -> i32 { let mut differences = 0; let margin = str::repeat(" ", depth); @@ -127,7 +140,7 @@ impl CLI { differences } - fn render_privilege_report(&self, report: &PrivilegeReport, depth: usize) -> i32 { + fn render_privilege_report(&self, report: &Report, depth: usize) -> i32 { let mut differences = 0; let margin = str::repeat(" ", depth); @@ -156,7 +169,7 @@ impl CLI { differences } - fn render_routine_report(self: &Self, report: &RoutineReport) -> i32 { + fn render_routine_report(&self, report: &Report) -> i32 { let mut differences = 0; for routine in &report.entries { @@ -195,7 +208,7 @@ impl CLI { differences } - fn render_sequence_report(&self, report: &SequenceReport) -> i32 { + fn render_sequence_report(&self, report: &Report) -> i32 { let mut differences = 0; for sequence in &report.entries { @@ -232,7 +245,7 @@ impl CLI { differences } - fn render_table_report(&self, report: &TableReport) -> i32 { + fn render_table_report(&self, report: &Report) -> i32 { let mut differences = 0; for table in &report.entries { @@ -273,7 +286,7 @@ impl CLI { differences } - fn render_table_column_report(&self, report: &TableColumnReport) -> i32 { + fn render_table_column_report(&self, report: &Report) -> i32 { let mut differences = 0; for column in &report.entries { @@ -311,7 +324,7 @@ impl CLI { differences } - fn render_table_constraint_report(&self, report: &TableConstraintReport) -> i32 { + fn render_table_constraint_report(&self, report: &Report) -> i32 { let mut differences = 0; for constraint in &report.entries { @@ -348,7 +361,7 @@ impl CLI { differences } - fn render_table_trigger_report(&self, report: &TableTriggerReport) -> i32 { + fn render_table_trigger_report(&self, report: &Report) -> i32 { let mut differences = 0; for trigger in &report.entries { @@ -385,7 +398,7 @@ impl CLI { differences } - fn render_view_report(&self, report: &ViewReport) -> i32 { + fn render_view_report(&self, report: &Report) -> i32 { let mut differences = 0; for view in &report.entries { @@ -410,38 +423,3 @@ impl CLI { differences } } - -#[derive(Parser, Debug)] -#[command(version, about, long_about = None)] -pub struct Args { - #[arg(short, long, short = 'l', help = "The left database URL")] - left: String, - - #[arg(short, long, short = 'r', help = "The right database URL")] - right: String, - - #[arg(short, long, required = true, short = 's', help = "Schema to compare")] - schema: Vec, - - #[arg(short, long, short = 'w', help = "Ignore routine whitespace differences")] - ignore_whitespace: bool, - - #[arg(short, long, short = 'o', help = "Ignore column ordering differences")] - ignore_column_ordinal: bool, - - #[arg(short, long, short = 'p', help = "Ignore privilege changes")] - ignore_privileges: bool, - - #[arg(short, long, short = 'v', help = "Show matches")] - verbose: bool, - - #[arg(short, long, short = 'c', alias = "colour", help = "Use colour", default_value = "auto")] - color: Colouring, -} - -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ValueEnum, Debug)] -enum Colouring { - Auto, - Always, - Never, -} diff --git a/src/compare/mod.rs b/src/compare/mod.rs index c3ae918..5054241 100644 --- a/src/compare/mod.rs +++ b/src/compare/mod.rs @@ -1,24 +1,32 @@ -pub(crate) mod report; - use std::collections::HashMap; -use std::fmt::{Display}; +use std::fmt::Display; use postgres::Error; -use SchemaComparison::{SchemaAdded, SchemaMissing}; -use crate::compare::report::{PropertyComparison, SchemaComparison, TableColumnReport, TableConstraintReport, SchemaReport, PropertyReport, RoutineReport, PrivilegeReport, SequenceReport, TableReport, ViewReport, TableTriggerReport}; -use crate::{db}; -use crate::compare::report::PrivilegeComparison::{PrivilegeAdded, PrivilegeMaintained, PrivilegeRemoved}; -use crate::compare::report::PropertyComparison::{PropertyChanged, PropertyUnchanged}; -use crate::compare::report::RoutineComparison::{RoutineAdded, RoutineMaintained, RoutineRemoved}; -use crate::compare::report::SchemaComparison::{SchemaMaintained, SchemaRemoved}; -use crate::compare::report::SequenceComparison::{SequenceAdded, SequenceMaintained, SequenceRemoved}; -use crate::compare::report::TableColumnComparison::{ColumnAdded, ColumnMaintained, ColumnRemoved}; -use crate::compare::report::TableComparison::{TableAdded, TableMaintained, TableRemoved}; -use crate::compare::report::TableConstraintComparison::{ConstraintAdded, ConstraintMaintained, ConstraintRemoved}; -use crate::compare::report::TableTriggerComparison::{TriggerAdded, TriggerMaintained, TriggerRemoved}; -use crate::compare::report::ViewComparison::ViewMaintained; -use crate::db::{Database}; -use crate::db::thing::{Privilege, Schema}; -use crate::string::{EqualIgnoreWhitespace}; +use crate::compare::report::privilege::PrivilegeComparison; +use crate::compare::report::privilege::PrivilegeComparison::{PrivilegeAdded, PrivilegeMaintained, PrivilegeRemoved}; +use crate::compare::report::property::PropertyComparison; +use crate::compare::report::property::PropertyComparison::{PropertyChanged, PropertyUnchanged}; +use crate::compare::report::Report; +use crate::compare::report::routine::RoutineComparison; +use crate::compare::report::routine::RoutineComparison::{RoutineAdded, RoutineMaintained, RoutineRemoved}; +use crate::compare::report::schema::SchemaComparison; +use crate::compare::report::schema::SchemaComparison::{SchemaAdded, SchemaMaintained, SchemaMissing, SchemaRemoved}; +use crate::compare::report::sequence::SequenceComparison; +use crate::compare::report::sequence::SequenceComparison::{SequenceAdded, SequenceMaintained, SequenceRemoved}; +use crate::compare::report::table::TableComparison; +use crate::compare::report::table::TableComparison::{TableAdded, TableMaintained, TableRemoved}; +use crate::compare::report::table_column::TableColumnComparison; +use crate::compare::report::table_column::TableColumnComparison::{ColumnAdded, ColumnMaintained, ColumnRemoved}; +use crate::compare::report::table_constraint::TableConstraintComparison; +use crate::compare::report::table_constraint::TableConstraintComparison::{ConstraintAdded, ConstraintMaintained, ConstraintRemoved}; +use crate::compare::report::table_trigger::TableTriggerComparison; +use crate::compare::report::table_trigger::TableTriggerComparison::{TriggerAdded, TriggerMaintained, TriggerRemoved}; +use crate::compare::report::view::ViewComparison; +use crate::compare::report::view::ViewComparison::ViewMaintained; +use crate::db::Database; +use crate::db::thing::{Column, Constraint, Privilege, Routine, Schema, Sequence, Table, Trigger, View}; +use crate::string::EqualIgnoreWhitespace; + +pub mod report; pub struct Comparer { left_db: Database, @@ -39,25 +47,20 @@ impl Comparer { } } - pub fn compare(&mut self, schemas: Vec) -> Result { - let left_schemas = self.left_db.schemas()?; - let right_schemas = self.right_db.schemas()?; - + pub fn compare(&mut self, schemas: Vec) -> Result, Error> { let mut entries = Vec::new(); - - for schema in schemas { - let left_schema = left_schemas.iter().find(|s| s.schema_name == schema); - let right_schema = right_schemas.iter().find(|s| s.schema_name == schema); - let entry: SchemaComparison; + for schema in schemas { + let left_schema = self.left_db.schema(&schema)?; + let right_schema = self.right_db.schema(&schema)?; if left_schema.is_none() && right_schema.is_none() { - entry = SchemaMissing { schema_name: String::from(schema) }; + entries.push(SchemaMissing { schema_name: String::from(schema) }); } else { if left_schema.is_none() { - entry = SchemaAdded { schema_name: String::from(schema) }; + entries.push(SchemaAdded { schema_name: String::from(schema) }); } else if right_schema.is_none() { - entry = SchemaRemoved { schema_name: String::from(schema) }; + entries.push(SchemaRemoved { schema_name: String::from(schema) }); } else { let properties = self.compare_schema_properties(&left_schema.unwrap(), &right_schema.unwrap()); @@ -66,29 +69,27 @@ impl Comparer { let tables = self.compare_tables(&schema)?; let views = self.compare_views(&schema)?; - entry = SchemaMaintained { schema_name: String::from(schema), properties, routines, sequences, tables, views }; + entries.push(SchemaMaintained { schema_name: String::from(schema), properties, routines, sequences, tables, views }); } } - - entries.push(entry) } - Ok(SchemaReport { entries }) + Ok(Report { entries }) } - fn compare_schema_properties(&self, left_schema: &Schema, right_schema: &Schema) -> PropertyReport { - PropertyReport { + fn compare_schema_properties(&self, left_schema: &Schema, right_schema: &Schema) -> Report { + Report { entries: vec![ self.compare_property("schema_owner", &left_schema.schema_owner, &right_schema.schema_owner) ] } } - fn compare_routines(&mut self, schema_name: &str) -> Result { + fn compare_routines(&mut self, schema_name: &str) -> Result, Error> { let left_routines = self.left_db.routines(schema_name)?; let right_routines = self.right_db.routines(schema_name)?; - let mut right_routines_map: HashMap = right_routines.into_iter().map(|t| (t.signature.clone(), t)).collect(); + let mut right_routines_map: HashMap = right_routines.into_iter().map(|t| (t.signature.clone(), t)).collect(); let mut entries = Vec::new(); for left_routine in left_routines { @@ -110,7 +111,7 @@ impl Comparer { } if right_routines_map.len() > 0 { - let mut added_routines: Vec<&db::thing::Routine> = right_routines_map.values().collect(); + let mut added_routines: Vec<&Routine> = right_routines_map.values().collect(); added_routines.sort_unstable_by_key(|r| &r.signature); for right_routine in added_routines { @@ -118,11 +119,11 @@ impl Comparer { } } - Ok(RoutineReport { entries }) + Ok(Report { entries }) } - fn compare_routine_properties(&self, left: &db::thing::Routine, right: &db::thing::Routine) -> PropertyReport { - PropertyReport { + fn compare_routine_properties(&self, left: &Routine, right: &Routine) -> Report { + Report { entries: vec![ self.compare_option_property("routine_type", &left.routine_type, &right.routine_type), self.compare_option_property("data_type", &left.data_type, &right.data_type), @@ -142,9 +143,9 @@ impl Comparer { } } - fn compare_routine_privileges(&mut self, schema_name: &str, routine_signature: &str) -> Result { + fn compare_routine_privileges(&mut self, schema_name: &str, routine_signature: &str) -> Result, Error> { if self.ignore_privileges { - return Ok(PrivilegeReport { entries: vec![] }) + return Ok(Report { entries: vec![] }) } let left_routine_privileges = self.left_db.routine_privileges(schema_name, routine_signature)?; @@ -153,7 +154,7 @@ impl Comparer { Ok(self.compare_privileges(left_routine_privileges, right_routine_privileges)) } - fn compare_privileges(&self, left_privileges: Vec, right_privileges: Vec) -> PrivilegeReport { + fn compare_privileges(&self, left_privileges: Vec, right_privileges: Vec) -> Report { let mut right_privileges_map: HashMap<(String, String, String), Privilege> = right_privileges.into_iter().map(|c| ((c.privilege_type.clone(), c.grantor.clone(), c.grantee.clone()), c)).collect(); let mut entries = Vec::new(); @@ -180,14 +181,14 @@ impl Comparer { } } - PrivilegeReport { entries } + Report { entries } } - fn compare_sequences(&mut self, schema_name: &str) -> Result { + fn compare_sequences(&mut self, schema_name: &str) -> Result, Error> { let left_sequences = self.left_db.sequences(schema_name)?; let right_sequences = self.right_db.sequences(schema_name)?; - let mut right_sequences_map: HashMap = right_sequences.into_iter().map(|t| (t.sequence_name.clone(), t)).collect(); + let mut right_sequences_map: HashMap = right_sequences.into_iter().map(|t| (t.sequence_name.clone(), t)).collect(); let mut entries = Vec::new(); for left_sequence in left_sequences { @@ -208,7 +209,7 @@ impl Comparer { } if right_sequences_map.len() > 0 { - let mut added_sequences: Vec<&db::thing::Sequence> = right_sequences_map.values().collect(); + let mut added_sequences: Vec<&Sequence> = right_sequences_map.values().collect(); added_sequences.sort_unstable_by_key(|s| &s.sequence_name); for right_sequence in added_sequences { @@ -216,11 +217,11 @@ impl Comparer { } } - Ok(SequenceReport { entries }) + Ok(Report { entries }) } - fn compare_sequence_properties(&self, left: &db::thing::Sequence, right: &db::thing::Sequence) -> PropertyReport { - PropertyReport { + fn compare_sequence_properties(&self, left: &Sequence, right: &Sequence) -> Report { + Report { entries: vec![ self.compare_property("data_type", &left.data_type, &right.data_type), self.compare_property("numeric_precision", &left.numeric_precision, &right.numeric_precision), @@ -235,11 +236,11 @@ impl Comparer { } } - fn compare_tables(&mut self, schema_name: &str) -> Result { + fn compare_tables(&mut self, schema_name: &str) -> Result, Error> { let left_tables = self.left_db.tables(schema_name)?; let right_tables = self.right_db.tables(schema_name)?; - let mut right_tables_map: HashMap = right_tables.into_iter().map(|t| (t.table_name.clone(), t)).collect(); + let mut right_tables_map: HashMap = right_tables.into_iter().map(|t| (t.table_name.clone(), t)).collect(); let mut entries = Vec::new(); for left_table in left_tables { @@ -264,7 +265,7 @@ impl Comparer { } if right_tables_map.len() > 0 { - let mut added_tables: Vec<&db::thing::Table> = right_tables_map.values().collect(); + let mut added_tables: Vec<&Table> = right_tables_map.values().collect(); added_tables.sort_unstable_by_key(|t| &t.table_name); for right_table in added_tables { @@ -272,11 +273,11 @@ impl Comparer { } } - Ok(TableReport { entries }) + Ok(Report { entries }) } - fn compare_table_properties(&self, left: &db::thing::Table, right: &db::thing::Table) -> PropertyReport { - PropertyReport { + fn compare_table_properties(&self, left: &Table, right: &Table) -> Report { + Report { entries: vec![ self.compare_property("table_type", &left.table_type, &right.table_type), self.compare_property("is_insertable_into", &left.is_insertable_into, &right.is_insertable_into), @@ -284,28 +285,28 @@ impl Comparer { } } - fn compare_table_privileges(&mut self, schema_name: &str, table_name: &str) -> Result { + fn compare_table_privileges(&mut self, schema_name: &str, table_name: &str) -> Result, Error> { if self.ignore_privileges { - return Ok(PrivilegeReport { entries: vec![] }) + return Ok(Report { entries: vec![] }) } let left_table_privileges = self.left_db.table_privileges(schema_name, table_name)?; let right_table_privileges = self.right_db.table_privileges(schema_name, table_name)?; - + Ok(self.compare_privileges(left_table_privileges, right_table_privileges)) } - fn compare_table_columns(&mut self, schema_name: &str, table_name: &str) -> Result { + fn compare_table_columns(&mut self, schema_name: &str, table_name: &str) -> Result, Error> { let left_columns = self.left_db.columns(schema_name, table_name)?; let right_columns = self.right_db.columns(schema_name, table_name)?; - - let mut right_columns_map : HashMap = right_columns.into_iter().map(|c| (c.column_name.clone(), c)).collect(); + + let mut right_columns_map : HashMap = right_columns.into_iter().map(|c| (c.column_name.clone(), c)).collect(); let mut entries = Vec::new(); - + for left_column in left_columns { let key = left_column.column_name.clone(); let right_column = right_columns_map.get_mut(&key); - + match right_column { None => { entries.push(ColumnRemoved { column_name: left_column.column_name.clone() }); @@ -315,25 +316,25 @@ impl Comparer { let privileges = self.compare_table_column_privileges(schema_name, table_name, &rc.column_name)?; entries.push(ColumnMaintained { column_name: rc.column_name.clone(), properties, privileges }); - + right_columns_map.remove(&key); }, } } - + if right_columns_map.len() > 0 { - let mut added_columns : Vec<&db::thing::Column> = right_columns_map.values().collect(); + let mut added_columns : Vec<&Column> = right_columns_map.values().collect(); added_columns.sort_unstable_by_key(|c| &c.column_name); - + for right_column in added_columns { entries.push(ColumnAdded { column_name: right_column.column_name.clone() }); } } - - Ok(TableColumnReport { entries }) + + Ok(Report { entries }) } - fn compare_table_column_properties(&self, left: &db::thing::Column, right: &db::thing::Column) -> PropertyReport { + fn compare_table_column_properties(&self, left: &Column, right: &Column) -> Report { let mut properties = vec![ self.compare_option_property("column_default", &left.column_default, &right.column_default), self.compare_property("is_nullable", &left.is_nullable, &right.is_nullable), @@ -348,17 +349,17 @@ impl Comparer { self.compare_option_property("generation_expression", &left.generation_expression, &right.generation_expression), self.compare_property("is_updatable", &left.is_updatable, &right.is_updatable), ]; - + if !self.ignore_column_ordinal { properties.push(self.compare_property("ordinal_position", &left.ordinal_position, &right.ordinal_position)); } - - PropertyReport { entries: properties } + + Report { entries: properties } } - - fn compare_table_column_privileges(&mut self, schema_name: &str, table_name: &str, column_name: &str) -> Result { + + fn compare_table_column_privileges(&mut self, schema_name: &str, table_name: &str, column_name: &str) -> Result, Error> { if self.ignore_privileges { - return Ok(PrivilegeReport { entries: vec![] }) + return Ok(Report { entries: vec![] }) } let left_column_privileges = self.left_db.column_privileges(schema_name, table_name, column_name)?; @@ -366,46 +367,46 @@ impl Comparer { Ok(self.compare_privileges(left_column_privileges, right_column_privileges)) } - - fn compare_table_constraints(&mut self, schema_name: &str, table_name: &str) -> Result { + + fn compare_table_constraints(&mut self, schema_name: &str, table_name: &str) -> Result, Error> { let left_table_constraints = self.left_db.table_constraints(schema_name, table_name)?; let right_table_constraints = self.right_db.table_constraints(schema_name, table_name)?; - - let mut right_table_constraints_map : HashMap = right_table_constraints.into_iter().map(|t| (t.constraint_name.clone(), t)).collect(); + + let mut right_table_constraints_map : HashMap = right_table_constraints.into_iter().map(|t| (t.constraint_name.clone(), t)).collect(); let mut entries = Vec::new(); - + for left_table_constraint in left_table_constraints { let key = left_table_constraint.constraint_name.clone(); let right_table_constraint = right_table_constraints_map.get(&key); - + match right_table_constraint { None => { entries.push(ConstraintRemoved { constraint_name: left_table_constraint.constraint_name }); }, Some(rtc) => { let properties = self.compare_table_constraint(&left_table_constraint, rtc); - + entries.push(ConstraintMaintained { constraint_name: rtc.constraint_name.clone(), properties }); - + right_table_constraints_map.remove(&key); }, } } - + if right_table_constraints_map.len() > 0 { - let mut added_table_constraints : Vec<&db::thing::TableConstraint> = right_table_constraints_map.values().collect(); + let mut added_table_constraints : Vec<&Constraint> = right_table_constraints_map.values().collect(); added_table_constraints.sort_unstable_by_key(|tc| &tc.constraint_name); - + for right_table_constraint in added_table_constraints { entries.push(ConstraintAdded { constraint_name: right_table_constraint.constraint_name.clone() }); } } - - Ok(TableConstraintReport { entries }) + + Ok(Report { entries }) } - - fn compare_table_constraint(&mut self, left: &db::thing::TableConstraint, right: &db::thing::TableConstraint) -> PropertyReport { - PropertyReport { + + fn compare_table_constraint(&mut self, left: &Constraint, right: &Constraint) -> Report { + Report { entries: vec![ self.compare_property("constraint_type", &left.constraint_type, &right.constraint_type), self.compare_property("is_deferrable", &left.is_deferrable, &right.is_deferrable), @@ -415,45 +416,45 @@ impl Comparer { } } - fn compare_table_triggers(&mut self, schema_name: &str, table_name: &str) -> Result { + fn compare_table_triggers(&mut self, schema_name: &str, table_name: &str) -> Result, Error> { let left_triggers = self.left_db.triggers(schema_name, table_name)?; let right_triggers = self.right_db.triggers(schema_name, table_name)?; - - let mut right_triggers_map : HashMap<(String, String), db::thing::Trigger> = right_triggers.into_iter().map(|t| ((t.trigger_name.clone(), t.event_manipulation.clone()), t)).collect(); + + let mut right_triggers_map : HashMap<(String, String), Trigger> = right_triggers.into_iter().map(|t| ((t.trigger_name.clone(), t.event_manipulation.clone()), t)).collect(); let mut entries = Vec::new(); - + for left_trigger in left_triggers { let key = &(left_trigger.trigger_name.clone(), left_trigger.event_manipulation.clone()); let right_trigger = right_triggers_map.get(&key); - + match right_trigger { None => { entries.push(TriggerRemoved { trigger_name: left_trigger.trigger_name, event_manipulation: left_trigger.event_manipulation }); }, Some(rt) => { let properties = self.compare_trigger_properties(&left_trigger, rt); - + entries.push(TriggerMaintained { trigger_name: rt.trigger_name.clone(), event_manipulation: rt.event_manipulation.clone(), properties }); - + right_triggers_map.remove(key); }, } } - + if right_triggers_map.len() > 0 { - let mut added_triggers : Vec<&db::thing::Trigger> = right_triggers_map.values().collect(); + let mut added_triggers : Vec<&Trigger> = right_triggers_map.values().collect(); added_triggers.sort_unstable_by_key(|t| (&t.trigger_name, &t.event_manipulation)); - + for right_trigger in added_triggers { entries.push(TriggerAdded { trigger_name: right_trigger.trigger_name.clone(), event_manipulation: right_trigger.event_manipulation.clone() }); } } - - Ok(TableTriggerReport { entries }) + + Ok(Report { entries }) } - - fn compare_trigger_properties(&mut self, left: &db::thing::Trigger, right: &db::thing::Trigger) -> PropertyReport { - PropertyReport { + + fn compare_trigger_properties(&mut self, left: &Trigger, right: &Trigger) -> Report { + Report { entries: vec![ self.compare_property("action_order", &left.action_order, &right.action_order), self.compare_option_property("action_condition", &left.action_condition, &right.action_condition), @@ -466,16 +467,16 @@ impl Comparer { } } - fn compare_views(&mut self, schema_name: &str) -> Result { + fn compare_views(&mut self, schema_name: &str) -> Result, Error> { let left_views = self.left_db.views(schema_name)?; let right_views = self.right_db.views(schema_name)?; - - let right_views_map: HashMap = right_views.into_iter().map(|t| (t.view_name.clone(), t)).collect(); + + let right_views_map: HashMap = right_views.into_iter().map(|t| (t.view_name.clone(), t)).collect(); let mut entries = Vec::new(); - + for left_view in left_views { let right_view = right_views_map.get(&left_view.view_name); - + match right_view { None => { // already detected by table comparison @@ -483,19 +484,19 @@ impl Comparer { }, Some(rv) => { let properties = self.compare_view_properties(&left_view, rv); - + entries.push(ViewMaintained { view_name: rv.view_name.clone(), properties }); } } } - + // added already detected by table comparison - - Ok(ViewReport { entries }) + + Ok(Report { entries }) } - - fn compare_view_properties(&mut self, left: &db::thing::View, right: &db::thing::View) -> PropertyReport { - PropertyReport { + + fn compare_view_properties(&mut self, left: &View, right: &View) -> Report { + Report { entries: vec![ self.compare_option_property("view_definition", &left.view_definition, &right.view_definition), self.compare_property("check_option", &left.check_option, &right.check_option), @@ -532,14 +533,14 @@ impl Comparer { if left_value.is_none() && right_value.is_none() { return PropertyUnchanged { property_name: String::from(property_name), value: String::from("") } } - + if left_value.is_none() || right_value.is_none() { return PropertyChanged { property_name: String::from(property_name), left_value: left_value.as_ref().map_or(String::from(""), |v| v.to_string()), right_value: right_value.as_ref().map_or(String::from(""), |v| v.to_string()) }; } - + let left = left_value.as_ref().unwrap(); let right = right_value.as_ref().unwrap(); - + if compare(left, right) { PropertyUnchanged { property_name: String::from(property_name), value: left.to_string() } } else { diff --git a/src/compare/report.rs b/src/compare/report.rs deleted file mode 100644 index 52cde82..0000000 --- a/src/compare/report.rs +++ /dev/null @@ -1,269 +0,0 @@ -pub trait HasChanges { - fn has_changes(&self) -> bool; -} - -pub struct SchemaReport { - pub entries: Vec -} - -pub enum SchemaComparison { - SchemaAdded { schema_name: String }, - SchemaRemoved { schema_name: String }, - SchemaMissing { schema_name: String }, - SchemaMaintained { schema_name: String, properties: PropertyReport, routines: RoutineReport, sequences: SequenceReport, tables: TableReport, views: ViewReport }, -} - -impl HasChanges for SchemaReport { - fn has_changes(self: &Self) -> bool { - self.entries.iter().any(|s| s.has_changes()) - } -} - -impl HasChanges for SchemaComparison { - fn has_changes(self: &Self) -> bool { - match self { - SchemaComparison::SchemaAdded { .. } | SchemaComparison::SchemaRemoved { .. } | SchemaComparison::SchemaMissing { .. } => true, - SchemaComparison::SchemaMaintained { schema_name: _schema_name, properties, routines, sequences, tables, views } => - properties.has_changes() || - routines.has_changes() || - sequences.has_changes() || - tables.has_changes() || - views.has_changes(), - } - } -} - -pub struct PropertyReport { - pub entries: Vec -} - -pub enum PropertyComparison { - PropertyChanged { property_name: String, left_value: String, right_value: String }, - PropertyUnchanged { property_name: String, value: String }, -} - -impl HasChanges for PropertyReport { - fn has_changes(self: &Self) -> bool { - self.entries.iter().any(|p| p.has_changes()) - } -} - -impl HasChanges for PropertyComparison { - fn has_changes(self: &Self) -> bool { - match self { - PropertyComparison::PropertyChanged { .. } => true, - PropertyComparison::PropertyUnchanged { .. } => false, - } - } - } - -pub struct PrivilegeReport { - pub entries: Vec -} - -pub enum PrivilegeComparison { - PrivilegeAdded { privilege_name: String, grantor: String, grantee: String }, - PrivilegeRemoved { privilege_name: String, grantor: String, grantee: String }, - PrivilegeMaintained { privilege_name: String, grantor: String, grantee: String } -} - -impl HasChanges for PrivilegeReport { - fn has_changes(self: &Self) -> bool { - self.entries.iter().any(|p| p.has_changes()) - } -} - -impl HasChanges for PrivilegeComparison { - fn has_changes(self: &Self) -> bool { - match self { - PrivilegeComparison::PrivilegeAdded { .. } | PrivilegeComparison::PrivilegeRemoved { .. } => true, - PrivilegeComparison::PrivilegeMaintained { .. } => false, - } - } -} - -pub struct RoutineReport { - pub entries: Vec -} - -pub enum RoutineComparison { - RoutineAdded { routine_signature: String }, - RoutineRemoved { routine_signature: String }, - RoutineMaintained { routine_signature: String, properties: PropertyReport, privileges: PrivilegeReport }, -} - -impl HasChanges for RoutineReport { - fn has_changes(self: &Self) -> bool { - self.entries.iter().any(|r| r.has_changes()) - } -} - -impl HasChanges for RoutineComparison { - fn has_changes(self: &Self) -> bool { - match self { - RoutineComparison::RoutineAdded { .. } | RoutineComparison::RoutineRemoved { .. } => true, - RoutineComparison::RoutineMaintained { routine_signature: _routine_signature, properties, privileges } => - properties.has_changes() || - privileges.has_changes(), - } - } -} - -pub struct SequenceReport { - pub entries: Vec -} - -pub enum SequenceComparison { - SequenceAdded { sequence_name: String }, - SequenceRemoved { sequence_name: String }, - SequenceMaintained { sequence_name: String, properties: PropertyReport }, -} - -impl HasChanges for SequenceReport { - fn has_changes(self: &Self) -> bool { - self.entries.iter().any(|s| s.has_changes()) - } -} - -impl HasChanges for SequenceComparison { - fn has_changes(self: &Self) -> bool { - match self { - SequenceComparison::SequenceAdded { .. } | SequenceComparison::SequenceRemoved { .. } => true, - SequenceComparison::SequenceMaintained { sequence_name: _sequence_name, properties } => - properties.has_changes(), - } - } -} - -pub struct TableReport { - pub entries: Vec -} - -pub enum TableComparison { - TableAdded { table_name: String }, - TableRemoved { table_name: String }, - TableMaintained { table_name: String, properties: PropertyReport, columns: TableColumnReport, privileges: PrivilegeReport, constraints: TableConstraintReport, triggers: TableTriggerReport }, -} - -impl HasChanges for TableReport { - fn has_changes(self: &Self) -> bool { - self.entries.iter().any(|t| t.has_changes()) - } -} - -impl HasChanges for TableComparison { - fn has_changes(self: &Self) -> bool { - match self { - TableComparison::TableAdded { .. } | TableComparison::TableRemoved { .. } => true, - TableComparison::TableMaintained { table_name: _table_name, properties, columns, privileges, constraints, triggers } => - properties.has_changes() || - columns.has_changes() || - privileges.has_changes() || - constraints.has_changes() || - triggers.has_changes(), - } - } -} - -pub struct TableColumnReport { - pub entries: Vec -} - -pub enum TableColumnComparison { - ColumnAdded { column_name: String }, - ColumnRemoved { column_name: String }, - ColumnMaintained { column_name: String, properties: PropertyReport, privileges: PrivilegeReport } -} - -impl HasChanges for TableColumnReport { - fn has_changes(self: &Self) -> bool { - self.entries.iter().any(|c| c.has_changes()) - } -} - -impl HasChanges for TableColumnComparison { - fn has_changes(self: &Self) -> bool { - match self { - TableColumnComparison::ColumnAdded { .. } | TableColumnComparison::ColumnRemoved { .. } => true, - TableColumnComparison::ColumnMaintained { column_name: _column_name, properties, privileges } => - properties.has_changes() | - privileges.has_changes(), - } - } -} - -pub struct TableConstraintReport { - pub entries: Vec -} - -pub enum TableConstraintComparison { - ConstraintAdded { constraint_name: String }, - ConstraintRemoved { constraint_name: String }, - ConstraintMaintained { constraint_name: String, properties: PropertyReport }, -} - -impl HasChanges for TableConstraintReport { - fn has_changes(self: &Self) -> bool { - self.entries.iter().any(|c| c.has_changes()) - } -} - -impl HasChanges for TableConstraintComparison { - fn has_changes(self: &Self) -> bool { - match self { - TableConstraintComparison::ConstraintAdded { .. } | TableConstraintComparison::ConstraintRemoved { .. } => true, - TableConstraintComparison::ConstraintMaintained { constraint_name: _constraint_name, properties } => - properties.has_changes(), - } - } -} - -pub struct TableTriggerReport { - pub entries: Vec -} - -pub enum TableTriggerComparison { - TriggerAdded { trigger_name: String, event_manipulation: String }, - TriggerRemoved { trigger_name: String, event_manipulation: String }, - TriggerMaintained { trigger_name: String, event_manipulation: String, properties: PropertyReport } -} - -impl HasChanges for TableTriggerReport { - fn has_changes(self: &Self) -> bool { - self.entries.iter().any(|t| t.has_changes()) - } -} - -impl HasChanges for TableTriggerComparison { - fn has_changes(self: &Self) -> bool { - match self { - TableTriggerComparison::TriggerAdded { .. } | TableTriggerComparison::TriggerRemoved { .. } => true, - TableTriggerComparison::TriggerMaintained { trigger_name: _trigger_name, event_manipulation: _event_manipulation, properties } => - properties.has_changes(), - } - } -} - -pub struct ViewReport { - pub entries: Vec -} - -pub enum ViewComparison { - ViewMaintained { view_name: String, properties: PropertyReport }, -} - -impl HasChanges for ViewReport { - fn has_changes(self: &Self) -> bool { - self.entries.iter().any(|v| v.has_changes()) - } -} - -impl HasChanges for ViewComparison { - fn has_changes(self: &Self) -> bool { - match self { - ViewComparison::ViewMaintained { view_name: _view_name, properties } => - properties.has_changes(), - } - } -} - diff --git a/src/compare/report/mod.rs b/src/compare/report/mod.rs new file mode 100644 index 0000000..040b0df --- /dev/null +++ b/src/compare/report/mod.rs @@ -0,0 +1,24 @@ +pub mod schema; +pub mod property; +pub mod privilege; +pub mod routine; +pub mod sequence; +pub mod table; +pub mod table_column; +pub mod table_constraint; +pub mod table_trigger; +pub mod view; + +pub struct Report { + pub entries: Vec, +} + +impl Report { + fn has_changes(&self) -> bool { + self.entries.iter().any(|e| e.has_changes()) + } +} + +pub trait HasChanges { + fn has_changes(&self) -> bool; +} diff --git a/src/compare/report/privilege.rs b/src/compare/report/privilege.rs new file mode 100644 index 0000000..4f704de --- /dev/null +++ b/src/compare/report/privilege.rs @@ -0,0 +1,16 @@ +use crate::compare::report::HasChanges; + +pub enum PrivilegeComparison { + PrivilegeAdded { privilege_name: String, grantor: String, grantee: String }, + PrivilegeRemoved { privilege_name: String, grantor: String, grantee: String }, + PrivilegeMaintained { privilege_name: String, grantor: String, grantee: String } +} + +impl HasChanges for PrivilegeComparison { + fn has_changes(&self) -> bool { + match self { + PrivilegeComparison::PrivilegeAdded { .. } | PrivilegeComparison::PrivilegeRemoved { .. } => true, + PrivilegeComparison::PrivilegeMaintained { .. } => false, + } + } +} diff --git a/src/compare/report/property.rs b/src/compare/report/property.rs new file mode 100644 index 0000000..e8151cc --- /dev/null +++ b/src/compare/report/property.rs @@ -0,0 +1,15 @@ +use crate::compare::report::HasChanges; + +pub enum PropertyComparison { + PropertyChanged { property_name: String, left_value: String, right_value: String }, + PropertyUnchanged { property_name: String, value: String }, +} + +impl HasChanges for PropertyComparison { + fn has_changes(&self) -> bool { + match self { + PropertyComparison::PropertyChanged { .. } => true, + PropertyComparison::PropertyUnchanged { .. } => false, + } + } +} diff --git a/src/compare/report/routine.rs b/src/compare/report/routine.rs new file mode 100644 index 0000000..e5a4695 --- /dev/null +++ b/src/compare/report/routine.rs @@ -0,0 +1,21 @@ +use crate::compare::report::property::{PropertyComparison}; +use crate::compare::report::{HasChanges, Report}; +use crate::compare::report::privilege::PrivilegeComparison; + +pub enum RoutineComparison { + RoutineAdded { routine_signature: String }, + RoutineRemoved { routine_signature: String }, + RoutineMaintained { routine_signature: String, properties: Report, privileges: Report }, +} + +impl HasChanges for RoutineComparison { + fn has_changes(&self) -> bool { + match self { + RoutineComparison::RoutineAdded { .. } | RoutineComparison::RoutineRemoved { .. } => true, + RoutineComparison::RoutineMaintained { routine_signature: _routine_signature, properties, privileges } => + properties.has_changes() || + privileges.has_changes(), + } + } +} + diff --git a/src/compare/report/schema.rs b/src/compare/report/schema.rs new file mode 100644 index 0000000..26c7e43 --- /dev/null +++ b/src/compare/report/schema.rs @@ -0,0 +1,27 @@ +use crate::compare::report::{HasChanges, Report}; +use crate::compare::report::property::PropertyComparison; +use crate::compare::report::routine::RoutineComparison; +use crate::compare::report::sequence::SequenceComparison; +use crate::compare::report::table::TableComparison; +use crate::compare::report::view::ViewComparison; + +pub enum SchemaComparison { + SchemaAdded { schema_name: String }, + SchemaRemoved { schema_name: String }, + SchemaMissing { schema_name: String }, + SchemaMaintained { schema_name: String, properties: Report, routines: Report, sequences: Report, tables: Report, views: Report }, +} + +impl HasChanges for SchemaComparison { + fn has_changes(&self) -> bool { + match self { + SchemaComparison::SchemaAdded { .. } | SchemaComparison::SchemaRemoved { .. } | SchemaComparison::SchemaMissing { .. } => true, + SchemaComparison::SchemaMaintained { schema_name: _schema_name, properties, routines, sequences, tables, views } => + properties.has_changes() || + routines.has_changes() || + sequences.has_changes() || + tables.has_changes() || + views.has_changes(), + } + } +} diff --git a/src/compare/report/sequence.rs b/src/compare/report/sequence.rs new file mode 100644 index 0000000..c67e24e --- /dev/null +++ b/src/compare/report/sequence.rs @@ -0,0 +1,19 @@ +use crate::compare::report::property::{PropertyComparison}; +use crate::compare::report::{HasChanges, Report}; + +pub enum SequenceComparison { + SequenceAdded { sequence_name: String }, + SequenceRemoved { sequence_name: String }, + SequenceMaintained { sequence_name: String, properties: Report }, +} + +impl HasChanges for SequenceComparison { + fn has_changes(&self) -> bool { + match self { + SequenceComparison::SequenceAdded { .. } | SequenceComparison::SequenceRemoved { .. } => true, + SequenceComparison::SequenceMaintained { sequence_name: _sequence_name, properties } => + properties.has_changes(), + } + } +} + diff --git a/src/compare/report/table.rs b/src/compare/report/table.rs new file mode 100644 index 0000000..635994a --- /dev/null +++ b/src/compare/report/table.rs @@ -0,0 +1,27 @@ +use crate::compare::report::{HasChanges, Report}; +use crate::compare::report::privilege::PrivilegeComparison; +use crate::compare::report::property::PropertyComparison; +use crate::compare::report::table_column::TableColumnComparison; +use crate::compare::report::table_constraint::TableConstraintComparison; +use crate::compare::report::table_trigger::TableTriggerComparison; + +pub enum TableComparison { + TableAdded { table_name: String }, + TableRemoved { table_name: String }, + TableMaintained { table_name: String, properties: Report, columns: Report, privileges: Report, constraints: Report, triggers: Report }, +} + +impl HasChanges for TableComparison { + fn has_changes(&self) -> bool { + match self { + TableComparison::TableAdded { .. } | TableComparison::TableRemoved { .. } => true, + TableComparison::TableMaintained { table_name: _table_name, properties, columns, privileges, constraints, triggers } => + properties.has_changes() || + columns.has_changes() || + privileges.has_changes() || + constraints.has_changes() || + triggers.has_changes(), + } + } +} + diff --git a/src/compare/report/table_column.rs b/src/compare/report/table_column.rs new file mode 100644 index 0000000..350f11a --- /dev/null +++ b/src/compare/report/table_column.rs @@ -0,0 +1,20 @@ +use crate::compare::report::privilege::{PrivilegeComparison}; +use crate::compare::report::property::{PropertyComparison}; +use crate::compare::report::{HasChanges, Report}; + +pub enum TableColumnComparison { + ColumnAdded { column_name: String }, + ColumnRemoved { column_name: String }, + ColumnMaintained { column_name: String, properties: Report, privileges: Report } +} + +impl HasChanges for TableColumnComparison { + fn has_changes(&self) -> bool { + match self { + TableColumnComparison::ColumnAdded { .. } | TableColumnComparison::ColumnRemoved { .. } => true, + TableColumnComparison::ColumnMaintained { column_name: _column_name, properties, privileges } => + properties.has_changes() | + privileges.has_changes(), + } + } +} diff --git a/src/compare/report/table_constraint.rs b/src/compare/report/table_constraint.rs new file mode 100644 index 0000000..3020ef6 --- /dev/null +++ b/src/compare/report/table_constraint.rs @@ -0,0 +1,18 @@ +use crate::compare::report::property::{PropertyComparison}; +use crate::compare::report::{HasChanges, Report}; + +pub enum TableConstraintComparison { + ConstraintAdded { constraint_name: String }, + ConstraintRemoved { constraint_name: String }, + ConstraintMaintained { constraint_name: String, properties: Report }, +} + +impl HasChanges for TableConstraintComparison { + fn has_changes(&self) -> bool { + match self { + TableConstraintComparison::ConstraintAdded { .. } | TableConstraintComparison::ConstraintRemoved { .. } => true, + TableConstraintComparison::ConstraintMaintained { constraint_name: _constraint_name, properties } => + properties.has_changes(), + } + } +} diff --git a/src/compare/report/table_trigger.rs b/src/compare/report/table_trigger.rs new file mode 100644 index 0000000..2471a8d --- /dev/null +++ b/src/compare/report/table_trigger.rs @@ -0,0 +1,18 @@ +use crate::compare::report::{HasChanges, Report}; +use crate::compare::report::property::PropertyComparison; + +pub enum TableTriggerComparison { + TriggerAdded { trigger_name: String, event_manipulation: String }, + TriggerRemoved { trigger_name: String, event_manipulation: String }, + TriggerMaintained { trigger_name: String, event_manipulation: String, properties: Report } +} + +impl HasChanges for TableTriggerComparison { + fn has_changes(&self) -> bool { + match self { + TableTriggerComparison::TriggerAdded { .. } | TableTriggerComparison::TriggerRemoved { .. } => true, + TableTriggerComparison::TriggerMaintained { trigger_name: _trigger_name, event_manipulation: _event_manipulation, properties } => + properties.has_changes(), + } + } +} diff --git a/src/compare/report/view.rs b/src/compare/report/view.rs new file mode 100644 index 0000000..4d3b871 --- /dev/null +++ b/src/compare/report/view.rs @@ -0,0 +1,15 @@ +use crate::compare::report::property::{PropertyComparison}; +use crate::compare::report::{HasChanges, Report}; + +pub enum ViewComparison { + ViewMaintained { view_name: String, properties: Report }, +} + +impl HasChanges for ViewComparison { + fn has_changes(&self) -> bool { + match self { + ViewComparison::ViewMaintained { view_name: _view_name, properties } => + properties.has_changes(), + } + } +} diff --git a/src/db/mod.rs b/src/db/mod.rs index 98fca99..f0f1fd3 100644 --- a/src/db/mod.rs +++ b/src/db/mod.rs @@ -1,7 +1,7 @@ -pub(crate) mod thing; +pub mod thing; use postgres::{Client, NoTls, Error}; -use crate::db::thing::{Column, Privilege, Routine, Schema, Sequence, Table, TableConstraint, Trigger, View}; +use crate::db::thing::{Column, Constraint, Privilege, Routine, Schema, Sequence, Table, Trigger, View}; pub struct Database { connection: Client @@ -21,7 +21,6 @@ impl Database { let rows = self.connection.query(r#" SELECT - table_name, column_name, ordinal_position, column_default, @@ -47,24 +46,22 @@ ORDER BY &[&schema_name, &table_name])?; for row in rows { - let table_name: String = row.get(0); - let column_name: String = row.get(1); - let ordinal_position: i32 = row.get(2); - let column_default: Option = row.get(3); - let is_nullable: String = row.get(4); - let data_type: String = row.get(5); - let character_maximum_length: Option = row.get(6); - let numeric_precision: Option = row.get(7); - let numeric_scale: Option = row.get(8); - let datetime_precision: Option = row.get(9); - let is_identity: String = row.get(10); - let identity_generation: Option = row.get(11); - let is_generated: String = row.get(12); - let generation_expression: Option = row.get(13); - let is_updatable: String = row.get(14); + let column_name: String = row.get(0); + let ordinal_position: i32 = row.get(1); + let column_default: Option = row.get(2); + let is_nullable: String = row.get(3); + let data_type: String = row.get(4); + let character_maximum_length: Option = row.get(5); + let numeric_precision: Option = row.get(6); + let numeric_scale: Option = row.get(7); + let datetime_precision: Option = row.get(8); + let is_identity: String = row.get(9); + let identity_generation: Option = row.get(10); + let is_generated: String = row.get(11); + let generation_expression: Option = row.get(12); + let is_updatable: String = row.get(13); let column = Column { - table_name, column_name, ordinal_position, column_default, @@ -247,32 +244,31 @@ ORDER BY Ok(routine_privileges) } - pub fn schemas(&mut self) -> Result, Error> { - let mut schemas = Vec::new(); - - let rows = self.connection.query(r#" + pub fn schema(&mut self, schema_name: &str) -> Result, Error> { + let row = self.connection.query_opt(r#" SELECT - schema_name, schema_owner FROM information_schema.schemata +WHERE + schema_name = $1 ORDER BY schema_name;"#, - &[])?; + &[&schema_name])?; - for row in rows { - let schema_name = row.get(0); - let schema_owner = row.get(1); - - let schema = Schema { - schema_name, - schema_owner, - }; - - schemas.push(schema); + match row { + None => Ok(None), + Some(row) => { + let schema_owner = row.get(0); + + let schema = Schema { + schema_name: String::from(schema_name), + schema_owner, + }; + + Ok(Some(schema)) + } } - - Ok(schemas) } pub fn sequences(&mut self, schema_name: &str) -> Result, Error> { @@ -362,7 +358,7 @@ ORDER BY Ok(tables) } - pub fn table_constraints(&mut self, schema_name: &str, table_name: &str) -> Result, Error> { + pub fn table_constraints(&mut self, schema_name: &str, table_name: &str) -> Result, Error> { let mut table_constraints = Vec::new(); let rows = self.connection.query(r#" @@ -390,7 +386,7 @@ ORDER BY let initially_deferred: String = row.get(3); let nulls_distinct: Option = row.get(4); - let table_constraint = TableConstraint { + let table_constraint = Constraint { constraint_name, constraint_type, is_deferrable, diff --git a/src/db/thing.rs b/src/db/thing.rs index 3e9179b..92c37dc 100644 --- a/src/db/thing.rs +++ b/src/db/thing.rs @@ -1,6 +1,5 @@ #[derive(Clone, PartialEq)] pub struct Column { - pub table_name: String, pub column_name: String, pub ordinal_position: i32, pub column_default: Option, @@ -68,7 +67,7 @@ pub struct Table { } #[derive(Clone, PartialEq)] -pub struct TableConstraint { +pub struct Constraint { pub constraint_name: String, pub constraint_type: String, pub is_deferrable: String,