surql_parser/upstream/syn/parser/
record_id.rs1use super::{ParseResult, Parser};
2use crate::upstream::sql::lookup::LookupSubject;
3use crate::upstream::sql::{
4 Param, RecordIdKeyGen, RecordIdKeyLit, RecordIdKeyRangeLit, RecordIdLit,
5};
6use crate::upstream::syn::error::bail;
7use crate::upstream::syn::lexer::compound;
8use crate::upstream::syn::parser::mac::{expected, expected_whitespace, unexpected};
9use crate::upstream::syn::token::{TokenKind, t};
10use reblessive::Stk;
11use std::cmp::Ordering;
12use std::ops::Bound;
13use surrealdb_types::ToSql;
14impl Parser<'_> {
15 pub async fn parse_record_id_or_range(
16 &mut self,
17 stk: &mut Stk,
18 ident: String,
19 ) -> ParseResult<RecordIdLit> {
20 expected_whitespace!(self, t!(":"));
21 if self.eat_whitespace(t!("..")) {
22 let end = if self.eat_whitespace(t!("=")) {
23 let id = stk.run(|stk| self.parse_record_id_key(stk)).await?;
24 Bound::Included(id)
25 } else if let Some(peek) = self.peek_whitespace()
26 && Self::kind_starts_record_id_key(peek.kind)
27 {
28 let id = stk.run(|stk| self.parse_record_id_key(stk)).await?;
29 Bound::Excluded(id)
30 } else {
31 Bound::Unbounded
32 };
33 return Ok(RecordIdLit {
34 table: ident,
35 key: RecordIdKeyLit::Range(Box::new(RecordIdKeyRangeLit {
36 start: Bound::Unbounded,
37 end,
38 })),
39 });
40 }
41 let beg = if let Some(peek) = self.peek_whitespace()
42 && Self::kind_starts_record_id_key(peek.kind)
43 {
44 let v = stk.run(|stk| self.parse_record_id_key(stk)).await?;
45 if self.eat_whitespace(t!(">")) {
46 Bound::Excluded(v)
47 } else {
48 Bound::Included(v)
49 }
50 } else {
51 Bound::Unbounded
52 };
53 if self.eat_whitespace(t!("..")) {
54 let end = if self.eat_whitespace(t!("=")) {
55 let id = stk.run(|stk| self.parse_record_id_key(stk)).await?;
56 Bound::Included(id)
57 } else if let Some(peek) = self.peek_whitespace()
58 && Self::kind_starts_record_id_key(peek.kind)
59 {
60 let id = stk.run(|stk| self.parse_record_id_key(stk)).await?;
61 Bound::Excluded(id)
62 } else {
63 Bound::Unbounded
64 };
65 Ok(RecordIdLit {
66 table: ident,
67 key: RecordIdKeyLit::Range(Box::new(RecordIdKeyRangeLit { start: beg, end })),
68 })
69 } else {
70 let id = match beg {
71 Bound::Unbounded => {
72 if let Some(token) = self.peek_whitespace()
73 && token.kind == t!("$param")
74 {
75 let param = self.next_token_value::<Param>()?;
76 bail!(
77 "Unexpected token `$param` expected a record-id key", @ token
78 .span =>
79 "Record-id's can be create from a param with `type::record(\"{}\",{})`",
80 ident, param.to_sql()
81 );
82 }
83 unexpected!(self, self.peek(), "a record-id key")
84 }
85 Bound::Excluded(_) => {
86 unexpected!(self, self.peek(), "the range operator `..`")
87 }
88 Bound::Included(v) => v,
89 };
90 Ok(RecordIdLit {
91 table: ident,
92 key: id,
93 })
94 }
95 }
96 pub async fn parse_id_range(&mut self, stk: &mut Stk) -> ParseResult<RecordIdKeyRangeLit> {
97 let beg = if let Some(peek) = self.peek_whitespace()
98 && Self::kind_starts_record_id_key(peek.kind)
99 {
100 let v = stk.run(|stk| self.parse_record_id_key(stk)).await?;
101 if self.eat_whitespace(t!(">")) {
102 Bound::Excluded(v)
103 } else {
104 Bound::Included(v)
105 }
106 } else {
107 Bound::Unbounded
108 };
109 expected!(self, t!(".."));
110 let end = if self.eat_whitespace(t!("=")) {
111 let id = stk.run(|stk| self.parse_record_id_key(stk)).await?;
112 Bound::Included(id)
113 } else if let Some(peek) = self.peek_whitespace()
114 && Self::kind_starts_record_id_key(peek.kind)
115 {
116 let id = stk.run(|stk| self.parse_record_id_key(stk)).await?;
117 Bound::Excluded(id)
118 } else {
119 Bound::Unbounded
120 };
121 Ok(RecordIdKeyRangeLit { start: beg, end })
122 }
123 pub async fn parse_lookup_subject(
124 &mut self,
125 stk: &mut Stk,
126 supports_referencing_field: bool,
127 ) -> ParseResult<LookupSubject> {
128 let table = self.parse_ident()?;
129 if self.eat_whitespace(t!(":")) {
130 let range = self.parse_id_range(stk).await?;
131 let referencing_field = self
132 .parse_referencing_field(supports_referencing_field)
133 .await?;
134 Ok(LookupSubject::Range {
135 table,
136 range,
137 referencing_field,
138 })
139 } else {
140 Ok(LookupSubject::Table {
141 table,
142 referencing_field: self
143 .parse_referencing_field(supports_referencing_field)
144 .await?,
145 })
146 }
147 }
148 pub async fn parse_referencing_field(
149 &mut self,
150 supports_referencing_field: bool,
151 ) -> ParseResult<Option<String>> {
152 if supports_referencing_field && self.eat(t!("FIELD")) {
153 Ok(Some(self.parse_ident()?))
154 } else {
155 Ok(None)
156 }
157 }
158 pub async fn parse_record_id(&mut self, stk: &mut Stk) -> ParseResult<RecordIdLit> {
159 let ident = self.parse_ident()?;
160 self.parse_record_id_from_ident(stk, ident).await
161 }
162 pub async fn parse_record_id_from_ident(
163 &mut self,
164 stk: &mut Stk,
165 ident: String,
166 ) -> ParseResult<RecordIdLit> {
167 expected!(self, t!(":"));
168 let id = stk.run(|ctx| self.parse_record_id_key(ctx)).await?;
169 Ok(RecordIdLit {
170 table: ident,
171 key: id,
172 })
173 }
174 pub async fn parse_record_id_key(&mut self, stk: &mut Stk) -> ParseResult<RecordIdKeyLit> {
175 let Some(token) = self.peek_whitespace() else {
176 bail!("Unexpected whitespace after record-id table", @ self.peek().span)
177 };
178 match token.kind {
179 t!("u'") | t!("u\"") => Ok(RecordIdKeyLit::Uuid(self.next_token_value()?)),
180 t!("{") => {
181 self.pop_peek();
182 let object = self.parse_object(stk, token.span).await?;
183 Ok(RecordIdKeyLit::Object(object))
184 }
185 t!("[") => {
186 self.pop_peek();
187 let array = self.parse_array(stk, token.span).await?;
188 Ok(RecordIdKeyLit::Array(array))
189 }
190 t!("+") => {
191 self.pop_peek();
192 let digits_token = if let Some(digits_token) = self.peek_whitespace() {
193 match digits_token.kind {
194 TokenKind::Digits => digits_token,
195 _ => unexpected!(self, digits_token, "an integer"),
196 }
197 } else {
198 unexpected!(self, token, "a record-id key")
199 };
200 if let Some(next) = self.peek_whitespace() {
201 match next.kind {
202 t!(".") => {
203 unexpected!(
204 self, next, "an integer", =>
205 "Numeric Record-id keys can only be integers"
206 );
207 }
208 x if Self::kind_is_identifier(x) => {
209 let span = token.span.covers(next.span);
210 bail!("Unexpected token `{x}` expected an integer", @ span);
211 }
212 _ => {}
213 }
214 }
215 let digits_str = self.span_str(digits_token.span);
216 if let Ok(number) = digits_str.parse() {
217 Ok(RecordIdKeyLit::Number(number))
218 } else {
219 Ok(RecordIdKeyLit::String(digits_str.to_owned()))
220 }
221 }
222 t!("-") => {
223 self.pop_peek();
224 let token = expected!(self, TokenKind::Digits);
225 if let Ok(number) = self.lex_compound(token, compound::integer::<u64>) {
226 match number.value.cmp(&((i64::MAX as u64) + 1)) {
227 Ordering::Less => Ok(RecordIdKeyLit::Number(-(number.value as i64))),
228 Ordering::Equal => Ok(RecordIdKeyLit::Number(i64::MIN)),
229 Ordering::Greater => Ok(RecordIdKeyLit::String(format!(
230 "-{}",
231 self.span_str(number.span)
232 ))),
233 }
234 } else {
235 let strand = format!("-{}", self.span_str(token.span));
236 Ok(RecordIdKeyLit::String(strand))
237 }
238 }
239 TokenKind::Digits => {
240 if self.settings.flexible_record_id
241 && let Some(next) = self.peek_whitespace1()
242 && (Self::kind_is_identifier(next.kind)
243 || next.kind == TokenKind::NaN
244 || next.kind == TokenKind::Infinity)
245 {
246 let ident = self.parse_flexible_ident()?;
247 return Ok(RecordIdKeyLit::String(ident));
248 }
249 self.pop_peek();
250 let digits_str = self.span_str(token.span);
251 if let Ok(number) = digits_str.parse::<i64>() {
252 Ok(RecordIdKeyLit::Number(number))
253 } else {
254 Ok(RecordIdKeyLit::String(digits_str.to_owned()))
255 }
256 }
257 t!("ULID") => {
258 let token = self.pop_peek();
259 if self.eat(t!("(")) {
260 expected!(self, t!(")"));
261 Ok(RecordIdKeyLit::Generate(RecordIdKeyGen::Ulid))
262 } else {
263 let slice = self.span_str(token.span);
264 Ok(RecordIdKeyLit::String(slice.to_owned()))
265 }
266 }
267 t!("UUID") => {
268 let token = self.pop_peek();
269 if self.eat(t!("(")) {
270 expected!(self, t!(")"));
271 Ok(RecordIdKeyLit::Generate(RecordIdKeyGen::Uuid))
272 } else {
273 let slice = self.span_str(token.span);
274 Ok(RecordIdKeyLit::String(slice.to_owned()))
275 }
276 }
277 t!("RAND") => {
278 let token = self.pop_peek();
279 if self.eat(t!("(")) {
280 expected!(self, t!(")"));
281 Ok(RecordIdKeyLit::Generate(RecordIdKeyGen::Rand))
282 } else {
283 let slice = self.span_str(token.span);
284 Ok(RecordIdKeyLit::String(slice.to_owned()))
285 }
286 }
287 _ => {
288 let ident = if self.settings.flexible_record_id {
289 self.parse_flexible_ident()?
290 } else {
291 self.parse_ident()?
292 };
293 Ok(RecordIdKeyLit::String(ident))
294 }
295 }
296 }
297}