Skip to content

Commit ba5071a

Browse files
committed
perf: avoid removing all files on prepare; prune the unused queries and add or update when needed
1 parent b180eba commit ba5071a

1 file changed

Lines changed: 56 additions & 1 deletion

File tree

sqlx-cli/src/prepare.rs

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,9 @@ async fn prepare(ctx: &PrepareCtx<'_>) -> anyhow::Result<()> {
7474
}
7575

7676
let prepare_dir = ctx.prepare_dir()?;
77-
run_prepare_step(ctx, &prepare_dir)?;
77+
let cache_dir = ctx.metadata.target_directory().join("sqlx-prepare");
78+
run_prepare_step(ctx, &cache_dir)?;
79+
sync_query_data(&cache_dir, &prepare_dir)?;
7880

7981
// Warn if no queries were generated. Glob since the directory may contain unrelated files.
8082
if glob_query_files(prepare_dir)?.is_empty() {
@@ -204,6 +206,59 @@ fn run_prepare_step(ctx: &PrepareCtx, cache_dir: &Path) -> anyhow::Result<()> {
204206
Ok(())
205207
}
206208

209+
fn sync_query_data(cache_dir: &Path, prepare_dir: &Path) -> anyhow::Result<()> {
210+
fs::create_dir_all(prepare_dir).context(format!(
211+
"Failed to create query cache directory: {:?}",
212+
prepare_dir
213+
))?;
214+
215+
let prepare_filenames: HashSet<String> = glob_query_files(prepare_dir)?
216+
.into_iter()
217+
.filter_map(|path| path.file_name().map(|f| f.to_string_lossy().into_owned()))
218+
.collect();
219+
let cache_filenames: HashSet<String> = glob_query_files(cache_dir)?
220+
.into_iter()
221+
.filter_map(|path| path.file_name().map(|f| f.to_string_lossy().into_owned()))
222+
.collect();
223+
224+
for stale_filename in prepare_filenames.difference(&cache_filenames) {
225+
let stale_file = prepare_dir.join(stale_filename);
226+
fs::remove_file(&stale_file)
227+
.with_context(|| format!("Failed to delete query file: {}", stale_file.display()))?;
228+
}
229+
230+
for filename in cache_filenames {
231+
let cache_file = cache_dir.join(&filename);
232+
let prepare_file = prepare_dir.join(&filename);
233+
234+
let should_copy = match fs::read(&prepare_file) {
235+
Ok(prepare_bytes) => {
236+
let cache_json = load_json_file(&cache_file)?;
237+
let prepare_json: serde_json::Value = serde_json::from_slice(&prepare_bytes)?;
238+
prepare_json != cache_json
239+
}
240+
Err(err) if err.kind() == std::io::ErrorKind::NotFound => true,
241+
Err(err) => {
242+
return Err(err).with_context(|| {
243+
format!("failed to load file: {}", prepare_file.display())
244+
})
245+
}
246+
};
247+
248+
if should_copy {
249+
fs::copy(&cache_file, &prepare_file).with_context(|| {
250+
format!(
251+
"Failed to copy query file from {} to {}",
252+
cache_file.display(),
253+
prepare_file.display()
254+
)
255+
})?;
256+
}
257+
}
258+
259+
Ok(())
260+
}
261+
207262
#[derive(Debug, PartialEq)]
208263
struct ProjectRecompileAction {
209264
// The names of the packages

0 commit comments

Comments
 (0)