use crate::{
db::{
PersistedRow, Row,
query::{AggregateExpr, FilterExpr, Predicate, Query, QueryTracePlan, SortExpr},
response::{PagedGroupedResponse, PagedResponse, Response},
session::macros::{impl_session_materialization_methods, impl_session_query_shape_methods},
},
error::Error,
traits::{EntityValue, SingletonEntity},
types::Id,
value::Value,
};
use icydb_core as core;
pub struct FluentLoadQuery<'a, E: PersistedRow> {
pub(crate) inner: core::db::FluentLoadQuery<'a, E>,
}
impl<'a, E: PersistedRow> 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
}
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: EntityValue,
{
self.page()?.execute()
}
pub fn execute_grouped(self) -> Result<PagedGroupedResponse, Error>
where
E: EntityValue,
{
let (rows, next_cursor, execution_trace) = self.inner.execute_grouped_text_cursor()?;
Ok(PagedGroupedResponse::new(
rows,
next_cursor,
execution_trace,
))
}
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 exists(&self) -> Result<bool, Error>
where
E: EntityValue,
{
Ok(self.inner.exists()?)
}
pub fn not_exists(&self) -> Result<bool, Error>
where
E: EntityValue,
{
Ok(self.inner.not_exists()?)
}
pub fn first(&self) -> Result<Option<Id<E>>, Error>
where
E: EntityValue,
{
Ok(self.inner.first()?)
}
pub fn bytes(&self) -> Result<u64, Error>
where
E: EntityValue,
{
Ok(self.inner.bytes()?)
}
pub fn last(&self) -> Result<Option<Id<E>>, Error>
where
E: EntityValue,
{
Ok(self.inner.last()?)
}
pub fn values_by(&self, field: impl AsRef<str>) -> Result<Vec<Value>, Error>
where
E: EntityValue,
{
Ok(self.inner.values_by(field)?)
}
pub fn distinct_values_by(&self, field: impl AsRef<str>) -> Result<Vec<Value>, Error>
where
E: EntityValue,
{
Ok(self.inner.distinct_values_by(field)?)
}
pub fn values_by_with_ids(&self, field: impl AsRef<str>) -> Result<Vec<(Id<E>, Value)>, Error>
where
E: EntityValue,
{
Ok(self.inner.values_by_with_ids(field)?)
}
pub fn first_value_by(&self, field: impl AsRef<str>) -> Result<Option<Value>, Error>
where
E: EntityValue,
{
Ok(self.inner.first_value_by(field)?)
}
pub fn last_value_by(&self, field: impl AsRef<str>) -> Result<Option<Value>, Error>
where
E: EntityValue,
{
Ok(self.inner.last_value_by(field)?)
}
pub fn one(&self) -> Result<E, Error>
where
E: EntityValue,
{
self.entity()
}
pub fn one_opt(&self) -> Result<Option<E>, Error>
where
E: EntityValue,
{
self.try_entity()
}
pub fn all(&self) -> Result<Vec<E>, Error>
where
E: EntityValue,
{
self.entities()
}
}
impl<E: PersistedRow + 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: PersistedRow> {
pub(crate) inner: core::db::PagedLoadQuery<'a, E>,
}
impl<E: PersistedRow> 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: EntityValue,
{
let execution = self.inner.execute()?;
let (response, continuation_cursor) = execution.into_parts();
let next_cursor = continuation_cursor.as_deref().map(core::db::encode_cursor);
Ok(PagedResponse::new(response.entities(), next_cursor))
}
}