Skip to main content

migrations_internals/
lib.rs

1// Built-in Lints
2// Clippy lints
3#![allow(
4    clippy::map_unwrap_or,
5    clippy::match_same_arms,
6    clippy::type_complexity
7)]
8#![warn(
9    clippy::unwrap_used,
10    clippy::print_stdout,
11    clippy::mut_mut,
12    clippy::non_ascii_literal,
13    clippy::similar_names,
14    clippy::unicode_not_nfc,
15    clippy::enum_glob_use,
16    clippy::if_not_else,
17    clippy::items_after_statements,
18    clippy::used_underscore_binding,
19    missing_debug_implementations,
20    missing_copy_implementations
21)]
22
23use std::ffi::OsString;
24use std::fs::{DirEntry, File};
25use std::io::Read;
26use std::path::{Path, PathBuf};
27
28#[doc(hidden)]
29#[derive(#[automatically_derived]
#[allow(missing_copy_implementations)]
impl ::core::fmt::Debug for TomlMetadata {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_struct_field1_finish(f, "TomlMetadata",
            "run_in_transaction", &&self.run_in_transaction)
    }
}Debug, #[doc(hidden)]
#[allow(non_upper_case_globals, unused_attributes, unused_qualifications,
clippy :: absolute_paths,)]
const _: () =
    {
        #[allow(unused_extern_crates, clippy :: useless_attribute)]
        extern crate serde as _serde;
        ;
        #[automatically_derived]
        impl<'de> _serde::Deserialize<'de> for TomlMetadata {
            fn deserialize<__D>(__deserializer: __D)
                -> _serde::__private229::Result<Self, __D::Error> where
                __D: _serde::Deserializer<'de> {
                #[allow(non_camel_case_types)]
                #[doc(hidden)]
                enum __Field { __field0, __ignore, }
                #[doc(hidden)]
                struct __FieldVisitor;
                #[automatically_derived]
                impl<'de> _serde::de::Visitor<'de> for __FieldVisitor {
                    type Value = __Field;
                    fn expecting(&self,
                        __formatter: &mut _serde::__private229::Formatter)
                        -> _serde::__private229::fmt::Result {
                        _serde::__private229::Formatter::write_str(__formatter,
                            "field identifier")
                    }
                    fn visit_u64<__E>(self, __value: u64)
                        -> _serde::__private229::Result<Self::Value, __E> where
                        __E: _serde::de::Error {
                        match __value {
                            0u64 => _serde::__private229::Ok(__Field::__field0),
                            _ => _serde::__private229::Ok(__Field::__ignore),
                        }
                    }
                    fn visit_str<__E>(self, __value: &str)
                        -> _serde::__private229::Result<Self::Value, __E> where
                        __E: _serde::de::Error {
                        match __value {
                            "run_in_transaction" =>
                                _serde::__private229::Ok(__Field::__field0),
                            _ => { _serde::__private229::Ok(__Field::__ignore) }
                        }
                    }
                    fn visit_bytes<__E>(self, __value: &[u8])
                        -> _serde::__private229::Result<Self::Value, __E> where
                        __E: _serde::de::Error {
                        match __value {
                            b"run_in_transaction" =>
                                _serde::__private229::Ok(__Field::__field0),
                            _ => { _serde::__private229::Ok(__Field::__ignore) }
                        }
                    }
                }
                #[automatically_derived]
                impl<'de> _serde::Deserialize<'de> for __Field {
                    #[inline]
                    fn deserialize<__D>(__deserializer: __D)
                        -> _serde::__private229::Result<Self, __D::Error> where
                        __D: _serde::Deserializer<'de> {
                        _serde::Deserializer::deserialize_identifier(__deserializer,
                            __FieldVisitor)
                    }
                }
                #[doc(hidden)]
                struct __Visitor<'de> {
                    marker: _serde::__private229::PhantomData<TomlMetadata>,
                    lifetime: _serde::__private229::PhantomData<&'de ()>,
                }
                #[automatically_derived]
                impl<'de> _serde::de::Visitor<'de> for __Visitor<'de> {
                    type Value = TomlMetadata;
                    fn expecting(&self,
                        __formatter: &mut _serde::__private229::Formatter)
                        -> _serde::__private229::fmt::Result {
                        _serde::__private229::Formatter::write_str(__formatter,
                            "struct TomlMetadata")
                    }
                    #[inline]
                    fn visit_seq<__A>(self, mut __seq: __A)
                        -> _serde::__private229::Result<Self::Value, __A::Error>
                        where __A: _serde::de::SeqAccess<'de> {
                        let __field0 =
                            match _serde::de::SeqAccess::next_element::<bool>(&mut __seq)?
                                {
                                _serde::__private229::Some(__value) => __value,
                                _serde::__private229::None =>
                                    _serde::__private229::Default::default(),
                            };
                        _serde::__private229::Ok(TomlMetadata {
                                run_in_transaction: __field0,
                            })
                    }
                    #[inline]
                    fn visit_map<__A>(self, mut __map: __A)
                        -> _serde::__private229::Result<Self::Value, __A::Error>
                        where __A: _serde::de::MapAccess<'de> {
                        let mut __field0: _serde::__private229::Option<bool> =
                            _serde::__private229::None;
                        while let _serde::__private229::Some(__key) =
                                _serde::de::MapAccess::next_key::<__Field>(&mut __map)? {
                            match __key {
                                __Field::__field0 => {
                                    if _serde::__private229::Option::is_some(&__field0) {
                                        return _serde::__private229::Err(<__A::Error as
                                                        _serde::de::Error>::duplicate_field("run_in_transaction"));
                                    }
                                    __field0 =
                                        _serde::__private229::Some(_serde::de::MapAccess::next_value::<bool>(&mut __map)?);
                                }
                                _ => {
                                    let _ =
                                        _serde::de::MapAccess::next_value::<_serde::de::IgnoredAny>(&mut __map)?;
                                }
                            }
                        }
                        let __field0 =
                            match __field0 {
                                _serde::__private229::Some(__field0) => __field0,
                                _serde::__private229::None =>
                                    _serde::__private229::Default::default(),
                            };
                        _serde::__private229::Ok(TomlMetadata {
                                run_in_transaction: __field0,
                            })
                    }
                }
                #[doc(hidden)]
                const FIELDS: &'static [&'static str] =
                    &["run_in_transaction"];
                _serde::Deserializer::deserialize_struct(__deserializer,
                    "TomlMetadata", FIELDS,
                    __Visitor {
                        marker: _serde::__private229::PhantomData::<TomlMetadata>,
                        lifetime: _serde::__private229::PhantomData,
                    })
            }
        }
    };serde::Deserialize)]
30#[allow(missing_copy_implementations)]
31pub struct TomlMetadata {
32    #[serde(default)]
33    pub run_in_transaction: bool,
34}
35
36impl Default for TomlMetadata {
37    fn default() -> Self {
38        Self {
39            run_in_transaction: true,
40        }
41    }
42}
43
44impl TomlMetadata {
45    pub const fn new(run_in_transaction: bool) -> Self {
46        Self { run_in_transaction }
47    }
48
49    pub fn read_from_file(path: &Path) -> Result<Self, Box<dyn std::error::Error>> {
50        let mut toml = String::new();
51        let mut file = File::open(path)?;
52        file.read_to_string(&mut toml)?;
53
54        Ok(toml::from_str(&toml)?)
55    }
56}
57
58pub fn search_for_migrations_directory(path: &Path) -> Option<PathBuf> {
59    let migration_path = path.join("migrations");
60    if migration_path.is_dir() {
61        Some(migration_path)
62    } else {
63        path.parent().and_then(search_for_migrations_directory)
64    }
65}
66
67pub fn valid_sql_migration_directory(path: &Path) -> bool {
68    file_names(path).is_ok_and(|files| files.iter().any(|f| f == "up.sql"))
69}
70
71pub fn version_from_string(path: &str) -> Option<String> {
72    path.split('_').next().map(|s| s.replace('-', ""))
73}
74
75fn file_names(path: &Path) -> Result<Vec<OsString>, std::io::Error> {
76    path.read_dir()?
77        .filter_map(|entry| match entry {
78            Ok(entry) if entry.file_name().to_string_lossy().starts_with('.') => None,
79            Ok(entry) => Some(Ok(entry.file_name())),
80            Err(e) => Some(Err(e)),
81        })
82        .collect::<Result<Vec<_>, _>>()
83}
84
85pub fn migrations_directories(
86    path: &'_ Path,
87) -> Result<impl Iterator<Item = Result<DirEntry, std::io::Error>> + '_, std::io::Error> {
88    Ok(path.read_dir()?.filter_map(|entry_res| {
89        entry_res
90            .and_then(|entry| {
91                Ok(
92                    if entry.metadata()?.is_file()
93                        || entry.file_name().to_string_lossy().starts_with('.')
94                    {
95                        None
96                    } else if entry.metadata()?.is_dir() {
97                        let inner_dir_entry_count = entry.path().read_dir()?.count();
98
99                        if inner_dir_entry_count == 0 {
100                            None
101                        } else {
102                            Some(entry)
103                        }
104                    } else {
105                        Some(entry)
106                    },
107                )
108            })
109            .transpose()
110    }))
111}