surrealdb_sql/statements/
select.rsuse crate::ctx::Context;
use crate::dbs::{Iterable, Iterator, Options, Statement, Transaction};
use crate::doc::CursorDoc;
use crate::err::Error;
use crate::idx::planner::QueryPlanner;
use crate::{
Cond, Explain, Fetchs, Field, Fields, Groups, Idioms, Limit, Orders, Splits, Start, Timeout,
Value, Values, Version, With,
};
use derive::Store;
use revision::revisioned;
use serde::{Deserialize, Serialize};
use std::fmt;
#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Store, Hash)]
#[revisioned(revision = 2)]
pub struct SelectStatement {
pub expr: Fields,
pub omit: Option<Idioms>,
#[revision(start = 2)]
pub only: bool,
pub what: Values,
pub with: Option<With>,
pub cond: Option<Cond>,
pub split: Option<Splits>,
pub group: Option<Groups>,
pub order: Option<Orders>,
pub limit: Option<Limit>,
pub start: Option<Start>,
pub fetch: Option<Fetchs>,
pub version: Option<Version>,
pub timeout: Option<Timeout>,
pub parallel: bool,
pub explain: Option<Explain>,
}
impl SelectStatement {
pub(crate) fn writeable(&self) -> bool {
if self.expr.iter().any(|v| match v {
Field::All => false,
Field::Single {
expr,
..
} => expr.writeable(),
}) {
return true;
}
if self.what.iter().any(|v| v.writeable()) {
return true;
}
self.cond.as_ref().map_or(false, |v| v.writeable())
}
pub(crate) async fn compute(
&self,
ctx: &Context<'_>,
opt: &Options,
txn: &Transaction,
doc: Option<&CursorDoc<'_>>,
) -> Result<Value, Error> {
opt.valid_for_db()?;
let mut i = Iterator::new();
let opt = &opt.new_with_futures(false).with_projections(true);
let mut planner = QueryPlanner::new(opt, &self.with, &self.cond);
let limit_is_one_or_zero = match &self.limit {
Some(l) => l.process(ctx, opt, txn, doc).await? <= 1,
_ => false,
};
if self.only && !limit_is_one_or_zero && self.what.0.len() > 1 {
return Err(Error::SingleOnlyOutput);
}
for w in self.what.0.iter() {
let v = w.compute(ctx, opt, txn, doc).await?;
match v {
Value::Table(t) => {
if self.only && !limit_is_one_or_zero {
return Err(Error::SingleOnlyOutput);
}
planner.add_iterables(ctx, txn, t, &mut i).await?;
}
Value::Thing(v) => i.ingest(Iterable::Thing(v)),
Value::Range(v) => {
if self.only && !limit_is_one_or_zero {
return Err(Error::SingleOnlyOutput);
}
i.ingest(Iterable::Range(*v))
}
Value::Edges(v) => {
if self.only && !limit_is_one_or_zero {
return Err(Error::SingleOnlyOutput);
}
i.ingest(Iterable::Edges(*v))
}
Value::Mock(v) => {
if self.only && !limit_is_one_or_zero {
return Err(Error::SingleOnlyOutput);
}
for v in v {
i.ingest(Iterable::Thing(v));
}
}
Value::Array(v) => {
if self.only && !limit_is_one_or_zero {
return Err(Error::SingleOnlyOutput);
}
for v in v {
match v {
Value::Table(t) => {
planner.add_iterables(ctx, txn, t, &mut i).await?;
}
Value::Thing(v) => i.ingest(Iterable::Thing(v)),
Value::Edges(v) => i.ingest(Iterable::Edges(*v)),
Value::Mock(v) => {
for v in v {
i.ingest(Iterable::Thing(v));
}
}
_ => i.ingest(Iterable::Value(v)),
}
}
}
v => i.ingest(Iterable::Value(v)),
};
}
let mut ctx = Context::new(ctx);
let stm = Statement::from(self);
if planner.has_executors() {
ctx.set_query_planner(&planner);
}
match i.output(&ctx, opt, txn, &stm).await? {
Value::Array(mut a) if self.only => match a.len() {
0 => Ok(Value::None),
1 => Ok(a.remove(0)),
_ => Err(Error::SingleOnlyOutput),
},
v => Ok(v),
}
}
}
impl fmt::Display for SelectStatement {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "SELECT {}", self.expr)?;
if let Some(ref v) = self.omit {
write!(f, " OMIT {v}")?
}
write!(f, " FROM")?;
if self.only {
f.write_str(" ONLY")?
}
write!(f, " {}", self.what)?;
if let Some(ref v) = self.with {
write!(f, " {v}")?
}
if let Some(ref v) = self.cond {
write!(f, " {v}")?
}
if let Some(ref v) = self.split {
write!(f, " {v}")?
}
if let Some(ref v) = self.group {
write!(f, " {v}")?
}
if let Some(ref v) = self.order {
write!(f, " {v}")?
}
if let Some(ref v) = self.limit {
write!(f, " {v}")?
}
if let Some(ref v) = self.start {
write!(f, " {v}")?
}
if let Some(ref v) = self.fetch {
write!(f, " {v}")?
}
if let Some(ref v) = self.version {
write!(f, " {v}")?
}
if let Some(ref v) = self.timeout {
write!(f, " {v}")?
}
if self.parallel {
f.write_str(" PARALLEL")?
}
if let Some(ref v) = self.explain {
write!(f, " {v}")?
}
Ok(())
}
}