From 83a7a50024a4bda4dfc6b9b6fa45b92b31168e5e Mon Sep 17 00:00:00 2001 From: Yannik_Sc Date: Thu, 4 Jul 2024 17:27:46 +0200 Subject: [PATCH] rust: Improve NewObject::get_or_create to properly upsert objects --- rust/Cargo.lock | 58 ++++++++++++++++++++--------------------- rust/Cargo.toml | 4 +-- rust/examples/commit.rs | 8 +++--- rust/src/api.rs | 2 +- rust/src/commit.rs | 16 +++++++++++- rust/src/new_object.rs | 48 +++++++++++++++++++++------------- 6 files changed, 81 insertions(+), 55 deletions(-) diff --git a/rust/Cargo.lock b/rust/Cargo.lock index 1b1dd4b4..ba99d0d3 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -929,7 +929,7 @@ dependencies = [ "libc", "redox_syscall", "smallvec", - "windows-targets 0.52.5", + "windows-targets 0.52.6", ] [[package]] @@ -1289,9 +1289,9 @@ checksum = "976295e77ce332211c0d24d92c0e83e50f5c5f046d11082cea19f3df13a3562d" [[package]] name = "rustls-webpki" -version = "0.102.4" +version = "0.102.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff448f7e92e913c4b7d4c6d8e4540a1724b319b4152b8aef6d4cf8339712b33e" +checksum = "f9a6fccd794a42c2c105b513a2f62bc3fd8f3ba57a4593677ceb0bd035164d78" dependencies = [ "ring", "rustls-pki-types", @@ -1854,7 +1854,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.5", + "windows-targets 0.52.6", ] [[package]] @@ -1874,18 +1874,18 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm 0.52.5", - "windows_aarch64_msvc 0.52.5", - "windows_i686_gnu 0.52.5", + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", "windows_i686_gnullvm", - "windows_i686_msvc 0.52.5", - "windows_x86_64_gnu 0.52.5", - "windows_x86_64_gnullvm 0.52.5", - "windows_x86_64_msvc 0.52.5", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", ] [[package]] @@ -1896,9 +1896,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_msvc" @@ -1908,9 +1908,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_i686_gnu" @@ -1920,15 +1920,15 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" [[package]] name = "windows_i686_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_msvc" @@ -1938,9 +1938,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_x86_64_gnu" @@ -1950,9 +1950,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnullvm" @@ -1962,9 +1962,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_msvc" @@ -1974,9 +1974,9 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winreg" diff --git a/rust/Cargo.toml b/rust/Cargo.toml index 455ce008..fbf8adc5 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -18,12 +18,12 @@ serde_json = "1.0" sha1 = "0.10" signature = "2.2" ssh-agent-client-rs = "0.9" -ssh-encoding = { version = "0.2.0", features = ["base64"] } +ssh-encoding = { version = "0.2", features = ["base64"] } ssh-key = { version = "0.6", features = ["serde", "ed25519", "dsa", "crypto", "rsa"] } [dev-dependencies] env_logger = "0.11" -tokio = { version = "1.37", features = ["full"] } +tokio = { version = "1.38", features = ["full"] } clap = "4.5" futures = "0.3" diff --git a/rust/examples/commit.rs b/rust/examples/commit.rs index 8ed1b523..12019557 100644 --- a/rust/examples/commit.rs +++ b/rust/examples/commit.rs @@ -25,10 +25,10 @@ pub async fn main() -> anyhow::Result<()> { let mut new_sg = NewObject::request_new("service_group").await?; new_sg - .set("hostname", "yannik-adminapi-rs-2.test.sg") - .set("project", "test") - .add("responsible_admin", "yannik.schwieger") - .add("protocol_ports_inbound", "tcp443"); + .set("hostname", "yannik-adminapi-rs-2.test.sg")? + .set("project", "test")? + .add("responsible_admin", "yannik.schwieger")? + .add("protocol_ports_inbound", "tcp443")?; let mut created_sg = new_sg.commit().await?; created_sg .add("protocol_ports_inbound", "tcp80")? diff --git a/rust/src/api.rs b/rust/src/api.rs index 84e5d141..12b5214e 100644 --- a/rust/src/api.rs +++ b/rust/src/api.rs @@ -159,7 +159,7 @@ impl Server { if self.attributes.get(&attribute).is_array() { return Err(anyhow::anyhow!( - "Attribute is a multi attribute, set is not supported!" + "Attribute {attribute} is a multi attribute, set is not supported!" )); } diff --git a/rust/src/commit.rs b/rust/src/commit.rs index bd257fd5..91cfeb03 100644 --- a/rust/src/commit.rs +++ b/rust/src/commit.rs @@ -60,7 +60,21 @@ impl Commit { self } - pub fn update(mut self, changeset: Changeset) -> Self { + pub fn update(mut self, mut changeset: Changeset) -> Self { + let filtered = changeset + .attributes + .into_iter() + .filter(|(_, change)| { + if let AttributeChange::Update { new, old } = change { + return new.ne(old); + } + + true + }) + .collect(); + + changeset.attributes = filtered; + self.changed.push(changeset); self diff --git a/rust/src/new_object.rs b/rust/src/new_object.rs index 741e46b3..9f0582a7 100644 --- a/rust/src/new_object.rs +++ b/rust/src/new_object.rs @@ -1,14 +1,14 @@ use std::ops::{Deref, DerefMut}; use crate::api::{commit_changes, new_object, NewObjectResponse, Server}; -use crate::commit::{AttributeValue, Changeset, Commit, Dataset}; +use crate::commit::{AttributeValue, Changeset, Commit}; use crate::query::Query; #[derive(Clone, Debug)] pub struct NewObject { object_id: Option, - attributes: Dataset, - changeset: Changeset, + server: Server, + deferred_changes: Changeset, } impl NewObject { @@ -18,8 +18,12 @@ impl NewObject { Ok(Self { object_id: None, - attributes: result, - changeset: Default::default(), + server: Server { + object_id: 0, + attributes: result, + changes: Default::default(), + }, + deferred_changes: Default::default(), }) } @@ -31,31 +35,39 @@ impl NewObject { if let Ok(server) = Query::builder() .filter("hostname", hostname.to_string()) - .restrict(new_object.attributes.keys()) + .restrict(new_object.server.attributes.keys()) .build() .request() .await? .one() { new_object.object_id = Some(server.object_id); - new_object.attributes = server.attributes; + new_object.server = server; } Ok(new_object) } + pub fn is_new(&self) -> bool { + self.object_id.is_none() + } + /// /// Commits the new object /// /// The changes done in [NewObject::deferred] will not be submitted yet, but the returned [Server] /// object is preloaded with them. /// - pub async fn commit(self) -> anyhow::Result { - let AttributeValue::String(hostname) = self.attributes.get("hostname") else { + pub async fn commit(mut self) -> anyhow::Result { + let AttributeValue::String(hostname) = self.server.get("hostname") else { return Err(anyhow::anyhow!("Required attribute 'hostname' is missing")); }; - let commit = Commit::new().create(self.attributes); - commit_changes(&commit).await?; + + if self.is_new() { + commit_changes(&Commit::new().create(self.server.attributes)).await?; + } else { + self.server.commit().await?; + } let mut server = Query::builder() .filter("hostname", hostname) @@ -64,7 +76,7 @@ impl NewObject { .await? .one()?; - server.changes = self.changeset; + server.changes = self.deferred_changes; Ok(server) } @@ -82,28 +94,28 @@ impl NewObject { pub fn deferred(&mut self, callback: impl FnOnce(&mut Server) -> R) -> R { let mut server = Server { object_id: 0, - attributes: self.attributes.clone(), - changes: std::mem::take(&mut self.changeset), + attributes: self.server.attributes.clone(), + changes: std::mem::take(&mut self.deferred_changes), }; let output = callback(&mut server); - self.changeset = std::mem::take(&mut server.changes); + self.deferred_changes = std::mem::take(&mut server.changes); output } } impl Deref for NewObject { - type Target = Dataset; + type Target = Server; fn deref(&self) -> &Self::Target { - &self.attributes + &self.server } } impl DerefMut for NewObject { fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.attributes + &mut self.server } }