toasty_cli/migration/
snapshot_file.rs1use serde::{Deserialize, Serialize};
2use std::fmt;
3use std::path::Path;
4use std::str::FromStr;
5use toasty::{Error, Result};
6use toasty_core::schema::db::Schema;
7use toml_edit::{DocumentMut, Item};
8
9const SNAPSHOT_FILE_VERSION: u32 = 1;
10
11#[derive(Debug, Clone, Serialize, Deserialize)]
34pub struct SnapshotFile {
35 version: u32,
37
38 pub schema: Schema,
40}
41
42impl SnapshotFile {
43 pub fn new(schema: Schema) -> Self {
45 Self {
46 version: SNAPSHOT_FILE_VERSION,
47 schema,
48 }
49 }
50
51 pub fn load(path: impl AsRef<Path>) -> Result<Self> {
53 let contents = std::fs::read_to_string(path.as_ref())?;
54 contents.parse()
55 }
56
57 pub fn save(&self, path: impl AsRef<Path>) -> Result<()> {
59 std::fs::write(path.as_ref(), self.to_string())?;
60 Ok(())
61 }
62}
63
64impl FromStr for SnapshotFile {
65 type Err = Error;
66
67 fn from_str(s: &str) -> Result<Self> {
68 let file: SnapshotFile =
69 toml::from_str(s).map_err(|err| Error::from_args(format_args!("{err}")))?;
70
71 if file.version != SNAPSHOT_FILE_VERSION {
72 return Err(Error::from_args(format_args!(
73 "unsupported snapshot file version: {}. Expected version {}",
74 file.version, SNAPSHOT_FILE_VERSION
75 )));
76 }
77
78 Ok(file)
79 }
80}
81
82impl fmt::Display for SnapshotFile {
83 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
84 let doc = self.to_toml_document().map_err(|_| fmt::Error)?;
85 write!(f, "{}", doc)
86 }
87}
88
89impl SnapshotFile {
90 fn to_toml_document(&self) -> Result<DocumentMut> {
91 let mut doc = toml_edit::ser::to_document(self)
92 .map_err(|err| Error::from_args(format_args!("{err}")))?;
93 for (_key, item) in doc.as_table_mut().iter_mut() {
94 if item.is_inline_table() {
95 let mut placeholder = Item::None;
96 std::mem::swap(item, &mut placeholder);
97 let mut table = placeholder.into_table().unwrap();
98
99 for (_key, item) in table.iter_mut() {
100 if item.is_array() {
101 let mut placeholder = Item::None;
102 std::mem::swap(item, &mut placeholder);
103 let mut array = placeholder.into_array_of_tables().unwrap();
104
105 for table in array.iter_mut() {
106 for (_key, item) in table.iter_mut() {
107 if item.is_array() {
108 let mut placeholder = Item::None;
109 std::mem::swap(item, &mut placeholder);
110 let array = placeholder.into_array_of_tables().unwrap();
111 *item = array.into();
112 }
113 }
114 }
115
116 *item = array.into();
117 }
118 }
119
120 *item = table.into();
121 }
122 }
123
124 Ok(doc)
125 }
126}