Skip to main content

drive/query/
mod.rs

1use std::sync::Arc;
2
3#[cfg(any(feature = "server", feature = "verify"))]
4pub use {
5    conditions::{ValueClause, WhereClause, WhereOperator},
6    // Average-query verifier-shareable types — same split as sum:
7    // `AverageEntry` is the per-key `(count, sum)` pair the verifier
8    // returns; `AverageMode` is the SQL-shape input the verifier needs
9    // to rebuild the path query.
10    drive_document_average_query::{AverageEntry, AverageMode},
11    // `CountMode` is the SQL-shape contract (Aggregate /
12    // GroupByIn / GroupByRange / GroupByCompound) the prover
13    // dispatches on; the verifier needs the same enum to route
14    // proof verification to the matching primitive
15    // (`DocumentCountMode`). Available under either `server`
16    // (executor input) or `verify` (proof-decode input).
17    drive_document_count_query::{
18        CountMode, DocumentCountMode, DriveDocumentCountQuery, SplitCountEntry,
19    },
20    // Sum-query verifier-shareable types: `SumEntry` is the per-key
21    // entry type the verifier returns, `SumMode` / `DriveDocumentSumQuery`
22    // are shape inputs the verifier needs to rebuild the path query.
23    // Parallels the count-side exports above.
24    drive_document_sum_query::{DriveDocumentSumQuery, SumEntry, SumMode},
25    grovedb::{PathQuery, Query, QueryItem, SizedQuery},
26    having::{
27        HavingAggregate, HavingAggregateFunction, HavingClause, HavingOperator, HavingRanking,
28        HavingRankingKind, HavingRightOperand,
29    },
30    ordering::OrderClause,
31    projection::{SelectFunction, SelectProjection},
32    single_document_drive_query::SingleDocumentDriveQuery,
33    single_document_drive_query::SingleDocumentDriveQueryContestedStatus,
34    vote_polls_by_end_date_query::VotePollsByEndDateDriveQuery,
35    vote_query::IdentityBasedVoteDriveQuery,
36};
37
38// `DocumentCountRequest` / `RangeCountOptions` are the
39// server-side executor inputs and stay `server`-only.
40#[cfg(feature = "server")]
41pub use drive_document_count_query::{
42    DocumentCountRequest, DocumentCountResponse, RangeCountOptions, MAX_LIMIT_AS_FAILSAFE,
43};
44
45// `DocumentSumRequest` / `DocumentSumResponse` / `RangeSumOptions` are
46// the server-side executor inputs and stay `server`-only (parallels
47// the count-side `DocumentCountRequest` etc. above).
48#[cfg(feature = "server")]
49pub use drive_document_sum_query::{DocumentSumRequest, DocumentSumResponse, RangeSumOptions};
50
51// `DocumentAverageRequest` / `DocumentAverageResponse` are the
52// server-side executor inputs for the average surface and stay
53// `server`-only (parallels the sum-side server-only exports above).
54#[cfg(feature = "server")]
55pub use drive_document_average_query::{DocumentAverageRequest, DocumentAverageResponse};
56// Imports available when either "server" or "verify" features are enabled
57#[cfg(any(feature = "server", feature = "verify"))]
58use {
59    crate::{
60        drive::contract::paths::DataContractPaths,
61        error::{drive::DriveError, query::QuerySyntaxError, Error},
62    },
63    dpp::{
64        data_contract::{
65            accessors::v0::DataContractV0Getters,
66            document_type::{accessors::DocumentTypeV0Getters, methods::DocumentTypeV0Methods},
67            document_type::{DocumentTypeRef, Index, IndexProperty},
68            DataContract,
69        },
70        document::{document_methods::DocumentMethodsV0, Document, DocumentV0Getters},
71        platform_value::{btreemap_extensions::BTreeValueRemoveFromMapHelper, Value},
72        version::PlatformVersion,
73        ProtocolError,
74    },
75    indexmap::IndexMap,
76    sqlparser::{
77        ast::{self, OrderByExpr, Select, Statement, TableFactor::Table, Value::Number},
78        dialect::MySqlDialect,
79        parser::Parser,
80    },
81    std::{collections::BTreeMap, ops::BitXor},
82};
83
84#[cfg(all(feature = "server", feature = "verify"))]
85use crate::verify::RootHash;
86
87#[cfg(feature = "server")]
88use dpp::document::serialization_traits::DocumentPlatformConversionMethodsV0;
89#[cfg(feature = "server")]
90pub use grovedb::{
91    query_result_type::{QueryResultElements, QueryResultType},
92    Element, Error as GroveError, TransactionArg,
93};
94
95use dpp::document;
96use dpp::prelude::Identifier;
97use dpp::validation::{SimpleValidationResult, ValidationResult};
98#[cfg(feature = "server")]
99use {
100    crate::{drive::Drive, fees::op::LowLevelDriveOperation},
101    dpp::block::block_info::BlockInfo,
102};
103// Crate-local unconditional imports
104use crate::config::DriveConfig;
105// Crate-local unconditional imports
106use crate::util::common::encode::encode_u64;
107#[cfg(feature = "server")]
108use crate::util::grove_operations::QueryType::StatefulQuery;
109
110// Module declarations that are conditional on either "server" or "verify" features
111#[cfg(any(feature = "server", feature = "verify"))]
112pub mod conditions;
113#[cfg(any(feature = "server", feature = "verify"))]
114mod defaults;
115#[cfg(any(feature = "server", feature = "verify"))]
116pub mod having;
117#[cfg(any(feature = "server", feature = "verify"))]
118pub mod ordering;
119#[cfg(any(feature = "server", feature = "verify"))]
120pub mod projection;
121#[cfg(any(feature = "server", feature = "verify"))]
122mod single_document_drive_query;
123
124// Module declarations exclusively for "server" feature
125#[cfg(feature = "server")]
126mod test_index;
127
128#[cfg(any(feature = "server", feature = "verify"))]
129/// Vote poll vote state query module
130pub mod vote_poll_vote_state_query;
131#[cfg(any(feature = "server", feature = "verify"))]
132/// Vote Query module
133pub mod vote_query;
134
135#[cfg(any(feature = "server", feature = "verify"))]
136/// Vote poll contestant votes query module
137pub mod vote_poll_contestant_votes_query;
138
139#[cfg(any(feature = "server", feature = "verify"))]
140/// Vote polls by end date query
141pub mod vote_polls_by_end_date_query;
142
143#[cfg(any(feature = "server", feature = "verify"))]
144/// Vote polls by document type query
145pub mod vote_polls_by_document_type_query;
146
147/// Function type for looking up a contract by identifier
148///
149/// This function is used to look up a contract by its identifier.
150/// It should be implemented by the caller in order to provide data
151/// contract required for operations like proof verification.
152#[cfg(any(feature = "server", feature = "verify"))]
153pub type ContractLookupFn<'a> =
154    dyn Fn(&Identifier) -> Result<Option<Arc<DataContract>>, Error> + 'a;
155
156/// Creates a [ContractLookupFn] function that returns provided data contract when requested.
157///
158/// # Arguments
159///
160/// * `data_contract` - [Arc<DataContract>](DataContract) to return
161///
162/// # Returns
163///
164/// [ContractLookupFn] that will return the `data_contract`, or `None` if
165/// the requested contract is not the same as the provided one.
166#[cfg(any(feature = "server", feature = "verify"))]
167pub fn contract_lookup_fn_for_contract<'a>(
168    data_contract: Arc<DataContract>,
169) -> Box<ContractLookupFn<'a>> {
170    let func = move |id: &Identifier| -> Result<Option<Arc<DataContract>>, Error> {
171        if data_contract.id().ne(id) {
172            return Ok(None);
173        }
174        Ok(Some(Arc::clone(&data_contract)))
175    };
176    Box::new(func)
177}
178
179/// A query to get the votes given out by an identity
180#[cfg(any(feature = "server", feature = "verify"))]
181pub mod contested_resource_votes_given_by_identity_query;
182/// A query to get contested documents before they have been awarded
183#[cfg(any(feature = "server", feature = "verify"))]
184pub mod drive_contested_document_query;
185
186/// A query to get the block counts of proposers in an epoch
187#[cfg(any(feature = "server", feature = "verify"))]
188pub mod proposer_block_count_query;
189
190/// A query to get the identity's token balance
191#[cfg(any(feature = "server", feature = "verify"))]
192pub mod identity_token_balance_drive_query;
193/// A query to get the identity's token info
194#[cfg(any(feature = "server", feature = "verify"))]
195pub mod identity_token_info_drive_query;
196
197/// Document subscription filtering
198#[cfg(any(feature = "server", feature = "verify"))]
199pub mod filter;
200/// A query to get the token's status
201#[cfg(any(feature = "server", feature = "verify"))]
202pub mod token_status_drive_query;
203
204/// A query to count documents using CountTree elements
205#[cfg(any(feature = "server", feature = "verify"))]
206pub mod drive_document_count_query;
207
208/// A query to sum an integer property across documents using SumTree
209/// elements. Parallels [`drive_document_count_query`] for the sum
210/// surface — see `book/src/drive/document-sum-trees.md` for the
211/// design and `book/src/drive/sum-index-examples.md` for the worked
212/// example contract.
213#[cfg(any(feature = "server", feature = "verify"))]
214pub mod drive_document_sum_query;
215
216/// A query to compute the average of an integer property across
217/// documents using `CountSumTree` / `ProvableCountProvableSumTree`
218/// (PCPS) elements. Averages are NOT computed server-side; the
219/// response carries a `(count, sum)` pair (atomic per group) and the
220/// client divides. See `book/src/drive/average-index-examples.md` for
221/// the worked example contract.
222#[cfg(any(feature = "server", feature = "verify"))]
223pub mod drive_document_average_query;
224
225/// Joint count-and-sum no-prove executor surface — backs the AVG
226/// no-prove path's unified single-walk dispatch. See its module
227/// docstring for the perf / atomicity contract. Server-only because
228/// the surface only fires on the no-prove (server-materialized) path.
229#[cfg(feature = "server")]
230pub mod drive_document_count_and_sum_query;
231
232/// A Query Syntax Validation Result that contains data
233pub type QuerySyntaxValidationResult<TData> = ValidationResult<TData, QuerySyntaxError>;
234
235/// A Query Syntax Validation Result
236pub type QuerySyntaxSimpleValidationResult = SimpleValidationResult<QuerySyntaxError>;
237
238#[cfg(any(feature = "server", feature = "verify"))]
239/// Represents a starting point for a query based on a specific document.
240///
241/// This struct encapsulates all the necessary details to define the starting
242/// conditions for a query, including the document to start from, its type,
243/// associated index property, and whether the document itself should be included
244/// in the query results.
245#[derive(Debug, Clone)]
246pub struct StartAtDocument<'a> {
247    /// The document that serves as the starting point for the query.
248    pub document: Document,
249
250    /// The type of the document, providing metadata about its schema and structure.
251    pub document_type: DocumentTypeRef<'a>,
252
253    /// Indicates whether the starting document itself should be included in the query results.
254    /// - `true`: The document is included in the results.
255    /// - `false`: The document is excluded, and the query starts from the next matching document.
256    pub included: bool,
257}
258
259/// Internal clauses struct
260#[cfg(any(feature = "server", feature = "verify"))]
261#[derive(Clone, Debug, PartialEq, Default)]
262pub struct InternalClauses {
263    /// Primary key in clause
264    pub primary_key_in_clause: Option<WhereClause>,
265    /// Primary key equal clause
266    pub primary_key_equal_clause: Option<WhereClause>,
267    /// In clause
268    pub in_clause: Option<WhereClause>,
269    /// Range clause
270    pub range_clause: Option<WhereClause>,
271    /// Equal clause
272    pub equal_clauses: BTreeMap<String, WhereClause>,
273}
274
275impl InternalClauses {
276    #[cfg(any(feature = "server", feature = "verify"))]
277    /// Returns true if the clause is a valid format.
278    pub fn verify(&self) -> bool {
279        // There can only be 1 primary key clause, or many other clauses
280        if self
281            .primary_key_in_clause
282            .is_some()
283            .bitxor(self.primary_key_equal_clause.is_some())
284        {
285            // One is set, all rest must be empty
286            !(self.in_clause.is_some()
287                || self.range_clause.is_some()
288                || !self.equal_clauses.is_empty())
289        } else {
290            !(self.primary_key_in_clause.is_some() && self.primary_key_equal_clause.is_some())
291        }
292    }
293
294    #[cfg(any(feature = "server", feature = "verify"))]
295    /// Returns true if the query clause is for primary keys.
296    pub fn is_for_primary_key(&self) -> bool {
297        self.primary_key_in_clause.is_some() || self.primary_key_equal_clause.is_some()
298    }
299
300    #[cfg(any(feature = "server", feature = "verify"))]
301    /// Returns true if self is empty.
302    pub fn is_empty(&self) -> bool {
303        self.in_clause.is_none()
304            && self.range_clause.is_none()
305            && self.equal_clauses.is_empty()
306            && self.primary_key_in_clause.is_none()
307            && self.primary_key_equal_clause.is_none()
308    }
309
310    #[cfg(any(feature = "server", feature = "verify"))]
311    /// Extracts the `WhereClause`s and returns them as type `InternalClauses`.
312    pub fn extract_from_clauses(all_where_clauses: Vec<WhereClause>) -> Result<Self, Error> {
313        let primary_key_equal_clauses_array = all_where_clauses
314            .iter()
315            .filter_map(|where_clause| match where_clause.operator {
316                WhereOperator::Equal => match where_clause.is_identifier() {
317                    true => Some(where_clause.clone()),
318                    false => None,
319                },
320                _ => None,
321            })
322            .collect::<Vec<WhereClause>>();
323
324        let primary_key_in_clauses_array = all_where_clauses
325            .iter()
326            .filter_map(|where_clause| match where_clause.operator {
327                WhereOperator::In => match where_clause.is_identifier() {
328                    true => Some(where_clause.clone()),
329                    false => None,
330                },
331                _ => None,
332            })
333            .collect::<Vec<WhereClause>>();
334
335        let (equal_clauses, range_clause, in_clause) =
336            WhereClause::group_clauses(&all_where_clauses)?;
337
338        let primary_key_equal_clause = match primary_key_equal_clauses_array.len() {
339            0 => Ok(None),
340            1 => Ok(Some(
341                primary_key_equal_clauses_array
342                    .first()
343                    .expect("there must be a value")
344                    .clone(),
345            )),
346            _ => Err(Error::Query(
347                QuerySyntaxError::DuplicateNonGroupableClauseSameField(
348                    "There should only be one equal clause for the primary key",
349                ),
350            )),
351        }?;
352
353        let primary_key_in_clause = match primary_key_in_clauses_array.len() {
354            0 => Ok(None),
355            1 => Ok(Some(
356                primary_key_in_clauses_array
357                    .first()
358                    .expect("there must be a value")
359                    .clone(),
360            )),
361            _ => Err(Error::Query(
362                QuerySyntaxError::DuplicateNonGroupableClauseSameField(
363                    "There should only be one in clause for the primary key",
364                ),
365            )),
366        }?;
367
368        let internal_clauses = InternalClauses {
369            primary_key_equal_clause,
370            primary_key_in_clause,
371            in_clause,
372            range_clause,
373            equal_clauses,
374        };
375
376        match internal_clauses.verify() {
377            true => Ok(internal_clauses),
378            false => Err(Error::Query(
379                QuerySyntaxError::InvalidWhereClauseComponents("Query has invalid where clauses"),
380            )),
381        }
382    }
383
384    /// Validate this collection of InternalClauses against the document schema
385    #[cfg(any(feature = "server", feature = "verify"))]
386    pub fn validate_against_schema(
387        &self,
388        document_type: DocumentTypeRef,
389    ) -> QuerySyntaxSimpleValidationResult {
390        // Basic composition
391        if !self.verify() {
392            return QuerySyntaxSimpleValidationResult::new_with_error(
393                QuerySyntaxError::InvalidWhereClauseComponents(
394                    "invalid composition of where clauses",
395                ),
396            );
397        }
398
399        // Validate in_clause against schema
400        if let Some(in_clause) = &self.in_clause {
401            // Forbid $id in non-primary-key clauses
402            if in_clause.field == "$id" {
403                return QuerySyntaxSimpleValidationResult::new_with_error(
404                    QuerySyntaxError::InvalidWhereClauseComponents(
405                        "use primary_key_* clauses for $id",
406                    ),
407                );
408            }
409            let result = in_clause.validate_against_schema(document_type);
410            if !result.is_valid() {
411                return result;
412            }
413        }
414
415        // Validate range_clause against schema
416        if let Some(range_clause) = &self.range_clause {
417            // Forbid $id in non-primary-key clauses
418            if range_clause.field == "$id" {
419                return QuerySyntaxSimpleValidationResult::new_with_error(
420                    QuerySyntaxError::InvalidWhereClauseComponents(
421                        "use primary_key_* clauses for $id",
422                    ),
423                );
424            }
425            let result = range_clause.validate_against_schema(document_type);
426            if !result.is_valid() {
427                return result;
428            }
429        }
430
431        // Validate equal_clauses against schema
432        for (field, eq_clause) in &self.equal_clauses {
433            // Forbid $id in non-primary-key clauses
434            if field.as_str() == "$id" {
435                return QuerySyntaxSimpleValidationResult::new_with_error(
436                    QuerySyntaxError::InvalidWhereClauseComponents(
437                        "use primary_key_* clauses for $id",
438                    ),
439                );
440            }
441            let result = eq_clause.validate_against_schema(document_type);
442            if !result.is_valid() {
443                return result;
444            }
445        }
446
447        // Validate primary key clauses typing
448        if let Some(pk_eq) = &self.primary_key_equal_clause {
449            if pk_eq.operator != WhereOperator::Equal
450                || !matches!(pk_eq.value, Value::Identifier(_))
451            {
452                return QuerySyntaxSimpleValidationResult::new_with_error(
453                    QuerySyntaxError::InvalidWhereClauseComponents(
454                        "primary key equality must compare an identifier",
455                    ),
456                );
457            }
458        }
459        if let Some(pk_in) = &self.primary_key_in_clause {
460            if pk_in.operator != WhereOperator::In {
461                return QuerySyntaxSimpleValidationResult::new_with_error(
462                    QuerySyntaxError::InvalidWhereClauseComponents(
463                        "primary key IN must use IN operator",
464                    ),
465                );
466            }
467            // enforce array shape and no duplicates/size
468            let result = pk_in.in_values();
469            if !result.is_valid() {
470                return QuerySyntaxSimpleValidationResult::new_with_errors(result.errors);
471            }
472            if let Value::Array(arr) = &pk_in.value {
473                if !arr.iter().all(|v| matches!(v, Value::Identifier(_))) {
474                    return QuerySyntaxSimpleValidationResult::new_with_error(
475                        QuerySyntaxError::InvalidWhereClauseComponents(
476                            "primary key IN must contain identifiers",
477                        ),
478                    );
479                }
480            } else {
481                return QuerySyntaxSimpleValidationResult::new_with_error(
482                    QuerySyntaxError::InvalidWhereClauseComponents(
483                        "primary key IN must contain an array of identifiers",
484                    ),
485                );
486            }
487        }
488
489        QuerySyntaxSimpleValidationResult::default()
490    }
491}
492
493impl From<InternalClauses> for Vec<WhereClause> {
494    fn from(clauses: InternalClauses) -> Self {
495        let mut result: Self = clauses.equal_clauses.into_values().collect();
496
497        if let Some(clause) = clauses.in_clause {
498            result.push(clause);
499        };
500        if let Some(clause) = clauses.primary_key_equal_clause {
501            result.push(clause);
502        };
503        if let Some(clause) = clauses.primary_key_in_clause {
504            result.push(clause);
505        };
506        if let Some(clause) = clauses.range_clause {
507            result.push(clause);
508        };
509
510        result
511    }
512}
513
514#[cfg(any(feature = "server", feature = "verify"))]
515/// Drive query struct
516#[derive(Debug, PartialEq, Clone)]
517pub struct DriveDocumentQuery<'a> {
518    ///DataContract
519    pub contract: &'a DataContract,
520    /// Document type
521    pub document_type: DocumentTypeRef<'a>,
522    /// Internal clauses
523    pub internal_clauses: InternalClauses,
524    /// Offset
525    pub offset: Option<u16>,
526    /// Limit
527    pub limit: Option<u16>,
528    /// Order by
529    pub order_by: IndexMap<String, OrderClause>,
530    /// Start at document id
531    pub start_at: Option<[u8; 32]>,
532    /// Start at included
533    pub start_at_included: bool,
534    /// Block time
535    pub block_time_ms: Option<u64>,
536}
537
538impl<'a> DriveDocumentQuery<'a> {
539    /// Gets a document by their primary key
540    #[cfg(any(feature = "server", feature = "verify"))]
541    pub fn new_primary_key_single_item_query(
542        contract: &'a DataContract,
543        document_type: DocumentTypeRef<'a>,
544        id: Identifier,
545    ) -> Self {
546        DriveDocumentQuery {
547            contract,
548            document_type,
549            internal_clauses: InternalClauses {
550                primary_key_in_clause: None,
551                primary_key_equal_clause: Some(WhereClause {
552                    field: document::property_names::ID.to_string(),
553                    operator: WhereOperator::Equal,
554                    value: Value::Identifier(id.to_buffer()),
555                }),
556                in_clause: None,
557                range_clause: None,
558                equal_clauses: Default::default(),
559            },
560            offset: None,
561            limit: None,
562            order_by: Default::default(),
563            start_at: None,
564            start_at_included: false,
565            block_time_ms: None,
566        }
567    }
568
569    #[cfg(feature = "server")]
570    /// Returns any item
571    pub fn any_item_query(contract: &'a DataContract, document_type: DocumentTypeRef<'a>) -> Self {
572        DriveDocumentQuery {
573            contract,
574            document_type,
575            internal_clauses: Default::default(),
576            offset: None,
577            limit: Some(1),
578            order_by: Default::default(),
579            start_at: None,
580            start_at_included: true,
581            block_time_ms: None,
582        }
583    }
584
585    #[cfg(feature = "server")]
586    /// Returns all items
587    pub fn all_items_query(
588        contract: &'a DataContract,
589        document_type: DocumentTypeRef<'a>,
590        limit: Option<u16>,
591    ) -> Self {
592        DriveDocumentQuery {
593            contract,
594            document_type,
595            internal_clauses: Default::default(),
596            offset: None,
597            limit,
598            order_by: Default::default(),
599            start_at: None,
600            start_at_included: true,
601            block_time_ms: None,
602        }
603    }
604
605    #[cfg(any(feature = "server", feature = "verify"))]
606    /// Returns true if the query clause if for primary keys.
607    pub fn is_for_primary_key(&self) -> bool {
608        self.internal_clauses.is_for_primary_key()
609            || (self.internal_clauses.is_empty()
610                && (self.order_by.is_empty()
611                    || (self.order_by.len() == 1
612                        && self
613                            .order_by
614                            .keys()
615                            .collect::<Vec<&String>>()
616                            .first()
617                            .unwrap()
618                            .as_str()
619                            == "$id")))
620    }
621
622    #[cfg(feature = "cbor_query")]
623    /// Converts a query CBOR to a `DriveQuery`.
624    pub fn from_cbor(
625        query_cbor: &[u8],
626        contract: &'a DataContract,
627        document_type: DocumentTypeRef<'a>,
628        config: &DriveConfig,
629    ) -> Result<Self, Error> {
630        let query_document_value: Value = ciborium::de::from_reader(query_cbor).map_err(|_| {
631            Error::Query(QuerySyntaxError::DeserializationError(
632                "unable to decode query from cbor".to_string(),
633            ))
634        })?;
635        Self::from_value(query_document_value, contract, document_type, config)
636    }
637
638    #[cfg(any(feature = "server", feature = "verify"))]
639    /// Converts a query Value to a `DriveQuery`.
640    pub fn from_value(
641        query_value: Value,
642        contract: &'a DataContract,
643        document_type: DocumentTypeRef<'a>,
644        config: &DriveConfig,
645    ) -> Result<Self, Error> {
646        let query_document: BTreeMap<String, Value> = query_value.into_btree_string_map()?;
647        Self::from_btree_map_value(query_document, contract, document_type, config)
648    }
649
650    #[cfg(any(feature = "server", feature = "verify"))]
651    /// Converts a query Value to a `DriveQuery`.
652    pub fn from_btree_map_value(
653        mut query_document: BTreeMap<String, Value>,
654        contract: &'a DataContract,
655        document_type: DocumentTypeRef<'a>,
656        config: &DriveConfig,
657    ) -> Result<Self, Error> {
658        if let Some(contract_id) = query_document
659            .remove_optional_identifier("contract_id")
660            .map_err(|e| Error::Protocol(Box::new(ProtocolError::ValueError(e))))?
661        {
662            if contract.id() != contract_id {
663                return Err(ProtocolError::IdentifierError(format!(
664                    "data contract id mismatch, expected: {}, got: {}",
665                    contract.id(),
666                    contract_id
667                ))
668                .into());
669            };
670        }
671
672        if let Some(document_type_name) = query_document
673            .remove_optional_string("document_type_name")
674            .map_err(|e| Error::Protocol(Box::new(ProtocolError::ValueError(e))))?
675        {
676            if document_type.name() != &document_type_name {
677                return Err(ProtocolError::IdentifierError(format!(
678                    "document type name mismatch, expected: {}, got: {}",
679                    document_type.name(),
680                    document_type_name
681                ))
682                .into());
683            }
684        }
685
686        let maybe_limit: Option<u16> = query_document
687            .remove_optional_integer("limit")
688            .map_err(|e| Error::Protocol(Box::new(ProtocolError::ValueError(e))))?;
689
690        let limit = maybe_limit
691            .map_or(Some(config.default_query_limit), |limit_value| {
692                if limit_value == 0 || limit_value > config.default_query_limit {
693                    None
694                } else {
695                    Some(limit_value)
696                }
697            })
698            .ok_or(Error::Query(QuerySyntaxError::InvalidLimit(format!(
699                "limit greater than max limit {}",
700                config.max_query_limit
701            ))))?;
702
703        let offset: Option<u16> = query_document
704            .remove_optional_integer("offset")
705            .map_err(|e| Error::Protocol(Box::new(ProtocolError::ValueError(e))))?;
706
707        let block_time_ms: Option<u64> = query_document
708            .remove_optional_integer("blockTime")
709            .map_err(|e| Error::Protocol(Box::new(ProtocolError::ValueError(e))))?;
710
711        let all_where_clauses: Vec<WhereClause> =
712            query_document
713                .remove("where")
714                .map_or(Ok(vec![]), |id_cbor| {
715                    if let Value::Array(clauses) = id_cbor {
716                        clauses
717                            .iter()
718                            .map(|where_clause| {
719                                if let Value::Array(clauses_components) = where_clause {
720                                    WhereClause::from_components(clauses_components)
721                                } else {
722                                    Err(Error::Query(QuerySyntaxError::InvalidFormatWhereClause(
723                                        "where clause must be an array".to_string(),
724                                    )))
725                                }
726                            })
727                            .collect::<Result<Vec<WhereClause>, Error>>()
728                    } else {
729                        Err(Error::Query(QuerySyntaxError::InvalidFormatWhereClause(
730                            "where clause must be an array".to_string(),
731                        )))
732                    }
733                })?;
734
735        let internal_clauses = InternalClauses::extract_from_clauses(all_where_clauses)?;
736
737        let start_at_option = query_document.remove("startAt");
738        let start_after_option = query_document.remove("startAfter");
739        if start_after_option.is_some() && start_at_option.is_some() {
740            return Err(Error::Query(QuerySyntaxError::DuplicateStartConditions(
741                "only one of startAt or startAfter should be provided",
742            )));
743        }
744
745        let mut start_at_included = true;
746
747        let mut start_option: Option<Value> = None;
748
749        if start_after_option.is_some() {
750            start_option = start_after_option;
751            start_at_included = false;
752        } else if start_at_option.is_some() {
753            start_option = start_at_option;
754            start_at_included = true;
755        }
756
757        let start_at: Option<[u8; 32]> = start_option
758            .map(|v| {
759                v.into_identifier()
760                    .map_err(|e| Error::Protocol(Box::new(ProtocolError::ValueError(e))))
761                    .map(|identifier| identifier.into_buffer())
762            })
763            .transpose()?;
764
765        let order_by: IndexMap<String, OrderClause> =
766            query_document
767                .remove("orderBy")
768                .map_or(Ok(IndexMap::new()), |id_cbor| {
769                    if let Value::Array(clauses) = id_cbor {
770                        clauses
771                            .into_iter()
772                            .filter_map(|order_clause| {
773                                if let Value::Array(clauses_components) = order_clause {
774                                    let order_clause =
775                                        OrderClause::from_components(&clauses_components)
776                                            .map_err(Error::from);
777                                    match order_clause {
778                                        Ok(order_clause) => {
779                                            Some(Ok((order_clause.field.clone(), order_clause)))
780                                        }
781                                        Err(err) => Some(Err(err)),
782                                    }
783                                } else {
784                                    None
785                                }
786                            })
787                            .collect::<Result<IndexMap<String, OrderClause>, Error>>()
788                    } else {
789                        Err(Error::Query(QuerySyntaxError::InvalidOrderByProperties(
790                            "order clauses must be an array",
791                        )))
792                    }
793                })?;
794
795        if !query_document.is_empty() {
796            return Err(Error::Query(QuerySyntaxError::Unsupported(format!(
797                "unsupported syntax in where clause: {:?}",
798                query_document
799            ))));
800        }
801
802        Ok(DriveDocumentQuery {
803            contract,
804            document_type,
805            internal_clauses,
806            limit: Some(limit),
807            offset,
808            order_by,
809            start_at,
810            start_at_included,
811            block_time_ms,
812        })
813    }
814
815    #[cfg(any(feature = "server", feature = "verify"))]
816    /// Converts a query Value to a `DriveQuery`.
817    #[allow(clippy::too_many_arguments)]
818    pub fn from_decomposed_values(
819        where_clause: Value,
820        order_by: Option<Value>,
821        maybe_limit: Option<u16>,
822        start_at: Option<[u8; 32]>,
823        start_at_included: bool,
824        block_time_ms: Option<u64>,
825        contract: &'a DataContract,
826        document_type: DocumentTypeRef<'a>,
827        config: &DriveConfig,
828    ) -> Result<Self, Error> {
829        let all_where_clauses: Vec<WhereClause> = match where_clause {
830            Value::Null => Ok(vec![]),
831            Value::Array(clauses) => clauses
832                .iter()
833                .map(|where_clause| {
834                    if let Value::Array(clauses_components) = where_clause {
835                        WhereClause::from_components(clauses_components)
836                    } else {
837                        Err(Error::Query(QuerySyntaxError::InvalidFormatWhereClause(
838                            "where clause must be an array".to_string(),
839                        )))
840                    }
841                })
842                .collect::<Result<Vec<WhereClause>, Error>>(),
843            _ => Err(Error::Query(QuerySyntaxError::InvalidFormatWhereClause(
844                "where clause must be an array".to_string(),
845            ))),
846        }?;
847
848        // Malformed `order_by` payloads reject the request — the
849        // pre-existing `filter_map(... .ok())` here silently dropped
850        // bad clauses (or the whole field for non-array shapes),
851        // which could mutate result ordering and (on the prove
852        // path) proof bytes without telling the caller. Tighten the
853        // contract: every clause must parse, and the top-level
854        // shape must be `Value::Null` or `Value::Array`.
855        let order_by_clauses: Vec<OrderClause> = match order_by {
856            None | Some(Value::Null) => Vec::new(),
857            Some(Value::Array(clauses)) => clauses
858                .iter()
859                .map(|order_clause| match order_clause {
860                    Value::Array(components) => {
861                        OrderClause::from_components(components).map_err(|_| {
862                            Error::Query(QuerySyntaxError::InvalidOrderByProperties(
863                                "invalid order_by clause components",
864                            ))
865                        })
866                    }
867                    _ => Err(Error::Query(QuerySyntaxError::InvalidOrderByProperties(
868                        "order_by clause must be an array",
869                    ))),
870                })
871                .collect::<Result<Vec<_>, _>>()?,
872            Some(_) => {
873                return Err(Error::Query(QuerySyntaxError::InvalidOrderByProperties(
874                    "order_by must be an array",
875                )));
876            }
877        };
878
879        Self::from_typed_clauses(
880            all_where_clauses,
881            order_by_clauses,
882            maybe_limit,
883            start_at,
884            start_at_included,
885            block_time_ms,
886            contract,
887            document_type,
888            config,
889        )
890    }
891
892    /// Build a `DriveDocumentQuery` from already-structured where /
893    /// order_by clauses. This is the typed-input twin of
894    /// [`Self::from_decomposed_values`] — same downstream shape, just
895    /// without the `Value::Array(...)` parse step.
896    ///
897    /// Used by the v1 `getDocuments` ABCI handler whose wire format
898    /// carries `repeated WhereClause` / `repeated OrderClause`
899    /// natively (no CBOR envelope). The v0 path keeps using
900    /// `from_decomposed_values` so its CBOR-decoded inputs flow
901    /// through the existing `WhereClause::from_components` parser
902    /// for shape validation; the typed path expects that validation
903    /// (or the equivalent proto→drive conversion) to have run
904    /// upstream.
905    ///
906    /// Limit semantics mirror `from_decomposed_values`:
907    /// `maybe_limit = None` or `Some(0)` falls back to
908    /// `config.default_query_limit`; `Some(N)` with `N >
909    /// config.default_query_limit` is rejected as
910    /// `QuerySyntaxError::InvalidLimit`.
911    #[cfg(any(feature = "server", feature = "verify"))]
912    #[allow(clippy::too_many_arguments)]
913    pub fn from_typed_clauses(
914        where_clauses: Vec<WhereClause>,
915        order_by_clauses: Vec<OrderClause>,
916        maybe_limit: Option<u16>,
917        start_at: Option<[u8; 32]>,
918        start_at_included: bool,
919        block_time_ms: Option<u64>,
920        contract: &'a DataContract,
921        document_type: DocumentTypeRef<'a>,
922        config: &DriveConfig,
923    ) -> Result<Self, Error> {
924        let limit = maybe_limit
925            .map_or(Some(config.default_query_limit), |limit_value| {
926                if limit_value == 0 || limit_value > config.default_query_limit {
927                    None
928                } else {
929                    Some(limit_value)
930                }
931            })
932            .ok_or(Error::Query(QuerySyntaxError::InvalidLimit(format!(
933                "limit greater than max limit {}",
934                config.max_query_limit
935            ))))?;
936
937        let internal_clauses = InternalClauses::extract_from_clauses(where_clauses)?;
938
939        let order_by: IndexMap<String, OrderClause> = order_by_clauses
940            .into_iter()
941            .map(|c| (c.field.clone(), c))
942            .collect();
943
944        Ok(DriveDocumentQuery {
945            contract,
946            document_type,
947            internal_clauses,
948            offset: None,
949            limit: Some(limit),
950            order_by,
951            start_at,
952            start_at_included,
953            block_time_ms,
954        })
955    }
956
957    #[cfg(any(feature = "server", feature = "verify"))]
958    /// Converts a SQL expression to a `DriveQuery`.
959    pub fn from_sql_expr(
960        sql_string: &str,
961        contract: &'a DataContract,
962        config: Option<&DriveConfig>,
963    ) -> Result<Self, Error> {
964        let dialect: MySqlDialect = MySqlDialect {};
965        let statements: Vec<Statement> = Parser::parse_sql(&dialect, sql_string)
966            .map_err(|e| Error::Query(QuerySyntaxError::SQLParsingError(e)))?;
967
968        // Should ideally iterate over each statement
969        let first_statement =
970            statements
971                .first()
972                .ok_or(Error::Query(QuerySyntaxError::InvalidSQL(
973                    "Issue parsing sql getting first statement".to_string(),
974                )))?;
975
976        let query: &ast::Query = match first_statement {
977            ast::Statement::Query(query_struct) => Some(query_struct),
978            _ => None,
979        }
980        .ok_or(Error::Query(QuerySyntaxError::InvalidSQL(
981            "Issue parsing sql: not a query".to_string(),
982        )))?;
983
984        let max_limit = config
985            .map(|config| config.max_query_limit)
986            .unwrap_or(DriveConfig::default().max_query_limit);
987
988        let limit: u16 = if let Some(limit_expr) = &query.limit {
989            match limit_expr {
990                ast::Expr::Value(Number(num_string, _)) => {
991                    let cast_num_string: &String = num_string;
992                    let user_limit = cast_num_string.parse::<u16>().map_err(|e| {
993                        Error::Query(QuerySyntaxError::InvalidLimit(format!(
994                            "limit could not be parsed {}",
995                            e
996                        )))
997                    })?;
998                    if user_limit > max_limit {
999                        return Err(Error::Query(QuerySyntaxError::InvalidLimit(format!(
1000                            "limit {} greater than max limit {}",
1001                            user_limit, max_limit
1002                        ))));
1003                    }
1004                    user_limit
1005                }
1006                result => {
1007                    return Err(Error::Query(QuerySyntaxError::InvalidLimit(format!(
1008                        "expression not a limit {}",
1009                        result
1010                    ))));
1011                }
1012            }
1013        } else {
1014            config
1015                .map(|config| config.default_query_limit)
1016                .unwrap_or(DriveConfig::default().default_query_limit)
1017        };
1018
1019        let order_by: IndexMap<String, OrderClause> = query
1020            .order_by
1021            .iter()
1022            .map(|order_exp: &OrderByExpr| {
1023                let ascending = order_exp.asc.is_none() || order_exp.asc.unwrap();
1024                let field = order_exp.expr.to_string();
1025                (field.clone(), OrderClause { field, ascending })
1026            })
1027            .collect::<IndexMap<String, OrderClause>>();
1028
1029        // Grab the select section of the query
1030        let select: &Select = match &*query.body {
1031            ast::SetExpr::Select(select) => Some(select),
1032            _ => None,
1033        }
1034        .ok_or(Error::Query(QuerySyntaxError::InvalidSQL(
1035            "Issue parsing sql: Not a select".to_string(),
1036        )))?;
1037
1038        // Get the document type from the 'from' section
1039        let document_type_name = match &select
1040            .from
1041            .first()
1042            .ok_or(Error::Query(QuerySyntaxError::InvalidSQL(
1043                "Invalid query: missing from section".to_string(),
1044            )))?
1045            .relation
1046        {
1047            Table { name, .. } => name.0.first().as_ref().map(|identifier| &identifier.value),
1048            _ => None,
1049        }
1050        .ok_or(Error::Query(QuerySyntaxError::InvalidSQL(
1051            "Issue parsing sql: invalid from value".to_string(),
1052        )))?;
1053
1054        let document_type =
1055            contract
1056                .document_types()
1057                .get(document_type_name)
1058                .ok_or(Error::Query(QuerySyntaxError::DocumentTypeNotFound(
1059                    "document type not found in contract",
1060                )))?;
1061
1062        // Restrictions
1063        // only binary where clauses are supported
1064        // i.e. [<fieldname>, <operator>, <value>]
1065        // [and] is used to separate where clauses
1066        // currently where clauses are either binary operations or list descriptions (in clauses)
1067        // hence once [and] is encountered [left] and [right] must be only one of the above
1068        // i.e other where clauses
1069        // e.g. firstname = wisdom and lastname = ogwu
1070        // if op is not [and] then [left] or [right] must not be a binary operation or list description
1071        let mut all_where_clauses: Vec<WhereClause> = Vec::new();
1072        let selection_tree = select.selection.as_ref();
1073
1074        // Where clauses are optional
1075        if let Some(selection_tree) = selection_tree {
1076            WhereClause::build_where_clauses_from_operations(
1077                selection_tree,
1078                document_type,
1079                &mut all_where_clauses,
1080            )?;
1081        }
1082
1083        let internal_clauses = InternalClauses::extract_from_clauses(all_where_clauses)?;
1084
1085        let start_at_option = None; //todo
1086        let start_after_option = None; //todo
1087        let mut start_at_included = true;
1088        let mut start_option: Option<Value> = None;
1089
1090        if start_after_option.is_some() {
1091            start_option = start_after_option;
1092            start_at_included = false;
1093        } else if start_at_option.is_some() {
1094            start_option = start_at_option;
1095            start_at_included = true;
1096        }
1097
1098        let start_at: Option<[u8; 32]> = start_option
1099            .map(|v| {
1100                v.into_identifier()
1101                    .map_err(|e| Error::Protocol(Box::new(ProtocolError::ValueError(e))))
1102                    .map(|identifier| identifier.into_buffer())
1103            })
1104            .transpose()?;
1105
1106        Ok(DriveDocumentQuery {
1107            contract,
1108            document_type: document_type.as_ref(),
1109            internal_clauses,
1110            offset: None,
1111            limit: Some(limit),
1112            order_by,
1113            start_at,
1114            start_at_included,
1115            block_time_ms: None,
1116        })
1117    }
1118
1119    /// Serialize drive query to CBOR format.
1120    ///
1121    /// FIXME: The data contract is only referred as ID, and document type as its name.
1122    /// This can change in the future to include full data contract and document type.
1123    #[cfg(feature = "cbor_query")]
1124    pub fn to_cbor(&self) -> Result<Vec<u8>, Error> {
1125        let data: BTreeMap<String, Value> = self.into();
1126        let cbor: BTreeMap<String, ciborium::Value> = Value::convert_to_cbor_map(data)?;
1127        let mut output = Vec::new();
1128
1129        ciborium::ser::into_writer(&cbor, &mut output)
1130            .map_err(|e| ProtocolError::PlatformSerializationError(e.to_string()))?;
1131        Ok(output)
1132    }
1133
1134    #[cfg(any(feature = "server", feature = "verify"))]
1135    /// Operations to construct a path query.
1136    pub fn start_at_document_path_and_key(&self, starts_at: &[u8; 32]) -> (Vec<Vec<u8>>, Vec<u8>) {
1137        if self.document_type.documents_keep_history() {
1138            let document_holding_path = self.contract.documents_with_history_primary_key_path(
1139                self.document_type.name().as_str(),
1140                starts_at,
1141            );
1142            (
1143                document_holding_path
1144                    .into_iter()
1145                    .map(|key| key.to_vec())
1146                    .collect::<Vec<_>>(),
1147                vec![0],
1148            )
1149        } else {
1150            let document_holding_path = self
1151                .contract
1152                .documents_primary_key_path(self.document_type.name().as_str());
1153            (
1154                document_holding_path
1155                    .into_iter()
1156                    .map(|key| key.to_vec())
1157                    .collect::<Vec<_>>(),
1158                starts_at.to_vec(),
1159            )
1160        }
1161    }
1162
1163    #[cfg(feature = "server")]
1164    /// Operations to construct a path query.
1165    pub fn construct_path_query_operations(
1166        &self,
1167        drive: &Drive,
1168        include_start_at_for_proof: bool,
1169        transaction: TransactionArg,
1170        drive_operations: &mut Vec<LowLevelDriveOperation>,
1171        platform_version: &PlatformVersion,
1172    ) -> Result<PathQuery, Error> {
1173        let drive_version = &platform_version.drive;
1174        // First we should get the overall document_type_path
1175        let document_type_path = self
1176            .contract
1177            .document_type_path(self.document_type.name().as_str())
1178            .into_iter()
1179            .map(|a| a.to_vec())
1180            .collect::<Vec<Vec<u8>>>();
1181
1182        let (starts_at_document, start_at_path_query) = match &self.start_at {
1183            None => Ok((None, None)),
1184            Some(starts_at) => {
1185                // First if we have a startAt or startsAfter we must get the element
1186                // from the backing store
1187
1188                let (start_at_document_path, start_at_document_key) =
1189                    self.start_at_document_path_and_key(starts_at);
1190                let start_at_document = drive
1191                    .grove_get(
1192                        start_at_document_path.as_slice().into(),
1193                        &start_at_document_key,
1194                        StatefulQuery,
1195                        transaction,
1196                        drive_operations,
1197                        drive_version,
1198                    )
1199                    .map_err(|e| match e {
1200                        Error::GroveDB(e)
1201                            if matches!(
1202                                e.as_ref(),
1203                                GroveError::PathKeyNotFound(_)
1204                                    | GroveError::PathNotFound(_)
1205                                    | GroveError::PathParentLayerNotFound(_)
1206                            ) =>
1207                        {
1208                            let error_message = if self.start_at_included {
1209                                "startAt document not found"
1210                            } else {
1211                                "startAfter document not found"
1212                            };
1213
1214                            Error::Query(QuerySyntaxError::StartDocumentNotFound(error_message))
1215                        }
1216                        _ => e,
1217                    })?
1218                    .ok_or(Error::Drive(DriveError::CorruptedCodeExecution(
1219                        "expected a value",
1220                    )))?;
1221
1222                let path_query =
1223                    PathQuery::new_single_key(start_at_document_path, start_at_document_key);
1224
1225                if let Element::Item(item, _) = start_at_document {
1226                    let document = Document::from_bytes(
1227                        item.as_slice(),
1228                        self.document_type,
1229                        platform_version,
1230                    )?;
1231                    Ok((Some((document, self.start_at_included)), Some(path_query)))
1232                } else {
1233                    Err(Error::Drive(DriveError::CorruptedDocumentPath(
1234                        "Holding paths should only have items",
1235                    )))
1236                }
1237            }
1238        }?;
1239        let mut main_path_query = if self.is_for_primary_key() {
1240            self.get_primary_key_path_query(
1241                document_type_path,
1242                starts_at_document,
1243                platform_version,
1244            )
1245        } else {
1246            self.get_non_primary_key_path_query(
1247                document_type_path,
1248                starts_at_document,
1249                platform_version,
1250            )
1251        }?;
1252        if !include_start_at_for_proof {
1253            return Ok(main_path_query);
1254        }
1255
1256        if let Some(start_at_path_query) = start_at_path_query {
1257            let limit = main_path_query.query.limit.take();
1258            let mut merged = PathQuery::merge(
1259                vec![&start_at_path_query, &main_path_query],
1260                &platform_version.drive.grove_version,
1261            )
1262            .map_err(Error::from)?;
1263            merged.query.limit = limit.map(|a| a.saturating_add(1));
1264            Ok(merged)
1265        } else {
1266            Ok(main_path_query)
1267        }
1268    }
1269
1270    #[cfg(any(feature = "server", feature = "verify"))]
1271    /// Operations to construct a path query.
1272    pub fn construct_path_query(
1273        &self,
1274        starts_at_document: Option<Document>,
1275        platform_version: &PlatformVersion,
1276    ) -> Result<PathQuery, Error> {
1277        // First we should get the overall document_type_path
1278        let document_type_path = self
1279            .contract
1280            .document_type_path(self.document_type.name().as_str())
1281            .into_iter()
1282            .map(|a| a.to_vec())
1283            .collect::<Vec<Vec<u8>>>();
1284        let starts_at_document = starts_at_document
1285            .map(|starts_at_document| (starts_at_document, self.start_at_included));
1286        if self.is_for_primary_key() {
1287            self.get_primary_key_path_query(
1288                document_type_path,
1289                starts_at_document,
1290                platform_version,
1291            )
1292        } else {
1293            self.get_non_primary_key_path_query(
1294                document_type_path,
1295                starts_at_document,
1296                platform_version,
1297            )
1298        }
1299    }
1300
1301    #[cfg(any(feature = "server", feature = "verify"))]
1302    /// Returns a path query given a document type path and starting document.
1303    pub fn get_primary_key_path_query(
1304        &self,
1305        document_type_path: Vec<Vec<u8>>,
1306        starts_at_document: Option<(Document, bool)>,
1307        platform_version: &PlatformVersion,
1308    ) -> Result<PathQuery, Error> {
1309        let mut path = document_type_path;
1310
1311        // Add primary key ($id) subtree
1312        path.push(vec![0]);
1313
1314        if let Some(primary_key_equal_clause) = &self.internal_clauses.primary_key_equal_clause {
1315            let mut query = Query::new();
1316            let key = self.document_type.serialize_value_for_key(
1317                "$id",
1318                &primary_key_equal_clause.value,
1319                platform_version,
1320            )?;
1321            query.insert_key(key);
1322
1323            if self.document_type.documents_keep_history() {
1324                // if the documents keep history then we should insert a subquery
1325                if let Some(block_time) = self.block_time_ms {
1326                    let encoded_block_time = encode_u64(block_time);
1327                    let mut sub_query = Query::new_with_direction(false);
1328                    sub_query.insert_range_to_inclusive(..=encoded_block_time);
1329                    query.set_subquery(sub_query);
1330                } else {
1331                    query.set_subquery_key(vec![0]);
1332                }
1333            }
1334
1335            Ok(PathQuery::new(path, SizedQuery::new(query, Some(1), None)))
1336        } else {
1337            // This is for a range
1338            let left_to_right = if self.order_by.keys().len() == 1 {
1339                if self.order_by.keys().next().unwrap() != "$id" {
1340                    return Err(Error::Query(QuerySyntaxError::InvalidOrderByProperties(
1341                        "order by should include $id only",
1342                    )));
1343                }
1344
1345                let order_clause = self.order_by.get("$id").unwrap();
1346
1347                order_clause.ascending
1348            } else {
1349                true
1350            };
1351
1352            let mut query = Query::new_with_direction(left_to_right);
1353            // If there is a start_at_document, we need to get the value that it has for the
1354            // current field.
1355            let starts_at_key_option = match starts_at_document {
1356                None => None,
1357                Some((document, included)) => {
1358                    // if the key doesn't exist then we should ignore the starts at key
1359                    document
1360                        .get_raw_for_document_type(
1361                            "$id",
1362                            self.document_type,
1363                            None,
1364                            platform_version,
1365                        )?
1366                        .map(|raw_value_option| (raw_value_option, included))
1367                }
1368            };
1369
1370            if let Some(primary_key_in_clause) = &self.internal_clauses.primary_key_in_clause {
1371                let in_values = primary_key_in_clause.in_values().into_data_with_error()??;
1372
1373                match starts_at_key_option {
1374                    None => {
1375                        for value in in_values.iter() {
1376                            let key = self.document_type.serialize_value_for_key(
1377                                "$id",
1378                                value,
1379                                platform_version,
1380                            )?;
1381                            query.insert_key(key)
1382                        }
1383                    }
1384                    Some((starts_at_key, included)) => {
1385                        for value in in_values.iter() {
1386                            let key = self.document_type.serialize_value_for_key(
1387                                "$id",
1388                                value,
1389                                platform_version,
1390                            )?;
1391
1392                            if (left_to_right && starts_at_key < key)
1393                                || (!left_to_right && starts_at_key > key)
1394                                || (included && starts_at_key == key)
1395                            {
1396                                query.insert_key(key);
1397                            }
1398                        }
1399                    }
1400                }
1401
1402                if self.document_type.documents_keep_history() {
1403                    // if the documents keep history then we should insert a subquery
1404                    if let Some(_block_time) = self.block_time_ms {
1405                        //todo
1406                        return Err(Error::Query(QuerySyntaxError::Unsupported(
1407                            "Not yet implemented".to_string(),
1408                        )));
1409                        // in order to be able to do this we would need limited subqueries
1410                        // as we only want the first element before the block_time
1411
1412                        // let encoded_block_time = encode_float(block_time)?;
1413                        // let mut sub_query = Query::new_with_direction(false);
1414                        // sub_query.insert_range_to_inclusive(..=encoded_block_time);
1415                        // query.set_subquery(sub_query);
1416                    } else {
1417                        query.set_subquery_key(vec![0]);
1418                    }
1419                }
1420
1421                Ok(PathQuery::new(
1422                    path,
1423                    SizedQuery::new(query, self.limit, self.offset),
1424                ))
1425            } else {
1426                // this is a range on all elements
1427                match starts_at_key_option {
1428                    None => {
1429                        query.insert_all();
1430                    }
1431                    Some((starts_at_key, included)) => match left_to_right {
1432                        true => match included {
1433                            true => query.insert_range_from(starts_at_key..),
1434                            false => query.insert_range_after(starts_at_key..),
1435                        },
1436                        false => match included {
1437                            true => query.insert_range_to_inclusive(..=starts_at_key),
1438                            false => query.insert_range_to(..starts_at_key),
1439                        },
1440                    },
1441                }
1442
1443                if self.document_type.documents_keep_history() {
1444                    // if the documents keep history then we should insert a subquery
1445                    if let Some(_block_time) = self.block_time_ms {
1446                        return Err(Error::Query(QuerySyntaxError::Unsupported(
1447                            "this query is not supported".to_string(),
1448                        )));
1449                        // in order to be able to do this we would need limited subqueries
1450                        // as we only want the first element before the block_time
1451
1452                        // let encoded_block_time = encode_float(block_time)?;
1453                        // let mut sub_query = Query::new_with_direction(false);
1454                        // sub_query.insert_range_to_inclusive(..=encoded_block_time);
1455                        // query.set_subquery(sub_query);
1456                    } else {
1457                        query.set_subquery_key(vec![0]);
1458                    }
1459                }
1460
1461                Ok(PathQuery::new(
1462                    path,
1463                    SizedQuery::new(query, self.limit, self.offset),
1464                ))
1465            }
1466        }
1467    }
1468
1469    #[cfg(any(feature = "server", feature = "verify"))]
1470    /// Finds the best index for the query.
1471    pub fn find_best_index(&self, platform_version: &PlatformVersion) -> Result<&Index, Error> {
1472        let equal_fields = self
1473            .internal_clauses
1474            .equal_clauses
1475            .keys()
1476            .map(|s| s.as_str())
1477            .collect::<Vec<&str>>();
1478        let in_field = self
1479            .internal_clauses
1480            .in_clause
1481            .as_ref()
1482            .map(|in_clause| in_clause.field.as_str());
1483        let range_field = self
1484            .internal_clauses
1485            .range_clause
1486            .as_ref()
1487            .map(|range_clause| range_clause.field.as_str());
1488        let mut fields = equal_fields;
1489        if let Some(range_field) = range_field {
1490            fields.push(range_field);
1491        }
1492        if let Some(in_field) = in_field {
1493            fields.push(in_field);
1494            //if there is an in_field, it always takes precedence
1495        }
1496
1497        let order_by_keys: Vec<&str> = self
1498            .order_by
1499            .keys()
1500            .map(|key: &String| {
1501                let str = key.as_str();
1502                if !fields.contains(&str) {
1503                    fields.push(str);
1504                }
1505                str
1506            })
1507            .collect();
1508
1509        let (index, difference) = self
1510            .document_type
1511            .index_for_types(
1512                fields.as_slice(),
1513                in_field,
1514                order_by_keys.as_slice(),
1515                platform_version,
1516            )?
1517            .ok_or(Error::Query(
1518                QuerySyntaxError::WhereClauseOnNonIndexedProperty(format!(
1519                    "query must be for valid indexes, valid indexes are: {:?}",
1520                    self.document_type.indexes()
1521                )),
1522            ))?;
1523        if difference > defaults::MAX_INDEX_DIFFERENCE {
1524            return Err(Error::Query(QuerySyntaxError::QueryTooFarFromIndex(
1525                "query must better match an existing index",
1526            )));
1527        }
1528        Ok(index)
1529    }
1530
1531    #[cfg(any(feature = "server", feature = "verify"))]
1532    /// Returns a `QueryItem` given a start key and query direction.
1533    pub fn query_item_for_starts_at_key(starts_at_key: Vec<u8>, left_to_right: bool) -> QueryItem {
1534        if left_to_right {
1535            QueryItem::RangeAfter(starts_at_key..)
1536        } else {
1537            QueryItem::RangeTo(..starts_at_key)
1538        }
1539    }
1540
1541    #[cfg(any(feature = "server", feature = "verify"))]
1542    /// Returns a `Query` that either starts at or after the given document ID if given.
1543    fn inner_query_from_starts_at_for_id(
1544        starts_at_document: Option<&StartAtDocument>,
1545        left_to_right: bool,
1546    ) -> Query {
1547        // We only need items after the start at document
1548        let mut inner_query = Query::new_with_direction(left_to_right);
1549
1550        if let Some(StartAtDocument {
1551            document, included, ..
1552        }) = starts_at_document
1553        {
1554            let start_at_key = document.id().to_vec();
1555            if *included {
1556                inner_query.insert_range_from(start_at_key..)
1557            } else {
1558                inner_query.insert_range_after(start_at_key..)
1559            }
1560        } else {
1561            // No starts at document, take all NULL items
1562            inner_query.insert_all();
1563        }
1564        inner_query
1565    }
1566
1567    #[cfg(any(feature = "server", feature = "verify"))]
1568    /// Returns a `Query` that either starts at or after the given key.
1569    fn inner_query_starts_from_key(
1570        start_at_key: Option<Vec<u8>>,
1571        left_to_right: bool,
1572        included: bool,
1573    ) -> Query {
1574        // We only need items after the start at document
1575        let mut inner_query = Query::new_with_direction(left_to_right);
1576
1577        if left_to_right {
1578            if let Some(start_at_key) = start_at_key {
1579                if included {
1580                    inner_query.insert_range_from(start_at_key..);
1581                } else {
1582                    inner_query.insert_range_after(start_at_key..);
1583                }
1584            } else {
1585                inner_query.insert_all();
1586            }
1587        } else if included {
1588            if let Some(start_at_key) = start_at_key {
1589                inner_query.insert_range_to_inclusive(..=start_at_key);
1590            } else {
1591                inner_query.insert_key(vec![]);
1592            }
1593        } else if let Some(start_at_key) = start_at_key {
1594            inner_query.insert_range_to(..start_at_key);
1595        } else {
1596            //todo: really not sure if this is correct
1597            // Should investigate more
1598            inner_query.insert_key(vec![]);
1599        }
1600
1601        inner_query
1602    }
1603
1604    #[cfg(any(feature = "server", feature = "verify"))]
1605    /// Returns a `Query` that either starts at or after the given document if given.
1606    fn inner_query_from_starts_at(
1607        starts_at_document: Option<&StartAtDocument>,
1608        indexed_property: &IndexProperty,
1609        left_to_right: bool,
1610        platform_version: &PlatformVersion,
1611    ) -> Result<Query, Error> {
1612        let mut inner_query = Query::new_with_direction(left_to_right);
1613        if let Some(StartAtDocument {
1614            document,
1615            document_type,
1616            included,
1617        }) = starts_at_document
1618        {
1619            // We only need items after the start at document
1620            let start_at_key = document.get_raw_for_document_type(
1621                indexed_property.name.as_str(),
1622                *document_type,
1623                None,
1624                platform_version,
1625            )?;
1626            // We want to get items starting at the start key
1627            if let Some(start_at_key) = start_at_key {
1628                if left_to_right {
1629                    if *included {
1630                        inner_query.insert_range_from(start_at_key..)
1631                    } else {
1632                        inner_query.insert_range_after(start_at_key..)
1633                    }
1634                } else if *included {
1635                    inner_query.insert_range_to_inclusive(..=start_at_key)
1636                } else {
1637                    inner_query.insert_range_to(..start_at_key)
1638                }
1639            } else if left_to_right {
1640                inner_query.insert_all();
1641            } else {
1642                inner_query.insert_key(vec![]);
1643            }
1644        } else {
1645            // No starts at document, take all NULL items
1646            inner_query.insert_all();
1647        }
1648        Ok(inner_query)
1649    }
1650
1651    #[cfg(any(feature = "server", feature = "verify"))]
1652    fn recursive_create_query(
1653        left_over_index_properties: &[&IndexProperty],
1654        unique: bool,
1655        starts_at_document: Option<&StartAtDocument>, //for key level, included
1656        indexed_property: &IndexProperty,
1657        order_by: Option<&IndexMap<String, OrderClause>>,
1658        platform_version: &PlatformVersion,
1659    ) -> Result<Option<Query>, Error> {
1660        match left_over_index_properties.split_first() {
1661            None => Ok(None),
1662            Some((first, left_over)) => {
1663                let left_to_right = if let Some(order_by) = order_by {
1664                    order_by
1665                        .get(first.name.as_str())
1666                        .map(|order_clause| order_clause.ascending)
1667                        .unwrap_or(first.ascending)
1668                } else {
1669                    first.ascending
1670                };
1671
1672                let mut inner_query = Self::inner_query_from_starts_at(
1673                    starts_at_document,
1674                    indexed_property,
1675                    left_to_right,
1676                    platform_version,
1677                )?;
1678                DriveDocumentQuery::recursive_insert_on_query(
1679                    &mut inner_query,
1680                    left_over,
1681                    unique,
1682                    starts_at_document,
1683                    left_to_right,
1684                    order_by,
1685                    platform_version,
1686                )?;
1687                Ok(Some(inner_query))
1688            }
1689        }
1690    }
1691
1692    #[cfg(any(feature = "server", feature = "verify"))]
1693    /// Recursively queries as long as there are leftover index properties.
1694    /// The in_start_at_document_sub_path_needing_conditional is interesting.
1695    /// It indicates whether the start at document should be applied as a conditional
1696    /// For example if we have a tree
1697    /// Root
1698    /// ├── model
1699    /// │   ├── sedan
1700    /// │   │   ├── brand_name
1701    /// │   │   │   ├── Honda
1702    /// │   │   │   │   ├── car_type
1703    /// │   │   │   │   │   ├── Accord
1704    /// │   │   │   │   │   │   ├── 0
1705    /// │   │   │   │   │   │   │   ├── a47d2...
1706    /// │   │   │   │   │   │   │   ├── e19c8...
1707    /// │   │   │   │   │   │   │   └── f1a7b...
1708    /// │   │   │   │   │   └── Civic
1709    /// │   │   │   │   │       ├── 0
1710    /// │   │   │   │   │       │   ├── b65a7...
1711    /// │   │   │   │   │       │   └── c43de...
1712    /// │   │   │   ├── Toyota
1713    /// │   │   │   │   ├── car_type
1714    /// │   │   │   │   │   ├── Camry
1715    /// │   │   │   │   │   │   ├── 0
1716    /// │   │   │   │   │   │   │   └── 1a9d2...
1717    /// │   │   │   │   │   └── Corolla
1718    /// │   │   │   │   │       ├── 0
1719    /// │   │   │   │   │       │   ├── 3f7b4...
1720    /// │   │   │   │   │       │   ├── 4e8fa...
1721    /// │   │   │   │   │       │   └── 9b1c6...
1722    /// │   ├── suv
1723    /// │   │   ├── brand_name
1724    /// │   │   │   ├── Ford*
1725    /// │   │   │   │   ├── car_type*
1726    /// │   │   │   │   │   ├── Escape*
1727    /// │   │   │   │   │   │   ├── 0
1728    /// │   │   │   │   │   │   │   ├── 102bc...
1729    /// │   │   │   │   │   │   │   ├── 29f8e... <- Set After this document
1730    /// │   │   │   │   │   │   │   └── 6b1a3...
1731    /// │   │   │   │   │   └── Explorer
1732    /// │   │   │   │   │       ├── 0
1733    /// │   │   │   │   │       │   ├── b2a9d...
1734    /// │   │   │   │   │       │   └── f4d5c...
1735    /// │   │   │   ├── Nissan
1736    /// │   │   │   │   ├── car_type
1737    /// │   │   │   │   │   ├── Rogue
1738    /// │   │   │   │   │   │   ├── 0
1739    /// │   │   │   │   │   │   │   ├── 5a9c3...
1740    /// │   │   │   │   │   │   │   └── 7e4b9...
1741    /// │   │   │   │   │   └── Murano
1742    /// │   │   │   │   │       ├── 0
1743    /// │   │   │   │   │       │   ├── 8f6a2...
1744    /// │   │   │   │   │       │   └── 9c7d4...
1745    /// │   ├── truck
1746    /// │   │   ├── brand_name
1747    /// │   │   │   ├── Ford
1748    /// │   │   │   │   ├── car_type
1749    /// │   │   │   │   │   ├── F-150
1750    /// │   │   │   │   │   │   ├── 0
1751    /// │   │   │   │   │   │   │   ├── 72a3b...
1752    /// │   │   │   │   │   │   │   └── 94c8e...
1753    /// │   │   │   │   │   └── Ranger
1754    /// │   │   │   │   │       ├── 0
1755    /// │   │   │   │   │       │   ├── 3f4b1...
1756    /// │   │   │   │   │       │   ├── 6e7d2...
1757    /// │   │   │   │   │       │   └── 8a1f5...
1758    /// │   │   │   ├── Toyota
1759    /// │   │   │   │   ├── car_type
1760    /// │   │   │   │   │   ├── Tundra
1761    /// │   │   │   │   │   │   ├── 0
1762    /// │   │   │   │   │   │   │   ├── 7c9a4...
1763    /// │   │   │   │   │   │   │   └── a5d1e...
1764    /// │   │   │   │   │   └── Tacoma
1765    /// │   │   │   │   │       ├── 0
1766    /// │   │   │   │   │       │   ├── 1e7f4...
1767    /// │   │   │   │   │       │   └── 6b9d3...
1768    ///
1769    /// let's say we are asking for suv's after 29f8e
1770    /// here the * denotes the area needing a conditional
1771    /// We need a conditional subquery on Ford to say only things after Ford (with Ford included)
1772    /// We need a conditional subquery on Escape to say only things after Escape (with Escape included)
1773    fn recursive_insert_on_query(
1774        query: &mut Query,
1775        left_over_index_properties: &[&IndexProperty],
1776        unique: bool,
1777        starts_at_document: Option<&StartAtDocument>, //for key level, included
1778        default_left_to_right: bool,
1779        order_by: Option<&IndexMap<String, OrderClause>>,
1780        platform_version: &PlatformVersion,
1781    ) -> Result<Option<Query>, Error> {
1782        match left_over_index_properties.split_first() {
1783            None => {
1784                match unique {
1785                    true => {
1786                        query.set_subquery_key(vec![0]);
1787
1788                        // In the case things are NULL we allow to have multiple values
1789                        let inner_query = Self::inner_query_from_starts_at_for_id(
1790                            starts_at_document,
1791                            true, //for ids we always go left to right
1792                        );
1793                        query.add_conditional_subquery(
1794                            QueryItem::Key(b"".to_vec()),
1795                            Some(vec![vec![0]]),
1796                            Some(inner_query),
1797                        );
1798                    }
1799                    false => {
1800                        query.set_subquery_key(vec![0]);
1801                        // we just get all by document id order ascending
1802                        let full_query =
1803                            Self::inner_query_from_starts_at_for_id(None, default_left_to_right);
1804                        query.set_subquery(full_query);
1805
1806                        let inner_query = Self::inner_query_from_starts_at_for_id(
1807                            starts_at_document,
1808                            default_left_to_right,
1809                        );
1810
1811                        query.add_conditional_subquery(
1812                            QueryItem::Key(b"".to_vec()),
1813                            Some(vec![vec![0]]),
1814                            Some(inner_query),
1815                        );
1816                    }
1817                }
1818                Ok(None)
1819            }
1820            Some((first, left_over)) => {
1821                let left_to_right = if let Some(order_by) = order_by {
1822                    order_by
1823                        .get(first.name.as_str())
1824                        .map(|order_clause| order_clause.ascending)
1825                        .unwrap_or(first.ascending)
1826                } else {
1827                    first.ascending
1828                };
1829
1830                if let Some(start_at_document_inner) = starts_at_document {
1831                    let StartAtDocument {
1832                        document,
1833                        document_type,
1834                        included,
1835                    } = start_at_document_inner;
1836                    let start_at_key = document
1837                        .get_raw_for_document_type(
1838                            first.name.as_str(),
1839                            *document_type,
1840                            None,
1841                            platform_version,
1842                        )
1843                        .ok()
1844                        .flatten();
1845
1846                    // We should always include if we have left_over
1847                    let non_conditional_included =
1848                        !left_over.is_empty() || *included || start_at_key.is_none();
1849
1850                    let mut non_conditional_query = Self::inner_query_starts_from_key(
1851                        start_at_key.clone(),
1852                        left_to_right,
1853                        non_conditional_included,
1854                    );
1855
1856                    // We place None here on purpose, this has been well-thought-out
1857                    // and should not change. The reason is that the path of the start
1858                    // at document is used only on the conditional subquery and not on the
1859                    // main query
1860                    // for example in the following
1861                    // Our query will be with $ownerId == a3f9b81c4d7e6a9f5b1c3e8a2d9c4f7b
1862                    // With start after 8f2d5
1863                    // We want to get from 2024-11-17T12:45:00Z
1864                    // withdrawal
1865                    // ├── $ownerId
1866                    // │   ├── a3f9b81c4d7e6a9f5b1c3e8a2d9c4f7b
1867                    // │   │   ├── $updatedAt
1868                    // │   │   │   ├── 2024-11-17T12:45:00Z <- conditional subquery here
1869                    // │   │   │   │   ├── status
1870                    // │   │   │   │   │   ├── 0
1871                    // │   │   │   │   │   │   ├── 7a9f1...
1872                    // │   │   │   │   │   │   └── 4b8c3...
1873                    // │   │   │   │   │   ├── 1
1874                    // │   │   │   │   │   │   ├── 8f2d5... <- start after
1875                    // │   │   │   │   │   │   └── 5c1e4...
1876                    // │   │   │   │   │   ├── 2
1877                    // │   │   │   │   │   │   ├── 2e7a9...
1878                    // │   │   │   │   │   │   └── 1c8b3...
1879                    // │   │   │   ├── 2024-11-18T11:25:00Z <- we want all statuses here, so normal subquery, with None as start at document
1880                    // │   │   │   │   ├── status
1881                    // │   │   │   │   │   ├── 0
1882                    // │   │   │   │   │   │   └── 1a4f2...
1883                    // │   │   │   │   │   ├── 2
1884                    // │   │   │   │   │   │   ├── 3e7a9...
1885                    // │   │   │   │   │   │   └── 198b4...
1886                    // │   ├── b6d7e9c4a5f2b3d8e1a7c9f4b1e8a3f
1887                    // │   │   ├── $updatedAt
1888                    // │   │   │   ├── 2024-11-17T13:30:00Z
1889                    // │   │   │   │   ├── status
1890                    // │   │   │   │   │   ├── 0
1891                    // │   │   │   │   │   │   ├── 6d7e2...
1892                    // │   │   │   │   │   │   └── 9c7f5...
1893                    // │   │   │   │   │   ├── 3
1894                    // │   │   │   │   │   │   ├── 3a9b7...
1895                    // │   │   │   │   │   │   └── 8e5c4...
1896                    // │   │   │   │   │   ├── 4
1897                    // │   │   │   │   │   │   ├── 1f7a8...
1898                    // │   │   │   │   │   │   └── 2c9b3...
1899                    // println!("going to call recursive_insert_on_query on non_conditional_query {} with left_over {:?}", non_conditional_query, left_over);
1900                    DriveDocumentQuery::recursive_insert_on_query(
1901                        &mut non_conditional_query,
1902                        left_over,
1903                        unique,
1904                        None,
1905                        left_to_right,
1906                        order_by,
1907                        platform_version,
1908                    )?;
1909
1910                    DriveDocumentQuery::recursive_conditional_insert_on_query(
1911                        &mut non_conditional_query,
1912                        start_at_key,
1913                        left_over,
1914                        unique,
1915                        start_at_document_inner,
1916                        left_to_right,
1917                        order_by,
1918                        platform_version,
1919                    )?;
1920
1921                    query.set_subquery(non_conditional_query);
1922                } else {
1923                    let mut inner_query = Query::new_with_direction(first.ascending);
1924                    inner_query.insert_all();
1925                    DriveDocumentQuery::recursive_insert_on_query(
1926                        &mut inner_query,
1927                        left_over,
1928                        unique,
1929                        starts_at_document,
1930                        left_to_right,
1931                        order_by,
1932                        platform_version,
1933                    )?;
1934                    query.set_subquery(inner_query);
1935                }
1936                query.set_subquery_key(first.name.as_bytes().to_vec());
1937                Ok(None)
1938            }
1939        }
1940    }
1941
1942    #[cfg(any(feature = "server", feature = "verify"))]
1943    #[allow(clippy::too_many_arguments)]
1944    fn recursive_conditional_insert_on_query(
1945        query: &mut Query,
1946        conditional_value: Option<Vec<u8>>,
1947        left_over_index_properties: &[&IndexProperty],
1948        unique: bool,
1949        starts_at_document: &StartAtDocument,
1950        default_left_to_right: bool,
1951        order_by: Option<&IndexMap<String, OrderClause>>,
1952        platform_version: &PlatformVersion,
1953    ) -> Result<(), Error> {
1954        match left_over_index_properties.split_first() {
1955            None => {
1956                match unique {
1957                    true => {
1958                        // In the case things are NULL we allow to have multiple values
1959                        let inner_query = Self::inner_query_from_starts_at_for_id(
1960                            Some(starts_at_document),
1961                            true, //for ids we always go left to right
1962                        );
1963                        query.add_conditional_subquery(
1964                            QueryItem::Key(b"".to_vec()),
1965                            Some(vec![vec![0]]),
1966                            Some(inner_query),
1967                        );
1968                    }
1969                    false => {
1970                        let inner_query = Self::inner_query_from_starts_at_for_id(
1971                            Some(starts_at_document),
1972                            default_left_to_right,
1973                        );
1974
1975                        query.add_conditional_subquery(
1976                            QueryItem::Key(conditional_value.unwrap_or_default()),
1977                            Some(vec![vec![0]]),
1978                            Some(inner_query),
1979                        );
1980                    }
1981                }
1982            }
1983            Some((first, left_over)) => {
1984                let left_to_right = if let Some(order_by) = order_by {
1985                    order_by
1986                        .get(first.name.as_str())
1987                        .map(|order_clause| order_clause.ascending)
1988                        .unwrap_or(first.ascending)
1989                } else {
1990                    first.ascending
1991                };
1992
1993                let StartAtDocument {
1994                    document,
1995                    document_type,
1996                    ..
1997                } = starts_at_document;
1998
1999                let lower_start_at_key = document
2000                    .get_raw_for_document_type(
2001                        first.name.as_str(),
2002                        *document_type,
2003                        None,
2004                        platform_version,
2005                    )
2006                    .ok()
2007                    .flatten();
2008
2009                // We include it if we are not unique,
2010                // or if we are unique but the value is empty
2011                let non_conditional_included = !unique || lower_start_at_key.is_none();
2012
2013                let mut non_conditional_query = Self::inner_query_starts_from_key(
2014                    lower_start_at_key.clone(),
2015                    left_to_right,
2016                    non_conditional_included,
2017                );
2018
2019                DriveDocumentQuery::recursive_insert_on_query(
2020                    &mut non_conditional_query,
2021                    left_over,
2022                    unique,
2023                    None,
2024                    left_to_right,
2025                    order_by,
2026                    platform_version,
2027                )?;
2028
2029                DriveDocumentQuery::recursive_conditional_insert_on_query(
2030                    &mut non_conditional_query,
2031                    lower_start_at_key,
2032                    left_over,
2033                    unique,
2034                    starts_at_document,
2035                    left_to_right,
2036                    order_by,
2037                    platform_version,
2038                )?;
2039
2040                query.add_conditional_subquery(
2041                    QueryItem::Key(conditional_value.unwrap_or_default()),
2042                    Some(vec![first.name.as_bytes().to_vec()]),
2043                    Some(non_conditional_query),
2044                );
2045            }
2046        }
2047        Ok(())
2048    }
2049
2050    #[cfg(any(feature = "server", feature = "verify"))]
2051    /// Returns a path query for non-primary keys given a document type path and starting document.
2052    pub fn get_non_primary_key_path_query(
2053        &self,
2054        document_type_path: Vec<Vec<u8>>,
2055        starts_at_document: Option<(Document, bool)>,
2056        platform_version: &PlatformVersion,
2057    ) -> Result<PathQuery, Error> {
2058        let index = self.find_best_index(platform_version)?;
2059        let ordered_clauses: Vec<&WhereClause> = index
2060            .properties
2061            .iter()
2062            .filter_map(|field| self.internal_clauses.equal_clauses.get(field.name.as_str()))
2063            .collect();
2064        let (last_clause, last_clause_is_range, subquery_clause) = match &self
2065            .internal_clauses
2066            .in_clause
2067        {
2068            None => match &self.internal_clauses.range_clause {
2069                None => (ordered_clauses.last().copied(), false, None),
2070                Some(where_clause) => (Some(where_clause), true, None),
2071            },
2072            Some(in_clause) => match &self.internal_clauses.range_clause {
2073                None => (Some(in_clause), true, None),
2074                Some(range_clause) => {
2075                    // Both an `in` clause and a range clause are present.
2076                    // The outer path query must operate on the field that
2077                    // appears *earlier* (closer to the index root) in the
2078                    // chosen index, and the other clause becomes the leaf
2079                    // subquery. Without this ordering, a query like
2080                    // `status > 0 AND transactionIndex in [..]` on an index
2081                    // `[status, transactionIndex]` builds a path that
2082                    // terminates at the `status` subtree while the primary
2083                    // query iterates `transactionIndex` keys, silently
2084                    // returning []. See issue #2409.
2085                    let position_of = |field: &str| -> Option<usize> {
2086                        index
2087                            .properties
2088                            .iter()
2089                            .position(|p| p.name.as_str() == field)
2090                    };
2091                    let in_pos = position_of(in_clause.field.as_str());
2092                    let range_pos = position_of(range_clause.field.as_str());
2093                    match (in_pos, range_pos) {
2094                        (Some(i), Some(r)) if i > r => (Some(range_clause), true, Some(in_clause)),
2095                        _ => (Some(in_clause), true, Some(range_clause)),
2096                    }
2097                }
2098            },
2099        };
2100
2101        // We need to get the terminal indexes unused by clauses.
2102        let left_over_index_properties = index
2103            .properties
2104            .iter()
2105            .filter(|field| {
2106                !(self
2107                    .internal_clauses
2108                    .equal_clauses
2109                    .contains_key(field.name.as_str())
2110                    || (last_clause.is_some() && last_clause.unwrap().field == field.name)
2111                    || (subquery_clause.is_some() && subquery_clause.unwrap().field == field.name))
2112            })
2113            .collect::<Vec<&IndexProperty>>();
2114
2115        let intermediate_values = index
2116            .properties
2117            .iter()
2118            .filter_map(|field| {
2119                match self.internal_clauses.equal_clauses.get(field.name.as_str()) {
2120                    None => None,
2121                    Some(where_clause) => {
2122                        if !last_clause_is_range
2123                            && last_clause.is_some()
2124                            && last_clause.unwrap().field == field.name
2125                        {
2126                            //there is no need to give an intermediate value as the last clause is an equality
2127                            None
2128                        } else {
2129                            Some(self.document_type.serialize_value_for_key(
2130                                field.name.as_str(),
2131                                &where_clause.value,
2132                                platform_version,
2133                            ))
2134                        }
2135                    }
2136                }
2137            })
2138            .collect::<Result<Vec<Vec<u8>>, ProtocolError>>()
2139            .map_err(Error::from)?;
2140
2141        let final_query = match last_clause {
2142            None => {
2143                // There is no last_clause which means we are using an index most likely because of an order_by, however we have no
2144                // clauses, in this case we should use the first value of the index.
2145                let first_index = index.properties.first().ok_or(Error::Drive(
2146                    DriveError::CorruptedContractIndexes("index must have properties".to_string()),
2147                ))?; // Index must have properties
2148                Self::recursive_create_query(
2149                    left_over_index_properties.as_slice(),
2150                    index.unique,
2151                    starts_at_document
2152                        .map(|(document, included)| StartAtDocument {
2153                            document,
2154                            document_type: self.document_type,
2155                            included,
2156                        })
2157                        .as_ref(),
2158                    first_index,
2159                    Some(&self.order_by),
2160                    platform_version,
2161                )?
2162                .expect("Index must have left over properties if no last clause")
2163            }
2164            Some(where_clause) => {
2165                let left_to_right = if where_clause.operator.is_range() {
2166                    let order_clause: &OrderClause = self
2167                        .order_by
2168                        .get(where_clause.field.as_str())
2169                        .ok_or(Error::Query(QuerySyntaxError::MissingOrderByForRange(
2170                            "query must have an orderBy field for each range element",
2171                        )))?;
2172
2173                    order_clause.ascending
2174                } else {
2175                    true
2176                };
2177
2178                // We should set the starts at document to be included for the query if there are
2179                // left over index properties.
2180
2181                let query_starts_at_document = if left_over_index_properties.is_empty() {
2182                    &starts_at_document
2183                } else {
2184                    &None
2185                };
2186
2187                let mut query = where_clause.to_path_query(
2188                    self.document_type,
2189                    query_starts_at_document,
2190                    left_to_right,
2191                    platform_version,
2192                )?;
2193
2194                match subquery_clause {
2195                    None => {
2196                        Self::recursive_insert_on_query(
2197                            &mut query,
2198                            left_over_index_properties.as_slice(),
2199                            index.unique,
2200                            starts_at_document
2201                                .map(|(document, included)| StartAtDocument {
2202                                    document,
2203                                    document_type: self.document_type,
2204                                    included,
2205                                })
2206                                .as_ref(),
2207                            left_to_right,
2208                            Some(&self.order_by),
2209                            platform_version,
2210                        )?;
2211                    }
2212                    Some(subquery_where_clause) => {
2213                        let order_clause: &OrderClause = self
2214                            .order_by
2215                            .get(subquery_where_clause.field.as_str())
2216                            .ok_or(Error::Query(QuerySyntaxError::MissingOrderByForRange(
2217                                "query must have an orderBy field for each range element",
2218                            )))?;
2219                        let mut subquery = subquery_where_clause.to_path_query(
2220                            self.document_type,
2221                            &starts_at_document,
2222                            order_clause.ascending,
2223                            platform_version,
2224                        )?;
2225                        Self::recursive_insert_on_query(
2226                            &mut subquery,
2227                            left_over_index_properties.as_slice(),
2228                            index.unique,
2229                            starts_at_document
2230                                .map(|(document, included)| StartAtDocument {
2231                                    document,
2232                                    document_type: self.document_type,
2233                                    included,
2234                                })
2235                                .as_ref(),
2236                            left_to_right,
2237                            Some(&self.order_by),
2238                            platform_version,
2239                        )?;
2240                        let subindex = subquery_where_clause.field.as_bytes().to_vec();
2241                        query.set_subquery_key(subindex);
2242                        query.set_subquery(subquery);
2243                    }
2244                };
2245
2246                query
2247            }
2248        };
2249
2250        let (intermediate_indexes, last_indexes) =
2251            index.properties.split_at(intermediate_values.len());
2252
2253        // Now we should construct the path
2254        let last_index = last_indexes.first().ok_or(Error::Query(
2255            QuerySyntaxError::QueryOnDocumentTypeWithNoIndexes(
2256                "document query has no index with fields",
2257            ),
2258        ))?;
2259
2260        let mut path = document_type_path;
2261
2262        for (intermediate_index, intermediate_value) in
2263            intermediate_indexes.iter().zip(intermediate_values.iter())
2264        {
2265            path.push(intermediate_index.name.as_bytes().to_vec());
2266            path.push(intermediate_value.as_slice().to_vec());
2267        }
2268
2269        path.push(last_index.name.as_bytes().to_vec());
2270
2271        Ok(PathQuery::new(
2272            path,
2273            SizedQuery::new(final_query, self.limit, self.offset),
2274        ))
2275    }
2276
2277    #[cfg(feature = "server")]
2278    /// Executes a query with proof and returns the items and fee.
2279    pub fn execute_with_proof(
2280        self,
2281        drive: &Drive,
2282        block_info: Option<BlockInfo>,
2283        transaction: TransactionArg,
2284        platform_version: &PlatformVersion,
2285    ) -> Result<(Vec<u8>, u64), Error> {
2286        let mut drive_operations = vec![];
2287        let items = self.execute_with_proof_internal(
2288            drive,
2289            transaction,
2290            &mut drive_operations,
2291            platform_version,
2292        )?;
2293        let cost = if let Some(block_info) = block_info {
2294            let fee_result = Drive::calculate_fee(
2295                None,
2296                Some(drive_operations),
2297                &block_info.epoch,
2298                drive.config.epochs_per_era,
2299                platform_version,
2300                None,
2301            )?;
2302            fee_result.processing_fee
2303        } else {
2304            0
2305        };
2306        Ok((items, cost))
2307    }
2308
2309    #[cfg(feature = "server")]
2310    /// Executes an internal query with proof and returns the items.
2311    pub(crate) fn execute_with_proof_internal(
2312        self,
2313        drive: &Drive,
2314        transaction: TransactionArg,
2315        drive_operations: &mut Vec<LowLevelDriveOperation>,
2316        platform_version: &PlatformVersion,
2317    ) -> Result<Vec<u8>, Error> {
2318        let path_query = self.construct_path_query_operations(
2319            drive,
2320            true,
2321            transaction,
2322            drive_operations,
2323            platform_version,
2324        )?;
2325        drive.grove_get_proved_path_query(
2326            &path_query,
2327            transaction,
2328            drive_operations,
2329            &platform_version.drive,
2330        )
2331    }
2332
2333    #[cfg(all(feature = "server", feature = "verify"))]
2334    /// Executes a query with proof and returns the root hash, items, and fee.
2335    pub fn execute_with_proof_only_get_elements(
2336        self,
2337        drive: &Drive,
2338        block_info: Option<BlockInfo>,
2339        transaction: TransactionArg,
2340        platform_version: &PlatformVersion,
2341    ) -> Result<(RootHash, Vec<Vec<u8>>, u64), Error> {
2342        let mut drive_operations = vec![];
2343        let (root_hash, items) = self.execute_with_proof_only_get_elements_internal(
2344            drive,
2345            transaction,
2346            &mut drive_operations,
2347            platform_version,
2348        )?;
2349        let cost = if let Some(block_info) = block_info {
2350            let fee_result = Drive::calculate_fee(
2351                None,
2352                Some(drive_operations),
2353                &block_info.epoch,
2354                drive.config.epochs_per_era,
2355                platform_version,
2356                None,
2357            )?;
2358            fee_result.processing_fee
2359        } else {
2360            0
2361        };
2362        Ok((root_hash, items, cost))
2363    }
2364
2365    #[cfg(all(feature = "server", feature = "verify"))]
2366    /// Executes an internal query with proof and returns the root hash and values.
2367    pub(crate) fn execute_with_proof_only_get_elements_internal(
2368        self,
2369        drive: &Drive,
2370        transaction: TransactionArg,
2371        drive_operations: &mut Vec<LowLevelDriveOperation>,
2372        platform_version: &PlatformVersion,
2373    ) -> Result<(RootHash, Vec<Vec<u8>>), Error> {
2374        let path_query = self.construct_path_query_operations(
2375            drive,
2376            true,
2377            transaction,
2378            drive_operations,
2379            platform_version,
2380        )?;
2381
2382        let proof = drive.grove_get_proved_path_query(
2383            &path_query,
2384            transaction,
2385            drive_operations,
2386            &platform_version.drive,
2387        )?;
2388        self.verify_proof_keep_serialized(proof.as_slice(), platform_version)
2389    }
2390
2391    #[cfg(feature = "server")]
2392    /// Executes a query with no proof and returns the items, skipped items, and fee.
2393    pub fn execute_raw_results_no_proof(
2394        &self,
2395        drive: &Drive,
2396        block_info: Option<BlockInfo>,
2397        transaction: TransactionArg,
2398        platform_version: &PlatformVersion,
2399    ) -> Result<(Vec<Vec<u8>>, u16, u64), Error> {
2400        let mut drive_operations = vec![];
2401        let (items, skipped) = self.execute_raw_results_no_proof_internal(
2402            drive,
2403            transaction,
2404            &mut drive_operations,
2405            platform_version,
2406        )?;
2407        let cost = if let Some(block_info) = block_info {
2408            let fee_result = Drive::calculate_fee(
2409                None,
2410                Some(drive_operations),
2411                &block_info.epoch,
2412                drive.config.epochs_per_era,
2413                platform_version,
2414                None,
2415            )?;
2416            fee_result.processing_fee
2417        } else {
2418            0
2419        };
2420        Ok((items, skipped, cost))
2421    }
2422
2423    #[cfg(feature = "server")]
2424    /// Executes an internal query with no proof and returns the values and skipped items.
2425    pub(crate) fn execute_raw_results_no_proof_internal(
2426        &self,
2427        drive: &Drive,
2428        transaction: TransactionArg,
2429        drive_operations: &mut Vec<LowLevelDriveOperation>,
2430        platform_version: &PlatformVersion,
2431    ) -> Result<(Vec<Vec<u8>>, u16), Error> {
2432        let path_query = self.construct_path_query_operations(
2433            drive,
2434            false,
2435            transaction,
2436            drive_operations,
2437            platform_version,
2438        )?;
2439
2440        let query_result = drive.grove_get_path_query_serialized_results(
2441            &path_query,
2442            transaction,
2443            drive_operations,
2444            &platform_version.drive,
2445        );
2446        match query_result {
2447            Err(Error::GroveDB(e))
2448                if matches!(
2449                    e.as_ref(),
2450                    GroveError::PathKeyNotFound(_)
2451                        | GroveError::PathNotFound(_)
2452                        | GroveError::PathParentLayerNotFound(_)
2453                ) =>
2454            {
2455                Ok((Vec::new(), 0))
2456            }
2457            _ => {
2458                let (data, skipped) = query_result?;
2459                {
2460                    Ok((data, skipped))
2461                }
2462            }
2463        }
2464    }
2465
2466    #[cfg(feature = "server")]
2467    /// Executes an internal query with no proof and returns the values and skipped items.
2468    pub(crate) fn execute_no_proof_internal(
2469        &self,
2470        drive: &Drive,
2471        result_type: QueryResultType,
2472        transaction: TransactionArg,
2473        drive_operations: &mut Vec<LowLevelDriveOperation>,
2474        platform_version: &PlatformVersion,
2475    ) -> Result<(QueryResultElements, u16), Error> {
2476        let path_query = self.construct_path_query_operations(
2477            drive,
2478            false,
2479            transaction,
2480            drive_operations,
2481            platform_version,
2482        )?;
2483        let query_result = drive.grove_get_path_query(
2484            &path_query,
2485            transaction,
2486            result_type,
2487            drive_operations,
2488            &platform_version.drive,
2489        );
2490        match query_result {
2491            Err(Error::GroveDB(e))
2492                if matches!(
2493                    e.as_ref(),
2494                    GroveError::PathKeyNotFound(_)
2495                        | GroveError::PathNotFound(_)
2496                        | GroveError::PathParentLayerNotFound(_)
2497                ) =>
2498            {
2499                Ok((QueryResultElements::new(), 0))
2500            }
2501            _ => {
2502                let (data, skipped) = query_result?;
2503                {
2504                    Ok((data, skipped))
2505                }
2506            }
2507        }
2508    }
2509}
2510
2511/// Convert DriveQuery to a BTreeMap of values
2512impl<'a> From<&DriveDocumentQuery<'a>> for BTreeMap<String, Value> {
2513    fn from(query: &DriveDocumentQuery<'a>) -> Self {
2514        let mut response = BTreeMap::<String, Value>::new();
2515
2516        //  contract
2517        // TODO: once contract can be serialized, maybe put full contract here instead of id
2518        response.insert(
2519            "contract_id".to_string(),
2520            Value::Identifier(query.contract.id().to_buffer()),
2521        );
2522
2523        // document_type
2524        // TODO: once DocumentType can be serialized, maybe put full DocumentType instead of name
2525        response.insert(
2526            "document_type_name".to_string(),
2527            Value::Text(query.document_type.name().to_string()),
2528        );
2529
2530        // Internal clauses
2531        let all_where_clauses: Vec<WhereClause> = query.internal_clauses.clone().into();
2532        response.insert(
2533            "where".to_string(),
2534            Value::Array(all_where_clauses.into_iter().map(|v| v.into()).collect()),
2535        );
2536
2537        // Offset
2538        if let Some(offset) = query.offset {
2539            response.insert("offset".to_string(), Value::U16(offset));
2540        };
2541        // Limit
2542        if let Some(limit) = query.limit {
2543            response.insert("limit".to_string(), Value::U16(limit));
2544        };
2545        // Order by
2546        let order_by = &query.order_by;
2547        let value: Vec<Value> = order_by
2548            .into_iter()
2549            .map(|(_k, v)| v.clone().into())
2550            .collect();
2551        response.insert("orderBy".to_string(), Value::Array(value));
2552
2553        // start_at, start_at_included
2554        if let Some(start_at) = query.start_at {
2555            let v = Value::Identifier(start_at);
2556            if query.start_at_included {
2557                response.insert("startAt".to_string(), v);
2558            } else {
2559                response.insert("startAfter".to_string(), v);
2560            }
2561        };
2562
2563        // block_time_ms
2564        if let Some(block_time_ms) = query.block_time_ms {
2565            response.insert("blockTime".to_string(), Value::U64(block_time_ms));
2566        };
2567
2568        response
2569    }
2570}
2571
2572#[cfg(feature = "server")]
2573#[cfg(test)]
2574mod tests {
2575
2576    use dpp::data_contract::document_type::accessors::DocumentTypeV0Getters;
2577
2578    use dpp::prelude::Identifier;
2579    use grovedb::Query;
2580    use indexmap::IndexMap;
2581    use rand::prelude::StdRng;
2582    use rand::SeedableRng;
2583    use serde_json::json;
2584    use std::borrow::Cow;
2585    use std::collections::BTreeMap;
2586    use std::option::Option::None;
2587    use tempfile::TempDir;
2588
2589    use crate::drive::Drive;
2590    use crate::query::{
2591        DriveDocumentQuery, InternalClauses, OrderClause, WhereClause, WhereOperator,
2592    };
2593    use crate::util::storage_flags::StorageFlags;
2594
2595    use dpp::data_contract::DataContract;
2596
2597    use serde_json::Value::Null;
2598
2599    use crate::config::DriveConfig;
2600    use crate::util::test_helpers::setup::setup_drive_with_initial_state_structure;
2601    use dpp::block::block_info::BlockInfo;
2602    use dpp::data_contract::accessors::v0::DataContractV0Getters;
2603    use dpp::data_contracts::SystemDataContract;
2604    use dpp::document::DocumentV0;
2605    use dpp::platform_value::string_encoding::Encoding;
2606    use dpp::platform_value::Value;
2607    use dpp::system_data_contracts::load_system_data_contract;
2608    use dpp::tests::fixtures::{get_data_contract_fixture, get_dpns_data_contract_fixture};
2609    use dpp::tests::json_document::json_document_to_contract;
2610    use dpp::util::cbor_serializer;
2611    use dpp::version::PlatformVersion;
2612
2613    fn setup_family_contract() -> (Drive, DataContract) {
2614        let tmp_dir = TempDir::new().unwrap();
2615
2616        let platform_version = PlatformVersion::latest();
2617
2618        let (drive, _) = Drive::open(tmp_dir, None).expect("expected to open Drive successfully");
2619
2620        drive
2621            .create_initial_state_structure(None, platform_version)
2622            .expect("expected to create root tree successfully");
2623
2624        let contract_path = "tests/supporting_files/contract/family/family-contract.json";
2625
2626        // let's construct the grovedb structure for the dashpay data contract
2627        let contract = json_document_to_contract(contract_path, false, platform_version)
2628            .expect("expected to get document");
2629
2630        let storage_flags = Some(Cow::Owned(StorageFlags::SingleEpoch(0)));
2631        drive
2632            .apply_contract(
2633                &contract,
2634                BlockInfo::default(),
2635                true,
2636                storage_flags,
2637                None,
2638                platform_version,
2639            )
2640            .expect("expected to apply contract successfully");
2641
2642        (drive, contract)
2643    }
2644
2645    fn setup_withdrawal_contract() -> (Drive, DataContract) {
2646        let tmp_dir = TempDir::new().unwrap();
2647
2648        let platform_version = PlatformVersion::latest();
2649
2650        let (drive, _) = Drive::open(tmp_dir, None).expect("expected to open Drive successfully");
2651
2652        drive
2653            .create_initial_state_structure(None, platform_version)
2654            .expect("expected to create root tree successfully");
2655
2656        // let's construct the grovedb structure for the dashpay data contract
2657        let contract = load_system_data_contract(SystemDataContract::Withdrawals, platform_version)
2658            .expect("load system contact");
2659
2660        let storage_flags = Some(Cow::Owned(StorageFlags::SingleEpoch(0)));
2661        drive
2662            .apply_contract(
2663                &contract,
2664                BlockInfo::default(),
2665                true,
2666                storage_flags,
2667                None,
2668                platform_version,
2669            )
2670            .expect("expected to apply contract successfully");
2671
2672        (drive, contract)
2673    }
2674
2675    fn setup_family_birthday_contract() -> (Drive, DataContract) {
2676        let drive = setup_drive_with_initial_state_structure(None);
2677
2678        let platform_version = PlatformVersion::latest();
2679
2680        let contract_path =
2681            "tests/supporting_files/contract/family/family-contract-with-birthday.json";
2682
2683        // let's construct the grovedb structure for the dashpay data contract
2684        let contract = json_document_to_contract(contract_path, false, platform_version)
2685            .expect("expected to get document");
2686        let storage_flags = Some(Cow::Owned(StorageFlags::SingleEpoch(0)));
2687        drive
2688            .apply_contract(
2689                &contract,
2690                BlockInfo::default(),
2691                true,
2692                storage_flags,
2693                None,
2694                platform_version,
2695            )
2696            .expect("expected to apply contract successfully");
2697
2698        (drive, contract)
2699    }
2700
2701    #[test]
2702    fn test_drive_query_from_to_cbor() {
2703        let config = DriveConfig::default();
2704        let contract = get_data_contract_fixture(None, 0, 1).data_contract_owned();
2705        let document_type = contract
2706            .document_type_for_name("niceDocument")
2707            .expect("expected to get nice document");
2708        let start_after = Identifier::random();
2709
2710        let query_value = json!({
2711            "contract_id": contract.id(),
2712            "document_type_name": document_type.name(),
2713            "where": [
2714                ["firstName", "<", "Gilligan"],
2715                ["lastName", "=", "Doe"]
2716            ],
2717            "limit": 100u16,
2718            "offset": 10u16,
2719            "orderBy": [
2720                ["firstName", "asc"],
2721                ["lastName", "desc"],
2722            ],
2723            "startAfter": start_after,
2724            "blockTime": 13453432u64,
2725        });
2726
2727        let where_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None)
2728            .expect("expected to serialize to cbor");
2729        let query =
2730            DriveDocumentQuery::from_cbor(where_cbor.as_slice(), &contract, document_type, &config)
2731                .expect("deserialize cbor shouldn't fail");
2732
2733        let cbor = query.to_cbor().expect("should serialize cbor");
2734
2735        let deserialized = DriveDocumentQuery::from_cbor(&cbor, &contract, document_type, &config)
2736            .expect("should deserialize cbor");
2737
2738        assert_eq!(query, deserialized);
2739
2740        assert_eq!(deserialized.start_at, Some(start_after.to_buffer()));
2741        assert!(!deserialized.start_at_included);
2742        assert_eq!(deserialized.block_time_ms, Some(13453432u64));
2743    }
2744
2745    #[test]
2746    fn test_invalid_query_ranges_different_fields() {
2747        let query_value = json!({
2748            "where": [
2749                ["firstName", "<", "Gilligan"],
2750                ["lastName", "<", "Michelle"],
2751            ],
2752            "limit": 100,
2753            "orderBy": [
2754                ["firstName", "asc"],
2755                ["lastName", "asc"],
2756            ]
2757        });
2758        let contract = get_data_contract_fixture(None, 0, 1).data_contract_owned();
2759        let document_type = contract
2760            .document_type_for_name("niceDocument")
2761            .expect("expected to get nice document");
2762
2763        let where_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None)
2764            .expect("expected to serialize to cbor");
2765        DriveDocumentQuery::from_cbor(
2766            where_cbor.as_slice(),
2767            &contract,
2768            document_type,
2769            &DriveConfig::default(),
2770        )
2771        .expect_err("all ranges must be on same field");
2772    }
2773
2774    #[test]
2775    fn test_invalid_query_extra_invalid_field() {
2776        let query_value = json!({
2777            "where": [
2778                ["firstName", "<", "Gilligan"],
2779            ],
2780            "limit": 100,
2781            "orderBy": [
2782                ["firstName", "asc"],
2783                ["lastName", "asc"],
2784            ],
2785            "invalid": 0,
2786        });
2787        let contract = get_data_contract_fixture(None, 0, 1).data_contract_owned();
2788        let document_type = contract
2789            .document_type_for_name("niceDocument")
2790            .expect("expected to get nice document");
2791
2792        let where_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None)
2793            .expect("expected to serialize to cbor");
2794        DriveDocumentQuery::from_cbor(
2795            where_cbor.as_slice(),
2796            &contract,
2797            document_type,
2798            &DriveConfig::default(),
2799        )
2800        .expect_err("fields of queries must of defined supported types (where, limit, orderBy...)");
2801    }
2802
2803    #[test]
2804    fn test_invalid_query_conflicting_clauses() {
2805        let query_value = json!({
2806            "where": [
2807                ["firstName", "<", "Gilligan"],
2808                ["firstName", ">", "Gilligan"],
2809            ],
2810            "limit": 100,
2811            "orderBy": [
2812                ["firstName", "asc"],
2813                ["lastName", "asc"],
2814            ],
2815        });
2816
2817        let contract = get_data_contract_fixture(None, 0, 1).data_contract_owned();
2818        let document_type = contract
2819            .document_type_for_name("niceDocument")
2820            .expect("expected to get nice document");
2821
2822        let where_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None)
2823            .expect("expected to serialize to cbor");
2824        DriveDocumentQuery::from_cbor(
2825            where_cbor.as_slice(),
2826            &contract,
2827            document_type,
2828            &DriveConfig::default(),
2829        )
2830        .expect_err("the query should not be created");
2831    }
2832
2833    #[test]
2834    fn test_valid_query_groupable_meeting_clauses() {
2835        let query_value = json!({
2836            "where": [
2837                ["firstName", "<=", "Gilligan"],
2838                ["firstName", ">", "Gilligan"],
2839            ],
2840            "limit": 100,
2841            "orderBy": [
2842                ["firstName", "asc"],
2843                ["lastName", "asc"],
2844            ],
2845        });
2846
2847        let contract = get_data_contract_fixture(None, 0, 1).data_contract_owned();
2848        let document_type = contract
2849            .document_type_for_name("niceDocument")
2850            .expect("expected to get nice document");
2851
2852        let where_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None)
2853            .expect("expected to serialize to cbor");
2854        DriveDocumentQuery::from_cbor(
2855            where_cbor.as_slice(),
2856            &contract,
2857            document_type,
2858            &DriveConfig::default(),
2859        )
2860        .expect("the query should be created");
2861    }
2862
2863    #[test]
2864    fn test_valid_query_query_field_at_max_length() {
2865        let long_string = "t".repeat(255);
2866        let query_value = json!({
2867            "where": [
2868                ["firstName", "<", long_string],
2869            ],
2870            "limit": 100,
2871            "orderBy": [
2872                ["firstName", "asc"],
2873                ["lastName", "asc"],
2874            ],
2875        });
2876        let contract = get_data_contract_fixture(None, 0, 1).data_contract_owned();
2877        let document_type = contract
2878            .document_type_for_name("niceDocument")
2879            .expect("expected to get nice document");
2880
2881        let where_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None)
2882            .expect("expected to serialize to cbor");
2883        DriveDocumentQuery::from_cbor(
2884            where_cbor.as_slice(),
2885            &contract,
2886            document_type,
2887            &DriveConfig::default(),
2888        )
2889        .expect("query should be fine for a 255 byte long string");
2890    }
2891
2892    #[test]
2893    fn test_valid_query_drive_document_query() {
2894        let platform_version = PlatformVersion::latest();
2895        let mut rng = StdRng::seed_from_u64(5);
2896        let contract =
2897            get_dpns_data_contract_fixture(Some(Identifier::random_with_rng(&mut rng)), 0, 1)
2898                .data_contract_owned();
2899        let domain = contract
2900            .document_type_for_name("domain")
2901            .expect("expected to get domain");
2902
2903        let query_asc = DriveDocumentQuery {
2904            contract: &contract,
2905            document_type: domain,
2906            internal_clauses: InternalClauses {
2907                primary_key_in_clause: None,
2908                primary_key_equal_clause: None,
2909                in_clause: None,
2910                range_clause: Some(WhereClause {
2911                    field: "records.identity".to_string(),
2912                    operator: WhereOperator::LessThan,
2913                    value: Value::Identifier(
2914                        Identifier::from_string(
2915                            "AYN4srupPWDrp833iG5qtmaAsbapNvaV7svAdncLN5Rh",
2916                            Encoding::Base58,
2917                        )
2918                        .unwrap()
2919                        .to_buffer(),
2920                    ),
2921                }),
2922                equal_clauses: BTreeMap::new(),
2923            },
2924            offset: None,
2925            limit: Some(6),
2926            order_by: vec![(
2927                "records.identity".to_string(),
2928                OrderClause {
2929                    field: "records.identity".to_string(),
2930                    ascending: false,
2931                },
2932            )]
2933            .into_iter()
2934            .collect(),
2935            start_at: None,
2936            start_at_included: false,
2937            block_time_ms: None,
2938        };
2939
2940        let path_query = query_asc
2941            .construct_path_query(None, platform_version)
2942            .expect("expected to create path query");
2943
2944        assert_eq!(path_query.to_string(), "PathQuery { path: [@, 0x1da29f488023e306ff9a680bc9837153fb0778c8ee9c934a87dc0de1d69abd3c, 0x01, domain, 0x7265636f7264732e6964656e74697479], query: SizedQuery { query: Query {\n  items: [\n    RangeTo(.. 0x8dc201fd7ad7905f8a84d66218e2b387daea7fe4739ae0e21e8c3ee755e6a2c0),\n  ],\n  default_subquery_branch: SubqueryBranch { subquery_path: [0x00], subquery: Query {\n  items: [\n    RangeFull,\n  ],\n  default_subquery_branch: SubqueryBranch { subquery_path: None subquery: None },\n  left_to_right: false,\n  add_parent_tree_on_subquery: false,\n} },\n  conditional_subquery_branches: {\n    Key(): SubqueryBranch { subquery_path: [0x00], subquery: Query {\n  items: [\n    RangeFull,\n  ],\n  default_subquery_branch: SubqueryBranch { subquery_path: None subquery: None },\n  left_to_right: false,\n  add_parent_tree_on_subquery: false,\n} },\n  },\n  left_to_right: false,\n  add_parent_tree_on_subquery: false,\n}, limit: 6 } }");
2945
2946        // Serialize the PathQuery to a Vec<u8>
2947        let encoded = bincode::encode_to_vec(&path_query, bincode::config::standard())
2948            .expect("Failed to serialize PathQuery");
2949
2950        // Convert the encoded bytes to a hex string
2951        let hex_string = hex::encode(encoded);
2952
2953        // Note: The expected encoding changed due to an upstream GroveDB
2954        // serialization update. Keep this value in sync with the current
2955        // GroveDB revision pinned in Cargo.toml.
2956        assert_eq!(hex_string, "050140201da29f488023e306ff9a680bc9837153fb0778c8ee9c934a87dc0de1d69abd3c010106646f6d61696e107265636f7264732e6964656e74697479010105208dc201fd7ad7905f8a84d66218e2b387daea7fe4739ae0e21e8c3ee755e6a2c00101010001010103000000000001010000010101000101010300000000000000010600");
2957    }
2958
2959    #[test]
2960    fn test_invalid_query_field_too_long() {
2961        let (drive, contract) = setup_family_contract();
2962
2963        let platform_version = PlatformVersion::latest();
2964
2965        let document_type = contract
2966            .document_type_for_name("person")
2967            .expect("expected to get a document type");
2968
2969        let too_long_string = "t".repeat(256);
2970        let query_value = json!({
2971            "where": [
2972                ["firstName", "<", too_long_string],
2973            ],
2974            "limit": 100,
2975            "orderBy": [
2976                ["firstName", "asc"],
2977                ["lastName", "asc"],
2978            ],
2979        });
2980
2981        let where_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None)
2982            .expect("expected to serialize to cbor");
2983        let query = DriveDocumentQuery::from_cbor(
2984            where_cbor.as_slice(),
2985            &contract,
2986            document_type,
2987            &DriveConfig::default(),
2988        )
2989        .expect("fields of queries length must be under 256 bytes long");
2990        query
2991            .execute_raw_results_no_proof(&drive, None, None, platform_version)
2992            .expect_err("fields of queries length must be under 256 bytes long");
2993    }
2994
2995    // TODO: Eventually we want to error with weird Null values
2996    // #[test]
2997    // fn test_invalid_query_scalar_field_with_null_value() {
2998    //     let (drive, contract) = setup_family_contract();
2999    //
3000    //     let document_type = contract
3001    //         .document_type("person")
3002    //         .expect("expected to get a document type");
3003    //
3004    //     let query_value = json!({
3005    //         "where": [
3006    //             ["age", "<", Null],
3007    //         ],
3008    //         "limit": 100,
3009    //         "orderBy": [
3010    //             ["age", "asc"],
3011    //         ],
3012    //     });
3013    //
3014    //     let where_cbor = serializer::value_to_cbor(query_value, None).expect("expected to serialize to cbor");
3015    //     let query = DriveQuery::from_cbor(where_cbor.as_slice(), &contract, document_type, &DriveConfig::default())
3016    //         .expect("The query itself should be valid for a null type");
3017    //     query
3018    //         .execute_no_proof(&drive, None, None)
3019    //         .expect_err("a Null value doesn't make sense for an integer");
3020    // }
3021
3022    // TODO: Eventually we want to error with weird Null values
3023    //
3024    // #[test]
3025    // fn test_invalid_query_timestamp_field_with_null_value() {
3026    //     let (drive, contract) = setup_family_birthday_contract();
3027    //
3028    //     let document_type = contract
3029    //         .document_type("person")
3030    //         .expect("expected to get a document type");
3031    //
3032    //     let query_value = json!({
3033    //         "where": [
3034    //             ["birthday", "<", Null],
3035    //         ],
3036    //         "limit": 100,
3037    //         "orderBy": [
3038    //             ["birthday", "asc"],
3039    //         ],
3040    //     });
3041    //
3042    //     let where_cbor = serializer::value_to_cbor(query_value, None).expect("expected to serialize to cbor");
3043    //     let query = DriveQuery::from_cbor(where_cbor.as_slice(), &contract, document_type, &DriveConfig::default())
3044    //         .expect("The query itself should be valid for a null type");
3045    //     query
3046    //         .execute_no_proof(&drive, None, None)
3047    //         .expect_err("the value can not be less than Null");
3048    // }
3049
3050    #[test]
3051    fn test_valid_query_timestamp_field_with_null_value() {
3052        let (drive, contract) = setup_family_birthday_contract();
3053
3054        let platform_version = PlatformVersion::latest();
3055
3056        let document_type = contract
3057            .document_type_for_name("person")
3058            .expect("expected to get a document type");
3059
3060        let query_value = json!({
3061            "where": [
3062                ["birthday", ">=", Null],
3063            ],
3064            "limit": 100,
3065            "orderBy": [
3066                ["birthday", "asc"],
3067            ],
3068        });
3069
3070        let where_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None)
3071            .expect("expected to serialize to cbor");
3072        let query = DriveDocumentQuery::from_cbor(
3073            where_cbor.as_slice(),
3074            &contract,
3075            document_type,
3076            &DriveConfig::default(),
3077        )
3078        .expect("The query itself should be valid for a null type");
3079        query
3080            .execute_raw_results_no_proof(&drive, None, None, platform_version)
3081            .expect("a Null value doesn't make sense for a float");
3082    }
3083
3084    #[test]
3085    fn test_invalid_query_in_with_empty_array() {
3086        let (drive, contract) = setup_family_contract();
3087
3088        let platform_version = PlatformVersion::latest();
3089
3090        let document_type = contract
3091            .document_type_for_name("person")
3092            .expect("expected to get a document type");
3093
3094        let query_value = json!({
3095            "where": [
3096                ["firstName", "in", []],
3097            ],
3098            "limit": 100,
3099            "orderBy": [
3100                ["firstName", "asc"],
3101            ],
3102        });
3103
3104        let where_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None)
3105            .expect("expected to serialize to cbor");
3106        let query = DriveDocumentQuery::from_cbor(
3107            where_cbor.as_slice(),
3108            &contract,
3109            document_type,
3110            &DriveConfig::default(),
3111        )
3112        .expect("query should be valid for empty array");
3113
3114        query
3115            .execute_raw_results_no_proof(&drive, None, None, platform_version)
3116            .expect_err("query should not be able to execute for empty array");
3117    }
3118
3119    #[test]
3120    fn test_invalid_query_in_too_many_elements() {
3121        let (drive, contract) = setup_family_contract();
3122
3123        let platform_version = PlatformVersion::latest();
3124
3125        let document_type = contract
3126            .document_type_for_name("person")
3127            .expect("expected to get a document type");
3128
3129        let mut array: Vec<String> = Vec::with_capacity(101);
3130        for _ in 0..array.capacity() {
3131            array.push(String::from("a"));
3132        }
3133        let query_value = json!({
3134            "where": [
3135                ["firstName", "in", array],
3136            ],
3137            "limit": 100,
3138            "orderBy": [
3139                ["firstName", "asc"],
3140            ],
3141        });
3142
3143        let where_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None)
3144            .expect("expected to serialize to cbor");
3145        let query = DriveDocumentQuery::from_cbor(
3146            where_cbor.as_slice(),
3147            &contract,
3148            document_type,
3149            &DriveConfig::default(),
3150        )
3151        .expect("query is valid for too many elements");
3152
3153        query
3154            .execute_raw_results_no_proof(&drive, None, None, platform_version)
3155            .expect_err("query should not be able to execute with too many elements");
3156    }
3157
3158    #[test]
3159    fn test_invalid_query_in_unique_elements() {
3160        let (drive, contract) = setup_family_contract();
3161
3162        let platform_version = PlatformVersion::latest();
3163
3164        let document_type = contract
3165            .document_type_for_name("person")
3166            .expect("expected to get a document type");
3167
3168        let query_value = json!({
3169            "where": [
3170                ["firstName", "in", ["a", "a"]],
3171            ],
3172            "limit": 100,
3173            "orderBy": [
3174                ["firstName", "asc"],
3175            ],
3176        });
3177
3178        let where_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None)
3179            .expect("expected to serialize to cbor");
3180
3181        // The is actually valid, however executing it is not
3182        // This is in order to optimize query execution
3183
3184        let query = DriveDocumentQuery::from_cbor(
3185            where_cbor.as_slice(),
3186            &contract,
3187            document_type,
3188            &DriveConfig::default(),
3189        )
3190        .expect("the query should be created");
3191
3192        query
3193            .execute_raw_results_no_proof(&drive, None, None, platform_version)
3194            .expect_err("there should be no duplicates values for In query");
3195    }
3196
3197    #[test]
3198    fn test_invalid_query_starts_with_empty_string() {
3199        let query_value = json!({
3200            "where": [
3201                ["firstName", "startsWith", ""],
3202            ],
3203            "limit": 100,
3204            "orderBy": [
3205                ["firstName", "asc"],
3206            ],
3207        });
3208
3209        let contract = get_data_contract_fixture(None, 0, 1).data_contract_owned();
3210        let document_type = contract
3211            .document_type_for_name("niceDocument")
3212            .expect("expected to get nice document");
3213
3214        let where_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None)
3215            .expect("expected to serialize to cbor");
3216        DriveDocumentQuery::from_cbor(
3217            where_cbor.as_slice(),
3218            &contract,
3219            document_type,
3220            &DriveConfig::default(),
3221        )
3222        .expect_err("starts with can not start with an empty string");
3223    }
3224
3225    #[test]
3226    fn test_invalid_query_limit_too_high() {
3227        let query_value = json!({
3228            "where": [
3229                ["firstName", "startsWith", "a"],
3230            ],
3231            "limit": 101,
3232            "orderBy": [
3233                ["firstName", "asc"],
3234            ],
3235        });
3236
3237        let contract = get_data_contract_fixture(None, 0, 1).data_contract_owned();
3238        let document_type = contract
3239            .document_type_for_name("niceDocument")
3240            .expect("expected to get nice document");
3241
3242        let where_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None)
3243            .expect("expected to serialize to cbor");
3244        DriveDocumentQuery::from_cbor(
3245            where_cbor.as_slice(),
3246            &contract,
3247            document_type,
3248            &DriveConfig::default(),
3249        )
3250        .expect_err("starts with can not start with an empty string");
3251    }
3252
3253    #[test]
3254    fn test_invalid_query_limit_too_low() {
3255        let query_value = json!({
3256            "where": [
3257                ["firstName", "startsWith", "a"],
3258            ],
3259            "limit": -1,
3260            "orderBy": [
3261                ["firstName", "asc"],
3262            ],
3263        });
3264
3265        let contract = get_data_contract_fixture(None, 0, 1).data_contract_owned();
3266        let document_type = contract
3267            .document_type_for_name("niceDocument")
3268            .expect("expected to get nice document");
3269
3270        let where_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None)
3271            .expect("expected to serialize to cbor");
3272        DriveDocumentQuery::from_cbor(
3273            where_cbor.as_slice(),
3274            &contract,
3275            document_type,
3276            &DriveConfig::default(),
3277        )
3278        .expect_err("starts with can not start with an empty string");
3279    }
3280
3281    #[test]
3282    fn test_invalid_query_limit_zero() {
3283        let query_value = json!({
3284            "where": [
3285                ["firstName", "startsWith", "a"],
3286            ],
3287            "limit": 0,
3288            "orderBy": [
3289                ["firstName", "asc"],
3290            ],
3291        });
3292
3293        let contract = get_data_contract_fixture(None, 0, 1).data_contract_owned();
3294        let document_type = contract
3295            .document_type_for_name("niceDocument")
3296            .expect("expected to get nice document");
3297
3298        let where_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None)
3299            .expect("expected to serialize to cbor");
3300        DriveDocumentQuery::from_cbor(
3301            where_cbor.as_slice(),
3302            &contract,
3303            document_type,
3304            &DriveConfig::default(),
3305        )
3306        .expect_err("starts with can not start with an empty string");
3307    }
3308
3309    #[test]
3310    fn test_withdrawal_query_with_missing_transaction_index() {
3311        // Setup the withdrawal contract
3312        let (_, contract) = setup_withdrawal_contract();
3313        let platform_version = PlatformVersion::latest();
3314
3315        let document_type_name = "withdrawal";
3316        let document_type = contract
3317            .document_type_for_name(document_type_name)
3318            .expect("expected to get document type");
3319
3320        // Create a DriveDocumentQuery that simulates missing 'transactionIndex' in documents
3321        let drive_document_query = DriveDocumentQuery {
3322            contract: &contract,
3323            document_type,
3324            internal_clauses: InternalClauses {
3325                primary_key_in_clause: None,
3326                primary_key_equal_clause: None,
3327                in_clause: Some(WhereClause {
3328                    field: "status".to_string(),
3329                    operator: WhereOperator::In,
3330                    value: Value::Array(vec![
3331                        Value::U64(0),
3332                        Value::U64(1),
3333                        Value::U64(2),
3334                        Value::U64(3),
3335                        Value::U64(4),
3336                    ]),
3337                }),
3338                range_clause: None,
3339                equal_clauses: BTreeMap::default(),
3340            },
3341            offset: None,
3342            limit: Some(3),
3343            order_by: IndexMap::from([
3344                (
3345                    "status".to_string(),
3346                    OrderClause {
3347                        field: "status".to_string(),
3348                        ascending: true,
3349                    },
3350                ),
3351                (
3352                    "transactionIndex".to_string(),
3353                    OrderClause {
3354                        field: "transactionIndex".to_string(),
3355                        ascending: true,
3356                    },
3357                ),
3358            ]),
3359            start_at: Some([3u8; 32]),
3360            start_at_included: false,
3361            block_time_ms: None,
3362        };
3363
3364        // Create a document that we are starting at, which may be missing 'transactionIndex'
3365        let mut properties = BTreeMap::new();
3366        properties.insert("status".to_string(), Value::U64(0));
3367        // We intentionally omit 'transactionIndex' to simulate missing field
3368
3369        let starts_at_document = DocumentV0 {
3370            id: Identifier::from([3u8; 32]), // The same as start_at
3371            owner_id: Identifier::random(),
3372            properties,
3373            revision: None,
3374            created_at: None,
3375            updated_at: None,
3376            transferred_at: None,
3377            created_at_block_height: None,
3378            updated_at_block_height: None,
3379            transferred_at_block_height: None,
3380            created_at_core_block_height: None,
3381            updated_at_core_block_height: None,
3382            transferred_at_core_block_height: None,
3383            creator_id: None,
3384        }
3385        .into();
3386
3387        // Attempt to construct the path query
3388        let result = drive_document_query
3389            .construct_path_query(Some(starts_at_document), platform_version)
3390            .expect("expected to construct a path query");
3391
3392        assert_eq!(
3393            result
3394                .clone()
3395                .query
3396                .query
3397                .default_subquery_branch
3398                .subquery
3399                .expect("expected subquery")
3400                .items,
3401            Query::new_range_full().items
3402        );
3403    }
3404}