Skip to content

Commit a2214bb

Browse files
authored
Merge pull request #8 from oniony/refactor-async-sqlx
chore(sqlx): Refactor to use async Sqlx
2 parents f0c200e + 1ed441b commit a2214bb

27 files changed

+2658
-1126
lines changed

Cargo.lock

Lines changed: 996 additions & 255 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@ version = "0.0.0"
44
edition = "2021"
55

66
[dependencies]
7-
clap = { version = "4.5.4", features = ["derive"] }
8-
colored = "2.1.0"
9-
postgres = "0.19.7"
7+
clap = { version = "=4.5.20", features = ["derive"] }
8+
colored = "=2.1.0"
9+
itertools = "=0.13.0"
10+
sqlformat = "=0.2.6"
11+
sqlx = { version = "=0.8.2", features = ["runtime-tokio", "postgres", "macros"] }
12+
tokio = { version = "=1.40.0", features = ["rt", "rt-multi-thread", "macros", "signal"] }
13+
futures-core = "=0.3.31"
14+
futures = "=0.3.31"

README.md

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,19 @@
66

77
Little Bobby Diff Tool is a CLI tool to compare database schemas.
88

9-
It currently compares the following across one or more schemas.
9+
RDBMS support:
10+
11+
- [ ] MySQL
12+
- [ ] Oracle
13+
- [X] PostgreSQL
14+
- [ ] SQLite
15+
- [ ] SQL Server
16+
17+
Items compared:
1018

1119
- [X] Columns
1220
- [X] Column Privileges
21+
- [ ] Indices
1322
- [X] Routines
1423
- [X] Routine Privileges
1524
- [X] Sequences

db/docker-compose.yml

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,14 @@
1-
version: '2'
2-
31
services:
42
left:
5-
image: postgres
3+
image: postgres:latest
64
container_name: postgres-left
75
environment:
86
- POSTGRES_PASSWORD=postgres
97
ports:
108
- 8901:5432
119
restart: unless-stopped
1210
right:
13-
image: postgres
11+
image: postgres:latest
1412
container_name: postgres-right
1513
environment:
1614
- POSTGRES_PASSWORD=postgres

src/cli/mod.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ mod args;
33
use std::process;
44
use clap::{Parser};
55
use colored::Colorize;
6-
use postgres::Error;
6+
use sqlx::Error;
77

88
use crate::{compare, db};
99
use crate::cli::args::{Args, Colouring::Always, Colouring::Never};
@@ -20,8 +20,8 @@ use crate::compare::report::sequence::SequenceComparison;
2020
use crate::compare::report::sequence::SequenceComparison::{SequenceAdded, SequenceMaintained, SequenceRemoved};
2121
use crate::compare::report::table::TableComparison;
2222
use crate::compare::report::table::TableComparison::{TableAdded, TableMaintained, TableRemoved};
23-
use crate::compare::report::table_column::TableColumnComparison;
24-
use crate::compare::report::table_column::TableColumnComparison::{ColumnAdded, ColumnMaintained, ColumnRemoved};
23+
use crate::compare::report::column::ColumnComparison;
24+
use crate::compare::report::column::ColumnComparison::{ColumnAdded, ColumnMaintained, ColumnRemoved};
2525
use crate::compare::report::table_constraint::TableConstraintComparison;
2626
use crate::compare::report::table_constraint::TableConstraintComparison::{ConstraintAdded, ConstraintMaintained, ConstraintRemoved};
2727
use crate::compare::report::table_trigger::TableTriggerComparison::{TriggerAdded, TriggerMaintained, TriggerRemoved};
@@ -51,9 +51,9 @@ impl CLI {
5151
CLI { args }
5252
}
5353

54-
pub fn run(&self) -> Result<i32, Error> {
55-
let left_db = db::Database::connect(self.args.left.as_str())?;
56-
let right_db = db::Database::connect(self.args.right.as_str())?;
54+
pub async fn run(&self) -> Result<i32, Error> {
55+
let left_db = db::Database::connect(self.args.left.as_str()).await?;
56+
let right_db = db::Database::connect(self.args.right.as_str()).await?;
5757

5858
let mut comparer = compare::Comparer::new(
5959
left_db,
@@ -64,7 +64,7 @@ impl CLI {
6464

6565
let mut differences = 0;
6666

67-
let report = comparer.compare(self.args.schema.clone())?;
67+
let report = comparer.compare(self.args.schema.clone()).await?;
6868
differences += self.render_schema_report(report);
6969

7070
process::exit(differences);
@@ -286,7 +286,7 @@ impl CLI {
286286
differences
287287
}
288288

289-
fn render_table_column_report(&self, report: &Report<TableColumnComparison>) -> i32 {
289+
fn render_table_column_report(&self, report: &Report<ColumnComparison>) -> i32 {
290290
let mut differences = 0;
291291

292292
for column in &report.entries {

src/compare/mod.rs

Lines changed: 399 additions & 225 deletions
Large diffs are not rendered by default.
Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,17 @@ use crate::compare::report::privilege::{PrivilegeComparison};
22
use crate::compare::report::property::{PropertyComparison};
33
use crate::compare::report::{HasChanges, Report};
44

5-
pub enum TableColumnComparison {
5+
pub enum ColumnComparison {
66
ColumnAdded { column_name: String },
77
ColumnRemoved { column_name: String },
88
ColumnMaintained { column_name: String, properties: Report<PropertyComparison>, privileges: Report<PrivilegeComparison> }
99
}
1010

11-
impl HasChanges for TableColumnComparison {
11+
impl HasChanges for ColumnComparison {
1212
fn has_changes(&self) -> bool {
1313
match self {
14-
TableColumnComparison::ColumnAdded { .. } | TableColumnComparison::ColumnRemoved { .. } => true,
15-
TableColumnComparison::ColumnMaintained { column_name: _column_name, properties, privileges } =>
14+
ColumnComparison::ColumnAdded { .. } | ColumnComparison::ColumnRemoved { .. } => true,
15+
ColumnComparison::ColumnMaintained { column_name: _column_name, properties, privileges } =>
1616
properties.has_changes() |
1717
privileges.has_changes(),
1818
}

src/compare/report/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ pub mod privilege;
44
pub mod routine;
55
pub mod sequence;
66
pub mod table;
7-
pub mod table_column;
7+
pub mod column;
88
pub mod table_constraint;
99
pub mod table_trigger;
1010
pub mod view;

src/compare/report/table.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
use crate::compare::report::{HasChanges, Report};
22
use crate::compare::report::privilege::PrivilegeComparison;
33
use crate::compare::report::property::PropertyComparison;
4-
use crate::compare::report::table_column::TableColumnComparison;
4+
use crate::compare::report::column::ColumnComparison;
55
use crate::compare::report::table_constraint::TableConstraintComparison;
66
use crate::compare::report::table_trigger::TableTriggerComparison;
77

88
pub enum TableComparison {
99
TableAdded { table_name: String },
1010
TableRemoved { table_name: String },
11-
TableMaintained { table_name: String, properties: Report<PropertyComparison>, columns: Report<TableColumnComparison>, privileges: Report<PrivilegeComparison>, constraints: Report<TableConstraintComparison>, triggers: Report<TableTriggerComparison> },
11+
TableMaintained { table_name: String, properties: Report<PropertyComparison>, columns: Report<ColumnComparison>, privileges: Report<PrivilegeComparison>, constraints: Report<TableConstraintComparison>, triggers: Report<TableTriggerComparison> },
1212
}
1313

1414
impl HasChanges for TableComparison {

src/db/column.rs

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
use sqlx::{Error, FromRow, PgConnection};
2+
3+
const QUERY: &str = r#"
4+
SELECT
5+
table_catalog,
6+
table_schema,
7+
table_name,
8+
column_name,
9+
ordinal_position,
10+
column_default,
11+
is_nullable,
12+
data_type,
13+
character_maximum_length,
14+
character_octet_length,
15+
numeric_precision,
16+
numeric_precision_radix,
17+
numeric_scale,
18+
datetime_precision,
19+
interval_type,
20+
interval_precision,
21+
character_set_catalog,
22+
character_set_schema,
23+
character_set_name,
24+
collation_catalog,
25+
collation_schema,
26+
collation_name,
27+
domain_catalog,
28+
domain_schema,
29+
domain_name,
30+
udt_catalog,
31+
udt_schema,
32+
udt_name,
33+
scope_catalog,
34+
scope_schema,
35+
scope_name,
36+
maximum_cardinality,
37+
dtd_identifier,
38+
is_self_referencing,
39+
is_identity,
40+
identity_generation,
41+
identity_start,
42+
identity_increment,
43+
identity_maximum,
44+
identity_minimum,
45+
identity_cycle,
46+
is_generated,
47+
generation_expression,
48+
is_updatable
49+
FROM
50+
information_schema.columns
51+
WHERE
52+
table_schema = ANY($1)
53+
ORDER BY
54+
table_catalog,
55+
table_schema,
56+
table_name,
57+
column_name;"#;
58+
59+
pub async fn columns(connection: &mut PgConnection, schema_names: &[String]) -> Result<Vec<Column>, Error> {
60+
sqlx::query_as(QUERY)
61+
.bind(&schema_names[..])
62+
.fetch_all(connection).await
63+
}
64+
65+
#[derive(Debug, Clone, PartialEq, FromRow)]
66+
pub struct Column {
67+
pub table_catalog: String,
68+
pub table_schema: String,
69+
pub table_name: String,
70+
pub column_name: String,
71+
pub ordinal_position: i32,
72+
pub column_default: Option<String>,
73+
pub is_nullable: String,
74+
pub data_type: String,
75+
pub character_maximum_length: Option<i32>,
76+
pub character_octet_length: Option<i32>,
77+
pub numeric_precision: Option<i32>,
78+
pub numeric_precision_radix: Option<i32>,
79+
pub numeric_scale: Option<i32>,
80+
pub datetime_precision: Option<i32>,
81+
pub interval_type: Option<String>,
82+
pub interval_precision: Option<i32>,
83+
pub character_set_catalog: Option<String>,
84+
pub character_set_schema: Option<String>,
85+
pub character_set_name: Option<String>,
86+
pub collation_catalog: Option<String>,
87+
pub collation_schema: Option<String>,
88+
pub collation_name: Option<String>,
89+
pub domain_catalog: Option<String>,
90+
pub domain_schema: Option<String>,
91+
pub domain_name: Option<String>,
92+
pub udt_catalog: Option<String>,
93+
pub udt_schema: Option<String>,
94+
pub udt_name: Option<String>,
95+
pub scope_catalog: Option<String>,
96+
pub scope_schema: Option<String>,
97+
pub scope_name: Option<String>,
98+
pub maximum_cardinality: Option<i32>,
99+
pub dtd_identifier: Option<String>,
100+
pub is_self_referencing: String,
101+
pub is_identity: String,
102+
pub identity_generation: Option<String>,
103+
pub identity_start: Option<String>,
104+
pub identity_increment: Option<String>,
105+
pub identity_maximum: Option<String>,
106+
pub identity_minimum: Option<String>,
107+
pub identity_cycle: Option<String>,
108+
pub is_generated: String,
109+
pub generation_expression: Option<String>,
110+
pub is_updatable: String,
111+
}
112+

0 commit comments

Comments
 (0)