1use crate::{
17 expr::{Column, DynExpr, Order, Path, Projection, RecordLink, SurrealQL},
18 types::{SurrealEdge, SurrealRecord, Thing},
19};
20use std::collections::BTreeMap;
21
22#[derive(Debug, Clone, Copy, PartialEq, Eq)]
24pub enum Returning {
25 None,
27 Nothing,
29 Before,
31 After,
33 Diff,
35}
36
37impl Returning {
38 fn render(self, buf: &mut String) {
39 match self {
40 Returning::None => {}
41 Returning::Nothing => buf.push_str(" RETURN NONE"),
42 Returning::Before => buf.push_str(" RETURN BEFORE"),
43 Returning::After => buf.push_str(" RETURN AFTER"),
44 Returning::Diff => buf.push_str(" RETURN DIFF"),
45 }
46 }
47}
48
49enum Target {
52 Table(&'static str),
53 Record(RecordLink),
54}
55
56impl Target {
57 fn render(&self, buf: &mut String) {
58 match self {
59 Target::Table(t) => buf.push_str(t),
60 Target::Record(r) => r.render_dyn(buf),
61 }
62 }
63 fn render_params(&self, buf: &mut String, params: &mut BTreeMap<String, serde_json::Value>) {
64 match self {
65 Target::Table(t) => buf.push_str(t),
66 Target::Record(r) => r.render_dyn_params(buf, params),
67 }
68 }
69}
70
71pub struct Table<T: SurrealRecord> {
78 _marker: std::marker::PhantomData<T>,
79}
80
81impl<T: SurrealRecord> Table<T> {
82 pub fn new() -> Self {
84 Self {
85 _marker: std::marker::PhantomData,
86 }
87 }
88
89 pub fn select(self, _cols: crate::expr::ColumnSet<T>) -> Select<T> {
91 Select::bare()
92 }
93
94 pub fn project(self, fields: Vec<Projection>) -> Select<T> {
96 let mut s = Select::bare();
97 s.projections = fields;
98 s
99 }
100
101 pub fn project_path(self, path: Path, alias: &'static str) -> Select<T> {
104 let mut s = Select::bare();
105 s.projections = vec![Projection::aliased(path, alias)];
106 s
107 }
108
109 pub fn count(self) -> Select<T> {
111 let mut s = Select::bare();
112 s.count = true;
113 s.group_all = true;
114 s
115 }
116
117 pub fn insert(self) -> Insert<T> {
119 Insert {
120 data: Vec::new(),
121 return_fields: vec![],
122 returning: Returning::None,
123 }
124 }
125 pub fn create(self) -> Create<T> {
127 Create::for_table()
128 }
129 pub fn update(self) -> Update<T> {
131 Update::for_table()
132 }
133 pub fn upsert(self) -> Update<T> {
137 Update::for_upsert()
138 }
139 pub fn delete(self) -> Delete<T> {
141 Delete::for_table()
142 }
143}
144
145impl<T: SurrealRecord> Default for Table<T> {
146 fn default() -> Self {
147 Self::new()
148 }
149}
150
151pub struct Select<T: SurrealRecord> {
159 _marker: std::marker::PhantomData<T>,
160 projections: Vec<Projection>,
161 value: bool,
162 omit: Vec<String>,
163 with: Option<String>,
164 filter: Option<Box<dyn DynExpr>>,
165 split: Vec<String>,
166 order: Vec<(String, Order)>,
167 limit: Option<u32>,
168 start: u32,
169 fetch: Vec<String>,
170 group_by: Vec<String>,
171 group_all: bool,
172 count: bool,
173 count_alias: Option<&'static str>,
174 timeout: Option<String>,
175 explain: Option<bool>,
176 from_sub: Option<Box<Select<T>>>,
177}
178
179impl<T: SurrealRecord> Select<T> {
180 fn bare() -> Self {
181 Select {
182 _marker: std::marker::PhantomData,
183 projections: Vec::new(),
184 value: false,
185 omit: Vec::new(),
186 with: None,
187 filter: None,
188 split: Vec::new(),
189 order: Vec::new(),
190 limit: None,
191 start: 0,
192 fetch: Vec::new(),
193 group_by: Vec::new(),
194 group_all: false,
195 count: false,
196 count_alias: None,
197 timeout: None,
198 explain: None,
199 from_sub: None,
200 }
201 }
202
203 pub fn filter(mut self, expr: impl DynExpr + 'static) -> Self {
204 self.filter = Some(Box::new(expr));
205 self
206 }
207 pub fn with_path(mut self, path: Path, alias: &'static str) -> Self {
212 if self.projections.is_empty() {
213 self.projections
214 .push(Projection::new(crate::expr::Raw("*".to_string())));
215 }
216 self.projections.push(Projection::aliased(path, alias));
217 self
218 }
219 pub fn limit(mut self, n: u32) -> Self {
220 self.limit = Some(n);
221 self
222 }
223 pub fn start(mut self, n: u32) -> Self {
224 self.start = n;
225 self
226 }
227 pub fn fetch(mut self, field: impl Into<String>) -> Self {
228 self.fetch.push(field.into());
229 self
230 }
231 pub fn group_by<C: DynExpr>(mut self, col: C) -> Self {
232 let mut buf = String::new();
233 col.render_dyn(&mut buf);
234 self.group_by.push(buf);
235 self
236 }
237 pub fn group_all(mut self) -> Self {
239 self.group_all = true;
240 self
241 }
242 pub fn count_as(mut self, alias: &'static str) -> Self {
244 self.count = true;
245 self.count_alias = Some(alias);
246 self
247 }
248
249 pub fn value(mut self) -> Self {
252 self.value = true;
253 self
254 }
255 pub fn omit(mut self, field: impl Into<String>) -> Self {
257 self.omit.push(field.into());
258 self
259 }
260 pub fn split(mut self, field: impl Into<String>) -> Self {
262 self.split.push(field.into());
263 self
264 }
265 pub fn with_index<I, S>(mut self, indexes: I) -> Self
267 where
268 I: IntoIterator<Item = S>,
269 S: AsRef<str>,
270 {
271 let list = indexes
272 .into_iter()
273 .map(|s| s.as_ref().to_string())
274 .collect::<Vec<_>>()
275 .join(", ");
276 self.with = Some(format!("WITH INDEX {list}"));
277 self
278 }
279 pub fn with_no_index(mut self) -> Self {
281 self.with = Some("WITH NOINDEX".to_string());
282 self
283 }
284 pub fn timeout(mut self, duration: impl Into<String>) -> Self {
286 self.timeout = Some(duration.into());
287 self
288 }
289 pub fn from_subquery(mut self, sub: Select<T>) -> Self {
293 self.from_sub = Some(Box::new(sub));
294 self
295 }
296
297 pub fn explain(mut self) -> Self {
299 self.explain = Some(false);
300 self
301 }
302 pub fn explain_full(mut self) -> Self {
304 self.explain = Some(true);
305 self
306 }
307
308 pub fn order_by<C: DynExpr>(mut self, col: C, dir: Order) -> Self {
309 let mut buf = String::new();
310 col.render_dyn(&mut buf);
311 self.order.push((buf, dir));
312 self
313 }
314
315 pub fn order_asc<C: DynExpr>(self, col: C) -> Self {
316 self.order_by(col, Order::Asc)
317 }
318 pub fn order_desc<C: DynExpr>(self, col: C) -> Self {
319 self.order_by(col, Order::Desc)
320 }
321
322 fn render_select_list(&self, q: &mut String) {
323 if self.count {
324 q.push_str("count()");
325 if let Some(a) = self.count_alias {
326 q.push_str(" AS ");
327 q.push_str(a);
328 }
329 } else if self.projections.is_empty() {
330 q.push('*');
331 } else {
332 for (i, p) in self.projections.iter().enumerate() {
333 if i > 0 {
334 q.push_str(", ");
335 }
336 p.render(q);
337 }
338 }
339 }
340
341 fn render_select_list_params(
342 &self,
343 q: &mut String,
344 params: &mut BTreeMap<String, serde_json::Value>,
345 ) {
346 if self.count {
347 q.push_str("count()");
348 if let Some(a) = self.count_alias {
349 q.push_str(" AS ");
350 q.push_str(a);
351 }
352 } else if self.projections.is_empty() {
353 q.push('*');
354 } else {
355 for (i, p) in self.projections.iter().enumerate() {
356 if i > 0 {
357 q.push_str(", ");
358 }
359 p.render_params(q, params);
360 }
361 }
362 }
363
364 fn render(
369 &self,
370 q: &mut String,
371 params: &mut BTreeMap<String, serde_json::Value>,
372 param_mode: bool,
373 ) {
374 q.push_str("SELECT ");
375 if self.value {
376 q.push_str("VALUE ");
377 }
378 if param_mode {
379 self.render_select_list_params(q, params);
380 } else {
381 self.render_select_list(q);
382 }
383 if !self.omit.is_empty() {
384 q.push_str(" OMIT ");
385 q.push_str(&self.omit.join(", "));
386 }
387 q.push_str(" FROM ");
388 match &self.from_sub {
389 Some(sub) => {
390 q.push('(');
391 sub.render(q, params, param_mode);
392 q.push(')');
393 }
394 None => q.push_str(T::table_name()),
395 }
396 if let Some(w) = &self.with {
397 q.push(' ');
398 q.push_str(w);
399 }
400 if let Some(ref f) = self.filter {
401 q.push_str(" WHERE ");
402 if param_mode {
403 f.render_dyn_params(q, params);
404 } else {
405 f.render_dyn(q);
406 }
407 }
408 for (i, s) in self.split.iter().enumerate() {
409 q.push_str(if i == 0 { " SPLIT " } else { ", " });
410 q.push_str(s);
411 }
412 for (i, (col, dir)) in self.order.iter().enumerate() {
413 q.push_str(if i == 0 { " ORDER BY " } else { ", " });
414 q.push_str(&format!("{col} {dir}"));
415 }
416 for (i, g) in self.group_by.iter().enumerate() {
417 q.push_str(if i == 0 { " GROUP BY " } else { ", " });
418 q.push_str(g);
419 }
420 if self.group_all {
421 q.push_str(" GROUP ALL");
422 }
423 if self.start > 0 {
424 q.push_str(&format!(" START {}", self.start));
425 }
426 if let Some(n) = self.limit {
427 q.push_str(&format!(" LIMIT {n}"));
428 }
429 for f in &self.fetch {
430 q.push_str(&format!(" FETCH {f}"));
431 }
432 if let Some(t) = &self.timeout {
433 q.push_str(" TIMEOUT ");
434 q.push_str(t);
435 }
436 match self.explain {
437 Some(true) => q.push_str(" EXPLAIN FULL"),
438 Some(false) => q.push_str(" EXPLAIN"),
439 None => {}
440 }
441 }
442
443 pub fn to_surrealql(&self) -> String {
444 let mut q = String::new();
445 let mut sink = BTreeMap::new();
446 self.render(&mut q, &mut sink, false);
447 q
448 }
449
450 pub fn to_surrealql_with_params(&self) -> (String, BTreeMap<String, serde_json::Value>) {
455 let mut params = BTreeMap::new();
456 let mut q = String::new();
457 self.render(&mut q, &mut params, true);
458 (q, params)
459 }
460}
461
462impl<T: SurrealRecord> std::fmt::Debug for Select<T> {
463 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
464 f.debug_struct("Select")
465 .field("sql", &self.to_surrealql())
466 .finish()
467 }
468}
469
470impl<T: SurrealRecord> DynExpr for Select<T> {
474 fn render_dyn(&self, buf: &mut String) {
475 let mut sink = BTreeMap::new();
476 buf.push('(');
477 self.render(buf, &mut sink, false);
478 buf.push(')');
479 }
480 fn render_dyn_params(
481 &self,
482 buf: &mut String,
483 params: &mut BTreeMap<String, serde_json::Value>,
484 ) {
485 buf.push('(');
486 self.render(buf, params, true);
487 buf.push(')');
488 }
489}
490
491impl<T: SurrealRecord> std::fmt::Display for Select<T> {
492 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
493 write!(f, "{}", self.to_surrealql())
494 }
495}
496
497pub struct Insert<T: SurrealRecord> {
504 data: Vec<T>,
505 return_fields: Vec<&'static str>,
506 returning: Returning,
507}
508
509impl<T: SurrealRecord> Insert<T> {
510 pub fn content(mut self, record: T) -> Self {
511 self.data.push(record);
512 self
513 }
514 pub fn return_field(mut self, field: &'static str) -> Self {
517 self.return_fields.push(field);
518 self
519 }
520 pub fn returning(mut self, r: Returning) -> Self {
523 self.returning = r;
524 self
525 }
526 pub fn data(&self) -> &[T] {
527 &self.data
528 }
529
530 pub fn to_surrealql(&self) -> String
536 where
537 T: serde::Serialize,
538 {
539 let body = match self.data.as_slice() {
540 [] => "[]".to_string(),
541 [one] => serde_json::to_string(one).unwrap_or_else(|_| "{}".to_string()),
542 many => serde_json::to_string(many).unwrap_or_else(|_| "[]".to_string()),
543 };
544 let mut q = format!("INSERT INTO {} {}", T::table_name(), body);
545 if !self.return_fields.is_empty() {
546 q.push_str(" RETURN ");
547 q.push_str(&self.return_fields.join(", "));
548 } else {
549 self.returning.render(&mut q);
550 }
551 q
552 }
553}
554
555enum SetVal {
560 Assign(String, Box<dyn DynExpr>),
562 Merge(Box<dyn DynExpr>),
564 Content(Box<dyn DynExpr>),
566}
567
568impl SetVal {
569 fn render(&self, buf: &mut String, set_pairs: &mut Vec<String>) {
570 match self {
571 SetVal::Assign(k, v) => {
572 let mut val_buf = String::new();
573 v.render_dyn(&mut val_buf);
574 set_pairs.push(format!("{k} = {val_buf}"));
575 }
576 SetVal::Merge(v) => {
577 let mut val_buf = String::new();
578 v.render_dyn(&mut val_buf);
579 buf.push_str(" MERGE ");
580 buf.push_str(&val_buf);
581 }
582 SetVal::Content(v) => {
583 let mut val_buf = String::new();
584 v.render_dyn(&mut val_buf);
585 buf.push_str(" CONTENT ");
586 buf.push_str(&val_buf);
587 }
588 }
589 }
590 fn render_params(
591 &self,
592 buf: &mut String,
593 set_pairs: &mut Vec<String>,
594 params: &mut BTreeMap<String, serde_json::Value>,
595 ) {
596 match self {
597 SetVal::Assign(k, v) => {
598 let mut val_buf = String::new();
599 v.render_dyn_params(&mut val_buf, params);
600 set_pairs.push(format!("{k} = {val_buf}"));
601 }
602 SetVal::Merge(v) => {
603 let mut val_buf = String::new();
604 v.render_dyn_params(&mut val_buf, params);
605 buf.push_str(" MERGE ");
606 buf.push_str(&val_buf);
607 }
608 SetVal::Content(v) => {
609 let mut val_buf = String::new();
610 v.render_dyn_params(&mut val_buf, params);
611 buf.push_str(" CONTENT ");
612 buf.push_str(&val_buf);
613 }
614 }
615 }
616}
617
618pub struct Update<T: SurrealRecord> {
621 _marker: std::marker::PhantomData<T>,
622 verb: &'static str,
623 target: Target,
624 filter: Option<Box<dyn DynExpr>>,
625 sets: Vec<SetVal>,
626 returning: Returning,
627}
628
629impl<T: SurrealRecord> Update<T> {
630 pub(crate) fn for_table() -> Self {
631 Self::with_verb("UPDATE")
632 }
633
634 pub(crate) fn for_upsert() -> Self {
637 Self::with_verb("UPSERT")
638 }
639
640 fn with_verb(verb: &'static str) -> Self {
641 Self {
642 _marker: std::marker::PhantomData,
643 verb,
644 target: Target::Table(T::table_name()),
645 filter: None,
646 sets: Vec::new(),
647 returning: Returning::None,
648 }
649 }
650
651 pub fn record<V: SurrealQL>(mut self, id: V) -> Self {
653 self.target = Target::Record(RecordLink::new(T::table_name(), id));
654 self
655 }
656
657 pub fn filter(mut self, expr: impl DynExpr + 'static) -> Self {
658 self.filter = Some(Box::new(expr));
659 self
660 }
661
662 pub fn set<C: SurrealQL>(mut self, col: Column<T, C>, value: C) -> Self {
664 self.sets.push(SetVal::Assign(
665 col.name.to_string(),
666 Box::new(crate::expr::Literal(value)),
667 ));
668 self
669 }
670 pub fn set_lit<C: SurrealQL>(mut self, col: impl Into<String>, value: C) -> Self {
672 self.sets.push(SetVal::Assign(
673 col.into(),
674 Box::new(crate::expr::Literal(value)),
675 ));
676 self
677 }
678 pub fn set_expr(mut self, col: impl Into<String>, expr: impl DynExpr + 'static) -> Self {
680 self.sets.push(SetVal::Assign(col.into(), Box::new(expr)));
681 self
682 }
683 pub fn set_raw(mut self, col: impl Into<String>, raw: impl Into<String>) -> Self {
685 self.sets.push(SetVal::Assign(
686 col.into(),
687 Box::new(crate::expr::Raw(raw.into())),
688 ));
689 self
690 }
691 pub fn merge(mut self, expr: impl DynExpr + 'static) -> Self {
693 self.sets.push(SetVal::Merge(Box::new(expr)));
694 self
695 }
696 pub fn content(mut self, expr: impl DynExpr + 'static) -> Self {
698 self.sets.push(SetVal::Content(Box::new(expr)));
699 self
700 }
701 pub fn returning(mut self, r: Returning) -> Self {
702 self.returning = r;
703 self
704 }
705
706 pub fn then_select(self, select: Select<T>) -> String {
709 format!("{};\n{}", self.to_surrealql(), select.to_surrealql())
710 }
711
712 pub fn then_select_params(
714 self,
715 select: Select<T>,
716 ) -> (String, BTreeMap<String, serde_json::Value>) {
717 let (mut_q, mut params) = self.to_surrealql_with_params();
718 let (sel_q, sel_params) = select.to_surrealql_with_params();
719 params.extend(sel_params);
720 (format!("{mut_q};\n{sel_q}"), params)
721 }
722
723 pub fn to_surrealql(&self) -> String {
724 let mut q = String::from(self.verb);
725 q.push(' ');
726 self.target.render(&mut q);
727 let mut set_pairs = Vec::new();
729 let mut trait_buf = String::new();
730 for s in &self.sets {
731 s.render(&mut trait_buf, &mut set_pairs);
732 }
733 if !trait_buf.is_empty() {
734 q.push_str(&trait_buf);
735 } else if !set_pairs.is_empty() {
736 q.push_str(" SET ");
737 q.push_str(&set_pairs.join(", "));
738 }
739 if let Some(ref f) = self.filter {
740 q.push_str(" WHERE ");
741 f.render_dyn(&mut q);
742 }
743 self.returning.render(&mut q);
744 q
745 }
746
747 pub fn to_surrealql_with_params(&self) -> (String, BTreeMap<String, serde_json::Value>) {
749 let mut params = BTreeMap::new();
750 let mut q = String::from(self.verb);
751 q.push(' ');
752 self.target.render_params(&mut q, &mut params);
753 let mut set_pairs = Vec::new();
754 let mut trait_buf = String::new();
755 for s in &self.sets {
756 s.render_params(&mut trait_buf, &mut set_pairs, &mut params);
757 }
758 if !trait_buf.is_empty() {
759 q.push_str(&trait_buf);
760 } else if !set_pairs.is_empty() {
761 q.push_str(" SET ");
762 q.push_str(&set_pairs.join(", "));
763 }
764 if let Some(ref f) = self.filter {
765 q.push_str(" WHERE ");
766 f.render_dyn_params(&mut q, &mut params);
767 }
768 self.returning.render(&mut q);
769 (q, params)
770 }
771}
772
773impl<T: SurrealRecord> std::fmt::Display for Update<T> {
774 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
775 write!(f, "{}", self.to_surrealql())
776 }
777}
778
779enum CreateBody {
784 Content(Box<dyn DynExpr>),
786 Set(Vec<(String, Box<dyn DynExpr>)>),
788}
789
790pub struct Create<T: SurrealRecord> {
792 _marker: std::marker::PhantomData<T>,
793 target: Target,
794 body: CreateBody,
795 returning: Returning,
796}
797
798impl<T: SurrealRecord> Create<T> {
799 pub(crate) fn for_table() -> Self {
800 Self {
801 _marker: std::marker::PhantomData,
802 target: Target::Table(T::table_name()),
803 body: CreateBody::Set(Vec::new()),
804 returning: Returning::None,
805 }
806 }
807
808 pub fn record<V: SurrealQL>(mut self, id: V) -> Self {
810 self.target = Target::Record(RecordLink::new(T::table_name(), id));
811 self
812 }
813
814 pub fn content(mut self, expr: impl DynExpr + 'static) -> Self {
816 self.body = CreateBody::Content(Box::new(expr));
817 self
818 }
819
820 pub fn set_lit<C: SurrealQL>(mut self, col: impl Into<String>, value: C) -> Self {
822 self.push_set(col.into(), Box::new(crate::expr::Literal(value)));
823 self
824 }
825 pub fn set_expr(mut self, col: impl Into<String>, expr: impl DynExpr + 'static) -> Self {
827 self.push_set(col.into(), Box::new(expr));
828 self
829 }
830 pub fn set_raw(mut self, col: impl Into<String>, raw: impl Into<String>) -> Self {
832 self.push_set(col.into(), Box::new(crate::expr::Raw(raw.into())));
833 self
834 }
835
836 fn push_set(&mut self, col: String, expr: Box<dyn DynExpr>) {
837 match &mut self.body {
838 CreateBody::Set(v) => v.push((col, expr)),
839 CreateBody::Content(_) => {
840 self.body = CreateBody::Set(vec![(col, expr)]);
841 }
842 }
843 }
844
845 pub fn returning(mut self, r: Returning) -> Self {
846 self.returning = r;
847 self
848 }
849
850 pub fn then_select(self, select: Select<T>) -> String {
857 format!("{};\n{}", self.to_surrealql(), select.to_surrealql())
858 }
859
860 pub fn then_select_params(
862 self,
863 select: Select<T>,
864 ) -> (String, BTreeMap<String, serde_json::Value>) {
865 let (mut_q, mut params) = self.to_surrealql_with_params();
866 let (sel_q, sel_params) = select.to_surrealql_with_params();
867 params.extend(sel_params);
868 (format!("{mut_q};\n{sel_q}"), params)
869 }
870
871 pub fn to_surrealql(&self) -> String {
872 let mut q = String::from("CREATE ");
873 self.target.render(&mut q);
874 match &self.body {
875 CreateBody::Content(c) => {
876 q.push_str(" CONTENT ");
877 c.render_dyn(&mut q);
878 }
879 CreateBody::Set(pairs) if !pairs.is_empty() => {
880 q.push_str(" SET ");
881 q.push_str(
882 &pairs
883 .iter()
884 .map(|(k, v)| {
885 let mut val = String::new();
886 v.render_dyn(&mut val);
887 format!("{k} = {val}")
888 })
889 .collect::<Vec<_>>()
890 .join(", "),
891 );
892 }
893 CreateBody::Set(_) => {}
894 }
895 self.returning.render(&mut q);
896 q
897 }
898
899 pub fn to_surrealql_with_params(&self) -> (String, BTreeMap<String, serde_json::Value>) {
901 let mut params = BTreeMap::new();
902 let mut q = String::from("CREATE ");
903 self.target.render_params(&mut q, &mut params);
904 match &self.body {
905 CreateBody::Content(c) => {
906 q.push_str(" CONTENT ");
907 c.render_dyn_params(&mut q, &mut params);
908 }
909 CreateBody::Set(pairs) if !pairs.is_empty() => {
910 q.push_str(" SET ");
911 q.push_str(
912 &pairs
913 .iter()
914 .map(|(k, v)| {
915 let mut val = String::new();
916 v.render_dyn_params(&mut val, &mut params);
917 format!("{k} = {val}")
918 })
919 .collect::<Vec<_>>()
920 .join(", "),
921 );
922 }
923 CreateBody::Set(_) => {}
924 }
925 self.returning.render(&mut q);
926 (q, params)
927 }
928}
929
930impl<T: SurrealRecord> std::fmt::Display for Create<T> {
931 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
932 write!(f, "{}", self.to_surrealql())
933 }
934}
935
936pub struct Delete<T: SurrealRecord> {
942 _marker: std::marker::PhantomData<T>,
943 target: Target,
944 filter: Option<Box<dyn DynExpr>>,
945 returning: Returning,
946}
947
948impl<T: SurrealRecord> Delete<T> {
949 pub(crate) fn for_table() -> Self {
950 Self {
951 _marker: std::marker::PhantomData,
952 target: Target::Table(T::table_name()),
953 filter: None,
954 returning: Returning::None,
955 }
956 }
957 pub fn record<V: SurrealQL>(mut self, id: V) -> Self {
959 self.target = Target::Record(RecordLink::new(T::table_name(), id));
960 self
961 }
962 pub fn filter(mut self, expr: impl DynExpr + 'static) -> Self {
963 self.filter = Some(Box::new(expr));
964 self
965 }
966 pub fn returning(mut self, r: Returning) -> Self {
967 self.returning = r;
968 self
969 }
970
971 pub fn then_select(self, select: Select<T>) -> String {
974 format!("{};\n{}", self.to_surrealql(), select.to_surrealql())
975 }
976
977 pub fn then_select_params(
979 self,
980 select: Select<T>,
981 ) -> (String, BTreeMap<String, serde_json::Value>) {
982 let (mut_q, mut params) = self.to_surrealql_with_params();
983 let (sel_q, sel_params) = select.to_surrealql_with_params();
984 params.extend(sel_params);
985 (format!("{mut_q};\n{sel_q}"), params)
986 }
987
988 pub fn to_surrealql(&self) -> String {
989 let mut q = String::from("DELETE ");
990 self.target.render(&mut q);
991 if let Some(ref f) = self.filter {
992 q.push_str(" WHERE ");
993 f.render_dyn(&mut q);
994 }
995 self.returning.render(&mut q);
996 q
997 }
998
999 pub fn to_surrealql_with_params(&self) -> (String, BTreeMap<String, serde_json::Value>) {
1001 let mut params = BTreeMap::new();
1002 let mut q = String::from("DELETE ");
1003 self.target.render_params(&mut q, &mut params);
1004 if let Some(ref f) = self.filter {
1005 q.push_str(" WHERE ");
1006 f.render_dyn_params(&mut q, &mut params);
1007 }
1008 self.returning.render(&mut q);
1009 (q, params)
1010 }
1011}
1012
1013impl<T: SurrealRecord> std::fmt::Display for Delete<T> {
1014 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1015 write!(f, "{}", self.to_surrealql())
1016 }
1017}
1018
1019#[derive(Default)]
1026pub struct Batch {
1027 statements: Vec<String>,
1028}
1029
1030impl Batch {
1031 pub fn new() -> Self {
1032 Self {
1033 statements: Vec::new(),
1034 }
1035 }
1036 pub fn push(mut self, stmt: impl ToString) -> Self {
1037 self.statements.push(stmt.to_string());
1038 self
1039 }
1040 pub fn to_surrealql(&self) -> String {
1041 self.statements.join(";\n")
1042 }
1043 pub fn len(&self) -> usize {
1045 self.statements.len()
1046 }
1047 pub fn is_empty(&self) -> bool {
1048 self.statements.is_empty()
1049 }
1050}
1051
1052impl std::fmt::Display for Batch {
1053 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1054 write!(f, "{}", self.to_surrealql())
1055 }
1056}
1057
1058#[derive(Default)]
1072pub struct Transaction {
1073 statements: Vec<String>,
1074 cancel: bool,
1075}
1076
1077impl Transaction {
1078 pub fn new() -> Self {
1079 Self::default()
1080 }
1081 pub fn push(mut self, stmt: impl ToString) -> Self {
1083 self.statements.push(stmt.to_string());
1084 self
1085 }
1086 pub fn cancel(mut self) -> Self {
1088 self.cancel = true;
1089 self
1090 }
1091 pub fn to_surrealql(&self) -> String {
1092 let mut out = String::from("BEGIN TRANSACTION;\n");
1093 for s in &self.statements {
1094 out.push_str(s);
1095 if !s.trim_end().ends_with(';') {
1096 out.push(';');
1097 }
1098 out.push('\n');
1099 }
1100 out.push_str(if self.cancel {
1101 "CANCEL TRANSACTION;"
1102 } else {
1103 "COMMIT TRANSACTION;"
1104 });
1105 out
1106 }
1107 pub fn len(&self) -> usize {
1109 self.statements.len()
1110 }
1111 pub fn is_empty(&self) -> bool {
1112 self.statements.is_empty()
1113 }
1114}
1115
1116impl std::fmt::Display for Transaction {
1117 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1118 write!(f, "{}", self.to_surrealql())
1119 }
1120}
1121
1122fn record_id(thing: &Thing<impl SurrealRecord>, buf: &mut String) {
1128 buf.push_str(thing.table());
1129 buf.push(':');
1130 thing.key.render_id(buf);
1131}
1132
1133fn record_id_string(thing: &Thing<impl SurrealRecord>) -> String {
1135 let mut s = String::new();
1136 record_id(thing, &mut s);
1137 s
1138}
1139
1140pub struct Relate<E: SurrealEdge> {
1143 _marker: std::marker::PhantomData<E>,
1144}
1145
1146impl<E: SurrealEdge> Relate<E> {
1147 pub fn new() -> Self {
1148 Self {
1149 _marker: std::marker::PhantomData,
1150 }
1151 }
1152
1153 pub fn to_surrealql(
1154 from: &Thing<impl SurrealRecord>,
1155 to: &Thing<impl SurrealRecord>,
1156 ) -> String {
1157 let mut q = String::from("RELATE ");
1158 record_id(from, &mut q);
1159 q.push_str(" -> ");
1160 q.push_str(E::edge_name());
1161 q.push_str(" -> ");
1162 record_id(to, &mut q);
1163 q
1164 }
1165}
1166
1167impl<E: SurrealEdge> Default for Relate<E> {
1168 fn default() -> Self {
1169 Self::new()
1170 }
1171}
1172
1173pub struct RelateEdge<E: SurrealEdge> {
1183 _marker: std::marker::PhantomData<E>,
1184 from_label: String,
1185 to_label: String,
1186 content_json: Option<serde_json::Value>,
1187 return_fields: Vec<&'static str>,
1188 returning: Returning,
1189}
1190
1191impl<E: SurrealEdge> RelateEdge<E> {
1192 pub fn from(from: &Thing<impl SurrealRecord>) -> Self {
1193 Self {
1194 _marker: std::marker::PhantomData,
1195 from_label: record_id_string(from),
1196 to_label: String::new(),
1197 content_json: None,
1198 return_fields: Vec::new(),
1199 returning: Returning::None,
1200 }
1201 }
1202
1203 pub fn to(mut self, to: &Thing<impl SurrealRecord>) -> Self {
1204 self.to_label = record_id_string(to);
1205 self
1206 }
1207
1208 pub fn content(mut self, edge: &impl serde::Serialize) -> Self {
1210 self.content_json = serde_json::to_value(edge).ok();
1211 self
1212 }
1213
1214 pub fn return_field(mut self, field: &'static str) -> Self {
1217 self.return_fields.push(field);
1218 self
1219 }
1220 pub fn returning(mut self, r: Returning) -> Self {
1222 self.returning = r;
1223 self
1224 }
1225
1226 pub fn build(&self) -> String {
1227 let mut q = format!(
1228 "RELATE {} -> {} -> {}",
1229 self.from_label,
1230 E::edge_name(),
1231 self.to_label
1232 );
1233 if let Some(ref c) = self.content_json {
1234 q.push_str(&format!(
1235 " CONTENT {}",
1236 serde_json::to_string(c).unwrap_or_default()
1237 ));
1238 }
1239 if !self.return_fields.is_empty() {
1240 q.push_str(" RETURN ");
1241 q.push_str(&self.return_fields.join(", "));
1242 } else {
1243 self.returning.render(&mut q);
1244 }
1245 q
1246 }
1247}
1248
1249pub struct LetVar {
1261 name: String,
1262 value: Box<dyn DynExpr>,
1263}
1264
1265impl LetVar {
1266 pub fn new(name: impl Into<String>, value: impl DynExpr + 'static) -> Self {
1268 Self {
1269 name: name.into(),
1270 value: Box::new(value),
1271 }
1272 }
1273
1274 pub fn literal<V: SurrealQL>(name: impl Into<String>, value: V) -> Self {
1276 Self {
1277 name: name.into(),
1278 value: Box::new(crate::expr::Literal(value)),
1279 }
1280 }
1281
1282 pub fn to_surrealql(&self) -> String {
1283 let mut q = format!("LET ${} = ", self.name);
1284 self.value.render_dyn(&mut q);
1285 q
1286 }
1287
1288 pub fn to_surrealql_with_params(&self) -> (String, BTreeMap<String, serde_json::Value>) {
1290 let mut params = BTreeMap::new();
1291 let mut q = format!("LET ${} = ", self.name);
1292 self.value.render_dyn_params(&mut q, &mut params);
1293 (q, params)
1294 }
1295}
1296
1297impl std::fmt::Display for LetVar {
1298 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1299 write!(f, "{}", self.to_surrealql())
1300 }
1301}
1302
1303pub struct For {
1317 var: String,
1318 array: Box<dyn DynExpr>,
1319 body: Vec<String>,
1320}
1321
1322impl For {
1323 pub fn new(var: impl Into<String>, array: impl DynExpr + 'static) -> Self {
1326 Self {
1327 var: var.into(),
1328 array: Box::new(array),
1329 body: Vec::new(),
1330 }
1331 }
1332 pub fn push(mut self, stmt: impl Into<String>) -> Self {
1334 self.body.push(stmt.into());
1335 self
1336 }
1337 pub fn to_surrealql(&self) -> String {
1338 let mut q = format!("FOR ${} IN ", self.var);
1339 self.array.render_dyn(&mut q);
1340 q.push_str(" { ");
1341 for s in &self.body {
1342 q.push_str(s);
1343 if !s.trim_end().ends_with(';') {
1344 q.push(';');
1345 }
1346 q.push(' ');
1347 }
1348 q.push('}');
1349 q
1350 }
1351}
1352
1353impl std::fmt::Display for For {
1354 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1355 write!(f, "{}", self.to_surrealql())
1356 }
1357}
1358
1359enum IndexKind {
1365 Plain,
1367 Unique,
1369 Raw(String),
1373}
1374
1375pub struct DefineIndex {
1387 name: String,
1388 table: String,
1389 fields: Vec<String>,
1390 kind: IndexKind,
1391 if_not_exists: bool,
1392 comment: Option<String>,
1393 concurrently: bool,
1394}
1395
1396impl DefineIndex {
1397 pub fn new(name: impl Into<String>, table: impl Into<String>) -> Self {
1399 Self {
1400 name: name.into(),
1401 table: table.into(),
1402 fields: Vec::new(),
1403 kind: IndexKind::Plain,
1404 if_not_exists: true,
1405 comment: None,
1406 concurrently: false,
1407 }
1408 }
1409
1410 pub fn field(mut self, name: impl Into<String>) -> Self {
1412 self.fields.push(name.into());
1413 self
1414 }
1415 pub fn fields<I, S>(mut self, names: I) -> Self
1417 where
1418 I: IntoIterator<Item = S>,
1419 S: Into<String>,
1420 {
1421 self.fields.extend(names.into_iter().map(Into::into));
1422 self
1423 }
1424
1425 pub fn unique(mut self) -> Self {
1427 self.kind = IndexKind::Unique;
1428 self
1429 }
1430 pub fn search(mut self, analyzer: impl Into<String>) -> Self {
1433 self.kind = IndexKind::Raw(format!("SEARCH ANALYZER {}", analyzer.into()));
1434 self
1435 }
1436 pub fn hnsw(mut self, dimension: u32, dist: impl Into<String>) -> Self {
1439 self.kind = IndexKind::Raw(format!("HNSW DIMENSION {dimension} DIST {}", dist.into()));
1440 self
1441 }
1442 pub fn mtree(mut self, dimension: u32, dist: impl Into<String>) -> Self {
1444 self.kind = IndexKind::Raw(format!("MTREE DIMENSION {dimension} DIST {}", dist.into()));
1445 self
1446 }
1447 pub fn raw(mut self, tail: impl Into<String>) -> Self {
1450 self.kind = IndexKind::Raw(tail.into());
1451 self
1452 }
1453
1454 pub fn overwrite(mut self) -> Self {
1456 self.if_not_exists = false;
1457 self
1458 }
1459 pub fn comment(mut self, text: impl Into<String>) -> Self {
1461 self.comment = Some(text.into());
1462 self
1463 }
1464 pub fn concurrently(mut self) -> Self {
1466 self.concurrently = true;
1467 self
1468 }
1469
1470 pub fn to_surrealql(&self) -> String {
1471 let guard = if self.if_not_exists {
1472 "IF NOT EXISTS "
1473 } else {
1474 ""
1475 };
1476 let mut q = format!(
1477 "DEFINE INDEX {guard}{} ON TABLE {} FIELDS {}",
1478 self.name,
1479 self.table,
1480 self.fields.join(", "),
1481 );
1482 match &self.kind {
1483 IndexKind::Plain => {}
1484 IndexKind::Unique => q.push_str(" UNIQUE"),
1485 IndexKind::Raw(tail) => {
1486 q.push(' ');
1487 q.push_str(tail);
1488 }
1489 }
1490 if let Some(c) = &self.comment {
1491 let escaped = c.replace('\\', "\\\\").replace('\'', "\\'");
1492 q.push_str(&format!(" COMMENT '{escaped}'"));
1493 }
1494 if self.concurrently {
1495 q.push_str(" CONCURRENTLY");
1496 }
1497 q
1498 }
1499
1500 pub fn remove(name: &str, table: &str) -> String {
1502 format!("REMOVE INDEX IF EXISTS {name} ON TABLE {table}")
1503 }
1504}
1505
1506impl std::fmt::Display for DefineIndex {
1507 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1508 write!(f, "{}", self.to_surrealql())
1509 }
1510}
1511
1512fn guard(if_not_exists: bool) -> &'static str {
1517 if if_not_exists {
1518 "IF NOT EXISTS "
1519 } else {
1520 ""
1521 }
1522}
1523
1524pub struct DefineEvent {
1535 name: String,
1536 table: String,
1537 when: String,
1538 then: String,
1539 if_not_exists: bool,
1540}
1541
1542impl DefineEvent {
1543 pub fn new(name: impl Into<String>, table: impl Into<String>) -> Self {
1544 Self {
1545 name: name.into(),
1546 table: table.into(),
1547 when: String::new(),
1548 then: String::new(),
1549 if_not_exists: true,
1550 }
1551 }
1552 pub fn when(mut self, cond: impl Into<String>) -> Self {
1554 self.when = cond.into();
1555 self
1556 }
1557 pub fn then(mut self, block: impl Into<String>) -> Self {
1559 self.then = block.into();
1560 self
1561 }
1562 pub fn overwrite(mut self) -> Self {
1564 self.if_not_exists = false;
1565 self
1566 }
1567 pub fn to_surrealql(&self) -> String {
1568 format!(
1569 "DEFINE EVENT {}{} ON TABLE {} WHEN {} THEN {}",
1570 guard(self.if_not_exists),
1571 self.name,
1572 self.table,
1573 self.when,
1574 self.then
1575 )
1576 }
1577 pub fn remove(name: &str, table: &str) -> String {
1579 format!("REMOVE EVENT IF EXISTS {name} ON TABLE {table}")
1580 }
1581}
1582
1583impl std::fmt::Display for DefineEvent {
1584 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1585 write!(f, "{}", self.to_surrealql())
1586 }
1587}
1588
1589pub struct DefineFunction {
1600 name: String,
1601 args: Vec<(String, String)>,
1602 returns: Option<String>,
1603 body: String,
1604 if_not_exists: bool,
1605}
1606
1607impl DefineFunction {
1608 pub fn new(name: impl Into<String>) -> Self {
1609 Self {
1610 name: name.into(),
1611 args: Vec::new(),
1612 returns: None,
1613 body: String::new(),
1614 if_not_exists: true,
1615 }
1616 }
1617 pub fn arg(mut self, name: impl Into<String>, ty: impl Into<String>) -> Self {
1619 self.args.push((name.into(), ty.into()));
1620 self
1621 }
1622 pub fn returns(mut self, ty: impl Into<String>) -> Self {
1624 self.returns = Some(ty.into());
1625 self
1626 }
1627 pub fn body(mut self, body: impl Into<String>) -> Self {
1629 self.body = body.into();
1630 self
1631 }
1632 pub fn overwrite(mut self) -> Self {
1633 self.if_not_exists = false;
1634 self
1635 }
1636 pub fn to_surrealql(&self) -> String {
1637 let args = self
1638 .args
1639 .iter()
1640 .map(|(n, t)| format!("${n}: {t}"))
1641 .collect::<Vec<_>>()
1642 .join(", ");
1643 let ret = self
1644 .returns
1645 .as_ref()
1646 .map(|r| format!(" -> {r}"))
1647 .unwrap_or_default();
1648 format!(
1649 "DEFINE FUNCTION {}fn::{}({}){} {{ {} }}",
1650 guard(self.if_not_exists),
1651 self.name,
1652 args,
1653 ret,
1654 self.body
1655 )
1656 }
1657 pub fn remove(name: &str) -> String {
1659 format!("REMOVE FUNCTION IF EXISTS fn::{name}")
1660 }
1661}
1662
1663impl std::fmt::Display for DefineFunction {
1664 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1665 write!(f, "{}", self.to_surrealql())
1666 }
1667}
1668
1669pub struct DefineAnalyzer {
1672 name: String,
1673 tokenizers: Vec<String>,
1674 filters: Vec<String>,
1675 if_not_exists: bool,
1676}
1677
1678impl DefineAnalyzer {
1679 pub fn new(name: impl Into<String>) -> Self {
1680 Self {
1681 name: name.into(),
1682 tokenizers: Vec::new(),
1683 filters: Vec::new(),
1684 if_not_exists: true,
1685 }
1686 }
1687 pub fn tokenizers<I, S>(mut self, toks: I) -> Self
1689 where
1690 I: IntoIterator<Item = S>,
1691 S: Into<String>,
1692 {
1693 self.tokenizers = toks.into_iter().map(Into::into).collect();
1694 self
1695 }
1696 pub fn filters<I, S>(mut self, filters: I) -> Self
1698 where
1699 I: IntoIterator<Item = S>,
1700 S: Into<String>,
1701 {
1702 self.filters = filters.into_iter().map(Into::into).collect();
1703 self
1704 }
1705 pub fn overwrite(mut self) -> Self {
1706 self.if_not_exists = false;
1707 self
1708 }
1709 pub fn to_surrealql(&self) -> String {
1710 let mut q = format!("DEFINE ANALYZER {}{}", guard(self.if_not_exists), self.name);
1711 if !self.tokenizers.is_empty() {
1712 q.push_str(" TOKENIZERS ");
1713 q.push_str(&self.tokenizers.join(", "));
1714 }
1715 if !self.filters.is_empty() {
1716 q.push_str(" FILTERS ");
1717 q.push_str(&self.filters.join(", "));
1718 }
1719 q
1720 }
1721 pub fn remove(name: &str) -> String {
1723 format!("REMOVE ANALYZER IF EXISTS {name}")
1724 }
1725}
1726
1727impl std::fmt::Display for DefineAnalyzer {
1728 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1729 write!(f, "{}", self.to_surrealql())
1730 }
1731}
1732
1733pub struct DefineParam {
1736 name: String,
1737 value: String,
1738 if_not_exists: bool,
1739}
1740
1741impl DefineParam {
1742 pub fn new(name: impl Into<String>, value: impl Into<String>) -> Self {
1744 Self {
1745 name: name.into(),
1746 value: value.into(),
1747 if_not_exists: true,
1748 }
1749 }
1750 pub fn value_lit<V: SurrealQL>(mut self, value: V) -> Self {
1752 let mut buf = String::new();
1753 V::render_literal(&value, &mut buf);
1754 self.value = buf;
1755 self
1756 }
1757 pub fn overwrite(mut self) -> Self {
1758 self.if_not_exists = false;
1759 self
1760 }
1761 pub fn to_surrealql(&self) -> String {
1762 format!(
1763 "DEFINE PARAM {}${} VALUE {}",
1764 guard(self.if_not_exists),
1765 self.name,
1766 self.value
1767 )
1768 }
1769 pub fn remove(name: &str) -> String {
1771 format!("REMOVE PARAM IF EXISTS ${name}")
1772 }
1773}
1774
1775impl std::fmt::Display for DefineParam {
1776 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1777 write!(f, "{}", self.to_surrealql())
1778 }
1779}