use crate::{
db::{
ExplainAggregateTerminalPlan, ExplainExecutionNodeDescriptor, Row,
query::{
AggregateExpr, CompareOp, CompiledQuery, ExplainPlan, FilterExpr, PlannedQuery, Query,
QueryTracePlan, ValueProjectionExpr,
},
response::{PagedResponse, QueryResponse, Response},
session::macros::{impl_session_materialization_methods, impl_session_query_shape_methods},
},
error::Error,
traits::{Entity, SingletonEntity},
types::{Decimal, Id},
value::{InputValue, OutputValue},
};
use icydb_core as core;
type MinMaxIds<E> = Option<(Id<E>, Id<E>)>;
pub struct FluentLoadQuery<'a, E: Entity> {
pub(crate) inner: core::db::FluentLoadQuery<'a, E>,
}
#[allow(
clippy::elidable_lifetime_names,
reason = "by-value pagination conversion needs the wrapper lifetime in its return type"
)]
impl<'a, E: Entity> FluentLoadQuery<'a, E> {
#[must_use]
pub const fn query(&self) -> &Query<E> {
self.inner.query()
}
impl_session_query_shape_methods!();
#[must_use]
pub fn offset(mut self, offset: u32) -> Self {
self.inner = self.inner.offset(offset);
self
}
#[must_use]
pub fn cursor(mut self, token: impl Into<String>) -> Self {
self.inner = self.inner.cursor(token);
self
}
pub fn group_by(mut self, field: impl AsRef<str>) -> Result<Self, Error> {
self.inner = self.inner.group_by(field)?;
Ok(self)
}
#[must_use]
pub fn aggregate(mut self, aggregate: AggregateExpr) -> Self {
self.inner = self.inner.aggregate(aggregate);
self
}
#[must_use]
pub fn grouped_limits(mut self, max_groups: u64, max_group_bytes: u64) -> Self {
self.inner = self.inner.grouped_limits(max_groups, max_group_bytes);
self
}
pub fn having_group(
mut self,
field: impl AsRef<str>,
op: CompareOp,
value: InputValue,
) -> Result<Self, Error> {
self.inner = self.inner.having_group(field, op, value)?;
Ok(self)
}
pub fn having_aggregate(
mut self,
aggregate_index: usize,
op: CompareOp,
value: InputValue,
) -> Result<Self, Error> {
self.inner = self.inner.having_aggregate(aggregate_index, op, value)?;
Ok(self)
}
impl_session_materialization_methods!();
pub fn page(self) -> Result<PagedLoadQuery<'a, E>, Error> {
Ok(PagedLoadQuery {
inner: self.inner.page()?,
})
}
pub fn execute_paged(self) -> Result<PagedResponse<E>, Error>
where
E: Entity,
{
self.page()?.execute()
}
pub fn execute_rows(&self) -> Result<Response<E>, Error>
where
E: Entity,
{
Ok(Response::from_core(self.inner.execute_rows()?))
}
pub fn plan_hash_hex(&self) -> Result<String, Error> {
Ok(self.inner.plan_hash_hex()?)
}
pub fn trace(&self) -> Result<QueryTracePlan, Error> {
Ok(self.inner.trace()?)
}
pub fn planned(&self) -> Result<PlannedQuery<E>, Error> {
Ok(self.inner.planned()?)
}
pub fn plan(&self) -> Result<CompiledQuery<E>, Error> {
Ok(self.inner.plan()?)
}
pub fn explain(&self) -> Result<ExplainPlan, Error> {
Ok(self.inner.explain()?)
}
pub fn exists(&self) -> Result<bool, Error>
where
E: Entity,
{
Ok(self.inner.exists()?)
}
pub fn explain_exists(&self) -> Result<ExplainAggregateTerminalPlan, Error>
where
E: Entity,
{
Ok(self.inner.explain_exists()?)
}
pub fn not_exists(&self) -> Result<bool, Error>
where
E: Entity,
{
Ok(self.inner.not_exists()?)
}
pub fn explain_not_exists(&self) -> Result<ExplainAggregateTerminalPlan, Error>
where
E: Entity,
{
Ok(self.inner.explain_not_exists()?)
}
pub fn explain_execution(&self) -> Result<ExplainExecutionNodeDescriptor, Error>
where
E: Entity,
{
Ok(self.inner.explain_execution()?)
}
pub fn explain_execution_text(&self) -> Result<String, Error>
where
E: Entity,
{
Ok(self.inner.explain_execution_text()?)
}
pub fn explain_execution_json(&self) -> Result<String, Error>
where
E: Entity,
{
Ok(self.inner.explain_execution_json()?)
}
pub fn explain_execution_verbose(&self) -> Result<String, Error>
where
E: Entity,
{
Ok(self.inner.explain_execution_verbose()?)
}
pub fn bytes(&self) -> Result<u64, Error>
where
E: Entity,
{
Ok(self.inner.bytes()?)
}
pub fn bytes_by(&self, field: impl AsRef<str>) -> Result<u64, Error>
where
E: Entity,
{
Ok(self.inner.bytes_by(field)?)
}
pub fn explain_bytes_by(
&self,
field: impl AsRef<str>,
) -> Result<ExplainExecutionNodeDescriptor, Error>
where
E: Entity,
{
Ok(self.inner.explain_bytes_by(field)?)
}
pub fn min(&self) -> Result<Option<Id<E>>, Error>
where
E: Entity,
{
Ok(self.inner.min()?)
}
pub fn explain_min(&self) -> Result<ExplainAggregateTerminalPlan, Error>
where
E: Entity,
{
Ok(self.inner.explain_min()?)
}
pub fn min_by(&self, field: impl AsRef<str>) -> Result<Option<Id<E>>, Error>
where
E: Entity,
{
Ok(self.inner.min_by(field)?)
}
pub fn max(&self) -> Result<Option<Id<E>>, Error>
where
E: Entity,
{
Ok(self.inner.max()?)
}
pub fn explain_max(&self) -> Result<ExplainAggregateTerminalPlan, Error>
where
E: Entity,
{
Ok(self.inner.explain_max()?)
}
pub fn max_by(&self, field: impl AsRef<str>) -> Result<Option<Id<E>>, Error>
where
E: Entity,
{
Ok(self.inner.max_by(field)?)
}
pub fn nth_by(&self, field: impl AsRef<str>, nth: usize) -> Result<Option<Id<E>>, Error>
where
E: Entity,
{
Ok(self.inner.nth_by(field, nth)?)
}
pub fn sum_by(&self, field: impl AsRef<str>) -> Result<Option<Decimal>, Error>
where
E: Entity,
{
Ok(self.inner.sum_by(field)?)
}
pub fn explain_sum_by(
&self,
field: impl AsRef<str>,
) -> Result<ExplainAggregateTerminalPlan, Error>
where
E: Entity,
{
Ok(self.inner.explain_sum_by(field)?)
}
pub fn sum_distinct_by(&self, field: impl AsRef<str>) -> Result<Option<Decimal>, Error>
where
E: Entity,
{
Ok(self.inner.sum_distinct_by(field)?)
}
pub fn explain_sum_distinct_by(
&self,
field: impl AsRef<str>,
) -> Result<ExplainAggregateTerminalPlan, Error>
where
E: Entity,
{
Ok(self.inner.explain_sum_distinct_by(field)?)
}
pub fn avg_by(&self, field: impl AsRef<str>) -> Result<Option<Decimal>, Error>
where
E: Entity,
{
Ok(self.inner.avg_by(field)?)
}
pub fn explain_avg_by(
&self,
field: impl AsRef<str>,
) -> Result<ExplainAggregateTerminalPlan, Error>
where
E: Entity,
{
Ok(self.inner.explain_avg_by(field)?)
}
pub fn avg_distinct_by(&self, field: impl AsRef<str>) -> Result<Option<Decimal>, Error>
where
E: Entity,
{
Ok(self.inner.avg_distinct_by(field)?)
}
pub fn explain_avg_distinct_by(
&self,
field: impl AsRef<str>,
) -> Result<ExplainAggregateTerminalPlan, Error>
where
E: Entity,
{
Ok(self.inner.explain_avg_distinct_by(field)?)
}
pub fn median_by(&self, field: impl AsRef<str>) -> Result<Option<Id<E>>, Error>
where
E: Entity,
{
Ok(self.inner.median_by(field)?)
}
pub fn count_distinct_by(&self, field: impl AsRef<str>) -> Result<u32, Error>
where
E: Entity,
{
Ok(self.inner.count_distinct_by(field)?)
}
pub fn explain_count_distinct_by(
&self,
field: impl AsRef<str>,
) -> Result<ExplainExecutionNodeDescriptor, Error>
where
E: Entity,
{
Ok(self.inner.explain_count_distinct_by(field)?)
}
pub fn min_max_by(&self, field: impl AsRef<str>) -> Result<MinMaxIds<E>, Error>
where
E: Entity,
{
Ok(self.inner.min_max_by(field)?)
}
pub fn values_by(&self, field: impl AsRef<str>) -> Result<Vec<OutputValue>, Error>
where
E: Entity,
{
Ok(self.inner.values_by(field)?)
}
pub fn project_values<P>(&self, projection: &P) -> Result<Vec<OutputValue>, Error>
where
E: Entity,
P: ValueProjectionExpr,
{
Ok(self.inner.project_values(projection)?)
}
pub fn explain_project_values<P>(
&self,
projection: &P,
) -> Result<ExplainExecutionNodeDescriptor, Error>
where
E: Entity,
P: ValueProjectionExpr,
{
Ok(self.inner.explain_project_values(projection)?)
}
pub fn explain_values_by(
&self,
field: impl AsRef<str>,
) -> Result<ExplainExecutionNodeDescriptor, Error>
where
E: Entity,
{
Ok(self.inner.explain_values_by(field)?)
}
pub fn take(&self, take_count: u32) -> Result<Response<E>, Error>
where
E: Entity,
{
Ok(Response::from_core(self.inner.take(take_count)?))
}
pub fn top_k_by(&self, field: impl AsRef<str>, take_count: u32) -> Result<Response<E>, Error>
where
E: Entity,
{
Ok(Response::from_core(self.inner.top_k_by(field, take_count)?))
}
pub fn bottom_k_by(&self, field: impl AsRef<str>, take_count: u32) -> Result<Response<E>, Error>
where
E: Entity,
{
Ok(Response::from_core(
self.inner.bottom_k_by(field, take_count)?,
))
}
pub fn top_k_by_values(
&self,
field: impl AsRef<str>,
take_count: u32,
) -> Result<Vec<OutputValue>, Error>
where
E: Entity,
{
Ok(self.inner.top_k_by_values(field, take_count)?)
}
pub fn bottom_k_by_values(
&self,
field: impl AsRef<str>,
take_count: u32,
) -> Result<Vec<OutputValue>, Error>
where
E: Entity,
{
Ok(self.inner.bottom_k_by_values(field, take_count)?)
}
pub fn top_k_by_with_ids(
&self,
field: impl AsRef<str>,
take_count: u32,
) -> Result<Vec<(Id<E>, OutputValue)>, Error>
where
E: Entity,
{
Ok(self.inner.top_k_by_with_ids(field, take_count)?)
}
pub fn bottom_k_by_with_ids(
&self,
field: impl AsRef<str>,
take_count: u32,
) -> Result<Vec<(Id<E>, OutputValue)>, Error>
where
E: Entity,
{
Ok(self.inner.bottom_k_by_with_ids(field, take_count)?)
}
pub fn distinct_values_by(&self, field: impl AsRef<str>) -> Result<Vec<OutputValue>, Error>
where
E: Entity,
{
Ok(self.inner.distinct_values_by(field)?)
}
pub fn explain_distinct_values_by(
&self,
field: impl AsRef<str>,
) -> Result<ExplainExecutionNodeDescriptor, Error>
where
E: Entity,
{
Ok(self.inner.explain_distinct_values_by(field)?)
}
pub fn values_by_with_ids(
&self,
field: impl AsRef<str>,
) -> Result<Vec<(Id<E>, OutputValue)>, Error>
where
E: Entity,
{
Ok(self.inner.values_by_with_ids(field)?)
}
pub fn project_values_with_ids<P>(
&self,
projection: &P,
) -> Result<Vec<(Id<E>, OutputValue)>, Error>
where
E: Entity,
P: ValueProjectionExpr,
{
Ok(self.inner.project_values_with_ids(projection)?)
}
pub fn explain_values_by_with_ids(
&self,
field: impl AsRef<str>,
) -> Result<ExplainExecutionNodeDescriptor, Error>
where
E: Entity,
{
Ok(self.inner.explain_values_by_with_ids(field)?)
}
pub fn first_value_by(&self, field: impl AsRef<str>) -> Result<Option<OutputValue>, Error>
where
E: Entity,
{
Ok(self.inner.first_value_by(field)?)
}
pub fn project_first_value<P>(&self, projection: &P) -> Result<Option<OutputValue>, Error>
where
E: Entity,
P: ValueProjectionExpr,
{
Ok(self.inner.project_first_value(projection)?)
}
pub fn explain_first_value_by(
&self,
field: impl AsRef<str>,
) -> Result<ExplainExecutionNodeDescriptor, Error>
where
E: Entity,
{
Ok(self.inner.explain_first_value_by(field)?)
}
pub fn last_value_by(&self, field: impl AsRef<str>) -> Result<Option<OutputValue>, Error>
where
E: Entity,
{
Ok(self.inner.last_value_by(field)?)
}
pub fn project_last_value<P>(&self, projection: &P) -> Result<Option<OutputValue>, Error>
where
E: Entity,
P: ValueProjectionExpr,
{
Ok(self.inner.project_last_value(projection)?)
}
pub fn explain_last_value_by(
&self,
field: impl AsRef<str>,
) -> Result<ExplainExecutionNodeDescriptor, Error>
where
E: Entity,
{
Ok(self.inner.explain_last_value_by(field)?)
}
pub fn first(&self) -> Result<Option<Id<E>>, Error>
where
E: Entity,
{
Ok(self.inner.first()?)
}
pub fn explain_first(&self) -> Result<ExplainAggregateTerminalPlan, Error>
where
E: Entity,
{
Ok(self.inner.explain_first()?)
}
pub fn last(&self) -> Result<Option<Id<E>>, Error>
where
E: Entity,
{
Ok(self.inner.last()?)
}
pub fn explain_last(&self) -> Result<ExplainAggregateTerminalPlan, Error>
where
E: Entity,
{
Ok(self.inner.explain_last()?)
}
pub fn one(&self) -> Result<E, Error>
where
E: Entity,
{
self.entity()
}
pub fn one_opt(&self) -> Result<Option<E>, Error>
where
E: Entity,
{
self.try_entity()
}
pub fn all(&self) -> Result<Vec<E>, Error>
where
E: Entity,
{
self.entities()
}
}
impl<E: Entity + SingletonEntity> FluentLoadQuery<'_, E> {
#[must_use]
pub fn only(mut self) -> Self
where
E::Key: Default,
{
self.inner = self.inner.only();
self
}
}
pub struct PagedLoadQuery<'a, E: Entity> {
pub(crate) inner: core::db::PagedLoadQuery<'a, E>,
}
impl<E: Entity> PagedLoadQuery<'_, E> {
#[must_use]
pub const fn query(&self) -> &Query<E> {
self.inner.query()
}
#[must_use]
pub fn cursor(mut self, token: impl Into<String>) -> Self {
self.inner = self.inner.cursor(token);
self
}
pub fn execute(self) -> Result<PagedResponse<E>, Error>
where
E: Entity,
{
let execution = self.inner.execute()?;
let (response, continuation_cursor) = execution.into_response_and_cursor();
let next_cursor = continuation_cursor.as_deref().map(core::db::encode_cursor);
Ok(PagedResponse::new(response.entities(), next_cursor))
}
}