1use std::path::Path;
2
3use miette::NamedSource;
4use tokio_postgres::Client;
5
6use crate::utils::db_err;
7
8use self::error::Error;
9
10#[allow(clippy::result_large_err)]
11pub fn load_schema<P: AsRef<Path>>(client: &Client, paths: &[P]) -> Result<(), Error> {
15 for path in paths {
16 let path = path.as_ref();
17 let sql = std::fs::read_to_string(path).map_err(|err| Error::Io {
18 path: path.to_string_lossy().to_string(),
19 err,
20 })?;
21 futures::executor::block_on(client.batch_execute(&sql)).map_err(|err| {
22 let msg = format!("{err:#}");
23 let src = NamedSource::new(path.to_string_lossy(), sql);
24 if let Some((position, msg, help)) = db_err(&err) {
25 Error::Postgres {
26 msg,
27 help,
28 src,
29 err_span: Some((position as usize..position as usize).into()),
30 }
31 } else {
32 Error::Postgres {
33 msg,
34 help: None,
35 src,
36 err_span: None,
37 }
38 }
39 })?;
40 }
41 Ok(())
42}
43
44pub(crate) mod error {
45 use miette::{Diagnostic, NamedSource, SourceSpan};
46 use thiserror::Error as ThisError;
47
48 #[derive(Debug, ThisError, Diagnostic)]
49 pub enum Error {
50 #[error("Could not read schema `{path}`: ({err})")]
51 Io { path: String, err: std::io::Error },
52 #[error("Could not execute schema: {msg}")]
53 Postgres {
54 msg: String,
55 #[source_code]
56 src: NamedSource<String>,
57 #[help]
58 help: Option<String>,
59 #[label("error occurs near this location")]
60 err_span: Option<SourceSpan>,
61 },
62 }
63}