diff --git a/sqlx-macros-core/Cargo.toml b/sqlx-macros-core/Cargo.toml index 48e8d26491..53fadd21c0 100644 --- a/sqlx-macros-core/Cargo.toml +++ b/sqlx-macros-core/Cargo.toml @@ -48,6 +48,7 @@ tokio = { workspace = true, optional = true } dotenvy = { workspace = true } +atomic-write-file = { version = "0.1" } hex = { version = "0.4.3" } heck = { version = "0.4", features = ["unicode"] } either = "1.6.1" diff --git a/sqlx-macros-core/src/query/data.rs b/sqlx-macros-core/src/query/data.rs index 868aaccc16..70eb9c04e0 100644 --- a/sqlx-macros-core/src/query/data.rs +++ b/sqlx-macros-core/src/query/data.rs @@ -151,39 +151,23 @@ where } pub(super) fn save_in(&self, dir: impl AsRef) -> crate::Result<()> { - fn inner(data: &QueryData, file: &mut std::fs::File) -> crate::Result<()> - where - DB: DatabaseExt, - Describe: serde::Serialize + serde::de::DeserializeOwned, - { - serde_json::to_writer_pretty(&mut *file, data) - .map_err(|err| format!("failed to serialize query data to file: {err:?}"))?; + let path = dir.as_ref().join(format!("query-{}.json", self.hash)); + let mut file = atomic_write_file::AtomicWriteFile::open(&path) + .map_err(|err| format!("failed to open the temporary file: {err:?}"))?; - // Ensure there is a newline at the end of the JSON file to avoid accidental modification by IDE - // and make github diff tool happier. - file.write_all(b"\n") - .map_err(|err| format!("failed to append a newline to file: {err:?}"))?; + serde_json::to_writer_pretty(file.as_file_mut(), self) + .map_err(|err| format!("failed to serialize query data to file: {err:?}"))?; - Ok(()) - } + // Ensure there is a newline at the end of the JSON file to avoid + // accidental modification by IDE and make github diff tool happier. + file.as_file_mut() + .write_all(b"\n") + .map_err(|err| format!("failed to append a newline to file: {err:?}"))?; - let path = dir.as_ref().join(format!("query-{}.json", self.hash)); - let mut file = match std::fs::OpenOptions::new() - .write(true) - .create_new(true) - .open(&path) - { - Ok(file) => file, - Err(error) if error.kind() == std::io::ErrorKind::AlreadyExists => return Ok(()), - Err(error) => return Err(format!("failed to create query file: {error:?}").into()), - }; - let res = inner(self, &mut file); - - if res.is_err() { - _ = std::fs::remove_file(&path); - } + file.commit() + .map_err(|err| format!("failed to commit the query data to {path:?}: {err:?}"))?; - res + Ok(()) } }