surrealdb_expr/expr/
lookup.rs1use surrealdb_types::{SqlFormat, ToSql};
2
3use crate::expr::order::Ordering;
4use crate::expr::start::Start;
5use crate::expr::{Cond, Dir, Fields, Groups, Idiom, Limit, RecordIdKeyRangeLit, Splits};
6use crate::val::{RecordIdKeyRange, TableName};
7
8#[derive(Clone, Debug, Default, Eq, PartialEq, Hash)]
11pub struct Lookup {
12 pub kind: LookupKind,
13 pub expr: Option<Fields>,
14 pub only: bool,
15 pub what: Vec<LookupSubject>,
16 pub cond: Option<Cond>,
17 pub split: Option<Splits>,
18 pub group: Option<Groups>,
19 pub order: Option<Ordering>,
20 pub limit: Option<Limit>,
21 pub start: Option<Start>,
22 pub alias: Option<Idiom>,
23}
24
25impl Lookup {
26 pub fn read_only(&self) -> bool {
31 self.what.iter().all(LookupSubject::read_only)
32 && self.expr.as_ref().map(|x| x.read_only()).unwrap_or(true)
33 && self.cond.as_ref().map(|x| x.0.read_only()).unwrap_or(true)
34 && self.split.as_ref().map(|x| x.read_only()).unwrap_or(true)
35 && self.group.as_ref().map(|x| x.read_only()).unwrap_or(true)
36 && self.order.as_ref().map(|x| x.read_only()).unwrap_or(true)
37 && self.limit.as_ref().map(|x| x.read_only()).unwrap_or(true)
38 && self.start.as_ref().map(|x| x.read_only()).unwrap_or(true)
39 && self.alias.as_ref().map(|x| x.read_only()).unwrap_or(true)
40 }
41}
42
43impl LookupSubject {
44 pub fn read_only(&self) -> bool {
47 match self {
48 LookupSubject::Table {
49 ..
50 } => true,
51 LookupSubject::Range {
52 range,
53 ..
54 } => range.read_only(),
55 }
56 }
57}
58
59impl ToSql for Lookup {
60 fn fmt_sql(&self, f: &mut String, fmt: SqlFormat) {
61 let stmt: crate::sql::lookup::Lookup = self.clone().into();
62 stmt.fmt_sql(f, fmt);
63 }
64}
65
66#[derive(Clone, Debug, Eq, PartialEq, Hash)]
68pub enum LookupKind {
69 Graph(Dir),
70 Reference,
71}
72
73impl Default for LookupKind {
74 fn default() -> Self {
75 Self::Graph(Dir::default())
76 }
77}
78
79impl ToSql for LookupKind {
80 fn fmt_sql(&self, f: &mut String, fmt: SqlFormat) {
81 match self {
82 Self::Graph(dir) => dir.fmt_sql(f, fmt),
83 Self::Reference => f.push_str("<~"),
84 }
85 }
86}
87
88#[derive(Clone, Debug, Eq, PartialEq, Hash)]
90pub enum LookupSubject {
91 Table {
92 table: TableName,
93 referencing_field: Option<String>,
94 },
95 Range {
96 table: TableName,
97 range: RecordIdKeyRangeLit,
98 referencing_field: Option<String>,
99 },
100}
101
102#[derive(Clone, Debug, Eq, PartialEq, Hash)]
104pub enum ComputedLookupSubject {
105 Table {
106 table: TableName,
107 referencing_field: Option<String>,
108 },
109 Range {
110 table: TableName,
111 range: RecordIdKeyRange,
112 referencing_field: Option<String>,
113 },
114}
115
116impl ComputedLookupSubject {
117 pub fn into_literal(self) -> LookupSubject {
118 match self {
119 ComputedLookupSubject::Table {
120 table,
121 referencing_field,
122 } => LookupSubject::Table {
123 table,
124 referencing_field,
125 },
126 ComputedLookupSubject::Range {
127 table,
128 range,
129 referencing_field,
130 } => LookupSubject::Range {
131 table,
132 range: range.into_literal(),
133 referencing_field,
134 },
135 }
136 }
137}
138
139impl ToSql for LookupSubject {
140 fn fmt_sql(&self, f: &mut String, fmt: SqlFormat) {
141 let stmt: crate::sql::lookup::LookupSubject = self.clone().into();
142 stmt.fmt_sql(f, fmt);
143 }
144}