1use std::ops::Bound;
31
32use crate::ast::TopLevelExpr;
33use crate::block::Block;
34use crate::closure::Closure;
35use crate::expression::Expr;
36use crate::fetch::{Fetch, Fetchs};
37use crate::field::{Field, Fields, Selector};
38use crate::function::{Function, FunctionCall};
39use crate::group::{Group, Groups};
40use crate::idiom::Idiom;
41use crate::limit::Limit;
42use crate::literal::Literal;
43use crate::lookup::{Lookup, LookupSubject};
44use crate::method::is_builtin_method;
45use crate::operator::PostfixOperator;
46use crate::order::{OrderList, Ordering};
47use crate::part::{DestructurePart, Part, RecurseInstruction};
48use crate::record_id::{RecordIdKeyLit, RecordIdKeyRangeLit, RecordIdLit};
49use crate::split::{Split, Splits};
50use crate::start::Start;
51use crate::statements::{
52 ForeachStatement, IfelseStatement, InfoStatement, OutputStatement, SelectStatement,
53 SetStatement,
54};
55
56impl TopLevelExpr {
57 pub fn read_only(&self) -> bool {
61 match self {
62 TopLevelExpr::Begin
63 | TopLevelExpr::Cancel
64 | TopLevelExpr::Commit
65 | TopLevelExpr::Show(_) => true,
66 TopLevelExpr::Kill(_)
67 | TopLevelExpr::Live(_)
68 | TopLevelExpr::Option(_)
69 | TopLevelExpr::Use(_)
70 | TopLevelExpr::Access(_) => false,
71 TopLevelExpr::Expr(expr) => expr.read_only(),
72 }
73 }
74}
75
76impl Expr {
77 pub fn read_only(&self) -> bool {
81 match self {
82 Expr::Param(_)
83 | Expr::Table(_)
84 | Expr::Mock(_)
85 | Expr::Constant(_)
86 | Expr::Break
87 | Expr::Continue
88 | Expr::Sleep(_) => true,
89
90 Expr::Info(info) => info.read_only(),
91
92 Expr::Literal(l) => l.read_only(),
94
95 Expr::Idiom(x) => x.read_only(),
96 Expr::Block(block) => block.read_only(),
97 Expr::Prefix {
98 expr,
99 ..
100 } => expr.read_only(),
101 Expr::Postfix {
102 expr,
103 op,
104 } => {
105 match op {
106 PostfixOperator::Call(args) => {
110 matches!(&**expr, Expr::Closure(_))
111 && expr.read_only() && args.iter().all(Expr::read_only)
112 }
113 PostfixOperator::MethodCall(name, args) => {
119 is_builtin_method(name)
120 && expr.read_only() && args.iter().all(Expr::read_only)
121 }
122 PostfixOperator::Range | PostfixOperator::RangeSkip => expr.read_only(),
123 }
124 }
125 Expr::Binary {
126 left,
127 right,
128 ..
129 } => left.read_only() && right.read_only(),
130 Expr::FunctionCall(function) => function.read_only(),
131 Expr::Return(stmt) => stmt.read_only(),
132 Expr::Throw(expr) => expr.read_only(),
133 Expr::IfElse(s) => s.read_only(),
134 Expr::Select(s) => s.read_only(),
135 Expr::Let(s) => s.read_only(),
136 Expr::Foreach(s) => s.read_only(),
137 Expr::Explain {
138 statement,
139 ..
140 } => statement.read_only(),
141 Expr::Closure(c) => c.read_only(),
145 Expr::Create(_)
146 | Expr::Update(_)
147 | Expr::Delete(_)
148 | Expr::Relate(_)
149 | Expr::Insert(_)
150 | Expr::Define(_)
151 | Expr::Remove(_)
152 | Expr::Rebuild(_)
153 | Expr::Upsert(_)
154 | Expr::Alter(_) => false,
155 }
156 }
157}
158
159impl Closure {
160 fn read_only(&self) -> bool {
161 self.body.read_only()
162 }
163}
164
165impl Block {
166 pub fn read_only(&self) -> bool {
167 self.0.iter().all(|x| x.read_only())
168 }
169}
170
171impl Literal {
172 pub fn read_only(&self) -> bool {
173 match self {
174 Literal::None
175 | Literal::Null
176 | Literal::UnboundedRange
177 | Literal::Bool(_)
178 | Literal::Float(_)
179 | Literal::Integer(_)
180 | Literal::Decimal(_)
181 | Literal::String(_)
182 | Literal::Bytes(_)
183 | Literal::Regex(_)
184 | Literal::Duration(_)
185 | Literal::Datetime(_)
186 | Literal::Uuid(_)
187 | Literal::File(_)
188 | Literal::Geometry(_) => true,
189 Literal::RecordId(record_id_lit) => record_id_lit.read_only(),
190 Literal::Array(exprs) => exprs.iter().all(|x| x.read_only()),
191 Literal::Set(exprs) => exprs.iter().all(|x| x.read_only()),
192 Literal::Object(items) => items.iter().all(|x| x.value.read_only()),
193 }
194 }
195}
196
197impl RecordIdLit {
198 pub fn read_only(&self) -> bool {
199 self.key.read_only()
200 }
201}
202
203impl RecordIdKeyLit {
204 pub fn read_only(&self) -> bool {
205 match self {
206 RecordIdKeyLit::Number(_)
207 | RecordIdKeyLit::String(_)
208 | RecordIdKeyLit::Uuid(_)
209 | RecordIdKeyLit::Generate(_) => true,
210 RecordIdKeyLit::Range(record_id_key_range_lit) => record_id_key_range_lit.read_only(),
211 RecordIdKeyLit::Array(exprs) => exprs.iter().all(|x| x.read_only()),
212 RecordIdKeyLit::Object(items) => items.iter().all(|x| x.value.read_only()),
213 }
214 }
215}
216
217impl RecordIdKeyRangeLit {
218 pub fn read_only(&self) -> bool {
219 let bound_read_only = |bound: &Bound<RecordIdKeyLit>| match bound {
220 Bound::Included(x) | Bound::Excluded(x) => x.read_only(),
221 Bound::Unbounded => true,
222 };
223 bound_read_only(&self.start) && bound_read_only(&self.end)
224 }
225}
226
227impl Idiom {
228 pub fn read_only(&self) -> bool {
229 self.0.iter().all(|v| v.read_only())
230 }
231}
232
233impl Part {
234 pub fn read_only(&self) -> bool {
235 match self {
236 Part::Start(v) => v.read_only(),
237 Part::Where(v) => v.read_only(),
238 Part::Value(v) => v.read_only(),
239 Part::Method(name, v) => is_builtin_method(name) && v.iter().all(Expr::read_only),
244 Part::Graph(v) => v.read_only(),
245 Part::Destructure(v) => v.iter().all(DestructurePart::read_only),
246 Part::Recurse(_, alias, instruction) => {
247 alias.as_ref().map(|x| x.read_only()).unwrap_or(true)
248 && instruction.as_ref().map(|x| x.read_only()).unwrap_or(true)
249 }
250 Part::All
251 | Part::Flatten
252 | Part::Last
253 | Part::First
254 | Part::Field(_)
255 | Part::Optional
256 | Part::Doc
257 | Part::RepeatRecurse => true,
258 }
259 }
260}
261
262impl DestructurePart {
263 pub fn read_only(&self) -> bool {
264 match self {
265 DestructurePart::All(_) | DestructurePart::Field(_) => true,
266 DestructurePart::Aliased(_, v) => v.read_only(),
267 DestructurePart::Destructure(_, v) => v.iter().all(DestructurePart::read_only),
268 }
269 }
270}
271
272impl RecurseInstruction {
273 pub fn read_only(&self) -> bool {
274 match self {
275 RecurseInstruction::Path {
276 ..
277 }
278 | RecurseInstruction::Collect {
279 ..
280 } => true,
281 RecurseInstruction::Shortest {
282 expects,
283 ..
284 } => expects.read_only(),
285 }
286 }
287}
288
289impl Lookup {
290 pub fn read_only(&self) -> bool {
291 self.what.iter().all(LookupSubject::read_only)
292 && self.expr.as_ref().map(|x| x.read_only()).unwrap_or(true)
293 && self.cond.as_ref().map(|x| x.0.read_only()).unwrap_or(true)
294 && self.split.as_ref().map(|x| x.read_only()).unwrap_or(true)
295 && self.group.as_ref().map(|x| x.read_only()).unwrap_or(true)
296 && self.order.as_ref().map(|x| x.read_only()).unwrap_or(true)
297 && self.limit.as_ref().map(|x| x.read_only()).unwrap_or(true)
298 && self.start.as_ref().map(|x| x.read_only()).unwrap_or(true)
299 && self.alias.as_ref().map(|x| x.read_only()).unwrap_or(true)
300 }
301}
302
303impl LookupSubject {
304 pub fn read_only(&self) -> bool {
307 match self {
308 LookupSubject::Table {
309 ..
310 } => true,
311 LookupSubject::Range {
312 range,
313 ..
314 } => range.read_only(),
315 }
316 }
317}
318
319impl InfoStatement {
323 pub fn read_only(&self) -> bool {
324 match self {
325 InfoStatement::Root(_, version)
326 | InfoStatement::Ns(_, version)
327 | InfoStatement::Db(_, version) => version.as_ref().is_none_or(|version| version.read_only()),
328 InfoStatement::Tb(table, _, version) => {
329 table.read_only() && version.as_ref().is_none_or(|version| version.read_only())
330 }
331 InfoStatement::User(user, _, _) => user.read_only(),
332 InfoStatement::Index(index, table, _) => index.read_only() && table.read_only(),
333 }
334 }
335}
336
337impl Function {
338 pub fn read_only(&self) -> bool {
339 match self {
340 Self::Custom(_)
341 | Self::Script(_)
342 | Self::Module(_, _)
343 | Self::Silo {
344 ..
345 } => false,
346 Self::Normal(f) => !crate::method::is_writer_builtin(f),
347 Self::Model(_) => true,
348 }
349 }
350}
351
352impl FunctionCall {
353 pub fn read_only(&self) -> bool {
354 self.receiver.read_only() && self.arguments.iter().all(|x| x.read_only())
355 }
356}
357
358impl Fields {
359 pub fn read_only(&self) -> bool {
360 match self {
361 Fields::Value(field) => field.read_only(),
362 Fields::Select(fields) => fields.iter().all(|x| x.read_only()),
363 }
364 }
365}
366
367impl Field {
368 pub fn read_only(&self) -> bool {
369 match self {
370 Field::All => true,
371 Field::Single(x) => x.read_only(),
372 }
373 }
374}
375
376impl Selector {
377 pub fn read_only(&self) -> bool {
378 self.expr.read_only()
379 }
380}
381
382impl Fetchs {
383 pub fn read_only(&self) -> bool {
384 self.0.iter().all(|x| x.read_only())
385 }
386}
387
388impl Fetch {
389 pub fn read_only(&self) -> bool {
390 self.0.read_only()
391 }
392}
393
394impl Groups {
395 pub fn read_only(&self) -> bool {
396 self.0.iter().all(|x| x.read_only())
397 }
398}
399
400impl Group {
401 pub fn read_only(&self) -> bool {
402 self.0.read_only()
403 }
404}
405
406impl Splits {
407 pub fn read_only(&self) -> bool {
408 self.0.iter().all(|x| x.read_only())
409 }
410}
411
412impl Split {
413 pub fn read_only(&self) -> bool {
414 self.0.read_only()
415 }
416}
417
418impl Ordering {
419 pub fn read_only(&self) -> bool {
420 match self {
421 Ordering::Random => true,
422 Ordering::Order(list) => list.read_only(),
423 }
424 }
425}
426
427impl OrderList {
428 pub fn read_only(&self) -> bool {
429 self.0.iter().all(|x| x.value.read_only())
430 }
431}
432
433impl Limit {
434 pub fn read_only(&self) -> bool {
435 self.0.read_only()
436 }
437}
438
439impl Start {
440 pub fn read_only(&self) -> bool {
441 self.0.read_only()
442 }
443}
444
445impl SelectStatement {
446 pub fn read_only(&self) -> bool {
447 !self.for_update
448 && self.fields.read_only()
449 && self.omit.iter().all(|v| v.read_only())
450 && self.what.iter().all(|v| v.read_only())
451 && self.cond.as_ref().map(|x| x.0.read_only()).unwrap_or(true)
452 && self.split.as_ref().map(|x| x.read_only()).unwrap_or(true)
453 && self.group.as_ref().map(|x| x.read_only()).unwrap_or(true)
454 && self.order.as_ref().map(|x| x.read_only()).unwrap_or(true)
455 && self.limit.as_ref().map(|x| x.read_only()).unwrap_or(true)
456 && self.start.as_ref().map(|x| x.read_only()).unwrap_or(true)
457 && self.fetch.as_ref().map(|x| x.read_only()).unwrap_or(true)
458 && self.version.read_only()
459 && self.timeout.read_only()
460 }
461}
462
463impl SetStatement {
464 pub fn read_only(&self) -> bool {
465 self.what.read_only()
466 }
467}
468
469impl OutputStatement {
470 pub fn read_only(&self) -> bool {
471 self.what.read_only() && self.fetch.as_ref().map(|x| x.read_only()).unwrap_or(true)
472 }
473}
474
475impl IfelseStatement {
476 pub fn read_only(&self) -> bool {
477 self.exprs.iter().all(|x| x.0.read_only() && x.1.read_only())
478 && self.close.as_ref().map(|x| x.read_only()).unwrap_or(true)
479 }
480}
481
482impl ForeachStatement {
483 pub fn read_only(&self) -> bool {
484 self.range.read_only() && self.block.read_only()
485 }
486}