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, _field: &str) -> 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: &str) -> Self {
228 self.fetch.push(field.to_string());
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: &str) -> Self {
257 self.omit.push(field.to_string());
258 self
259 }
260 pub fn split(mut self, field: &str) -> Self {
262 self.split.push(field.to_string());
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: &str, value: C) -> Self {
672 self.sets.push(SetVal::Assign(
673 col.to_string(),
674 Box::new(crate::expr::Literal(value)),
675 ));
676 self
677 }
678 pub fn set_expr(mut self, col: &str, expr: impl DynExpr + 'static) -> Self {
680 self.sets
681 .push(SetVal::Assign(col.to_string(), Box::new(expr)));
682 self
683 }
684 pub fn set_raw(mut self, col: &str, raw: impl Into<String>) -> Self {
686 self.sets.push(SetVal::Assign(
687 col.to_string(),
688 Box::new(crate::expr::Raw(raw.into())),
689 ));
690 self
691 }
692 pub fn merge(mut self, expr: impl DynExpr + 'static) -> Self {
694 self.sets.push(SetVal::Merge(Box::new(expr)));
695 self
696 }
697 pub fn content(mut self, expr: impl DynExpr + 'static) -> Self {
699 self.sets.push(SetVal::Content(Box::new(expr)));
700 self
701 }
702 pub fn returning(mut self, r: Returning) -> Self {
703 self.returning = r;
704 self
705 }
706
707 pub fn then_select(self, select: Select<T>) -> String {
710 format!("{};\n{}", self.to_surrealql(), select.to_surrealql())
711 }
712
713 pub fn then_select_params(
715 self,
716 select: Select<T>,
717 ) -> (String, BTreeMap<String, serde_json::Value>) {
718 let (mut_q, mut params) = self.to_surrealql_with_params();
719 let (sel_q, sel_params) = select.to_surrealql_with_params();
720 params.extend(sel_params);
721 (format!("{mut_q};\n{sel_q}"), params)
722 }
723
724 pub fn to_surrealql(&self) -> String {
725 let mut q = String::from(self.verb);
726 q.push(' ');
727 self.target.render(&mut q);
728 let mut set_pairs = Vec::new();
730 let mut trait_buf = String::new();
731 for s in &self.sets {
732 s.render(&mut trait_buf, &mut set_pairs);
733 }
734 if !trait_buf.is_empty() {
735 q.push_str(&trait_buf);
736 } else if !set_pairs.is_empty() {
737 q.push_str(" SET ");
738 q.push_str(&set_pairs.join(", "));
739 }
740 if let Some(ref f) = self.filter {
741 q.push_str(" WHERE ");
742 f.render_dyn(&mut q);
743 }
744 self.returning.render(&mut q);
745 q
746 }
747
748 pub fn to_surrealql_with_params(&self) -> (String, BTreeMap<String, serde_json::Value>) {
750 let mut params = BTreeMap::new();
751 let mut q = String::from(self.verb);
752 q.push(' ');
753 self.target.render_params(&mut q, &mut params);
754 let mut set_pairs = Vec::new();
755 let mut trait_buf = String::new();
756 for s in &self.sets {
757 s.render_params(&mut trait_buf, &mut set_pairs, &mut params);
758 }
759 if !trait_buf.is_empty() {
760 q.push_str(&trait_buf);
761 } else if !set_pairs.is_empty() {
762 q.push_str(" SET ");
763 q.push_str(&set_pairs.join(", "));
764 }
765 if let Some(ref f) = self.filter {
766 q.push_str(" WHERE ");
767 f.render_dyn_params(&mut q, &mut params);
768 }
769 self.returning.render(&mut q);
770 (q, params)
771 }
772}
773
774impl<T: SurrealRecord> std::fmt::Display for Update<T> {
775 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
776 write!(f, "{}", self.to_surrealql())
777 }
778}
779
780enum CreateBody {
785 Content(Box<dyn DynExpr>),
787 Set(Vec<(String, Box<dyn DynExpr>)>),
789}
790
791pub struct Create<T: SurrealRecord> {
793 _marker: std::marker::PhantomData<T>,
794 target: Target,
795 body: CreateBody,
796 returning: Returning,
797}
798
799impl<T: SurrealRecord> Create<T> {
800 pub(crate) fn for_table() -> Self {
801 Self {
802 _marker: std::marker::PhantomData,
803 target: Target::Table(T::table_name()),
804 body: CreateBody::Set(Vec::new()),
805 returning: Returning::None,
806 }
807 }
808
809 pub fn record<V: SurrealQL>(mut self, id: V) -> Self {
811 self.target = Target::Record(RecordLink::new(T::table_name(), id));
812 self
813 }
814
815 pub fn content(mut self, expr: impl DynExpr + 'static) -> Self {
817 self.body = CreateBody::Content(Box::new(expr));
818 self
819 }
820
821 pub fn set_lit<C: SurrealQL>(mut self, col: &str, value: C) -> Self {
823 self.push_set(col, Box::new(crate::expr::Literal(value)));
824 self
825 }
826 pub fn set_expr(mut self, col: &str, expr: impl DynExpr + 'static) -> Self {
828 self.push_set(col, Box::new(expr));
829 self
830 }
831 pub fn set_raw(mut self, col: &str, raw: impl Into<String>) -> Self {
833 self.push_set(col, Box::new(crate::expr::Raw(raw.into())));
834 self
835 }
836
837 fn push_set(&mut self, col: &str, expr: Box<dyn DynExpr>) {
838 match &mut self.body {
839 CreateBody::Set(v) => v.push((col.to_string(), expr)),
840 CreateBody::Content(_) => {
841 self.body = CreateBody::Set(vec![(col.to_string(), expr)]);
842 }
843 }
844 }
845
846 pub fn returning(mut self, r: Returning) -> Self {
847 self.returning = r;
848 self
849 }
850
851 pub fn then_select(self, select: Select<T>) -> String {
858 format!("{};\n{}", self.to_surrealql(), select.to_surrealql())
859 }
860
861 pub fn then_select_params(
863 self,
864 select: Select<T>,
865 ) -> (String, BTreeMap<String, serde_json::Value>) {
866 let (mut_q, mut params) = self.to_surrealql_with_params();
867 let (sel_q, sel_params) = select.to_surrealql_with_params();
868 params.extend(sel_params);
869 (format!("{mut_q};\n{sel_q}"), params)
870 }
871
872 pub fn to_surrealql(&self) -> String {
873 let mut q = String::from("CREATE ");
874 self.target.render(&mut q);
875 match &self.body {
876 CreateBody::Content(c) => {
877 q.push_str(" CONTENT ");
878 c.render_dyn(&mut q);
879 }
880 CreateBody::Set(pairs) if !pairs.is_empty() => {
881 q.push_str(" SET ");
882 q.push_str(
883 &pairs
884 .iter()
885 .map(|(k, v)| {
886 let mut val = String::new();
887 v.render_dyn(&mut val);
888 format!("{k} = {val}")
889 })
890 .collect::<Vec<_>>()
891 .join(", "),
892 );
893 }
894 CreateBody::Set(_) => {}
895 }
896 self.returning.render(&mut q);
897 q
898 }
899
900 pub fn to_surrealql_with_params(&self) -> (String, BTreeMap<String, serde_json::Value>) {
902 let mut params = BTreeMap::new();
903 let mut q = String::from("CREATE ");
904 self.target.render_params(&mut q, &mut params);
905 match &self.body {
906 CreateBody::Content(c) => {
907 q.push_str(" CONTENT ");
908 c.render_dyn_params(&mut q, &mut params);
909 }
910 CreateBody::Set(pairs) if !pairs.is_empty() => {
911 q.push_str(" SET ");
912 q.push_str(
913 &pairs
914 .iter()
915 .map(|(k, v)| {
916 let mut val = String::new();
917 v.render_dyn_params(&mut val, &mut params);
918 format!("{k} = {val}")
919 })
920 .collect::<Vec<_>>()
921 .join(", "),
922 );
923 }
924 CreateBody::Set(_) => {}
925 }
926 self.returning.render(&mut q);
927 (q, params)
928 }
929}
930
931impl<T: SurrealRecord> std::fmt::Display for Create<T> {
932 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
933 write!(f, "{}", self.to_surrealql())
934 }
935}
936
937pub struct Delete<T: SurrealRecord> {
943 _marker: std::marker::PhantomData<T>,
944 target: Target,
945 filter: Option<Box<dyn DynExpr>>,
946 returning: Returning,
947}
948
949impl<T: SurrealRecord> Delete<T> {
950 pub(crate) fn for_table() -> Self {
951 Self {
952 _marker: std::marker::PhantomData,
953 target: Target::Table(T::table_name()),
954 filter: None,
955 returning: Returning::None,
956 }
957 }
958 pub fn record<V: SurrealQL>(mut self, id: V) -> Self {
960 self.target = Target::Record(RecordLink::new(T::table_name(), id));
961 self
962 }
963 pub fn filter(mut self, expr: impl DynExpr + 'static) -> Self {
964 self.filter = Some(Box::new(expr));
965 self
966 }
967 pub fn returning(mut self, r: Returning) -> Self {
968 self.returning = r;
969 self
970 }
971
972 pub fn then_select(self, select: Select<T>) -> String {
975 format!("{};\n{}", self.to_surrealql(), select.to_surrealql())
976 }
977
978 pub fn then_select_params(
980 self,
981 select: Select<T>,
982 ) -> (String, BTreeMap<String, serde_json::Value>) {
983 let (mut_q, mut params) = self.to_surrealql_with_params();
984 let (sel_q, sel_params) = select.to_surrealql_with_params();
985 params.extend(sel_params);
986 (format!("{mut_q};\n{sel_q}"), params)
987 }
988
989 pub fn to_surrealql(&self) -> String {
990 let mut q = String::from("DELETE ");
991 self.target.render(&mut q);
992 if let Some(ref f) = self.filter {
993 q.push_str(" WHERE ");
994 f.render_dyn(&mut q);
995 }
996 self.returning.render(&mut q);
997 q
998 }
999
1000 pub fn to_surrealql_with_params(&self) -> (String, BTreeMap<String, serde_json::Value>) {
1002 let mut params = BTreeMap::new();
1003 let mut q = String::from("DELETE ");
1004 self.target.render_params(&mut q, &mut params);
1005 if let Some(ref f) = self.filter {
1006 q.push_str(" WHERE ");
1007 f.render_dyn_params(&mut q, &mut params);
1008 }
1009 self.returning.render(&mut q);
1010 (q, params)
1011 }
1012}
1013
1014impl<T: SurrealRecord> std::fmt::Display for Delete<T> {
1015 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1016 write!(f, "{}", self.to_surrealql())
1017 }
1018}
1019
1020#[derive(Default)]
1027pub struct Batch {
1028 statements: Vec<String>,
1029}
1030
1031impl Batch {
1032 pub fn new() -> Self {
1033 Self {
1034 statements: Vec::new(),
1035 }
1036 }
1037 pub fn push(mut self, stmt: impl ToString) -> Self {
1038 self.statements.push(stmt.to_string());
1039 self
1040 }
1041 pub fn to_surrealql(&self) -> String {
1042 self.statements.join(";\n")
1043 }
1044 pub fn len(&self) -> usize {
1046 self.statements.len()
1047 }
1048 pub fn is_empty(&self) -> bool {
1049 self.statements.is_empty()
1050 }
1051}
1052
1053impl std::fmt::Display for Batch {
1054 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1055 write!(f, "{}", self.to_surrealql())
1056 }
1057}
1058
1059#[derive(Default)]
1073pub struct Transaction {
1074 statements: Vec<String>,
1075 cancel: bool,
1076}
1077
1078impl Transaction {
1079 pub fn new() -> Self {
1080 Self::default()
1081 }
1082 pub fn push(mut self, stmt: impl ToString) -> Self {
1084 self.statements.push(stmt.to_string());
1085 self
1086 }
1087 pub fn cancel(mut self) -> Self {
1089 self.cancel = true;
1090 self
1091 }
1092 pub fn to_surrealql(&self) -> String {
1093 let mut out = String::from("BEGIN TRANSACTION;\n");
1094 for s in &self.statements {
1095 out.push_str(s);
1096 if !s.trim_end().ends_with(';') {
1097 out.push(';');
1098 }
1099 out.push('\n');
1100 }
1101 out.push_str(if self.cancel {
1102 "CANCEL TRANSACTION;"
1103 } else {
1104 "COMMIT TRANSACTION;"
1105 });
1106 out
1107 }
1108 pub fn len(&self) -> usize {
1110 self.statements.len()
1111 }
1112 pub fn is_empty(&self) -> bool {
1113 self.statements.is_empty()
1114 }
1115}
1116
1117impl std::fmt::Display for Transaction {
1118 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1119 write!(f, "{}", self.to_surrealql())
1120 }
1121}
1122
1123fn record_id(thing: &Thing<impl SurrealRecord>, buf: &mut String) {
1129 buf.push_str(thing.table());
1130 buf.push(':');
1131 thing.key.render_id(buf);
1132}
1133
1134fn record_id_string(thing: &Thing<impl SurrealRecord>) -> String {
1136 let mut s = String::new();
1137 record_id(thing, &mut s);
1138 s
1139}
1140
1141pub struct Relate<E: SurrealEdge> {
1144 _marker: std::marker::PhantomData<E>,
1145}
1146
1147impl<E: SurrealEdge> Relate<E> {
1148 pub fn new() -> Self {
1149 Self {
1150 _marker: std::marker::PhantomData,
1151 }
1152 }
1153
1154 pub fn to_surrealql(
1155 from: &Thing<impl SurrealRecord>,
1156 to: &Thing<impl SurrealRecord>,
1157 ) -> String {
1158 let mut q = String::from("RELATE ");
1159 record_id(from, &mut q);
1160 q.push_str(" -> ");
1161 q.push_str(E::edge_name());
1162 q.push_str(" -> ");
1163 record_id(to, &mut q);
1164 q
1165 }
1166}
1167
1168impl<E: SurrealEdge> Default for Relate<E> {
1169 fn default() -> Self {
1170 Self::new()
1171 }
1172}
1173
1174pub struct RelateEdge<E: SurrealEdge> {
1184 _marker: std::marker::PhantomData<E>,
1185 from_label: String,
1186 to_label: String,
1187 content_json: Option<serde_json::Value>,
1188 return_fields: Vec<&'static str>,
1189 returning: Returning,
1190}
1191
1192impl<E: SurrealEdge> RelateEdge<E> {
1193 pub fn from(from: &Thing<impl SurrealRecord>) -> Self {
1194 Self {
1195 _marker: std::marker::PhantomData,
1196 from_label: record_id_string(from),
1197 to_label: String::new(),
1198 content_json: None,
1199 return_fields: Vec::new(),
1200 returning: Returning::None,
1201 }
1202 }
1203
1204 pub fn to(mut self, to: &Thing<impl SurrealRecord>) -> Self {
1205 self.to_label = record_id_string(to);
1206 self
1207 }
1208
1209 pub fn content(mut self, edge: &impl serde::Serialize) -> Self {
1211 self.content_json = serde_json::to_value(edge).ok();
1212 self
1213 }
1214
1215 pub fn return_field(mut self, field: &'static str) -> Self {
1218 self.return_fields.push(field);
1219 self
1220 }
1221 pub fn returning(mut self, r: Returning) -> Self {
1223 self.returning = r;
1224 self
1225 }
1226
1227 pub fn build(&self) -> String {
1228 let mut q = format!(
1229 "RELATE {} -> {} -> {}",
1230 self.from_label,
1231 E::edge_name(),
1232 self.to_label
1233 );
1234 if let Some(ref c) = self.content_json {
1235 q.push_str(&format!(
1236 " CONTENT {}",
1237 serde_json::to_string(c).unwrap_or_default()
1238 ));
1239 }
1240 if !self.return_fields.is_empty() {
1241 q.push_str(" RETURN ");
1242 q.push_str(&self.return_fields.join(", "));
1243 } else {
1244 self.returning.render(&mut q);
1245 }
1246 q
1247 }
1248}
1249
1250pub struct LetVar {
1262 name: String,
1263 value: Box<dyn DynExpr>,
1264}
1265
1266impl LetVar {
1267 pub fn new(name: impl Into<String>, value: impl DynExpr + 'static) -> Self {
1269 Self {
1270 name: name.into(),
1271 value: Box::new(value),
1272 }
1273 }
1274
1275 pub fn literal<V: SurrealQL>(name: impl Into<String>, value: V) -> Self {
1277 Self {
1278 name: name.into(),
1279 value: Box::new(crate::expr::Literal(value)),
1280 }
1281 }
1282
1283 pub fn to_surrealql(&self) -> String {
1284 let mut q = format!("LET ${} = ", self.name);
1285 self.value.render_dyn(&mut q);
1286 q
1287 }
1288
1289 pub fn to_surrealql_with_params(&self) -> (String, BTreeMap<String, serde_json::Value>) {
1291 let mut params = BTreeMap::new();
1292 let mut q = format!("LET ${} = ", self.name);
1293 self.value.render_dyn_params(&mut q, &mut params);
1294 (q, params)
1295 }
1296}
1297
1298impl std::fmt::Display for LetVar {
1299 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1300 write!(f, "{}", self.to_surrealql())
1301 }
1302}
1303
1304pub struct For {
1318 var: String,
1319 array: Box<dyn DynExpr>,
1320 body: Vec<String>,
1321}
1322
1323impl For {
1324 pub fn new(var: impl Into<String>, array: impl DynExpr + 'static) -> Self {
1327 Self {
1328 var: var.into(),
1329 array: Box::new(array),
1330 body: Vec::new(),
1331 }
1332 }
1333 pub fn push(mut self, stmt: impl Into<String>) -> Self {
1335 self.body.push(stmt.into());
1336 self
1337 }
1338 pub fn to_surrealql(&self) -> String {
1339 let mut q = format!("FOR ${} IN ", self.var);
1340 self.array.render_dyn(&mut q);
1341 q.push_str(" { ");
1342 for s in &self.body {
1343 q.push_str(s);
1344 if !s.trim_end().ends_with(';') {
1345 q.push(';');
1346 }
1347 q.push(' ');
1348 }
1349 q.push('}');
1350 q
1351 }
1352}
1353
1354impl std::fmt::Display for For {
1355 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1356 write!(f, "{}", self.to_surrealql())
1357 }
1358}
1359
1360enum IndexKind {
1366 Plain,
1368 Unique,
1370 Raw(String),
1374}
1375
1376pub struct DefineIndex {
1388 name: String,
1389 table: String,
1390 fields: Vec<String>,
1391 kind: IndexKind,
1392 if_not_exists: bool,
1393 comment: Option<String>,
1394 concurrently: bool,
1395}
1396
1397impl DefineIndex {
1398 pub fn new(name: impl Into<String>, table: impl Into<String>) -> Self {
1400 Self {
1401 name: name.into(),
1402 table: table.into(),
1403 fields: Vec::new(),
1404 kind: IndexKind::Plain,
1405 if_not_exists: true,
1406 comment: None,
1407 concurrently: false,
1408 }
1409 }
1410
1411 pub fn field(mut self, name: impl Into<String>) -> Self {
1413 self.fields.push(name.into());
1414 self
1415 }
1416 pub fn fields<I, S>(mut self, names: I) -> Self
1418 where
1419 I: IntoIterator<Item = S>,
1420 S: Into<String>,
1421 {
1422 self.fields.extend(names.into_iter().map(Into::into));
1423 self
1424 }
1425
1426 pub fn unique(mut self) -> Self {
1428 self.kind = IndexKind::Unique;
1429 self
1430 }
1431 pub fn search(mut self, analyzer: &str) -> Self {
1434 self.kind = IndexKind::Raw(format!("SEARCH ANALYZER {analyzer}"));
1435 self
1436 }
1437 pub fn hnsw(mut self, dimension: u32, dist: &str) -> Self {
1440 self.kind = IndexKind::Raw(format!("HNSW DIMENSION {dimension} DIST {dist}"));
1441 self
1442 }
1443 pub fn mtree(mut self, dimension: u32, dist: &str) -> Self {
1445 self.kind = IndexKind::Raw(format!("MTREE DIMENSION {dimension} DIST {dist}"));
1446 self
1447 }
1448 pub fn raw(mut self, tail: impl Into<String>) -> Self {
1451 self.kind = IndexKind::Raw(tail.into());
1452 self
1453 }
1454
1455 pub fn overwrite(mut self) -> Self {
1457 self.if_not_exists = false;
1458 self
1459 }
1460 pub fn comment(mut self, text: impl Into<String>) -> Self {
1462 self.comment = Some(text.into());
1463 self
1464 }
1465 pub fn concurrently(mut self) -> Self {
1467 self.concurrently = true;
1468 self
1469 }
1470
1471 pub fn to_surrealql(&self) -> String {
1472 let guard = if self.if_not_exists {
1473 "IF NOT EXISTS "
1474 } else {
1475 ""
1476 };
1477 let mut q = format!(
1478 "DEFINE INDEX {guard}{} ON TABLE {} FIELDS {}",
1479 self.name,
1480 self.table,
1481 self.fields.join(", "),
1482 );
1483 match &self.kind {
1484 IndexKind::Plain => {}
1485 IndexKind::Unique => q.push_str(" UNIQUE"),
1486 IndexKind::Raw(tail) => {
1487 q.push(' ');
1488 q.push_str(tail);
1489 }
1490 }
1491 if let Some(c) = &self.comment {
1492 let escaped = c.replace('\\', "\\\\").replace('\'', "\\'");
1493 q.push_str(&format!(" COMMENT '{escaped}'"));
1494 }
1495 if self.concurrently {
1496 q.push_str(" CONCURRENTLY");
1497 }
1498 q
1499 }
1500
1501 pub fn remove(name: &str, table: &str) -> String {
1503 format!("REMOVE INDEX IF EXISTS {name} ON TABLE {table}")
1504 }
1505}
1506
1507impl std::fmt::Display for DefineIndex {
1508 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1509 write!(f, "{}", self.to_surrealql())
1510 }
1511}
1512
1513fn guard(if_not_exists: bool) -> &'static str {
1518 if if_not_exists {
1519 "IF NOT EXISTS "
1520 } else {
1521 ""
1522 }
1523}
1524
1525pub struct DefineEvent {
1536 name: String,
1537 table: String,
1538 when: String,
1539 then: String,
1540 if_not_exists: bool,
1541}
1542
1543impl DefineEvent {
1544 pub fn new(name: impl Into<String>, table: impl Into<String>) -> Self {
1545 Self {
1546 name: name.into(),
1547 table: table.into(),
1548 when: String::new(),
1549 then: String::new(),
1550 if_not_exists: true,
1551 }
1552 }
1553 pub fn when(mut self, cond: impl Into<String>) -> Self {
1555 self.when = cond.into();
1556 self
1557 }
1558 pub fn then(mut self, block: impl Into<String>) -> Self {
1560 self.then = block.into();
1561 self
1562 }
1563 pub fn overwrite(mut self) -> Self {
1565 self.if_not_exists = false;
1566 self
1567 }
1568 pub fn to_surrealql(&self) -> String {
1569 format!(
1570 "DEFINE EVENT {}{} ON TABLE {} WHEN {} THEN {}",
1571 guard(self.if_not_exists),
1572 self.name,
1573 self.table,
1574 self.when,
1575 self.then
1576 )
1577 }
1578 pub fn remove(name: &str, table: &str) -> String {
1580 format!("REMOVE EVENT IF EXISTS {name} ON TABLE {table}")
1581 }
1582}
1583
1584impl std::fmt::Display for DefineEvent {
1585 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1586 write!(f, "{}", self.to_surrealql())
1587 }
1588}
1589
1590pub struct DefineFunction {
1601 name: String,
1602 args: Vec<(String, String)>,
1603 returns: Option<String>,
1604 body: String,
1605 if_not_exists: bool,
1606}
1607
1608impl DefineFunction {
1609 pub fn new(name: impl Into<String>) -> Self {
1610 Self {
1611 name: name.into(),
1612 args: Vec::new(),
1613 returns: None,
1614 body: String::new(),
1615 if_not_exists: true,
1616 }
1617 }
1618 pub fn arg(mut self, name: impl Into<String>, ty: impl Into<String>) -> Self {
1620 self.args.push((name.into(), ty.into()));
1621 self
1622 }
1623 pub fn returns(mut self, ty: impl Into<String>) -> Self {
1625 self.returns = Some(ty.into());
1626 self
1627 }
1628 pub fn body(mut self, body: impl Into<String>) -> Self {
1630 self.body = body.into();
1631 self
1632 }
1633 pub fn overwrite(mut self) -> Self {
1634 self.if_not_exists = false;
1635 self
1636 }
1637 pub fn to_surrealql(&self) -> String {
1638 let args = self
1639 .args
1640 .iter()
1641 .map(|(n, t)| format!("${n}: {t}"))
1642 .collect::<Vec<_>>()
1643 .join(", ");
1644 let ret = self
1645 .returns
1646 .as_ref()
1647 .map(|r| format!(" -> {r}"))
1648 .unwrap_or_default();
1649 format!(
1650 "DEFINE FUNCTION {}fn::{}({}){} {{ {} }}",
1651 guard(self.if_not_exists),
1652 self.name,
1653 args,
1654 ret,
1655 self.body
1656 )
1657 }
1658 pub fn remove(name: &str) -> String {
1660 format!("REMOVE FUNCTION IF EXISTS fn::{name}")
1661 }
1662}
1663
1664impl std::fmt::Display for DefineFunction {
1665 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1666 write!(f, "{}", self.to_surrealql())
1667 }
1668}
1669
1670pub struct DefineAnalyzer {
1673 name: String,
1674 tokenizers: Vec<String>,
1675 filters: Vec<String>,
1676 if_not_exists: bool,
1677}
1678
1679impl DefineAnalyzer {
1680 pub fn new(name: impl Into<String>) -> Self {
1681 Self {
1682 name: name.into(),
1683 tokenizers: Vec::new(),
1684 filters: Vec::new(),
1685 if_not_exists: true,
1686 }
1687 }
1688 pub fn tokenizers<I, S>(mut self, toks: I) -> Self
1690 where
1691 I: IntoIterator<Item = S>,
1692 S: Into<String>,
1693 {
1694 self.tokenizers = toks.into_iter().map(Into::into).collect();
1695 self
1696 }
1697 pub fn filters<I, S>(mut self, filters: I) -> Self
1699 where
1700 I: IntoIterator<Item = S>,
1701 S: Into<String>,
1702 {
1703 self.filters = filters.into_iter().map(Into::into).collect();
1704 self
1705 }
1706 pub fn overwrite(mut self) -> Self {
1707 self.if_not_exists = false;
1708 self
1709 }
1710 pub fn to_surrealql(&self) -> String {
1711 let mut q = format!("DEFINE ANALYZER {}{}", guard(self.if_not_exists), self.name);
1712 if !self.tokenizers.is_empty() {
1713 q.push_str(" TOKENIZERS ");
1714 q.push_str(&self.tokenizers.join(", "));
1715 }
1716 if !self.filters.is_empty() {
1717 q.push_str(" FILTERS ");
1718 q.push_str(&self.filters.join(", "));
1719 }
1720 q
1721 }
1722 pub fn remove(name: &str) -> String {
1724 format!("REMOVE ANALYZER IF EXISTS {name}")
1725 }
1726}
1727
1728impl std::fmt::Display for DefineAnalyzer {
1729 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1730 write!(f, "{}", self.to_surrealql())
1731 }
1732}
1733
1734pub struct DefineParam {
1737 name: String,
1738 value: String,
1739 if_not_exists: bool,
1740}
1741
1742impl DefineParam {
1743 pub fn new(name: impl Into<String>, value: impl Into<String>) -> Self {
1745 Self {
1746 name: name.into(),
1747 value: value.into(),
1748 if_not_exists: true,
1749 }
1750 }
1751 pub fn value_lit<V: SurrealQL>(mut self, value: V) -> Self {
1753 let mut buf = String::new();
1754 V::render_literal(&value, &mut buf);
1755 self.value = buf;
1756 self
1757 }
1758 pub fn overwrite(mut self) -> Self {
1759 self.if_not_exists = false;
1760 self
1761 }
1762 pub fn to_surrealql(&self) -> String {
1763 format!(
1764 "DEFINE PARAM {}${} VALUE {}",
1765 guard(self.if_not_exists),
1766 self.name,
1767 self.value
1768 )
1769 }
1770 pub fn remove(name: &str) -> String {
1772 format!("REMOVE PARAM IF EXISTS ${name}")
1773 }
1774}
1775
1776impl std::fmt::Display for DefineParam {
1777 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1778 write!(f, "{}", self.to_surrealql())
1779 }
1780}