1use {
2 self::{
3 graph::{
4 constraint::NodeConstraint_,
5 field::NodeField_,
6 index::NodeIndex_,
7 table::NodeTable_,
8 utils::MigrateNode,
9 GraphId,
10 Node,
11 },
12 query::{
13 delete::Delete,
14 expr::Expr,
15 insert::{
16 Insert,
17 InsertConflict,
18 },
19 select::Select,
20 select_body::{
21 Join,
22 JoinSource,
23 NamedSelectSource,
24 Order,
25 Returning,
26 },
27 update::Update,
28 utils::{
29 QueryBody,
30 SqliteQueryCtx,
31 },
32 },
33 schema::{
34 constraint::{
35 Constraint,
36 ConstraintType,
37 Constraint_,
38 SchemaConstraintId,
39 },
40 field::{
41 Field,
42 FieldType,
43 Field_,
44 SchemaFieldId,
45 },
46 index::{
47 Index,
48 Index_,
49 SchemaIndexId,
50 },
51 table::{
52 SchemaTableId,
53 Table,
54 Table_,
55 },
56 },
57 types::{
58 SimpleSimpleType,
59 SimpleType,
60 },
61 },
62 crate::{
63 sqlite::{
64 graph::utils::SqliteMigrateCtx,
65 query::expr::Binding,
66 types::{
67 to_rust_types,
68 Type,
69 },
70 },
71 utils::{
72 sanitize_ident,
73 Errs,
74 },
75 },
76 proc_macro2::{
77 Ident,
78 TokenStream,
79 },
80 query::{
81 select_body::{
82 SelectBody,
83 SelectJunction,
84 },
85 utils::With,
86 },
87 quote::{
88 format_ident,
89 quote,
90 ToTokens,
91 },
92 std::{
93 collections::{
94 BTreeMap,
95 HashMap,
96 HashSet,
97 },
98 fs,
99 path::Path,
100 rc::Rc,
101 },
102};
103
104pub mod types;
105pub mod query;
106pub mod schema;
107pub mod graph;
108
109#[derive(Debug, Clone)]
113pub enum QueryResCount {
114 None,
115 MaybeOne,
116 One,
117 Many,
118}
119
120pub struct InsertBuilder {
123 pub q: Insert,
124}
125
126impl InsertBuilder {
127 pub fn with(mut self, w: With) -> Self {
129 self.q.with = Some(w);
130 return self;
131 }
132
133 pub fn on_conflict(mut self, v: InsertConflict) -> Self {
134 self.q.on_conflict = Some(v);
135 self
136 }
137
138 pub fn return_(mut self, v: Expr) -> Self {
139 self.q.returning.push(Returning {
140 e: v,
141 rename: None,
142 });
143 self
144 }
145
146 pub fn return_named(mut self, name: impl ToString, v: Expr) -> Self {
147 self.q.returning.push(Returning {
148 e: v,
149 rename: Some(name.to_string()),
150 });
151 self
152 }
153
154 pub fn return_field(mut self, f: &Field) -> Self {
155 self.q.returning.push(Returning {
156 e: Expr::Binding(Binding::field(f)),
157 rename: None,
158 });
159 self
160 }
161
162 pub fn return_fields(mut self, f: &[&Field]) -> Self {
163 for f in f {
164 self.q.returning.push(Returning {
165 e: Expr::Binding(Binding::field(f)),
166 rename: None,
167 });
168 }
169 self
170 }
171
172 pub fn returns_from_iter(mut self, f: impl Iterator<Item = Returning>) -> Self {
173 self.q.returning.extend(f);
174 self
175 }
176
177 pub fn build_migration(self) -> Insert {
179 self.q
180 }
181
182 pub fn build_query(self, name: impl ToString, res_count: QueryResCount) -> Query {
188 Query {
189 name: name.to_string(),
190 body: Box::new(self.q),
191 res_count: res_count,
192 res_name: None,
193 }
194 }
195
196 pub fn build_query_named_res(self, name: impl ToString, res_count: QueryResCount, res_name: impl ToString) -> Query {
199 Query {
200 name: name.to_string(),
201 body: Box::new(self.q),
202 res_count: res_count,
203 res_name: Some(res_name.to_string()),
204 }
205 }
206}
207
208pub struct SelectBuilder {
211 pub q: Select,
212}
213
214impl SelectBuilder {
215 pub fn distinct(mut self) -> Self {
216 self.q.body.distinct = true;
217 return self;
218 }
219
220 pub fn with(mut self, w: With) -> Self {
222 self.q.with = Some(w);
223 return self;
224 }
225
226 pub fn return_(mut self, v: Expr) -> Self {
227 self.q.body.returning.push(Returning {
228 e: v,
229 rename: None,
230 });
231 self
232 }
233
234 pub fn return_named(mut self, name: impl ToString, v: Expr) -> Self {
235 self.q.body.returning.push(Returning {
236 e: v,
237 rename: Some(name.to_string()),
238 });
239 self
240 }
241
242 pub fn return_field(mut self, f: &Field) -> Self {
243 self.q.body.returning.push(Returning {
244 e: Expr::Binding(Binding::field(f)),
245 rename: None,
246 });
247 self
248 }
249
250 pub fn return_fields(mut self, f: &[&Field]) -> Self {
251 for f in f {
252 self.q.body.returning.push(Returning {
253 e: Expr::Binding(Binding::field(f)),
254 rename: None,
255 });
256 }
257 self
258 }
259
260 pub fn returns_from_iter(mut self, f: impl Iterator<Item = Returning>) -> Self {
261 self.q.body.returning.extend(f);
262 self
263 }
264
265 pub fn join(mut self, join: Join) -> Self {
266 self.q.body.join.push(join);
267 self
268 }
269
270 pub fn where_(mut self, predicate: Expr) -> Self {
271 self.q.body.where_ = Some(predicate);
272 self
273 }
274
275 pub fn group(mut self, clauses: Vec<Expr>) -> Self {
276 self.q.body.group = clauses;
277 self
278 }
279
280 pub fn order(mut self, expr: Expr, order: Order) -> Self {
281 self.q.body.order.push((expr, order));
282 self
283 }
284
285 pub fn order_from_iter(mut self, clauses: impl Iterator<Item = (Expr, Order)>) -> Self {
286 self.q.body.order.extend(clauses);
287 self
288 }
289
290 pub fn limit(mut self, v: Expr) -> Self {
292 self.q.body.limit = Some(v);
293 self
294 }
295
296 pub fn junction(mut self, j: SelectJunction) -> Self {
298 self.q.body_junctions.push(j);
299 return self;
300 }
301
302 pub fn build_migration(self) -> Select {
304 self.q
305 }
306
307 pub fn build_query(self, name: impl ToString, res_count: QueryResCount) -> Query {
313 Query {
314 name: name.to_string(),
315 body: Box::new(self.q),
316 res_count: res_count,
317 res_name: None,
318 }
319 }
320
321 pub fn build_query_named_res(self, name: impl ToString, res_count: QueryResCount, res_name: impl ToString) -> Query {
324 Query {
325 name: name.to_string(),
326 body: Box::new(self.q),
327 res_count: res_count,
328 res_name: Some(res_name.to_string()),
329 }
330 }
331}
332
333pub struct SelectBodyBuilder {
336 pub q: SelectBody,
337}
338
339impl SelectBodyBuilder {
340 pub fn distinct(mut self) -> Self {
341 self.q.distinct = true;
342 return self;
343 }
344
345 pub fn return_(mut self, v: Expr) -> Self {
346 self.q.returning.push(Returning {
347 e: v,
348 rename: None,
349 });
350 self
351 }
352
353 pub fn return_named(mut self, name: impl ToString, v: Expr) -> Self {
354 self.q.returning.push(Returning {
355 e: v,
356 rename: Some(name.to_string()),
357 });
358 self
359 }
360
361 pub fn return_field(mut self, f: &Field) -> Self {
362 self.q.returning.push(Returning {
363 e: Expr::Binding(Binding::field(f)),
364 rename: None,
365 });
366 self
367 }
368
369 pub fn return_fields(mut self, f: &[&Field]) -> Self {
370 for f in f {
371 self.q.returning.push(Returning {
372 e: Expr::Binding(Binding::field(f)),
373 rename: None,
374 });
375 }
376 self
377 }
378
379 pub fn returns_from_iter(mut self, f: impl Iterator<Item = Returning>) -> Self {
380 self.q.returning.extend(f);
381 self
382 }
383
384 pub fn join(mut self, join: Join) -> Self {
385 self.q.join.push(join);
386 self
387 }
388
389 pub fn where_(mut self, predicate: Expr) -> Self {
390 self.q.where_ = Some(predicate);
391 self
392 }
393
394 pub fn group(mut self, clauses: Vec<Expr>) -> Self {
395 self.q.group = clauses;
396 self
397 }
398
399 pub fn order(mut self, expr: Expr, order: Order) -> Self {
400 self.q.order.push((expr, order));
401 self
402 }
403
404 pub fn order_from_iter(mut self, clauses: impl Iterator<Item = (Expr, Order)>) -> Self {
405 self.q.order.extend(clauses);
406 self
407 }
408
409 pub fn limit(mut self, v: Expr) -> Self {
411 self.q.limit = Some(v);
412 self
413 }
414
415 pub fn build(self) -> SelectBody {
417 return self.q;
418 }
419}
420
421pub struct UpdateBuilder {
424 pub q: Update,
425}
426
427impl UpdateBuilder {
428 pub fn with(mut self, w: With) -> Self {
430 self.q.with = Some(w);
431 return self;
432 }
433
434 pub fn where_(mut self, v: Expr) -> Self {
435 self.q.where_ = Some(v);
436 self
437 }
438
439 pub fn return_(mut self, v: Expr) -> Self {
440 self.q.returning.push(Returning {
441 e: v,
442 rename: None,
443 });
444 self
445 }
446
447 pub fn return_named(mut self, name: impl ToString, v: Expr) -> Self {
448 self.q.returning.push(Returning {
449 e: v,
450 rename: Some(name.to_string()),
451 });
452 self
453 }
454
455 pub fn return_field(mut self, f: &Field) -> Self {
456 self.q.returning.push(Returning {
457 e: Expr::Binding(Binding::field(f)),
458 rename: None,
459 });
460 self
461 }
462
463 pub fn return_fields(mut self, f: &[&Field]) -> Self {
464 for f in f {
465 self.q.returning.push(Returning {
466 e: Expr::Binding(Binding::field(f)),
467 rename: None,
468 });
469 }
470 self
471 }
472
473 pub fn returns_from_iter(mut self, f: impl Iterator<Item = Returning>) -> Self {
474 self.q.returning.extend(f);
475 self
476 }
477
478 pub fn build_migration(self) -> Update {
480 self.q
481 }
482
483 pub fn build_query(self, name: impl ToString, res_count: QueryResCount) -> Query {
489 Query {
490 name: name.to_string(),
491 body: Box::new(self.q),
492 res_count: res_count,
493 res_name: None,
494 }
495 }
496
497 pub fn build_query_named_res(self, name: impl ToString, res_count: QueryResCount, res_name: impl ToString) -> Query {
500 Query {
501 name: name.to_string(),
502 body: Box::new(self.q),
503 res_count: res_count,
504 res_name: Some(res_name.to_string()),
505 }
506 }
507}
508
509pub struct DeleteBuilder {
512 pub q: Delete,
513}
514
515impl DeleteBuilder {
516 pub fn with(mut self, w: With) -> Self {
518 self.q.with = Some(w);
519 return self;
520 }
521
522 pub fn where_(mut self, v: Expr) -> Self {
523 self.q.where_ = Some(v);
524 self
525 }
526
527 pub fn return_(mut self, v: Expr) -> Self {
528 self.q.returning.push(Returning {
529 e: v,
530 rename: None,
531 });
532 self
533 }
534
535 pub fn return_named(mut self, name: impl ToString, v: Expr) -> Self {
536 self.q.returning.push(Returning {
537 e: v,
538 rename: Some(name.to_string()),
539 });
540 self
541 }
542
543 pub fn return_field(mut self, f: &Field) -> Self {
544 self.q.returning.push(Returning {
545 e: Expr::Binding(Binding::field(f)),
546 rename: None,
547 });
548 self
549 }
550
551 pub fn return_fields(mut self, f: &[&Field]) -> Self {
552 for f in f {
553 self.q.returning.push(Returning {
554 e: Expr::Binding(Binding::field(f)),
555 rename: None,
556 });
557 }
558 self
559 }
560
561 pub fn returns_from_iter(mut self, f: impl Iterator<Item = Returning>) -> Self {
562 self.q.returning.extend(f);
563 self
564 }
565
566 pub fn build_migration(self) -> Delete {
568 self.q
569 }
570
571 pub fn build_query(self, name: impl ToString, res_count: QueryResCount) -> Query {
577 Query {
578 name: name.to_string(),
579 body: Box::new(self.q),
580 res_count: res_count,
581 res_name: None,
582 }
583 }
584
585 pub fn build_query_named_res(self, name: impl ToString, res_count: QueryResCount, res_name: impl ToString) -> Query {
588 Query {
589 name: name.to_string(),
590 body: Box::new(self.q),
591 res_count: res_count,
592 res_name: Some(res_name.to_string()),
593 }
594 }
595}
596
597pub struct Query {
601 pub name: String,
602 pub body: Box<dyn QueryBody>,
603 pub res_count: QueryResCount,
604 pub res_name: Option<String>,
605}
606
607pub fn new_insert(table: &Table, values: Vec<(Field, Expr)>) -> InsertBuilder {
613 let mut unique = HashSet::new();
614 for v in &values {
615 if !unique.insert(&v.0) {
616 panic!("Duplicate field {} in insert", v.0);
617 }
618 }
619 InsertBuilder { q: Insert {
620 with: None,
621 table: table.clone(),
622 values: values,
623 on_conflict: None,
624 returning: vec![],
625 } }
626}
627
628pub fn new_select(table: &Table) -> SelectBuilder {
630 SelectBuilder { q: Select {
631 with: None,
632 body: SelectBody {
633 distinct: false,
634 table: NamedSelectSource {
635 source: JoinSource::Table(table.clone()),
636 alias: None,
637 },
638 returning: vec![],
639 join: vec![],
640 where_: None,
641 group: vec![],
642 order: vec![],
643 limit: None,
644 },
645 body_junctions: vec![],
646 } }
647}
648
649pub fn new_select_from(source: NamedSelectSource) -> SelectBuilder {
652 SelectBuilder { q: Select {
653 with: None,
654 body: SelectBody {
655 distinct: false,
656 table: source,
657 returning: vec![],
658 join: vec![],
659 where_: None,
660 group: vec![],
661 order: vec![],
662 limit: None,
663 },
664 body_junctions: vec![],
665 } }
666}
667
668pub fn new_select_body(table: &Table) -> SelectBodyBuilder {
670 SelectBodyBuilder { q: SelectBody {
671 distinct: false,
672 table: NamedSelectSource {
673 source: JoinSource::Table(table.clone()),
674 alias: None,
675 },
676 returning: vec![],
677 join: vec![],
678 where_: None,
679 group: vec![],
680 order: vec![],
681 limit: None,
682 } }
683}
684
685pub fn new_update(table: &Table, values: Vec<(Field, Expr)>) -> UpdateBuilder {
691 let mut unique = HashSet::new();
692 for v in &values {
693 if !unique.insert(&v.0) {
694 panic!("Duplicate field {} in update", v.0);
695 }
696 }
697 UpdateBuilder { q: Update {
698 with: None,
699 table: table.clone(),
700 values: values,
701 where_: None,
702 returning: vec![],
703 } }
704}
705
706pub fn new_delete(table: &Table) -> DeleteBuilder {
712 DeleteBuilder { q: Delete {
713 with: None,
714 table: table.clone(),
715 returning: vec![],
716 where_: None,
717 } }
718}
719
720#[derive(Default)]
722pub struct Version {
723 schema: BTreeMap<GraphId, MigrateNode>,
724 pre_migration: Vec<Box<dyn QueryBody>>,
725 post_migration: Vec<Box<dyn QueryBody>>,
726}
727
728impl Version {
729 pub fn table(&mut self, schema_id: &str, id: &str) -> Table {
731 let out = Table(Rc::new(Table_ {
732 schema_id: SchemaTableId(schema_id.into()),
733 id: id.into(),
734 }));
735 if self.schema.insert(GraphId::Table(out.schema_id.clone()), MigrateNode::new(vec![], Node::table(NodeTable_ {
736 def: out.clone(),
737 fields: vec![],
738 constraints: vec![],
739 }))).is_some() {
740 panic!("Table with schema id {} already exists", out.schema_id);
741 };
742 out
743 }
744
745 pub fn pre_migration(&mut self, q: impl QueryBody + 'static) {
751 self.pre_migration.push(Box::new(q));
752 }
753
754 pub fn post_migration(&mut self, q: impl QueryBody + 'static) {
757 self.post_migration.push(Box::new(q));
758 }
759}
760
761impl Table {
762 pub fn field(&self, v: &mut Version, schema_id: impl ToString, id: impl ToString, type_: FieldType) -> Field {
764 let out = Field(Rc::new(Field_ {
765 table: self.clone(),
766 schema_id: SchemaFieldId(schema_id.to_string()),
767 id: id.to_string(),
768 type_: type_,
769 }));
770 if &out.id == "rowid" {
771 panic!("Use rowid_field to define a rowid field");
772 }
773 if v
774 .schema
775 .insert(
776 GraphId::Field(self.schema_id.clone(), out.schema_id.clone()),
777 MigrateNode::new(
778 vec![GraphId::Table(self.schema_id.clone())],
779 Node::field(NodeField_ { def: out.clone() }),
780 ),
781 )
782 .is_some() {
783 panic!("Field with schema id {}.{} already exists", self.schema_id, out.schema_id);
784 };
785 out
786 }
787
788 pub fn rowid_field(&self, v: &mut Version, custom_type: Option<String>) -> Field {
789 let out = Field(Rc::new(Field_ {
790 table: self.clone(),
791 schema_id: SchemaFieldId("rowid".into()),
792 id: "rowid".into(),
793 type_: FieldType {
794 type_: Type {
795 type_: SimpleType {
796 type_: SimpleSimpleType::I64,
797 custom: custom_type,
798 },
799 opt: false,
800 array: false,
801 },
802 migration_default: None,
803 },
804 }));
805 if v
806 .schema
807 .insert(
808 GraphId::Field(self.schema_id.clone(), out.schema_id.clone()),
809 MigrateNode::new(
810 vec![GraphId::Table(self.schema_id.clone())],
811 Node::field(NodeField_ { def: out.clone() }),
812 ),
813 )
814 .is_some() {
815 panic!("Field with schema id {}.{} already exists", self.schema_id, out.schema_id);
816 };
817 out
818 }
819
820 pub fn constraint(&self, v: &mut Version, schema_id: impl ToString, id: impl ToString, type_: ConstraintType) {
822 let out = Constraint(Rc::new(Constraint_ {
823 table: self.clone(),
824 schema_id: SchemaConstraintId(schema_id.to_string()),
825 id: id.to_string(),
826 type_: type_,
827 }));
828 let mut deps = vec![GraphId::Table(self.schema_id.clone())];
829 match &out.type_ {
830 ConstraintType::PrimaryKey(x) => {
831 for f in &x.fields {
832 if &f.table != self {
833 panic!(
834 "Field {} in primary key constraint {} is in table {}, but constraint is in table {}",
835 f,
836 out.id,
837 f.table,
838 self
839 );
840 }
841 deps.push(GraphId::Field(self.schema_id.clone(), f.schema_id.clone()));
842 }
843 },
844 ConstraintType::ForeignKey(x) => {
845 let mut last_foreign_table: Option<Field> = None;
846 for f in &x.fields {
847 if &f.0.table != self {
848 panic!(
849 "Local field {} in foreign key constraint {} is in table {}, but constraint is in table {}",
850 f.0,
851 out.id,
852 f.0.table,
853 self
854 );
855 }
856 deps.push(GraphId::Field(f.0.table.schema_id.clone(), f.0.schema_id.clone()));
857 if let Some(t) = last_foreign_table.take() {
858 if t.table != f.1.table {
859 panic!(
860 "Foreign field {} in foreign key constraint {} is in table {}, but constraint is in table {}",
861 f.1,
862 out.id,
863 f.1.table,
864 self
865 );
866 }
867 }
868 last_foreign_table = Some(f.1.clone());
869 deps.push(GraphId::Field(f.1.table.schema_id.clone(), f.1.schema_id.clone()));
870 }
871 },
872 }
873 if v
874 .schema
875 .insert(
876 GraphId::Constraint(self.schema_id.clone(), out.schema_id.clone()),
877 MigrateNode::new(deps, Node::table_constraint(NodeConstraint_ { def: out.clone() })),
878 )
879 .is_some() {
880 panic!("Constraint with schema id {}.{} aleady exists", self.schema_id, out.schema_id)
881 };
882 }
883
884 pub fn index(&self, schema_id: impl ToString, id: impl ToString, fields: &[&Field]) -> IndexBuilder {
886 IndexBuilder {
887 table: self.clone(),
888 schema_id: schema_id.to_string(),
889 id: id.to_string(),
890 fields: fields.iter().map(|e| (*e).clone()).collect(),
891 unique: false,
892 }
893 }
894}
895
896pub struct IndexBuilder {
897 table: Table,
898 schema_id: String,
899 id: String,
900 fields: Vec<Field>,
901 unique: bool,
902}
903
904impl IndexBuilder {
905 pub fn unique(mut self) -> Self {
906 self.unique = true;
907 self
908 }
909
910 pub fn build(self, v: &mut Version) -> Index {
911 let mut deps = vec![GraphId::Table(self.table.schema_id.clone())];
912 for field in &self.fields {
913 deps.push(GraphId::Field(field.table.schema_id.clone(), field.schema_id.clone()));
914 }
915 let out = Index(Rc::new(Index_ {
916 table: self.table,
917 schema_id: SchemaIndexId(self.schema_id),
918 id: self.id,
919 fields: self.fields,
920 unique: self.unique,
921 }));
922 if v
923 .schema
924 .insert(
925 GraphId::Index(out.table.schema_id.clone(), out.schema_id.clone()),
926 MigrateNode::new(deps, Node::table_index(NodeIndex_ { def: out.clone() })),
927 )
928 .is_some() {
929 panic!("Index with schema id {}.{} already exists", out.table.schema_id, out.schema_id);
930 };
931 out
932 }
933}
934
935pub fn generate(output: &Path, versions: Vec<(usize, Version)>, queries: Vec<Query>) -> Result<(), Vec<String>> {
955 {
956 let mut prev_relations: HashMap<&String, String> = HashMap::new();
957 let mut prev_fields = HashMap::new();
958 let mut prev_constraints = HashMap::new();
959 for (v_i, v) in &versions {
960 let mut relations = HashMap::new();
961 let mut fields = HashMap::new();
962 let mut constraints = HashMap::new();
963 for n in v.schema.values() {
964 match &n.body {
965 Node::Table(t) => {
966 let id = &t.def.id;
967 let comp_id = format!("table {}", t.def.schema_id);
968 if relations.insert(id, comp_id.clone()).is_some() {
969 panic!("Duplicate table id {} -- {}", t.def.id, t.def);
970 }
971 if let Some(schema_id) = prev_relations.get(id) {
972 if schema_id != &comp_id {
973 panic!(
974 "Table {} id in version {} swapped with another relation since previous version; unsupported",
975 t.def,
976 v_i
977 );
978 }
979 }
980 },
981 Node::Field(f) => {
982 let id = (&f.def.table.schema_id, &f.def.id);
983 if fields.insert(id, f.def.schema_id.clone()).is_some() {
984 panic!("Duplicate field id {} -- {}", f.def.id, f.def);
985 }
986 if let Some(schema_id) = prev_fields.get(&id) {
987 if schema_id != &f.def.schema_id {
988 panic!(
989 "Field {} id in version {} swapped with another field since previous version; unsupported",
990 f.def,
991 v_i
992 );
993 }
994 }
995 },
996 Node::Constraint(c) => {
997 let id = (&c.def.table.schema_id, &c.def.id);
998 if constraints.insert(id, c.def.schema_id.clone()).is_some() {
999 panic!("Duplicate constraint id {} -- {}", c.def.id, c.def);
1000 }
1001 if let Some(schema_id) = prev_constraints.get(&id) {
1002 if schema_id != &c.def.schema_id {
1003 panic!(
1004 "Constraint {} id in version {} swapped with another constraint since previous version; unsupported",
1005 c.def,
1006 v_i
1007 );
1008 }
1009 }
1010 },
1011 Node::Index(i) => {
1012 let id = &i.def.id;
1013 let comp_id = format!("index {}", i.def.schema_id);
1014 if relations.insert(id, comp_id.clone()).is_some() {
1015 panic!("Duplicate index id {} -- {}", i.def.id, i.def);
1016 }
1017 if let Some(schema_id) = prev_relations.get(&id) {
1018 if schema_id != &comp_id {
1019 panic!(
1020 "Index {} id in version {} swapped with another relation since previous version; unsupported",
1021 i.def,
1022 v_i
1023 );
1024 }
1025 }
1026 },
1027 }
1028 }
1029 prev_relations = relations;
1030 prev_fields = fields;
1031 prev_constraints = constraints;
1032 }
1033 }
1034 let mut errs = Errs::new();
1035 let mut migrations = vec![];
1036 let mut prev_version: Option<Version> = None;
1037 let mut prev_version_i: Option<i64> = None;
1038 let mut field_lookup = HashMap::new();
1039 for (version_i, version) in versions {
1040 let path = rpds::vector![format!("Migration to {}", version_i)];
1041 let mut migration = vec![];
1042
1043 fn do_migration_query(
1044 errs: &mut Errs,
1045 path: &rpds::Vector<String>,
1046 migration: &mut Vec<TokenStream>,
1047 field_lookup: &HashMap<Table, HashSet<Field>>,
1048 q: &dyn QueryBody,
1049 ) {
1050 let mut qctx = SqliteQueryCtx::new(errs.clone(), field_lookup.clone());
1051 let e_res = q.build(&mut qctx, path, QueryResCount::None);
1052 if !qctx.rust_args.is_empty() {
1053 qctx.errs.err(path, format!("Migration statements can't receive arguments"));
1054 }
1055 let statement = e_res.1.to_string();
1056 let args = qctx.query_args;
1057 migration.push(quote!{
1058 {
1059 let query = #statement;
1060 txn.execute(query, rusqlite::params![#(#args,) *]).to_good_error_query(query)?
1061 };
1062 });
1063 }
1064
1065 for (i, q) in version.pre_migration.iter().enumerate() {
1067 do_migration_query(
1068 &mut errs,
1069 &path.push_back(format!("Pre-migration statement {}", i)),
1070 &mut migration,
1071 &field_lookup,
1072 q.as_ref(),
1073 );
1074 }
1075
1076 field_lookup.clear();
1078 let version_i = version_i as i64;
1079 if let Some(i) = prev_version_i {
1080 if version_i != i as i64 + 1 {
1081 errs.err(
1082 &path,
1083 format!(
1084 "Version numbers are not consecutive ({} to {}) - was an intermediate version deleted?",
1085 i,
1086 version_i
1087 ),
1088 );
1089 }
1090 }
1091
1092 for v in version.schema.values() {
1094 match &v.body {
1095 Node::Field(f) => {
1096 match field_lookup.entry(f.def.table.clone()) {
1097 std::collections::hash_map::Entry::Occupied(_) => { },
1098 std::collections::hash_map::Entry::Vacant(e) => {
1099 e.insert(HashSet::new());
1100 },
1101 };
1102 let table = field_lookup.get_mut(&f.def.table).unwrap();
1103 table.insert(f.def.clone());
1104 },
1105 _ => { },
1106 };
1107 }
1108
1109 {
1111 let mut state = SqliteMigrateCtx::new(errs.clone());
1112 crate::graphmigrate::migrate(&mut state, prev_version.take().map(|s| s.schema), &version.schema);
1113 for statement in &state.statements {
1114 migration.push(quote!{
1115 {
1116 let query = #statement;
1117 txn.execute(query, ()).to_good_error_query(query)?
1118 };
1119 });
1120 }
1121 }
1122
1123 for (i, q) in version.post_migration.iter().enumerate() {
1125 do_migration_query(
1126 &mut errs,
1127 &path.push_back(format!("Post-migration statement {}", i)),
1128 &mut migration,
1129 &field_lookup,
1130 q.as_ref(),
1131 );
1132 }
1133
1134 migrations.push(quote!{
1136 if version < #version_i {
1137 #(#migration) *
1138 }
1139 });
1140
1141 prev_version = Some(version);
1143 prev_version_i = Some(version_i);
1144 }
1145
1146 let mut db_others = Vec::new();
1148 {
1149 let mut res_type_idents: HashMap<String, Ident> = HashMap::new();
1150 for q in queries {
1151 let path = rpds::vector![format!("Query {}", q.name)];
1152 let mut ctx = SqliteQueryCtx::new(errs.clone(), field_lookup.clone());
1153 let res = QueryBody::build(q.body.as_ref(), &mut ctx, &path, q.res_count.clone());
1154 let ident = format_ident!("{}", q.name);
1155 let q_text = res.1.to_string();
1156 let args = ctx.rust_args.split_off(0);
1157 let args_forward = ctx.query_args.split_off(0);
1158 drop(ctx);
1159 let (res_ident, res_def, unforward_res) = {
1160 fn convert_one_res(
1161 errs: &mut Errs,
1162 path: &rpds::Vector<String>,
1163 i: usize,
1164 k: &Binding,
1165 v: &Type,
1166 ) -> Option<(Ident, TokenStream, TokenStream)> {
1167 if k.id.is_empty() {
1168 errs.err(
1169 path,
1170 format!("Result element {} has no name; name it using `rename` if this is intentional", i),
1171 );
1172 return None;
1173 }
1174 let rust_types = to_rust_types(&v.type_.type_);
1175 let custom_trait_ident = rust_types.custom_trait;
1176 let mut ident = rust_types.ret_type;
1177 if v.opt {
1178 ident = quote!(Option < #ident >);
1179 }
1180 let mut unforward = match v.type_.type_ {
1181 types::SimpleSimpleType::U32 |
1182 types::SimpleSimpleType::I32 |
1183 types::SimpleSimpleType::I64 |
1184 types::SimpleSimpleType::F32 |
1185 types::SimpleSimpleType::F64 |
1186 types::SimpleSimpleType::Bool |
1187 types::SimpleSimpleType::String |
1188 types::SimpleSimpleType::Bytes => {
1189 quote!{
1190 let x: #ident = r.get(#i).to_good_error(|| format!("Getting result {}", #i)) ?;
1191 }
1192 },
1193 #[cfg(feature = "chrono")]
1194 types::SimpleSimpleType::UtcTimeSChrono => {
1195 quote!{
1196 let x: i64 = r.get(#i).to_good_error(|| format!("Getting result {}", #i)) ?;
1197 let x = chrono::TimeZone::timestamp_opt(&chrono::Utc, x, 0).unwrap();
1198 }
1199 },
1200 #[cfg(feature = "chrono")]
1201 types::SimpleSimpleType::UtcTimeMsChrono => {
1202 quote!{
1203 let x: String = r.get(#i).to_good_error(|| format!("Getting result {}", #i)) ?;
1204 let x =
1205 chrono::DateTime::<chrono::Utc>::from(
1206 chrono::DateTime::<chrono::FixedOffset>::parse_from_rfc3339(
1207 &x,
1208 ).to_good_error(|| format!("Getting result {}", #i))?,
1209 );
1210 }
1211 },
1212 #[cfg(feature = "chrono")]
1213 types::SimpleSimpleType::FixedOffsetTimeMsChrono => {
1214 quote!{
1215 let x: String = r.get(#i).to_good_error(|| format!("Getting result {}", #i)) ?;
1216 let x =
1217 chrono::DateTime::<chrono::FixedOffset>::from(
1218 chrono::DateTime::<chrono::FixedOffset>::parse_from_rfc3339(
1219 &x,
1220 ).to_good_error(|| format!("Getting result {}", #i))?,
1221 );
1222 }
1223 },
1224 #[cfg(feature = "jiff")]
1225 types::SimpleSimpleType::UtcTimeSJiff => {
1226 quote!{
1227 let x: i64 = r.get(#i).to_good_error(|| format!("Getting result {}", #i)) ?;
1228 let x = jiff::Timestamp::from_second(x).unwrap();
1229 }
1230 },
1231 #[cfg(feature = "jiff")]
1232 types::SimpleSimpleType::UtcTimeMsJiff => {
1233 quote!{
1234 let x: String = r.get(#i).to_good_error(|| format!("Getting result {}", #i)) ?;
1235 let x =
1236 <jiff::Timestamp as std::str::FromStr>::from_str(
1237 &x,
1238 ).to_good_error(|| format!("Getting result {}", #i))?;
1239 }
1240 },
1241 };
1242 if let Some(custom) = &v.type_.custom {
1243 ident = match syn::parse_str::<syn::Path>(&custom) {
1244 Ok(i) => i.to_token_stream(),
1245 Err(e) => {
1246 errs.err(
1247 path,
1248 format!(
1249 "Couldn't parse provided custom type name [{}] as identifier path: {:?}",
1250 custom,
1251 e
1252 ),
1253 );
1254 return None;
1255 },
1256 };
1257 if v.opt {
1258 unforward = quote!{
1259 #unforward let x = if let Some(x) = x {
1260 Some(
1261 < #ident as #custom_trait_ident < #ident >>:: from_sql(
1262 x
1263 ).to_good_error(|| format!("Parsing result {}", #i)) ?
1264 )
1265 }
1266 else {
1267 None
1268 };
1269 };
1270 ident = quote!(Option < #ident >);
1271 } else {
1272 unforward = quote!{
1273 #unforward let x =< #ident as #custom_trait_ident < #ident >>:: from_sql(
1274 x
1275 ).to_good_error(|| format!("Parsing result {}", #i)) ?;
1276 };
1277 }
1278 }
1279 return Some((format_ident!("{}", sanitize_ident(&k.id).1), ident, quote!({
1280 #unforward x
1281 })));
1282 }
1283
1284 if res.0.0.len() == 1 {
1285 let e = &res.0.0[0];
1286 let (_, type_ident, unforward) = match convert_one_res(&mut errs, &path, 0, &e.0, &e.1) {
1287 None => {
1288 continue;
1289 },
1290 Some(x) => x,
1291 };
1292 (type_ident, None, unforward)
1293 } else {
1294 let mut fields = vec![];
1295 let mut unforward_fields = vec![];
1296 for (i, (k, v)) in res.0.0.into_iter().enumerate() {
1297 let (k_ident, type_ident, unforward) = match convert_one_res(&mut errs, &path, i, &k, &v) {
1298 Some(x) => x,
1299 None => continue,
1300 };
1301 fields.push(quote!{
1302 pub #k_ident: #type_ident
1303 });
1304 unforward_fields.push(quote!{
1305 #k_ident: #unforward
1306 });
1307 }
1308 let body = quote!({
1309 #(#fields,) *
1310 });
1311 let res_type_count = res_type_idents.len();
1312 let (res_ident, res_def) = match res_type_idents.entry(body.to_string()) {
1313 std::collections::hash_map::Entry::Occupied(e) => {
1314 (e.get().clone(), None)
1315 },
1316 std::collections::hash_map::Entry::Vacant(e) => {
1317 let ident = if let Some(name) = q.res_name {
1318 format_ident!("{}", name)
1319 } else {
1320 format_ident!("DbRes{}", res_type_count)
1321 };
1322 e.insert(ident.clone());
1323 let res_def = quote!(pub struct #ident #body);
1324 (ident, Some(res_def))
1325 },
1326 };
1327 let unforward = quote!(#res_ident {
1328 #(#unforward_fields,) *
1329 });
1330 (res_ident.to_token_stream(), res_def, unforward)
1331 }
1332 };
1333 let db_arg = quote!(db:& rusqlite:: Connection);
1334 match q.res_count {
1335 QueryResCount::None => {
1336 db_others.push(quote!{
1337 pub fn #ident(#db_arg, #(#args,) *) -> Result <(),
1338 GoodError > {
1339 let query = #q_text;
1340 db.execute(query, rusqlite::params![#(#args_forward,) *]).to_good_error_query(query)?;
1341 Ok(())
1342 }
1343 });
1344 },
1345 QueryResCount::MaybeOne => {
1346 if let Some(res_def) = res_def {
1347 db_others.push(res_def);
1348 }
1349 db_others.push(quote!{
1350 pub fn #ident(#db_arg, #(#args,) *) -> Result < Option < #res_ident >,
1351 GoodError > {
1352 let query = #q_text;
1353 let mut stmt = db.prepare(query).to_good_error_query(query)?;
1354 let mut rows =
1355 stmt.query(rusqlite::params![#(#args_forward,) *]).to_good_error_query(query)?;
1356 let r = rows.next().to_good_error(|| format!("Getting row in query [{}]", query))?;
1357 if let Some(r) = r {
1358 return Ok(Some(#unforward_res));
1359 }
1360 Ok(None)
1361 }
1362 });
1363 },
1364 QueryResCount::One => {
1365 if let Some(res_def) = res_def {
1366 db_others.push(res_def);
1367 }
1368 db_others.push(quote!{
1369 pub fn #ident(#db_arg, #(#args,) *) -> Result < #res_ident,
1370 GoodError > {
1371 let query = #q_text;
1372 let mut stmt = db.prepare(query).to_good_error_query(query)?;
1373 let mut rows =
1374 stmt.query(rusqlite::params![#(#args_forward,) *]).to_good_error_query(query)?;
1375 let r =
1376 rows
1377 .next()
1378 .to_good_error(|| format!("Getting row in query [{}]", query))?
1379 .ok_or_else(
1380 || GoodError(
1381 format!(
1382 "Expected to return one row but returned no rows in query [{}]",
1383 query
1384 ),
1385 ),
1386 )?;
1387 Ok(#unforward_res)
1388 }
1389 });
1390 },
1391 QueryResCount::Many => {
1392 if let Some(res_def) = res_def {
1393 db_others.push(res_def);
1394 }
1395 db_others.push(quote!{
1396 pub fn #ident(#db_arg, #(#args,) *) -> Result < Vec < #res_ident >,
1397 GoodError > {
1398 let mut out = vec![];
1399 let query = #q_text;
1400 let mut stmt = db.prepare(query).to_good_error_query(query)?;
1401 let mut rows =
1402 stmt.query(rusqlite::params![#(#args_forward,) *]).to_good_error_query(query)?;
1403 while let Some(
1404 r
1405 ) = rows.next().to_good_error(|| format!("Getting row in query [{}]", query)) ? {
1406 out.push(#unforward_res);
1407 }
1408 Ok(out)
1409 }
1410 });
1411 },
1412 }
1413 }
1414 }
1415
1416 let last_version_i = prev_version_i.unwrap() as i64;
1418 let tokens = quote!{
1419 use good_ormning_runtime::GoodError;
1420 use good_ormning_runtime::ToGoodError;
1421 pub fn migrate(db:& mut rusqlite:: Connection) -> Result <(),
1422 GoodError > {
1423 rusqlite::vtab::array::load_module(
1424 &db,
1425 ).to_good_error(|| "Error loading array extension for array values".to_string())?;
1426 {
1427 let query =
1428 "create table if not exists __good_version (rid int primary key, version bigint not null, lock int not null);";
1429 db.execute(query, ()).to_good_error_query(query)?;
1430 }
1431 {
1432 let query =
1433 "insert into __good_version (rid, version, lock) values (0, -1, 0) on conflict do nothing;";
1434 db.execute(query, ()).to_good_error_query(query)?;
1435 }
1436 loop {
1437 let txn = db.transaction().to_good_error(|| "Starting transaction".to_string())?;
1438 match(|| {
1439 let query = "update __good_version set lock = 1 where rid = 0 and lock = 0 returning version";
1440 let mut stmt = txn.prepare(query).to_good_error_query(query)?;
1441 let mut rows = stmt.query(()).to_good_error_query(query)?;
1442 let version = match rows.next().to_good_error_query(query)? {
1443 Some(r) => {
1444 let ver: i64 = r.get(0usize).to_good_error_query(query)?;
1445 ver
1446 },
1447 None => return Ok(false),
1448 };
1449 drop(rows);
1450 stmt.finalize().to_good_error_query(query)?;
1451 if version > #last_version_i {
1452 return Err(
1453 GoodError(
1454 format!(
1455 "The latest known version is {}, but the schema is at unknown version {}",
1456 #last_version_i,
1457 version
1458 ),
1459 ),
1460 );
1461 }
1462 #(#migrations) * let query = "update __good_version set version = $1, lock = 0";
1463 txn.execute(query, rusqlite::params![#last_version_i]).to_good_error_query(query)?;
1464 let out: Result < bool,
1465 GoodError >= Ok(true);
1466 out
1467 })() {
1468 Err(e) => {
1469 match txn.rollback() {
1470 Err(e1) => {
1471 return Err(
1472 GoodError(
1473 format!(
1474 "{}\n\nRolling back the transaction due to the above also failed: {}",
1475 e,
1476 e1
1477 ),
1478 ),
1479 );
1480 },
1481 Ok(_) => {
1482 return Err(e);
1483 },
1484 };
1485 }
1486 Ok(migrated) => {
1487 match txn.commit() {
1488 Err(e) => {
1489 return Err(GoodError(format!("Error committing the migration transaction: {}", e)));
1490 },
1491 Ok(_) => {
1492 if migrated {
1493 return Ok(())
1494 } else {
1495 std::thread::sleep(std::time::Duration::from_millis(5 * 1000));
1496 }
1497 },
1498 };
1499 }
1500 }
1501 }
1502 }
1503 #(#db_others) *
1504 };
1505 if let Some(p) = output.parent() {
1506 if let Err(e) = fs::create_dir_all(&p) {
1507 errs.err(
1508 &rpds::vector![],
1509 format!("Error creating output parent directories {}: {:?}", p.to_string_lossy(), e),
1510 );
1511 }
1512 }
1513 match genemichaels_lib::format_str(&tokens.to_string(), &genemichaels_lib::FormatConfig::default()) {
1514 Ok(src) => {
1515 match fs::write(output, src.rendered.as_bytes()) {
1516 Ok(_) => { },
1517 Err(e) => errs.err(
1518 &rpds::vector![],
1519 format!("Failed to write generated code to {}: {:?}", output.to_string_lossy(), e),
1520 ),
1521 };
1522 },
1523 Err(e) => {
1524 errs.err(&rpds::vector![], format!("Error formatting generated code: {:?}\n{}", e, tokens));
1525 },
1526 };
1527 errs.raise()?;
1528 Ok(())
1529}
1530
1531#[cfg(test)]
1532mod test {
1533 use std::{
1534 path::PathBuf,
1535 str::FromStr,
1536 };
1537 use crate::sqlite::{
1538 new_select,
1539 QueryResCount,
1540 new_insert,
1541 };
1542 use super::{
1543 schema::field::{
1544 field_str,
1545 field_i32,
1546 },
1547 generate,
1548 Version,
1549 query::expr::Expr,
1550 };
1551
1552 #[test]
1553 #[should_panic]
1554 fn test_add_field_dup_bad() {
1555 generate(&PathBuf::from_str("/dev/null").unwrap(), vec![
1556 (0usize, {
1558 let mut v = Version::default();
1559 let bananna = v.table("zPAO2PJU4", "bananna");
1560 bananna.field(&mut v, "z437INV6D", "hizat", field_str().build());
1561 v
1562 }),
1563 (1usize, {
1564 let mut v = Version::default();
1565 let bananna = v.table("zQZQ8E2WD", "bananna");
1566 bananna.field(&mut v, "z437INV6D", "hizat", field_str().build());
1567 bananna.field(&mut v, "z437INV6D", "zomzom", field_i32().build());
1568 v
1569 })
1570 ], vec![]).unwrap();
1571 }
1572
1573 #[test]
1574 #[should_panic]
1575 fn test_add_table_dup_bad() {
1576 generate(&PathBuf::from_str("/dev/null").unwrap(), vec![
1577 (0usize, {
1579 let mut v = Version::default();
1580 let bananna = v.table("zSNS34DYI", "bananna");
1581 bananna.field(&mut v, "z437INV6D", "hizat", field_str().build());
1582 v
1583 }),
1584 (1usize, {
1585 let mut v = Version::default();
1586 let bananna = v.table("zSNS34DYI", "bananna");
1587 bananna.field(&mut v, "z437INV6D", "hizat", field_str().build());
1588 let bananna = v.table("zSNS34DYI", "bananna");
1589 bananna.field(&mut v, "z437INV6D", "hizat", field_str().build());
1590 v
1591 })
1592 ], vec![]).unwrap();
1593 }
1594
1595 #[test]
1596 fn test_res_count_none_bad() {
1597 let mut v = Version::default();
1598 let bananna = v.table("z5S18LWQE", "bananna");
1599 let hizat = bananna.field(&mut v, "z437INV6D", "hizat", field_str().build());
1600 assert!(
1601 generate(
1602 &PathBuf::from_str("/dev/null").unwrap(),
1603 vec![(0usize, v)],
1604 vec![new_select(&bananna).return_field(&hizat).build_query("x", QueryResCount::None)],
1605 ).is_err()
1606 );
1607 }
1608
1609 #[test]
1610 fn test_select_nothing_bad() {
1611 let mut v = Version::default();
1612 let bananna = v.table("zOOR88EQ9", "bananna");
1613 bananna.field(&mut v, "z437INV6D", "hizat", field_str().build());
1614 assert!(
1615 generate(
1616 &PathBuf::from_str("/dev/null").unwrap(),
1617 vec![(0usize, v)],
1618 vec![new_select(&bananna).build_query("x", QueryResCount::None)],
1619 ).is_err()
1620 );
1621 }
1622
1623 #[test]
1624 fn test_returning_none_bad() {
1625 let mut v = Version::default();
1626 let bananna = v.table("zZPD1I2EF", "bananna");
1627 let hizat = bananna.field(&mut v, "z437INV6D", "hizat", field_str().build());
1628 assert!(
1629 generate(
1630 &PathBuf::from_str("/dev/null").unwrap(),
1631 vec![(0usize, v)],
1632 vec![
1633 new_insert(&bananna, vec![(hizat.clone(), Expr::LitString("hoy".into()))])
1634 .return_field(&hizat)
1635 .build_query("x", QueryResCount::None)
1636 ],
1637 ).is_err()
1638 );
1639 }
1640}