1use std::ops::Not;
2use std::{borrow::BorrowMut, marker::PhantomData};
3
4use constraints::dyn_object::{DynConstraint, ImplConstraint};
5use constraints::exports::not_null;
6use constraints::{Constraints, Noop};
7use foreign_key::Fk;
8use sqlx::{Database, Type};
9use types::{ColumnType, ColumnTypeStruct};
10
11use crate::{HasQuery, Query};
12
13pub struct CreateTableSt<'q, S, Q: Query<S>> {
15 pub(crate) header: String,
16 pub(crate) ident: (Option<String>, String),
17 pub(crate) columns: Vec<(
18 String,
19 Box<dyn ColumnType + Send + Sync>,
20 Box<dyn DynConstraint<S, Q> + 'q + Send + Sync>,
21 )>,
22 pub(crate) foreign_keys: Vec<Fk>,
23 pub(crate) verbatim: Vec<String>,
24 pub(crate) ctx: Q::Context1,
25 pub(crate) _sqlx: PhantomData<S>,
26}
27
28impl<'q, S, Q> CreateTableSt<'q, S, Q>
29where
30 S: 'static + Database,
31 Q: Query<S>,
32{
33 pub fn verbatim(&mut self, verbatim: &str) -> &mut Self {
34 self.verbatim.push(verbatim.to_string());
35 self
36 }
37 pub fn column<Ty>(
38 &mut self,
39 column: &'static str,
40 con: impl Constraints<S, Q, Ty> + 'static + Send + Sync,
41 ) -> &mut Self
42 where
43 S: Sync,
44 Ty: Type<S> + 'static + Send + Sync,
45 Q::Context1: 'q,
46 Q: 'q,
47 Ty: 'q,
48 {
49 self.columns.push((
50 column.to_string(),
51 Box::new(ColumnTypeStruct::<S, Ty>(PhantomData)),
52 {
53 let bo_mut = self.ctx.borrow_mut();
54 let bo_mut = unsafe { &mut *(bo_mut as *mut _) };
55 let part = con.constraint(bo_mut);
56
57 Box::new(ImplConstraint {
58 closure: Some(part),
59 _pd: PhantomData::<Ty>,
60 })
61 },
62 ));
63 self
64 }
65
66 #[deprecated = "use constraint in create_table_st2"]
67 pub fn foreign_key(&mut self, fk: Fk) -> &mut Self
68 where
69 S: SqlxQuery + Sync,
70 Q: 'q,
71 <S as SqlxQuery>::KeyType: Send,
72 {
73 if fk.not_null {
74 self.column::<S::KeyType>(fk.column, not_null());
75 } else {
76 self.column::<Option<S::KeyType>>(fk.column, Noop);
77 }
78 self.foreign_keys.push(fk);
79 self
80 }
81}
82
83pub trait SqlxQuery: Database {
84 type KeyType: Type<Self>
85 + constraints::IsNull
86 + Send
87 + Sync
88 + 'static;
89 fn default_primary_key() -> &'static str;
90}
91
92impl SqlxQuery for sqlx::Sqlite {
93 type KeyType = i64;
94 fn default_primary_key() -> &'static str {
95 "PRIMARY KEY AUTOINCREMENT"
96 }
97}
98
99impl<'q, S, Q> HasQuery<S, Q> for CreateTableSt<'q, S, Q>
100where
101 S: 'static + Database,
102 Q: Query<S>,
103{
104 fn _build(self) -> (String, Q::Output) {
105 Q::build_query(self.ctx, |ctx| {
106 let mut str = String::from(&self.header);
107
108 str.push(' ');
109
110 if let Some(schema) = self.ident.0 {
111 str.push_str(&schema);
112 }
113
114 str.push_str(&self.ident.1);
115
116 str.push_str(" (");
117
118 let mut clauses = Vec::new();
119
120 for mut col in self.columns {
121 let mut str =
122 format!("{} {}", col.0, col.1.sqlx_info());
123
124 let mut str_2 = String::new();
125 col.2.call(ctx, &mut str_2);
126
127 if str_2.is_empty().not() {
128 str.push(' ');
129 str.push_str(&str_2);
130 }
131
132 clauses.push(str);
133 }
134
135 for fk in self.foreign_keys {
136 let mut str = format!(
137 "FOREIGN KEY ({}) REFERENCES {}({})",
138 fk.column, fk.refer_table, fk.refer_column
139 );
140
141 if fk.not_null.not() {
142 str.push_str(" ON DELETE SET NULL");
143 }
144
145 clauses.push(str);
146 }
147
148 for verbatim in self.verbatim {
149 clauses.push(verbatim);
150 }
151
152 str.push_str(&clauses.join(", "));
153 str.push_str(");");
154
155 str
156 })
157 }
158}
159
160pub mod foreign_key {
161 #[derive(Clone)]
162 #[deprecated = "use create_table_st2"]
163 pub struct Fk {
164 pub not_null: bool,
165 pub column: &'static str,
166 pub refer_table: &'static str,
167 pub refer_column: &'static str,
168 }
169}
170
171pub mod types {
172 use std::marker::PhantomData;
173
174 use sqlx::{prelude::Type, Database};
175
176 pub trait ColumnType {
177 fn sqlx_info(&self) -> String;
178 fn clone_dyn(&self) -> Box<dyn ColumnType>;
179 }
180
181 impl Clone for Box<dyn ColumnType> {
182 fn clone(&self) -> Box<dyn ColumnType> {
183 self.clone_dyn()
184 }
185 }
186 pub struct ColumnTypeStruct<S, Ty>(
187 pub(crate) PhantomData<(S, Ty)>,
188 );
189 impl<S, Ty> ColumnType for ColumnTypeStruct<S, Ty>
190 where
191 S: Database,
192 Ty: Type<S> + 'static,
193 {
194 fn clone_dyn(&self) -> Box<dyn ColumnType> {
195 Box::new(ColumnTypeStruct::<S, Ty>(PhantomData))
196 }
197 fn sqlx_info(&self) -> String {
198 use sqlx::TypeInfo;
199 Ty::type_info().name().to_string()
200 }
201 }
202}
203
204pub mod constraints {
205 use std::ops::Not;
206
207 use crate::{Accept, Query};
208
209 use super::SqlxQuery;
210
211 pub trait Constraints<S, Q: Query<S>, Ty> {
212 fn constraint(
213 self,
214 ctx1: &mut Q::Context1,
215 ) -> impl FnOnce(&mut Q::Context2, &mut String) + Send + Sync
216 where
217 Self: Sized;
218 }
219 pub mod dyn_object {
220 use std::{marker::PhantomData, mem::take};
221
222 use crate::Query;
223
224 pub trait DynConstraint<S, Q: Query<S>> {
225 fn call(
226 &mut self,
227 ctx2: &mut Q::Context2,
228 str: &mut String,
229 );
230 }
231
232 impl<'q, S, Q: Query<S>> Clone
233 for Box<dyn DynConstraint<S, Q> + 'q>
234 {
235 fn clone(&self) -> Self {
236 todo!("Clonsing constraint is not supported yet")
237 }
238 }
239
240 pub struct ImplConstraint<F: Send + Sync, T> {
241 pub closure: Option<F>,
242 pub _pd: PhantomData<T>,
243 }
244
245 impl<S, Q, F, T> DynConstraint<S, Q> for ImplConstraint<F, T>
246 where
247 Q: Query<S>,
248 F: FnOnce(&mut Q::Context2, &mut String)
249 + Send
250 + Sync,
251 {
252 fn call(
253 &mut self,
254 ctx2: &mut <Q as Query<S>>::Context2,
255 str: &mut String,
256 ) {
257 if let Some(c) = take(&mut self.closure) {
258 c(ctx2, str)
259 } else {
260 panic!("is there an issue with cloning")
261 }
262 }
263 }
264 }
265
266 pub struct Noop;
267
268 impl<S, Q: Query<S>, Ty> Constraints<S, Q, Ty> for Noop {
269 fn constraint(
270 self,
271 _ctx1: &mut Q::Context1,
272 ) -> impl FnOnce(&mut Q::Context2, &mut String)
273 where
274 Self: Sized,
275 {
276 |_, _| {}
277 }
278 }
279
280 pub fn noop() -> Noop {
281 Noop
282 }
283
284 impl<S, Q: Query<S>, Ty: IsNull> Constraints<S, Q, Ty> for () {
285 fn constraint(
286 self,
287 _ctx1: &mut Q::Context1,
288 ) -> impl FnOnce(&mut Q::Context2, &mut String)
289 where
290 Self: Sized,
291 {
292 |_, str| {
293 if Ty::is_null().not() {
294 str.push_str("NOT NULL");
295 }
296 }
297 }
298 }
299
300 pub struct NotNull;
301
302 impl<S, Q: Query<S>, Ty> Constraints<S, Q, Ty> for NotNull {
303 fn constraint(
304 self,
305 _ctx1: &mut Q::Context1,
306 ) -> impl FnOnce(&mut Q::Context2, &mut String)
307 where
308 Self: Sized,
309 {
310 |_, str| str.push_str("NOT NULL")
311 }
312 }
313
314 pub struct DefaultConstraint<T>(T);
315
316 impl<S, Q, Ty, T> Constraints<S, Q, Ty> for DefaultConstraint<T>
317 where
318 Q: Accept<T, S>,
319 {
320 fn constraint(
321 self,
322 ctx1: &mut Q::Context1,
323 ) -> impl FnOnce(&mut Q::Context2, &mut String) + Send + Sync
324 where
325 Self: Sized,
326 {
327 let save = Q::accept(self.0, ctx1);
328 |ctx, str| {
329 str.push_str(&format!("DEFAULT {}", save(ctx)))
330 }
331 }
332 }
333
334 pub struct DefaultPrimaryKey;
335
336 impl<S: SqlxQuery, Q: Query<S>> Constraints<S, Q, S::KeyType>
337 for DefaultPrimaryKey
338 {
339 fn constraint(
340 self,
341 _ctx1: &mut Q::Context1,
342 ) -> impl FnOnce(&mut Q::Context2, &mut String)
343 where
344 Self: Sized,
345 {
346 |_, str| str.push_str(&S::default_primary_key())
347 }
348 }
349
350 pub struct CheckIfNull;
351
352 pub trait IsNull {
359 fn is_null() -> bool;
360 }
361
362 impl<S, Q: Query<S>, T: IsNull> Constraints<S, Q, T>
363 for CheckIfNull
364 {
365 fn constraint(
366 self,
367 _ctx1: &mut Q::Context1,
368 ) -> impl FnOnce(&mut Q::Context2, &mut String)
369 where
370 Self: Sized,
371 {
372 |_, str| {
373 if T::is_null().not() {
374 str.push_str("NOT NULL");
375 }
376 }
377 }
378 }
379
380 mod impl_waiting_specialization {
381 use super::IsNull;
382
383 impl<T> IsNull for Option<T> {
384 fn is_null() -> bool {
385 true
386 }
387 }
388
389 macro_rules! impl_no_gens {
390 ($($ident:ident)*) => {
391 $(impl IsNull for $ident {
392 fn is_null() -> bool {
393 false
394 }
395 })*
396 };
397 }
398
399 impl_no_gens!(i32 i64 bool char String);
400 }
401
402 pub trait IsConstraint {}
403 pub trait NotNullOnlyOnce {}
404 pub trait DefaultOnlyOnce {}
405 pub trait CheckIfNullOnlyOnce {}
406
407 mod waiting_auto_feature_and_negative_impl_feature {
408 use super::*;
409
410 impl IsConstraint for () {}
411 impl IsConstraint for NotNull {}
412 impl<T> IsConstraint for DefaultConstraint<T> {}
413
414 impl NotNullOnlyOnce for () {}
415 impl DefaultOnlyOnce for () {}
416 impl CheckIfNullOnlyOnce for () {}
417
418 impl<T> NotNullOnlyOnce for DefaultConstraint<T> {}
419 impl<T> CheckIfNullOnlyOnce for DefaultConstraint<T> {}
420
421 impl DefaultOnlyOnce for NotNull {}
422 impl CheckIfNullOnlyOnce for NotNull {}
423
424 impl NotNullOnlyOnce for CheckIfNull {}
425 impl DefaultOnlyOnce for CheckIfNull {}
426
427 impl<A1, A2> NotNullOnlyOnce for And<A1, A2> where
428 A1: NotNullOnlyOnce {
430 }
431 }
432
433 pub mod exports {
434 use super::CheckIfNull;
435
436 pub trait ConstraintExtention: Sized {
437 fn not_null(self) -> And<Self, NotNull>
438 where
439 Self: NotNullOnlyOnce,
440 {
441 And(self, not_null())
442 }
443 fn default<T>(
444 self,
445 t: T,
446 ) -> And<Self, DefaultConstraint<T>>
447 where
448 Self: DefaultOnlyOnce,
449 {
450 And(self, default(t))
451 }
452 fn check_if_null(self) -> And<Self, CheckIfNull>
453 where
454 Self: CheckIfNullOnlyOnce,
455 {
456 And(self, check_if_null())
457 }
458 }
459
460 impl<T: IsConstraint> ConstraintExtention for T {}
461
462 pub fn check_if_null() -> CheckIfNull {
463 CheckIfNull
464 }
465
466 use super::*;
467 pub fn not_null() -> NotNull {
468 super::NotNull
469 }
470 pub fn default<T>(t: T) -> DefaultConstraint<T> {
471 super::DefaultConstraint(t)
472 }
473 pub fn primary_key() -> DefaultPrimaryKey {
474 DefaultPrimaryKey
475 }
476 }
477
478 pub struct And<T1, T2>(T1, T2);
479
480 impl<S, Q: Query<S>, Ty, T1, T2> Constraints<S, Q, Ty>
481 for And<T1, T2>
482 where
483 T1: Constraints<S, Q, Ty>,
484 T2: Constraints<S, Q, Ty>,
485 {
486 fn constraint(
487 self,
488 ctx1: &mut Q::Context1,
489 ) -> impl FnOnce(&mut Q::Context2, &mut String)
490 where
491 Self: Sized,
492 {
493 let ctx_u1 = unsafe { &mut *(ctx1 as *mut _) };
494 let s1 = self.0.constraint(ctx_u1);
495 let s2 = self.1.constraint(ctx1);
497 |ctx, str| {
498 s1(ctx, str);
499 let mut str_inner = String::new();
500 s2(ctx, &mut str_inner);
501
502 if str_inner.is_empty().not() {
503 str.push(' ');
504 str.push_str(&str_inner);
505 }
506 }
507 }
508 }
509}
510
511pub mod exports {
512 pub use super::foreign_key::Fk;
513}