1use std::{marker::PhantomData, ops::Deref};
6
7use sea_query::TableCreateStatement;
8
9use crate::value::{EqTyp, MyTyp};
10
11#[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
12pub enum ColumnType {
13 Integer = 0,
14 Float = 1,
15 String = 2,
16 Blob = 3,
17}
18
19impl ColumnType {
20 pub fn sea_type(&self) -> sea_query::ColumnType {
21 use sea_query::ColumnType as T;
22 match self {
23 ColumnType::Integer => T::Integer,
24 ColumnType::Float => T::custom("REAL"),
25 ColumnType::String => T::Text,
26 ColumnType::Blob => T::Blob,
27 }
28 }
29}
30
31#[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
32pub struct Column {
33 pub name: String,
34 pub typ: ColumnType,
35 pub nullable: bool,
36 pub fk: Option<(String, String)>,
37}
38
39#[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Default)]
40pub struct Unique {
41 pub columns: MyVec<String>,
42}
43
44#[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Default)]
45pub struct Table {
46 pub columns: MyVec<Column>,
47 pub uniques: MyVec<Unique>,
48}
49
50pub struct MyVec<T> {
52 inner: Vec<T>,
53 original: Vec<usize>,
54}
55
56impl<T: std::fmt::Debug> std::fmt::Debug for MyVec<T> {
57 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
58 self.inner.fmt(f)
59 }
60}
61
62impl<T: std::hash::Hash> std::hash::Hash for MyVec<T> {
63 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
64 self.inner.hash(state);
65 }
66}
67
68impl<T: PartialEq> PartialEq for MyVec<T> {
69 fn eq(&self, other: &Self) -> bool {
70 self.inner == other.inner
71 }
72}
73
74impl<T: Eq> Eq for MyVec<T> {}
75
76impl<T: PartialOrd> PartialOrd for MyVec<T> {
77 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
78 self.inner.partial_cmp(&other.inner)
79 }
80}
81
82impl<T: Ord> Ord for MyVec<T> {
83 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
84 self.inner.cmp(&other.inner)
85 }
86}
87
88impl<T> Default for MyVec<T> {
89 fn default() -> Self {
90 Self {
91 inner: Default::default(),
92 original: Default::default(),
93 }
94 }
95}
96
97impl<T: Ord> MyVec<T> {
98 pub fn insert(&mut self, item: T) {
99 let index = self.inner.partition_point(|x| x < &item);
100 self.original.insert(index, self.inner.len());
101 self.inner.insert(index, item);
102 }
103}
104
105impl<T> Deref for MyVec<T> {
106 type Target = [T];
107
108 fn deref(&self) -> &Self::Target {
109 &self.inner
110 }
111}
112
113impl<T> MyVec<T> {
114 pub fn original_order(&self) -> impl Iterator<Item = &T> {
115 (0..self.original.len())
117 .map(|x| self.original.iter().position(|a| a == &x).unwrap())
118 .map(|i| &self.inner[i])
119 }
120}
121
122impl Table {
123 pub fn create(&self) -> TableCreateStatement {
124 use sea_query::*;
125 let mut create = Table::create();
126 for col in &*self.columns {
127 let name = Alias::new(&col.name);
128 let mut def = ColumnDef::new_with_type(name.clone(), col.typ.sea_type());
129 if col.nullable {
130 def.null();
131 } else {
132 def.not_null();
133 }
134 create.col(&mut def);
135 if let Some((table, fk)) = &col.fk {
136 create.foreign_key(
137 ForeignKey::create()
138 .to(Alias::new(table), Alias::new(fk))
139 .from_col(name),
140 );
141 }
142 }
143 for unique in &*self.uniques {
144 let mut index = sea_query::Index::create().unique().take();
145 for col in unique.columns.original_order() {
148 index.col(Alias::new(col));
149 }
150 create.index(&mut index);
151 }
152 create
153 }
154}
155
156#[derive(Debug, Hash, Default, PartialEq, Eq)]
157pub struct Schema {
158 pub tables: MyVec<(String, Table)>,
159}
160
161impl Schema {
162 pub(crate) fn new<S: crate::migrate::Schema>() -> Self {
163 let mut b = crate::migrate::TableTypBuilder::default();
164 S::typs(&mut b);
165 b.ast
166 }
167}
168
169#[cfg(feature = "dev")]
170pub mod dev {
171 use std::{
172 hash::{Hash, Hasher},
173 io::{Read, Write},
174 };
175
176 use k12::{
177 KangarooTwelve, KangarooTwelveCore,
178 digest::{ExtendableOutput, core_api::CoreWrapper},
179 };
180
181 pub struct KangarooHasher {
182 inner: CoreWrapper<KangarooTwelveCore<'static>>,
183 }
184
185 impl Default for KangarooHasher {
186 fn default() -> Self {
187 let core = KangarooTwelveCore::new(&[]);
188 let hasher = KangarooTwelve::from_core(core);
189 Self { inner: hasher }
190 }
191 }
192
193 impl Hasher for KangarooHasher {
194 fn finish(&self) -> u64 {
195 let mut xof = self.inner.clone().finalize_xof();
196 let mut buf = [0; 8];
197 xof.read_exact(&mut buf).unwrap();
198 u64::from_le_bytes(buf)
199 }
200
201 fn write(&mut self, bytes: &[u8]) {
202 self.inner.write_all(bytes).unwrap();
203 }
204 }
205
206 pub fn hash_schema<S: crate::migrate::Schema>() -> String {
210 let mut hasher = KangarooHasher::default();
211 super::Schema::new::<S>().hash(&mut hasher);
212 format!("{:x}", hasher.finish())
213 }
214}
215
216pub struct TypBuilder<S> {
217 pub(crate) ast: Table,
218 _p: PhantomData<S>,
219}
220
221impl<S> Default for TypBuilder<S> {
222 fn default() -> Self {
223 Self {
224 ast: Default::default(),
225 _p: Default::default(),
226 }
227 }
228}
229
230impl<S> TypBuilder<S> {
231 pub fn col<T: SchemaType<S>>(&mut self, name: &'static str) {
232 let mut item = Column {
233 name: name.to_owned(),
234 typ: T::TYP,
235 nullable: T::NULLABLE,
236 fk: None,
237 };
238 if let Some((table, fk)) = T::FK {
239 item.fk = Some((table.to_owned(), fk.to_owned()))
240 }
241 self.ast.columns.insert(item)
242 }
243
244 pub fn unique(&mut self, cols: &[&'static str]) {
245 let mut unique = Unique::default();
246 for &col in cols {
247 unique.columns.insert(col.to_owned());
248 }
249 self.ast.uniques.insert(unique);
250 }
251
252 pub fn check_unique_compatible<T: EqTyp>(&mut self) {}
253}
254
255struct Null;
256struct NotNull;
257
258#[diagnostic::on_unimplemented(
261 message = "Can not use `{Self}` as a column type in schema `{S}`",
262 note = "Table names can be used as schema column types as long as they are not #[no_reference]"
263)]
264trait SchemaType<S>: MyTyp {
265 type N;
266}
267
268impl<S> SchemaType<S> for String {
269 type N = NotNull;
270}
271impl<S> SchemaType<S> for Vec<u8> {
272 type N = NotNull;
273}
274impl<S> SchemaType<S> for i64 {
275 type N = NotNull;
276}
277impl<S> SchemaType<S> for f64 {
278 type N = NotNull;
279}
280impl<S, T: SchemaType<S, N = NotNull>> SchemaType<S> for Option<T> {
281 type N = Null;
282}
283#[diagnostic::do_not_recommend]
285impl<T: crate::Table<Referer = ()>> SchemaType<T::Schema> for T {
286 type N = NotNull;
287}