1use dpp::data_contract::document_type::TimeRangeTransform;
2use std::sync::Arc;
3
4#[cfg(any(feature = "server", feature = "verify"))]
5pub use {
6 conditions::{ValueClause, WhereClause, WhereOperator},
7 drive_document_average_query::{AverageEntry, AverageMode},
12 drive_document_count_query::{
19 CountMode, DocumentCountMode, DriveDocumentCountQuery, SplitCountEntry,
20 },
21 drive_document_having_query::{
27 AxisRangeBounds, DocumentHavingMode, DriveDocumentHavingQuery, MAX_HAVING_LIMIT,
28 },
29 drive_document_ranked_query::{
35 DocumentRankedMode, DriveDocumentRankedQuery, RankedAxis, RankedEntry, RankedEntryValue,
36 RankedPage, RankedPaginationInputs, MAX_RANKED_LIMIT, RANKED_AVG_SCALE,
37 RANKED_COUNT_ORDER_KEY,
38 },
39 drive_document_sum_query::{DriveDocumentSumQuery, SumEntry, SumMode},
44 grovedb::{PathQuery, Query, QueryItem, SizedQuery},
45 having::{
46 HavingAggregate, HavingAggregateFunction, HavingClause, HavingOperator, HavingRightOperand,
47 },
48 ordering::OrderClause,
49 projection::{SelectFunction, SelectProjection},
50 single_document_drive_query::SingleDocumentDriveQuery,
51 single_document_drive_query::SingleDocumentDriveQueryContestedStatus,
52 vote_polls_by_end_date_query::VotePollsByEndDateDriveQuery,
53 vote_query::IdentityBasedVoteDriveQuery,
54};
55
56#[cfg(feature = "server")]
59pub use drive_document_count_query::{
60 DocumentCountRequest, DocumentCountResponse, RangeCountOptions, MAX_LIMIT_AS_FAILSAFE,
61};
62
63#[cfg(feature = "server")]
67pub use drive_document_sum_query::{
68 DocumentSumRequest, DocumentSumResponse, RangeSumOptions, RangeSumWalkMode,
69};
70
71#[cfg(feature = "server")]
75pub use drive_document_average_query::{DocumentAverageRequest, DocumentAverageResponse};
76
77#[cfg(feature = "server")]
82pub use drive_document_ranked_query::{DocumentRankedRequest, DocumentRankedResponse};
83
84#[cfg(feature = "server")]
89pub use drive_document_having_query::{DocumentHavingRequest, DocumentHavingResponse};
90#[cfg(any(feature = "server", feature = "verify"))]
92use {
93 crate::{
94 drive::contract::paths::DataContractPaths,
95 error::{drive::DriveError, query::QuerySyntaxError, Error},
96 },
97 dpp::{
98 data_contract::{
99 accessors::v0::DataContractV0Getters,
100 document_type::{accessors::DocumentTypeV0Getters, methods::DocumentTypeV0Methods},
101 document_type::{DocumentTypeRef, Index},
102 DataContract,
103 },
104 document::{document_methods::DocumentMethodsV0, Document},
105 platform_value::{btreemap_extensions::BTreeValueRemoveFromMapHelper, Value},
106 version::PlatformVersion,
107 ProtocolError,
108 },
109 indexmap::IndexMap,
110 sqlparser::{
111 ast::{self, OrderByExpr, Select, Statement, TableFactor::Table, Value::Number},
112 dialect::MySqlDialect,
113 parser::Parser,
114 },
115 std::{collections::BTreeMap, ops::BitXor},
116};
117
118#[cfg(all(feature = "server", feature = "verify"))]
119use crate::verify::RootHash;
120
121#[cfg(feature = "server")]
122use dpp::document::serialization_traits::DocumentPlatformConversionMethodsV0;
123#[cfg(feature = "server")]
124pub use grovedb::{
125 query_result_type::{QueryResultElements, QueryResultType},
126 Element, Error as GroveError, TransactionArg,
127};
128
129use dpp::document;
130use dpp::prelude::Identifier;
131use dpp::validation::{SimpleValidationResult, ValidationResult};
132#[cfg(feature = "server")]
133use {
134 crate::{drive::Drive, fees::op::LowLevelDriveOperation},
135 dpp::block::block_info::BlockInfo,
136};
137use crate::config::DriveConfig;
139use crate::util::common::encode::encode_u64;
141#[cfg(feature = "server")]
142use crate::util::grove_operations::QueryType::StatefulQuery;
143
144#[cfg(any(feature = "server", feature = "verify"))]
146pub mod canonicalize;
147#[cfg(any(feature = "server", feature = "verify"))]
148pub use canonicalize::validate_and_canonicalize_where_clauses;
149#[cfg(any(feature = "server", feature = "verify"))]
150pub mod conditions;
151#[cfg(any(feature = "server", feature = "verify"))]
152mod defaults;
153#[cfg(any(feature = "server", feature = "verify"))]
154pub mod having;
155mod non_primary_key_path_query;
156#[cfg(any(feature = "server", feature = "verify"))]
157pub mod ordering;
158#[cfg(any(feature = "server", feature = "verify"))]
159pub mod projection;
160#[cfg(any(feature = "server", feature = "verify"))]
161mod single_document_drive_query;
162pub(crate) mod where_clause_grouping;
164
165#[cfg(feature = "server")]
167mod test_index;
168
169#[cfg(any(feature = "server", feature = "verify"))]
170pub mod vote_poll_vote_state_query;
172#[cfg(any(feature = "server", feature = "verify"))]
173pub mod vote_query;
175
176#[cfg(any(feature = "server", feature = "verify"))]
177pub mod vote_poll_contestant_votes_query;
179
180#[cfg(any(feature = "server", feature = "verify"))]
181pub mod vote_polls_by_end_date_query;
183
184#[cfg(any(feature = "server", feature = "verify"))]
185pub mod vote_polls_by_document_type_query;
187
188#[cfg(any(feature = "server", feature = "verify"))]
194pub type ContractLookupFn<'a> =
195 dyn Fn(&Identifier) -> Result<Option<Arc<DataContract>>, Error> + 'a;
196
197#[cfg(any(feature = "server", feature = "verify"))]
208pub fn contract_lookup_fn_for_contract<'a>(
209 data_contract: Arc<DataContract>,
210) -> Box<ContractLookupFn<'a>> {
211 let func = move |id: &Identifier| -> Result<Option<Arc<DataContract>>, Error> {
212 if data_contract.id().ne(id) {
213 return Ok(None);
214 }
215 Ok(Some(Arc::clone(&data_contract)))
216 };
217 Box::new(func)
218}
219
220#[cfg(any(feature = "server", feature = "verify"))]
222pub mod contested_resource_votes_given_by_identity_query;
223#[cfg(any(feature = "server", feature = "verify"))]
225pub mod drive_contested_document_query;
226
227#[cfg(any(feature = "server", feature = "verify"))]
229pub mod proposer_block_count_query;
230
231#[cfg(any(feature = "server", feature = "verify"))]
233pub mod identity_token_balance_drive_query;
234#[cfg(any(feature = "server", feature = "verify"))]
236pub mod identity_token_info_drive_query;
237
238#[cfg(any(feature = "server", feature = "verify"))]
240pub mod filter;
241#[cfg(any(feature = "server", feature = "verify"))]
243pub mod token_status_drive_query;
244
245#[cfg(any(feature = "server", feature = "verify"))]
247pub mod drive_document_count_query;
248
249#[cfg(any(feature = "server", feature = "verify"))]
255pub mod drive_document_sum_query;
256
257#[cfg(any(feature = "server", feature = "verify"))]
264pub mod drive_document_average_query;
265
266#[cfg(any(feature = "server", feature = "verify"))]
272pub mod drive_document_having_query;
273
274#[cfg(any(feature = "server", feature = "verify"))]
281pub mod drive_document_ranked_query;
282
283#[cfg(any(feature = "server", feature = "verify"))]
288pub(crate) mod index_only_synthesis;
289
290#[cfg(feature = "server")]
295pub mod drive_document_count_and_sum_query;
296
297pub type QuerySyntaxValidationResult<TData> = ValidationResult<TData, QuerySyntaxError>;
299
300pub type QuerySyntaxSimpleValidationResult = SimpleValidationResult<QuerySyntaxError>;
302
303#[cfg(any(feature = "server", feature = "verify"))]
304#[derive(Debug, Clone)]
311pub struct StartAtDocument<'a> {
312 pub document: Document,
314
315 pub document_type: DocumentTypeRef<'a>,
317
318 pub included: bool,
322}
323
324#[cfg(any(feature = "server", feature = "verify"))]
326#[derive(Clone, Debug, PartialEq, Default)]
327pub struct InternalClauses {
328 pub primary_key_in_clause: Option<WhereClause>,
330 pub primary_key_equal_clause: Option<WhereClause>,
332 pub in_clauses: Vec<WhereClause>,
339 pub range_clause: Option<WhereClause>,
346 pub equal_clauses: BTreeMap<String, WhereClause>,
348}
349
350#[cfg(any(feature = "server", feature = "verify"))]
356#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
357pub struct ClauseFieldRoles {
358 pub primary_key: bool,
360 pub index_property: bool,
362 pub terminal: bool,
365}
366
367#[cfg(any(feature = "server", feature = "verify"))]
368impl ClauseFieldRoles {
369 pub fn unindexed(&self) -> bool {
372 !self.primary_key && !self.index_property && !self.terminal
373 }
374}
375
376#[cfg(any(feature = "server", feature = "verify"))]
383pub(crate) enum BestIndexOutcome<'a> {
384 Matched(&'a Index),
386 NoIndexMatches(Error),
389}
390
391impl InternalClauses {
392 #[cfg(any(feature = "server", feature = "verify"))]
398 pub fn classify_field(document_type: DocumentTypeRef, field: &str) -> ClauseFieldRoles {
399 let mut roles = ClauseFieldRoles {
400 primary_key: field == "$id",
401 ..Default::default()
402 };
403 for index in document_type.indexes().values() {
404 if index
405 .properties
406 .iter()
407 .any(|property| property.name == field)
408 {
409 roles.index_property = true;
410 }
411 if index.terminal.as_deref() == Some(field) {
412 roles.terminal = true;
413 }
414 if roles.index_property && roles.terminal {
415 break;
416 }
417 }
418 roles
419 }
420
421 #[cfg(any(feature = "server", feature = "verify"))]
425 pub fn classify_fields(
426 &self,
427 document_type: DocumentTypeRef,
428 ) -> BTreeMap<String, ClauseFieldRoles> {
429 let mut classified = BTreeMap::new();
430 let mut add = |field: &str| {
431 classified
432 .entry(field.to_string())
433 .or_insert_with(|| Self::classify_field(document_type, field));
434 };
435 if self.primary_key_equal_clause.is_some() || self.primary_key_in_clause.is_some() {
436 add("$id");
437 }
438 for field in self.equal_clauses.keys() {
439 add(field);
440 }
441 if let Some(range_clause) = &self.range_clause {
442 add(&range_clause.field);
443 }
444 for in_clause in &self.in_clauses {
445 add(&in_clause.field);
446 }
447 classified
448 }
449
450 #[cfg(any(feature = "server", feature = "verify"))]
451 pub fn verify(&self) -> bool {
453 if self
455 .primary_key_in_clause
456 .is_some()
457 .bitxor(self.primary_key_equal_clause.is_some())
458 {
459 !(!self.in_clauses.is_empty()
461 || self.range_clause.is_some()
462 || !self.equal_clauses.is_empty())
463 } else {
464 !(self.primary_key_in_clause.is_some() && self.primary_key_equal_clause.is_some())
465 }
466 }
467
468 #[cfg(any(feature = "server", feature = "verify"))]
469 pub fn is_for_primary_key(&self) -> bool {
471 self.primary_key_in_clause.is_some() || self.primary_key_equal_clause.is_some()
472 }
473
474 #[cfg(any(feature = "server", feature = "verify"))]
475 pub fn is_empty(&self) -> bool {
477 self.in_clauses.is_empty()
478 && self.range_clause.is_none()
479 && self.equal_clauses.is_empty()
480 && self.primary_key_in_clause.is_none()
481 && self.primary_key_equal_clause.is_none()
482 }
483
484 #[cfg(any(feature = "server", feature = "verify"))]
485 pub fn extract_from_clauses(
487 all_where_clauses: Vec<WhereClause>,
488 platform_version: &PlatformVersion,
489 ) -> Result<Self, Error> {
490 let primary_key_equal_clauses_array = all_where_clauses
491 .iter()
492 .filter_map(|where_clause| match where_clause.operator {
493 WhereOperator::Equal => match where_clause.is_identifier() {
494 true => Some(where_clause.clone()),
495 false => None,
496 },
497 _ => None,
498 })
499 .collect::<Vec<WhereClause>>();
500
501 let primary_key_in_clauses_array = all_where_clauses
502 .iter()
503 .filter_map(|where_clause| match where_clause.operator {
504 WhereOperator::In => match where_clause.is_identifier() {
505 true => Some(where_clause.clone()),
506 false => None,
507 },
508 _ => None,
509 })
510 .collect::<Vec<WhereClause>>();
511
512 let (equal_clauses, range_clause, in_clauses) =
513 WhereClause::group_clauses(&all_where_clauses, platform_version)?;
514
515 let primary_key_equal_clause = match primary_key_equal_clauses_array.len() {
516 0 => Ok(None),
517 1 => Ok(Some(
518 primary_key_equal_clauses_array
519 .first()
520 .expect("there must be a value")
521 .clone(),
522 )),
523 _ => Err(Error::Query(
524 QuerySyntaxError::DuplicateNonGroupableClauseSameField(
525 "There should only be one equal clause for the primary key",
526 ),
527 )),
528 }?;
529
530 let primary_key_in_clause = match primary_key_in_clauses_array.len() {
531 0 => Ok(None),
532 1 => Ok(Some(
533 primary_key_in_clauses_array
534 .first()
535 .expect("there must be a value")
536 .clone(),
537 )),
538 _ => Err(Error::Query(
539 QuerySyntaxError::DuplicateNonGroupableClauseSameField(
540 "There should only be one in clause for the primary key",
541 ),
542 )),
543 }?;
544
545 let internal_clauses = InternalClauses {
546 primary_key_equal_clause,
547 primary_key_in_clause,
548 in_clauses,
549 range_clause,
550 equal_clauses,
551 };
552
553 match internal_clauses.verify() {
554 true => Ok(internal_clauses),
555 false => Err(Error::Query(
556 QuerySyntaxError::InvalidWhereClauseComponents("Query has invalid where clauses"),
557 )),
558 }
559 }
560
561 #[cfg(any(feature = "server", feature = "verify"))]
563 pub fn validate_against_schema(
564 &self,
565 document_type: DocumentTypeRef,
566 ) -> QuerySyntaxSimpleValidationResult {
567 if !self.verify() {
569 return QuerySyntaxSimpleValidationResult::new_with_error(
570 QuerySyntaxError::InvalidWhereClauseComponents(
571 "invalid composition of where clauses",
572 ),
573 );
574 }
575
576 for in_clause in &self.in_clauses {
578 if in_clause.field == "$id" {
580 return QuerySyntaxSimpleValidationResult::new_with_error(
581 QuerySyntaxError::InvalidWhereClauseComponents(
582 "use primary_key_* clauses for $id",
583 ),
584 );
585 }
586 let result = in_clause.validate_against_schema(document_type);
587 if !result.is_valid() {
588 return result;
589 }
590 }
591
592 if let Some(range_clause) = &self.range_clause {
594 if range_clause.field == "$id" {
596 return QuerySyntaxSimpleValidationResult::new_with_error(
597 QuerySyntaxError::InvalidWhereClauseComponents(
598 "use primary_key_* clauses for $id",
599 ),
600 );
601 }
602 let result = range_clause.validate_against_schema(document_type);
603 if !result.is_valid() {
604 return result;
605 }
606 }
607
608 for (field, eq_clause) in &self.equal_clauses {
610 if field.as_str() == "$id" {
612 return QuerySyntaxSimpleValidationResult::new_with_error(
613 QuerySyntaxError::InvalidWhereClauseComponents(
614 "use primary_key_* clauses for $id",
615 ),
616 );
617 }
618 let result = eq_clause.validate_against_schema(document_type);
619 if !result.is_valid() {
620 return result;
621 }
622 }
623
624 if let Some(pk_eq) = &self.primary_key_equal_clause {
626 if pk_eq.operator != WhereOperator::Equal
627 || !matches!(pk_eq.value, Value::Identifier(_))
628 {
629 return QuerySyntaxSimpleValidationResult::new_with_error(
630 QuerySyntaxError::InvalidWhereClauseComponents(
631 "primary key equality must compare an identifier",
632 ),
633 );
634 }
635 }
636 if let Some(pk_in) = &self.primary_key_in_clause {
637 if pk_in.operator != WhereOperator::In {
638 return QuerySyntaxSimpleValidationResult::new_with_error(
639 QuerySyntaxError::InvalidWhereClauseComponents(
640 "primary key IN must use IN operator",
641 ),
642 );
643 }
644 let result = pk_in.in_values();
646 if !result.is_valid() {
647 return QuerySyntaxSimpleValidationResult::new_with_errors(result.errors);
648 }
649 if let Value::Array(arr) = &pk_in.value {
650 if !arr.iter().all(|v| matches!(v, Value::Identifier(_))) {
651 return QuerySyntaxSimpleValidationResult::new_with_error(
652 QuerySyntaxError::InvalidWhereClauseComponents(
653 "primary key IN must contain identifiers",
654 ),
655 );
656 }
657 } else {
658 return QuerySyntaxSimpleValidationResult::new_with_error(
659 QuerySyntaxError::InvalidWhereClauseComponents(
660 "primary key IN must contain an array of identifiers",
661 ),
662 );
663 }
664 }
665
666 QuerySyntaxSimpleValidationResult::default()
667 }
668}
669
670impl From<InternalClauses> for Vec<WhereClause> {
671 fn from(clauses: InternalClauses) -> Self {
672 let mut result: Self = clauses.equal_clauses.into_values().collect();
673
674 result.extend(clauses.in_clauses);
675 if let Some(clause) = clauses.primary_key_equal_clause {
676 result.push(clause);
677 };
678 if let Some(clause) = clauses.primary_key_in_clause {
679 result.push(clause);
680 };
681 if let Some(clause) = clauses.range_clause {
682 result.push(clause);
683 };
684
685 result
686 }
687}
688
689#[cfg(any(feature = "server", feature = "verify"))]
693#[derive(Copy, Clone, Debug, PartialEq, Eq)]
694#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
695#[cfg_attr(feature = "serde", serde(rename_all = "lowercase"))]
696pub enum TimeRangeSelector {
697 Newest,
700 Oldest,
703}
704
705#[cfg(any(feature = "server", feature = "verify"))]
706impl TimeRangeSelector {
707 pub fn as_str(&self) -> &'static str {
713 match self {
714 TimeRangeSelector::Newest => "newest",
715 TimeRangeSelector::Oldest => "oldest",
716 }
717 }
718
719 pub fn from_string(value: &str) -> Option<Self> {
722 match value {
723 "newest" => Some(TimeRangeSelector::Newest),
724 "oldest" => Some(TimeRangeSelector::Oldest),
725 _ => None,
726 }
727 }
728}
729
730#[cfg(any(feature = "server", feature = "verify"))]
739#[derive(Debug, Clone, Copy, PartialEq, Eq)]
740#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
741pub struct TimeRangeGridSpec {
742 pub range_seconds: u64,
744 pub step_seconds: u64,
746 pub phase_seconds: u64,
748}
749
750#[cfg(any(feature = "server", feature = "verify"))]
751impl TimeRangeGridSpec {
752 pub fn matches(&self, transform: &TimeRangeTransform) -> bool {
754 self.range_seconds == transform.range_seconds
755 && self.step_seconds == transform.step_seconds
756 && self.phase_seconds == transform.phase_seconds
757 }
758}
759
760#[cfg(any(feature = "server", feature = "verify"))]
769#[derive(Debug, Clone, PartialEq)]
770pub struct ResolvedTimeRange {
771 pub transform: TimeRangeTransform,
775}
776
777#[cfg(any(feature = "server", feature = "verify"))]
778impl ResolvedTimeRange {
779 pub fn field(&self) -> &str {
782 &self.transform.source
783 }
784}
785
786#[cfg(any(feature = "server", feature = "verify"))]
809pub fn resolve_time_range_bucket_clause(
810 field: &str,
811 selector: TimeRangeSelector,
812 grid: Option<TimeRangeGridSpec>,
813 document_type: DocumentTypeRef,
814 block_time_ms: u64,
815) -> Result<(WhereClause, ResolvedTimeRange), Error> {
816 let mut grids: Vec<&TimeRangeTransform> = Vec::new();
819 for index in document_type.indexes().values() {
820 if let Some(transform) = index
821 .time_range
822 .as_ref()
823 .filter(|transform| transform.source == field)
824 {
825 if !grids.contains(&transform) {
826 grids.push(transform);
827 }
828 }
829 }
830 if grids.is_empty() {
831 return Err(Error::Query(
832 QuerySyntaxError::WhereClauseOnNonIndexedProperty(format!(
833 "no time-range index is defined on field \"{}\"",
834 field
835 )),
836 ));
837 }
838
839 let transform = match grid {
840 Some(spec) => *grids
841 .iter()
842 .find(|transform| spec.matches(transform))
843 .ok_or(Error::Query(QuerySyntaxError::Unsupported(format!(
844 "no time-range index on \"{}\" declares the grid range={}s step={}s phase={}s",
845 field, spec.range_seconds, spec.step_seconds, spec.phase_seconds
846 ))))?,
847 None => {
848 if grids.len() > 1 {
849 return Err(Error::Query(QuerySyntaxError::Unsupported(format!(
850 "field \"{}\" is bucketed by {} different grids; the IN_TIME_RANGE operand \
851 must name one as [selector, range, step] or [selector, range, step, phase] \
852 (seconds, as the contract declares them)",
853 field,
854 grids.len()
855 ))));
856 }
857 grids[0]
858 }
859 };
860
861 let bucket_start = match selector {
862 TimeRangeSelector::Newest => transform.newest_active_start(block_time_ms),
863 TimeRangeSelector::Oldest => transform.oldest_active_start(block_time_ms),
864 }
865 .ok_or(Error::Query(QuerySyntaxError::Unsupported(format!(
866 "no time range on \"{}\" is active yet: the block time predates the grid's phase \
867 anchor (only possible within the first step after the epoch)",
868 field
869 ))))?;
870
871 Ok((
872 WhereClause {
873 field: field.to_string(),
874 operator: WhereOperator::Equal,
875 value: Value::U64(bucket_start),
876 },
877 ResolvedTimeRange {
878 transform: transform.clone(),
879 },
880 ))
881}
882
883#[cfg(any(feature = "server", feature = "verify"))]
910pub fn index_admissible_for_resolved_time_range(
911 index: &Index,
912 resolved_time_ranges: &[ResolvedTimeRange],
913) -> bool {
914 match resolved_time_ranges {
915 [] => index.time_range.is_none(),
916 [resolved] => index
923 .time_range
924 .as_ref()
925 .is_some_and(|transform| *transform == resolved.transform),
926 _ => false,
927 }
928}
929
930#[cfg(any(feature = "server", feature = "verify"))]
945pub fn validate_resolved_time_range_clause_shapes(
946 where_clauses: &[WhereClause],
947 resolved_time_ranges: &[ResolvedTimeRange],
948) -> Result<(), Error> {
949 for field in resolved_time_ranges.iter().map(|resolved| resolved.field()) {
950 let mut equalities = 0usize;
951 for clause in where_clauses.iter().filter(|c| c.field == field) {
952 if clause.operator == WhereOperator::Equal {
953 equalities += 1;
954 } else {
955 return Err(Error::Query(
956 QuerySyntaxError::InvalidWhereClauseComponents(
957 "a time-range-resolved field may only carry the single equality its \
958 resolution produced, not a range or In clause",
959 ),
960 ));
961 }
962 }
963 if equalities != 1 {
964 return Err(Error::Query(
965 QuerySyntaxError::InvalidWhereClauseComponents(
966 "a time-range-resolved field must carry exactly one equality clause — the \
967 one its resolution produced",
968 ),
969 ));
970 }
971 }
972 Ok(())
973}
974
975#[cfg(any(feature = "server", feature = "verify"))]
976#[derive(Debug, PartialEq, Clone)]
978pub struct DriveDocumentQuery<'a> {
979 pub contract: &'a DataContract,
981 pub document_type: DocumentTypeRef<'a>,
983 pub internal_clauses: InternalClauses,
985 pub offset: Option<u16>,
987 pub limit: Option<u16>,
989 pub order_by: IndexMap<String, OrderClause>,
991 pub start_at: Option<[u8; 32]>,
993 pub start_at_included: bool,
995 pub block_time_ms: Option<u64>,
997 pub resolved_time_ranges: Vec<ResolvedTimeRange>,
1013}
1014
1015impl<'a> DriveDocumentQuery<'a> {
1016 #[cfg(any(feature = "server", feature = "verify"))]
1018 pub fn new_primary_key_single_item_query(
1019 contract: &'a DataContract,
1020 document_type: DocumentTypeRef<'a>,
1021 id: Identifier,
1022 ) -> Self {
1023 DriveDocumentQuery {
1024 contract,
1025 document_type,
1026 internal_clauses: InternalClauses {
1027 primary_key_in_clause: None,
1028 primary_key_equal_clause: Some(WhereClause {
1029 field: document::property_names::ID.to_string(),
1030 operator: WhereOperator::Equal,
1031 value: Value::Identifier(id.to_buffer()),
1032 }),
1033 in_clauses: Vec::new(),
1034 range_clause: None,
1035 equal_clauses: Default::default(),
1036 },
1037 offset: None,
1038 limit: None,
1039 order_by: Default::default(),
1040 start_at: None,
1041 start_at_included: false,
1042 block_time_ms: None,
1043 resolved_time_ranges: vec![],
1044 }
1045 }
1046
1047 #[cfg(feature = "server")]
1048 pub fn any_item_query(contract: &'a DataContract, document_type: DocumentTypeRef<'a>) -> Self {
1050 DriveDocumentQuery {
1051 contract,
1052 document_type,
1053 internal_clauses: Default::default(),
1054 offset: None,
1055 limit: Some(1),
1056 order_by: Default::default(),
1057 start_at: None,
1058 start_at_included: true,
1059 block_time_ms: None,
1060 resolved_time_ranges: vec![],
1061 }
1062 }
1063
1064 #[cfg(feature = "server")]
1065 pub fn all_items_query(
1067 contract: &'a DataContract,
1068 document_type: DocumentTypeRef<'a>,
1069 limit: Option<u16>,
1070 ) -> Self {
1071 DriveDocumentQuery {
1072 contract,
1073 document_type,
1074 internal_clauses: Default::default(),
1075 offset: None,
1076 limit,
1077 order_by: Default::default(),
1078 start_at: None,
1079 start_at_included: true,
1080 block_time_ms: None,
1081 resolved_time_ranges: vec![],
1082 }
1083 }
1084
1085 #[cfg(any(feature = "server", feature = "verify"))]
1086 pub fn is_for_primary_key(&self) -> bool {
1088 self.internal_clauses.is_for_primary_key()
1089 || (self.internal_clauses.is_empty()
1090 && (self.order_by.is_empty()
1091 || (self.order_by.len() == 1
1092 && self
1093 .order_by
1094 .keys()
1095 .collect::<Vec<&String>>()
1096 .first()
1097 .unwrap()
1098 .as_str()
1099 == "$id")))
1100 }
1101
1102 #[cfg(feature = "cbor_query")]
1103 pub fn from_cbor(
1105 query_cbor: &[u8],
1106 contract: &'a DataContract,
1107 document_type: DocumentTypeRef<'a>,
1108 config: &DriveConfig,
1109 platform_version: &PlatformVersion,
1110 ) -> Result<Self, Error> {
1111 let query_document_value: Value = ciborium::de::from_reader(query_cbor).map_err(|_| {
1112 Error::Query(QuerySyntaxError::DeserializationError(
1113 "unable to decode query from cbor".to_string(),
1114 ))
1115 })?;
1116 Self::from_value(
1117 query_document_value,
1118 contract,
1119 document_type,
1120 config,
1121 platform_version,
1122 )
1123 }
1124
1125 #[cfg(any(feature = "server", feature = "verify"))]
1126 pub fn from_value(
1128 query_value: Value,
1129 contract: &'a DataContract,
1130 document_type: DocumentTypeRef<'a>,
1131 config: &DriveConfig,
1132 platform_version: &PlatformVersion,
1133 ) -> Result<Self, Error> {
1134 let query_document: BTreeMap<String, Value> = query_value.into_btree_string_map()?;
1135 Self::from_btree_map_value(
1136 query_document,
1137 contract,
1138 document_type,
1139 config,
1140 platform_version,
1141 )
1142 }
1143
1144 #[cfg(any(feature = "server", feature = "verify"))]
1145 pub fn from_btree_map_value(
1147 mut query_document: BTreeMap<String, Value>,
1148 contract: &'a DataContract,
1149 document_type: DocumentTypeRef<'a>,
1150 config: &DriveConfig,
1151 platform_version: &PlatformVersion,
1152 ) -> Result<Self, Error> {
1153 if let Some(contract_id) = query_document
1154 .remove_optional_identifier("contract_id")
1155 .map_err(|e| Error::Protocol(Box::new(ProtocolError::ValueError(e))))?
1156 {
1157 if contract.id() != contract_id {
1158 return Err(ProtocolError::IdentifierError(format!(
1159 "data contract id mismatch, expected: {}, got: {}",
1160 contract.id(),
1161 contract_id
1162 ))
1163 .into());
1164 };
1165 }
1166
1167 if let Some(document_type_name) = query_document
1168 .remove_optional_string("document_type_name")
1169 .map_err(|e| Error::Protocol(Box::new(ProtocolError::ValueError(e))))?
1170 {
1171 if document_type.name() != &document_type_name {
1172 return Err(ProtocolError::IdentifierError(format!(
1173 "document type name mismatch, expected: {}, got: {}",
1174 document_type.name(),
1175 document_type_name
1176 ))
1177 .into());
1178 }
1179 }
1180
1181 let maybe_limit: Option<u16> = query_document
1182 .remove_optional_integer("limit")
1183 .map_err(|e| Error::Protocol(Box::new(ProtocolError::ValueError(e))))?;
1184
1185 let limit = maybe_limit
1186 .map_or(Some(config.default_query_limit), |limit_value| {
1187 if limit_value == 0 || limit_value > config.default_query_limit {
1188 None
1189 } else {
1190 Some(limit_value)
1191 }
1192 })
1193 .ok_or(Error::Query(QuerySyntaxError::InvalidLimit(format!(
1194 "limit greater than max limit {}",
1195 config.max_query_limit
1196 ))))?;
1197
1198 let offset: Option<u16> = query_document
1199 .remove_optional_integer("offset")
1200 .map_err(|e| Error::Protocol(Box::new(ProtocolError::ValueError(e))))?;
1201
1202 let block_time_ms: Option<u64> = query_document
1203 .remove_optional_integer("blockTime")
1204 .map_err(|e| Error::Protocol(Box::new(ProtocolError::ValueError(e))))?;
1205
1206 let all_where_clauses: Vec<WhereClause> =
1207 query_document
1208 .remove("where")
1209 .map_or(Ok(vec![]), |id_cbor| {
1210 if let Value::Array(clauses) = id_cbor {
1211 clauses
1212 .iter()
1213 .map(|where_clause| {
1214 if let Value::Array(clauses_components) = where_clause {
1215 WhereClause::from_components(clauses_components)
1216 } else {
1217 Err(Error::Query(QuerySyntaxError::InvalidFormatWhereClause(
1218 "where clause must be an array".to_string(),
1219 )))
1220 }
1221 })
1222 .collect::<Result<Vec<WhereClause>, Error>>()
1223 } else {
1224 Err(Error::Query(QuerySyntaxError::InvalidFormatWhereClause(
1225 "where clause must be an array".to_string(),
1226 )))
1227 }
1228 })?;
1229
1230 let internal_clauses =
1231 InternalClauses::extract_from_clauses(all_where_clauses, platform_version)?;
1232
1233 let start_at_option = query_document.remove("startAt");
1234 let start_after_option = query_document.remove("startAfter");
1235 if start_after_option.is_some() && start_at_option.is_some() {
1236 return Err(Error::Query(QuerySyntaxError::DuplicateStartConditions(
1237 "only one of startAt or startAfter should be provided",
1238 )));
1239 }
1240
1241 let mut start_at_included = true;
1242
1243 let mut start_option: Option<Value> = None;
1244
1245 if start_after_option.is_some() {
1246 start_option = start_after_option;
1247 start_at_included = false;
1248 } else if start_at_option.is_some() {
1249 start_option = start_at_option;
1250 start_at_included = true;
1251 }
1252
1253 let start_at: Option<[u8; 32]> = start_option
1254 .map(|v| {
1255 v.into_identifier()
1256 .map_err(|e| Error::Protocol(Box::new(ProtocolError::ValueError(e))))
1257 .map(|identifier| identifier.into_buffer())
1258 })
1259 .transpose()?;
1260
1261 let order_by: IndexMap<String, OrderClause> =
1262 query_document
1263 .remove("orderBy")
1264 .map_or(Ok(IndexMap::new()), |id_cbor| {
1265 if let Value::Array(clauses) = id_cbor {
1266 clauses
1267 .into_iter()
1268 .filter_map(|order_clause| {
1269 if let Value::Array(clauses_components) = order_clause {
1270 let order_clause =
1271 OrderClause::from_components(&clauses_components)
1272 .map_err(Error::from);
1273 match order_clause {
1274 Ok(order_clause) => {
1275 Some(Ok((order_clause.field.clone(), order_clause)))
1276 }
1277 Err(err) => Some(Err(err)),
1278 }
1279 } else {
1280 None
1281 }
1282 })
1283 .collect::<Result<IndexMap<String, OrderClause>, Error>>()
1284 } else {
1285 Err(Error::Query(QuerySyntaxError::InvalidOrderByProperties(
1286 "order clauses must be an array",
1287 )))
1288 }
1289 })?;
1290
1291 if !query_document.is_empty() {
1292 return Err(Error::Query(QuerySyntaxError::Unsupported(format!(
1293 "unsupported syntax in where clause: {:?}",
1294 query_document
1295 ))));
1296 }
1297
1298 Ok(DriveDocumentQuery {
1299 contract,
1300 document_type,
1301 internal_clauses,
1302 limit: Some(limit),
1303 offset,
1304 order_by,
1305 start_at,
1306 start_at_included,
1307 block_time_ms,
1308 resolved_time_ranges: vec![],
1309 })
1310 }
1311
1312 #[cfg(any(feature = "server", feature = "verify"))]
1313 #[allow(clippy::too_many_arguments)]
1315 pub fn from_decomposed_values(
1316 where_clause: Value,
1317 order_by: Option<Value>,
1318 maybe_limit: Option<u16>,
1319 start_at: Option<[u8; 32]>,
1320 start_at_included: bool,
1321 block_time_ms: Option<u64>,
1322 contract: &'a DataContract,
1323 document_type: DocumentTypeRef<'a>,
1324 config: &DriveConfig,
1325 platform_version: &PlatformVersion,
1326 ) -> Result<Self, Error> {
1327 let all_where_clauses: Vec<WhereClause> = match where_clause {
1328 Value::Null => Ok(vec![]),
1329 Value::Array(clauses) => clauses
1330 .iter()
1331 .map(|where_clause| {
1332 if let Value::Array(clauses_components) = where_clause {
1333 WhereClause::from_components(clauses_components)
1334 } else {
1335 Err(Error::Query(QuerySyntaxError::InvalidFormatWhereClause(
1336 "where clause must be an array".to_string(),
1337 )))
1338 }
1339 })
1340 .collect::<Result<Vec<WhereClause>, Error>>(),
1341 _ => Err(Error::Query(QuerySyntaxError::InvalidFormatWhereClause(
1342 "where clause must be an array".to_string(),
1343 ))),
1344 }?;
1345
1346 let order_by_clauses: Vec<OrderClause> = match order_by {
1354 None | Some(Value::Null) => Vec::new(),
1355 Some(Value::Array(clauses)) => clauses
1356 .iter()
1357 .map(|order_clause| match order_clause {
1358 Value::Array(components) => {
1359 OrderClause::from_components(components).map_err(|_| {
1360 Error::Query(QuerySyntaxError::InvalidOrderByProperties(
1361 "invalid order_by clause components",
1362 ))
1363 })
1364 }
1365 _ => Err(Error::Query(QuerySyntaxError::InvalidOrderByProperties(
1366 "order_by clause must be an array",
1367 ))),
1368 })
1369 .collect::<Result<Vec<_>, _>>()?,
1370 Some(_) => {
1371 return Err(Error::Query(QuerySyntaxError::InvalidOrderByProperties(
1372 "order_by must be an array",
1373 )));
1374 }
1375 };
1376
1377 Self::from_typed_clauses(
1378 all_where_clauses,
1379 order_by_clauses,
1380 maybe_limit,
1381 start_at,
1382 start_at_included,
1383 block_time_ms,
1384 contract,
1385 document_type,
1386 config,
1387 platform_version,
1388 )
1389 }
1390
1391 #[cfg(any(feature = "server", feature = "verify"))]
1411 #[allow(clippy::too_many_arguments)]
1412 pub fn from_typed_clauses(
1413 where_clauses: Vec<WhereClause>,
1414 order_by_clauses: Vec<OrderClause>,
1415 maybe_limit: Option<u16>,
1416 start_at: Option<[u8; 32]>,
1417 start_at_included: bool,
1418 block_time_ms: Option<u64>,
1419 contract: &'a DataContract,
1420 document_type: DocumentTypeRef<'a>,
1421 config: &DriveConfig,
1422 platform_version: &PlatformVersion,
1423 ) -> Result<Self, Error> {
1424 let limit = maybe_limit
1425 .map_or(Some(config.default_query_limit), |limit_value| {
1426 if limit_value == 0 || limit_value > config.default_query_limit {
1427 None
1428 } else {
1429 Some(limit_value)
1430 }
1431 })
1432 .ok_or(Error::Query(QuerySyntaxError::InvalidLimit(format!(
1433 "limit greater than max limit {}",
1434 config.max_query_limit
1435 ))))?;
1436
1437 let internal_clauses =
1438 InternalClauses::extract_from_clauses(where_clauses, platform_version)?;
1439
1440 let order_by: IndexMap<String, OrderClause> = order_by_clauses
1441 .into_iter()
1442 .map(|c| (c.field.clone(), c))
1443 .collect();
1444
1445 Ok(DriveDocumentQuery {
1446 contract,
1447 document_type,
1448 internal_clauses,
1449 offset: None,
1450 limit: Some(limit),
1451 order_by,
1452 start_at,
1453 start_at_included,
1454 block_time_ms,
1455 resolved_time_ranges: vec![],
1456 })
1457 }
1458
1459 #[cfg(any(feature = "server", feature = "verify"))]
1460 pub fn from_sql_expr(
1462 sql_string: &str,
1463 contract: &'a DataContract,
1464 config: Option<&DriveConfig>,
1465 platform_version: &PlatformVersion,
1466 ) -> Result<Self, Error> {
1467 let dialect: MySqlDialect = MySqlDialect {};
1468 let statements: Vec<Statement> = Parser::parse_sql(&dialect, sql_string)
1469 .map_err(|e| Error::Query(QuerySyntaxError::SQLParsingError(e)))?;
1470
1471 let first_statement =
1473 statements
1474 .first()
1475 .ok_or(Error::Query(QuerySyntaxError::InvalidSQL(
1476 "Issue parsing sql getting first statement".to_string(),
1477 )))?;
1478
1479 let query: &ast::Query = match first_statement {
1480 ast::Statement::Query(query_struct) => Some(query_struct),
1481 _ => None,
1482 }
1483 .ok_or(Error::Query(QuerySyntaxError::InvalidSQL(
1484 "Issue parsing sql: not a query".to_string(),
1485 )))?;
1486
1487 let max_limit = config
1488 .map(|config| config.max_query_limit)
1489 .unwrap_or(DriveConfig::default().max_query_limit);
1490
1491 let limit: u16 = if let Some(limit_expr) = &query.limit {
1492 match limit_expr {
1493 ast::Expr::Value(Number(num_string, _)) => {
1494 let cast_num_string: &String = num_string;
1495 let user_limit = cast_num_string.parse::<u16>().map_err(|e| {
1496 Error::Query(QuerySyntaxError::InvalidLimit(format!(
1497 "limit could not be parsed {}",
1498 e
1499 )))
1500 })?;
1501 if user_limit > max_limit {
1502 return Err(Error::Query(QuerySyntaxError::InvalidLimit(format!(
1503 "limit {} greater than max limit {}",
1504 user_limit, max_limit
1505 ))));
1506 }
1507 user_limit
1508 }
1509 result => {
1510 return Err(Error::Query(QuerySyntaxError::InvalidLimit(format!(
1511 "expression not a limit {}",
1512 result
1513 ))));
1514 }
1515 }
1516 } else {
1517 config
1518 .map(|config| config.default_query_limit)
1519 .unwrap_or(DriveConfig::default().default_query_limit)
1520 };
1521
1522 let order_by: IndexMap<String, OrderClause> = query
1523 .order_by
1524 .iter()
1525 .map(|order_exp: &OrderByExpr| {
1526 let ascending = order_exp.asc.is_none() || order_exp.asc.unwrap();
1527 let field = order_exp.expr.to_string();
1528 (field.clone(), OrderClause { field, ascending })
1529 })
1530 .collect::<IndexMap<String, OrderClause>>();
1531
1532 let select: &Select = match &*query.body {
1534 ast::SetExpr::Select(select) => Some(select),
1535 _ => None,
1536 }
1537 .ok_or(Error::Query(QuerySyntaxError::InvalidSQL(
1538 "Issue parsing sql: Not a select".to_string(),
1539 )))?;
1540
1541 let document_type_name = match &select
1543 .from
1544 .first()
1545 .ok_or(Error::Query(QuerySyntaxError::InvalidSQL(
1546 "Invalid query: missing from section".to_string(),
1547 )))?
1548 .relation
1549 {
1550 Table { name, .. } => name.0.first().as_ref().map(|identifier| &identifier.value),
1551 _ => None,
1552 }
1553 .ok_or(Error::Query(QuerySyntaxError::InvalidSQL(
1554 "Issue parsing sql: invalid from value".to_string(),
1555 )))?;
1556
1557 let document_type =
1558 contract
1559 .document_types()
1560 .get(document_type_name)
1561 .ok_or(Error::Query(QuerySyntaxError::DocumentTypeNotFound(
1562 "document type not found in contract",
1563 )))?;
1564
1565 let mut all_where_clauses: Vec<WhereClause> = Vec::new();
1575 let selection_tree = select.selection.as_ref();
1576
1577 if let Some(selection_tree) = selection_tree {
1579 WhereClause::build_where_clauses_from_operations(
1580 selection_tree,
1581 document_type,
1582 &mut all_where_clauses,
1583 )?;
1584 }
1585
1586 let internal_clauses =
1587 InternalClauses::extract_from_clauses(all_where_clauses, platform_version)?;
1588
1589 let start_at_option = None; let start_after_option = None; let mut start_at_included = true;
1592 let mut start_option: Option<Value> = None;
1593
1594 if start_after_option.is_some() {
1595 start_option = start_after_option;
1596 start_at_included = false;
1597 } else if start_at_option.is_some() {
1598 start_option = start_at_option;
1599 start_at_included = true;
1600 }
1601
1602 let start_at: Option<[u8; 32]> = start_option
1603 .map(|v| {
1604 v.into_identifier()
1605 .map_err(|e| Error::Protocol(Box::new(ProtocolError::ValueError(e))))
1606 .map(|identifier| identifier.into_buffer())
1607 })
1608 .transpose()?;
1609
1610 Ok(DriveDocumentQuery {
1611 contract,
1612 document_type: document_type.as_ref(),
1613 internal_clauses,
1614 offset: None,
1615 limit: Some(limit),
1616 order_by,
1617 start_at,
1618 start_at_included,
1619 block_time_ms: None,
1620 resolved_time_ranges: vec![],
1621 })
1622 }
1623
1624 #[cfg(feature = "cbor_query")]
1629 pub fn to_cbor(&self) -> Result<Vec<u8>, Error> {
1630 let data: BTreeMap<String, Value> = self.into();
1631 let cbor: BTreeMap<String, ciborium::Value> = Value::convert_to_cbor_map(data)?;
1632 let mut output = Vec::new();
1633
1634 ciborium::ser::into_writer(&cbor, &mut output)
1635 .map_err(|e| ProtocolError::PlatformSerializationError(e.to_string()))?;
1636 Ok(output)
1637 }
1638
1639 #[cfg(any(feature = "server", feature = "verify"))]
1640 pub fn start_at_document_path_and_key(&self, starts_at: &[u8; 32]) -> (Vec<Vec<u8>>, Vec<u8>) {
1642 if self.document_type.documents_keep_history() {
1643 let document_holding_path = self.contract.documents_with_history_primary_key_path(
1644 self.document_type.name().as_str(),
1645 starts_at,
1646 );
1647 (
1648 document_holding_path
1649 .into_iter()
1650 .map(|key| key.to_vec())
1651 .collect::<Vec<_>>(),
1652 vec![0],
1653 )
1654 } else {
1655 let document_holding_path = self
1656 .contract
1657 .documents_primary_key_path(self.document_type.name().as_str());
1658 (
1659 document_holding_path
1660 .into_iter()
1661 .map(|key| key.to_vec())
1662 .collect::<Vec<_>>(),
1663 starts_at.to_vec(),
1664 )
1665 }
1666 }
1667
1668 #[cfg(any(feature = "server", feature = "verify"))]
1669 pub fn validate_in_clause_shape(
1680 &self,
1681 platform_version: &PlatformVersion,
1682 ) -> Result<(), Error> {
1683 match platform_version
1684 .drive
1685 .methods
1686 .document
1687 .query
1688 .non_primary_key_path_query
1689 {
1690 0 => {
1691 if self.internal_clauses.in_clauses.len() > 1 {
1692 return Err(Error::Query(QuerySyntaxError::MultipleInClauses(
1693 "There should only be one in clause",
1694 )));
1695 }
1696 Ok(())
1697 }
1698 1 => {
1699 if self.internal_clauses.in_clauses.len() > 1 && self.start_at.is_some() {
1700 return Err(Error::Query(QuerySyntaxError::Unsupported(
1701 "startAt/startAfter is not supported with multiple in clauses".to_string(),
1702 )));
1703 }
1704 Ok(())
1705 }
1706 version => Err(Error::Drive(DriveError::UnknownVersionMismatch {
1707 method: "DriveDocumentQuery::validate_in_clause_shape".to_string(),
1708 known_versions: vec![0, 1],
1709 received: version,
1710 })),
1711 }
1712 }
1713
1714 #[cfg(feature = "server")]
1715 pub fn construct_path_query_operations(
1717 &self,
1718 drive: &Drive,
1719 include_start_at_for_proof: bool,
1720 transaction: TransactionArg,
1721 drive_operations: &mut Vec<LowLevelDriveOperation>,
1722 platform_version: &PlatformVersion,
1723 ) -> Result<PathQuery, Error> {
1724 self.validate_in_clause_shape(platform_version)?;
1725 {
1728 use dpp::data_contract::document_type::accessors::DocumentTypeV2Getters;
1729 if self.document_type.index_only() && self.is_for_primary_key() {
1730 return Err(Error::Query(QuerySyntaxError::Unsupported(
1731 "indexOnly documents cannot be fetched by id: there is no primary-key \
1732 tree; query through one of the type's indexes"
1733 .to_string(),
1734 )));
1735 }
1736 if self.document_type.index_only() && self.start_at.is_some() {
1737 return Err(Error::Query(QuerySyntaxError::Unsupported(
1738 "startAt/startAfter cursors cannot address an indexOnly position (the \
1739 synthesized document id is a one-way hash of it); paginate with a \
1740 range clause on the terminal property instead — equality clauses on \
1741 the index's properties, `terminal > <last seen value>` ordered by the \
1742 terminal, and a limit"
1743 .to_string(),
1744 )));
1745 }
1746 }
1747 let drive_version = &platform_version.drive;
1748 let document_type_path = self
1750 .contract
1751 .document_type_path(self.document_type.name().as_str())
1752 .into_iter()
1753 .map(|a| a.to_vec())
1754 .collect::<Vec<Vec<u8>>>();
1755
1756 {
1761 use dpp::data_contract::document_type::accessors::DocumentTypeV2Getters;
1762 if self.document_type.index_only() {
1763 if let Some(path_query) =
1764 self.index_only_route(&document_type_path, platform_version)?
1765 {
1766 return Ok(path_query);
1767 }
1768 }
1769 }
1770
1771 let (starts_at_document, start_at_path_query) = match &self.start_at {
1772 None => Ok((None, None)),
1773 Some(starts_at) => {
1774 let (start_at_document_path, start_at_document_key) =
1778 self.start_at_document_path_and_key(starts_at);
1779 let start_at_document = drive
1780 .grove_get(
1781 start_at_document_path.as_slice().into(),
1782 &start_at_document_key,
1783 StatefulQuery,
1784 transaction,
1785 drive_operations,
1786 drive_version,
1787 )
1788 .map_err(|e| match e {
1789 Error::GroveDB(e)
1790 if matches!(
1791 e.as_ref(),
1792 GroveError::PathKeyNotFound(_)
1793 | GroveError::PathNotFound(_)
1794 | GroveError::PathParentLayerNotFound(_)
1795 ) =>
1796 {
1797 let error_message = if self.start_at_included {
1798 "startAt document not found"
1799 } else {
1800 "startAfter document not found"
1801 };
1802
1803 Error::Query(QuerySyntaxError::StartDocumentNotFound(error_message))
1804 }
1805 _ => e,
1806 })?
1807 .ok_or(Error::Drive(DriveError::CorruptedCodeExecution(
1808 "expected a value",
1809 )))?;
1810
1811 let path_query =
1812 PathQuery::new_single_key(start_at_document_path, start_at_document_key);
1813
1814 if let Element::Item(item, _) = start_at_document {
1815 let document = Document::from_bytes(
1816 item.as_slice(),
1817 self.document_type,
1818 platform_version,
1819 )?;
1820 Ok((Some((document, self.start_at_included)), Some(path_query)))
1821 } else {
1822 Err(Error::Drive(DriveError::CorruptedDocumentPath(
1823 "Holding paths should only have items",
1824 )))
1825 }
1826 }
1827 }?;
1828 let mut main_path_query = if self.is_for_primary_key() {
1829 self.get_primary_key_path_query(
1830 document_type_path,
1831 starts_at_document,
1832 platform_version,
1833 )
1834 } else {
1835 self.get_non_primary_key_path_query(
1836 document_type_path,
1837 starts_at_document,
1838 platform_version,
1839 )
1840 }?;
1841 if !include_start_at_for_proof {
1842 return Ok(main_path_query);
1843 }
1844
1845 if let Some(mut start_at_path_query) = start_at_path_query {
1846 start_at_path_query.query.query.left_to_right =
1854 main_path_query.query.query.left_to_right;
1855 let limit = main_path_query.query.limit.take();
1856 let mut merged = PathQuery::merge(
1857 vec![&start_at_path_query, &main_path_query],
1858 &platform_version.drive.grove_version,
1859 )
1860 .map_err(Error::from)?;
1861 merged.query.limit = limit.map(|a| a.saturating_add(1));
1862 Ok(merged)
1863 } else {
1864 Ok(main_path_query)
1865 }
1866 }
1867
1868 #[cfg(any(feature = "server", feature = "verify"))]
1869 pub fn construct_path_query(
1871 &self,
1872 starts_at_document: Option<Document>,
1873 platform_version: &PlatformVersion,
1874 ) -> Result<PathQuery, Error> {
1875 self.validate_in_clause_shape(platform_version)?;
1876 {
1879 use dpp::data_contract::document_type::accessors::DocumentTypeV2Getters;
1880 if self.document_type.index_only() && self.is_for_primary_key() {
1881 return Err(Error::Query(QuerySyntaxError::Unsupported(
1882 "indexOnly documents cannot be fetched by id: there is no primary-key \
1883 tree; query through one of the type's indexes"
1884 .to_string(),
1885 )));
1886 }
1887 if self.document_type.index_only() && self.start_at.is_some() {
1888 return Err(Error::Query(QuerySyntaxError::Unsupported(
1889 "startAt/startAfter cursors cannot address an indexOnly position (the \
1890 synthesized document id is a one-way hash of it); paginate with a \
1891 range clause on the terminal property instead — equality clauses on \
1892 the index's properties, `terminal > <last seen value>` ordered by the \
1893 terminal, and a limit"
1894 .to_string(),
1895 )));
1896 }
1897 }
1898 let document_type_path = self
1900 .contract
1901 .document_type_path(self.document_type.name().as_str())
1902 .into_iter()
1903 .map(|a| a.to_vec())
1904 .collect::<Vec<Vec<u8>>>();
1905
1906 {
1910 use dpp::data_contract::document_type::accessors::DocumentTypeV2Getters;
1911 if self.document_type.index_only() {
1912 if let Some(path_query) =
1913 self.index_only_route(&document_type_path, platform_version)?
1914 {
1915 return Ok(path_query);
1916 }
1917 }
1918 }
1919
1920 let starts_at_document = starts_at_document
1921 .map(|starts_at_document| (starts_at_document, self.start_at_included));
1922 if self.is_for_primary_key() {
1923 self.get_primary_key_path_query(
1924 document_type_path,
1925 starts_at_document,
1926 platform_version,
1927 )
1928 } else {
1929 self.get_non_primary_key_path_query(
1930 document_type_path,
1931 starts_at_document,
1932 platform_version,
1933 )
1934 }
1935 }
1936
1937 #[cfg(any(feature = "server", feature = "verify"))]
1938 pub fn get_primary_key_path_query(
1940 &self,
1941 document_type_path: Vec<Vec<u8>>,
1942 starts_at_document: Option<(Document, bool)>,
1943 platform_version: &PlatformVersion,
1944 ) -> Result<PathQuery, Error> {
1945 let mut path = document_type_path;
1946
1947 path.push(vec![0]);
1949
1950 if let Some(primary_key_equal_clause) = &self.internal_clauses.primary_key_equal_clause {
1951 let mut query = Query::new();
1952 let key = self.document_type.serialize_value_for_key(
1953 "$id",
1954 &primary_key_equal_clause.value,
1955 platform_version,
1956 )?;
1957 query.insert_key(key);
1958
1959 if self.document_type.documents_keep_history() {
1960 if let Some(block_time) = self.block_time_ms {
1962 let encoded_block_time = encode_u64(block_time);
1963 let mut sub_query = Query::new_with_direction(false);
1964 sub_query.insert_range_to_inclusive(..=encoded_block_time);
1965 query.set_subquery(sub_query);
1966 } else {
1967 query.set_subquery_key(vec![0]);
1968 }
1969 }
1970
1971 Ok(PathQuery::new(path, SizedQuery::new(query, Some(1), None)))
1972 } else {
1973 let left_to_right = if self.order_by.keys().len() == 1 {
1975 if self.order_by.keys().next().unwrap() != "$id" {
1976 return Err(Error::Query(QuerySyntaxError::InvalidOrderByProperties(
1977 "order by should include $id only",
1978 )));
1979 }
1980
1981 let order_clause = self.order_by.get("$id").unwrap();
1982
1983 order_clause.ascending
1984 } else {
1985 true
1986 };
1987
1988 let mut query = Query::new_with_direction(left_to_right);
1989 let starts_at_key_option = match starts_at_document {
1992 None => None,
1993 Some((document, included)) => {
1994 document
1996 .get_raw_for_document_type(
1997 "$id",
1998 self.document_type,
1999 None,
2000 platform_version,
2001 )?
2002 .map(|raw_value_option| (raw_value_option, included))
2003 }
2004 };
2005
2006 if let Some(primary_key_in_clause) = &self.internal_clauses.primary_key_in_clause {
2007 let in_values = primary_key_in_clause.in_values().into_data_with_error()??;
2008
2009 match starts_at_key_option {
2010 None => {
2011 for value in in_values.iter() {
2012 let key = self.document_type.serialize_value_for_key(
2013 "$id",
2014 value,
2015 platform_version,
2016 )?;
2017 query.insert_key(key)
2018 }
2019 }
2020 Some((starts_at_key, included)) => {
2021 for value in in_values.iter() {
2022 let key = self.document_type.serialize_value_for_key(
2023 "$id",
2024 value,
2025 platform_version,
2026 )?;
2027
2028 if (left_to_right && starts_at_key < key)
2029 || (!left_to_right && starts_at_key > key)
2030 || (included && starts_at_key == key)
2031 {
2032 query.insert_key(key);
2033 }
2034 }
2035 }
2036 }
2037
2038 if self.document_type.documents_keep_history() {
2039 if let Some(_block_time) = self.block_time_ms {
2041 return Err(Error::Query(QuerySyntaxError::Unsupported(
2043 "Not yet implemented".to_string(),
2044 )));
2045 } else {
2053 query.set_subquery_key(vec![0]);
2054 }
2055 }
2056
2057 Ok(PathQuery::new(
2058 path,
2059 SizedQuery::new(query, self.limit, self.offset),
2060 ))
2061 } else {
2062 match starts_at_key_option {
2064 None => {
2065 query.insert_all();
2066 }
2067 Some((starts_at_key, included)) => match left_to_right {
2068 true => match included {
2069 true => query.insert_range_from(starts_at_key..),
2070 false => query.insert_range_after(starts_at_key..),
2071 },
2072 false => match included {
2073 true => query.insert_range_to_inclusive(..=starts_at_key),
2074 false => query.insert_range_to(..starts_at_key),
2075 },
2076 },
2077 }
2078
2079 if self.document_type.documents_keep_history() {
2080 if let Some(_block_time) = self.block_time_ms {
2082 return Err(Error::Query(QuerySyntaxError::Unsupported(
2083 "this query is not supported".to_string(),
2084 )));
2085 } else {
2093 query.set_subquery_key(vec![0]);
2094 }
2095 }
2096
2097 Ok(PathQuery::new(
2098 path,
2099 SizedQuery::new(query, self.limit, self.offset),
2100 ))
2101 }
2102 }
2103 }
2104
2105 #[cfg(any(feature = "server", feature = "verify"))]
2106 pub fn find_best_index(&self, platform_version: &PlatformVersion) -> Result<&Index, Error> {
2121 match self.select_best_index(platform_version)? {
2122 BestIndexOutcome::Matched(index) => Ok(index),
2123 BestIndexOutcome::NoIndexMatches(no_index_error) => Err(no_index_error),
2124 }
2125 }
2126
2127 pub(crate) fn select_best_index(
2136 &self,
2137 platform_version: &PlatformVersion,
2138 ) -> Result<BestIndexOutcome<'_>, Error> {
2139 if self.resolved_time_ranges.len() > 1 {
2145 return Err(Error::Query(QuerySyntaxError::Unsupported(format!(
2146 "at most one time-range selection (IN_TIME_RANGE) is supported per query; this \
2147 one resolves {:?}, and no single index can bucket more than one field",
2148 self.resolved_time_ranges
2149 ))));
2150 }
2151
2152 self.validate_resolved_source_shape()?;
2156
2157 if self.internal_clauses.in_clauses.len() > 1 {
2158 return Ok(BestIndexOutcome::Matched(
2162 self.find_best_index_for_multiple_in_clauses()?.0,
2163 ));
2164 }
2165
2166 let equal_fields = self
2167 .internal_clauses
2168 .equal_clauses
2169 .keys()
2170 .map(|s| s.as_str())
2171 .collect::<Vec<&str>>();
2172 let in_field = self
2173 .internal_clauses
2174 .in_clauses
2175 .first()
2176 .map(|in_clause| in_clause.field.as_str());
2177 let range_field = self
2178 .internal_clauses
2179 .range_clause
2180 .as_ref()
2181 .map(|range_clause| range_clause.field.as_str());
2182 let mut fields = equal_fields;
2183 if let Some(range_field) = range_field {
2184 fields.push(range_field);
2185 }
2186 if let Some(in_field) = in_field {
2187 fields.push(in_field);
2188 }
2190
2191 let order_by_keys: Vec<&str> = self
2192 .order_by
2193 .keys()
2194 .map(|key: &String| {
2195 let str = key.as_str();
2196 if !fields.contains(&str) {
2197 fields.push(str);
2198 }
2199 str
2200 })
2201 .collect();
2202
2203 let Some((index, difference)) = self.document_type.index_for_types_matching(
2204 fields.as_slice(),
2205 in_field,
2206 order_by_keys.as_slice(),
2207 |index| index_admissible_for_resolved_time_range(index, &self.resolved_time_ranges),
2208 platform_version,
2209 )?
2210 else {
2211 return Ok(BestIndexOutcome::NoIndexMatches(
2212 match self.resolved_time_ranges.first() {
2213 Some(resolved) => {
2220 Error::Query(QuerySyntaxError::WhereClauseOnNonIndexedProperty(format!(
2221 "a time-range query on \"{}\" requires an index that buckets it with \
2222 the resolved grid AND covers the query's other where and order-by \
2223 fields; valid indexes are: {:?}",
2224 resolved.field(),
2225 self.document_type.indexes()
2226 )))
2227 }
2228 None => {
2229 let has_bucketed_index = self
2235 .document_type
2236 .indexes()
2237 .values()
2238 .any(|index| index.time_range.is_some());
2239 if has_bucketed_index {
2240 Error::Query(QuerySyntaxError::WhereClauseOnNonIndexedProperty(
2241 format!(
2242 "query must be for valid indexes, valid indexes are: {:?}; note: \
2243 this document type's time-range (timeRange) indexes only serve \
2244 IN_TIME_RANGE selections carrying their resolution — a raw clause \
2245 on the bucketed field never binds to them",
2246 self.document_type.indexes()
2247 ),
2248 ))
2249 } else {
2250 Error::Query(QuerySyntaxError::WhereClauseOnNonIndexedProperty(
2251 format!(
2252 "query must be for valid indexes, valid indexes are: {:?}",
2253 self.document_type.indexes()
2254 ),
2255 ))
2256 }
2257 }
2258 },
2259 ));
2260 };
2261 if difference > defaults::MAX_INDEX_DIFFERENCE {
2262 return Ok(BestIndexOutcome::NoIndexMatches(Error::Query(
2263 QuerySyntaxError::QueryTooFarFromIndex("query must better match an existing index"),
2264 )));
2265 }
2266
2267 Ok(BestIndexOutcome::Matched(index))
2274 }
2275
2276 #[cfg(any(feature = "server", feature = "verify"))]
2291 pub(crate) fn validate_resolved_source_shape(&self) -> Result<(), Error> {
2292 let Some(source) = self
2293 .resolved_time_ranges
2294 .first()
2295 .map(|resolved| resolved.field())
2296 else {
2297 return Ok(());
2298 };
2299 let has_equality_on_source = self.internal_clauses.equal_clauses.contains_key(source);
2300 let range_or_in_on_source = self
2301 .internal_clauses
2302 .range_clause
2303 .as_ref()
2304 .is_some_and(|clause| clause.field == source)
2305 || self
2306 .internal_clauses
2307 .in_clauses
2308 .iter()
2309 .any(|clause| clause.field == source);
2310 if !has_equality_on_source || range_or_in_on_source || self.order_by.contains_key(source) {
2311 return Err(Error::Query(QuerySyntaxError::Unsupported(format!(
2312 "the index on \"{source}\" buckets it into time ranges: it can only be queried \
2313 through a time-range selection (IN_TIME_RANGE, which resolves to an exact \
2314 bucket equality), not with ranges, IN, or ordering on that property"
2315 ))));
2316 }
2317 Ok(())
2318 }
2319
2320 #[cfg(any(feature = "server", feature = "verify"))]
2321 pub fn query_item_for_starts_at_key(starts_at_key: Vec<u8>, left_to_right: bool) -> QueryItem {
2323 if left_to_right {
2324 QueryItem::RangeAfter(starts_at_key..)
2325 } else {
2326 QueryItem::RangeTo(..starts_at_key)
2327 }
2328 }
2329
2330 #[cfg(any(feature = "server", feature = "verify"))]
2331 pub fn get_non_primary_key_path_query(
2338 &self,
2339 document_type_path: Vec<Vec<u8>>,
2340 starts_at_document: Option<(Document, bool)>,
2341 platform_version: &PlatformVersion,
2342 ) -> Result<PathQuery, Error> {
2343 match platform_version
2344 .drive
2345 .methods
2346 .document
2347 .query
2348 .non_primary_key_path_query
2349 {
2350 0 => self.get_non_primary_key_path_query_v0(
2351 document_type_path,
2352 starts_at_document,
2353 platform_version,
2354 ),
2355 1 => self.get_non_primary_key_path_query_v1(
2356 document_type_path,
2357 starts_at_document,
2358 platform_version,
2359 ),
2360 version => Err(Error::Drive(DriveError::UnknownVersionMismatch {
2361 method: "DriveDocumentQuery::get_non_primary_key_path_query".to_string(),
2362 known_versions: vec![0, 1],
2363 received: version,
2364 })),
2365 }
2366 }
2367
2368 #[cfg(feature = "server")]
2369 pub fn execute_with_proof(
2371 self,
2372 drive: &Drive,
2373 block_info: Option<BlockInfo>,
2374 transaction: TransactionArg,
2375 platform_version: &PlatformVersion,
2376 ) -> Result<(Vec<u8>, u64), Error> {
2377 let mut drive_operations = vec![];
2378 let items = self.execute_with_proof_internal(
2379 drive,
2380 transaction,
2381 &mut drive_operations,
2382 platform_version,
2383 )?;
2384 let cost = if let Some(block_info) = block_info {
2385 let fee_result = Drive::calculate_fee(
2386 None,
2387 Some(drive_operations),
2388 &block_info.epoch,
2389 drive.config.epochs_per_era,
2390 platform_version,
2391 None,
2392 )?;
2393 fee_result.processing_fee
2394 } else {
2395 0
2396 };
2397 Ok((items, cost))
2398 }
2399
2400 #[cfg(feature = "server")]
2401 pub(crate) fn execute_with_proof_internal(
2403 self,
2404 drive: &Drive,
2405 transaction: TransactionArg,
2406 drive_operations: &mut Vec<LowLevelDriveOperation>,
2407 platform_version: &PlatformVersion,
2408 ) -> Result<Vec<u8>, Error> {
2409 let path_query = self.construct_path_query_operations(
2410 drive,
2411 true,
2412 transaction,
2413 drive_operations,
2414 platform_version,
2415 )?;
2416 drive.grove_get_proved_path_query(
2417 &path_query,
2418 transaction,
2419 drive_operations,
2420 &platform_version.drive,
2421 )
2422 }
2423
2424 #[cfg(all(feature = "server", feature = "verify"))]
2425 pub fn execute_with_proof_only_get_elements(
2427 self,
2428 drive: &Drive,
2429 block_info: Option<BlockInfo>,
2430 transaction: TransactionArg,
2431 platform_version: &PlatformVersion,
2432 ) -> Result<(RootHash, Vec<Vec<u8>>, u64), Error> {
2433 let mut drive_operations = vec![];
2434 let (root_hash, items) = self.execute_with_proof_only_get_elements_internal(
2435 drive,
2436 transaction,
2437 &mut drive_operations,
2438 platform_version,
2439 )?;
2440 let cost = if let Some(block_info) = block_info {
2441 let fee_result = Drive::calculate_fee(
2442 None,
2443 Some(drive_operations),
2444 &block_info.epoch,
2445 drive.config.epochs_per_era,
2446 platform_version,
2447 None,
2448 )?;
2449 fee_result.processing_fee
2450 } else {
2451 0
2452 };
2453 Ok((root_hash, items, cost))
2454 }
2455
2456 #[cfg(all(feature = "server", feature = "verify"))]
2457 pub(crate) fn execute_with_proof_only_get_elements_internal(
2459 self,
2460 drive: &Drive,
2461 transaction: TransactionArg,
2462 drive_operations: &mut Vec<LowLevelDriveOperation>,
2463 platform_version: &PlatformVersion,
2464 ) -> Result<(RootHash, Vec<Vec<u8>>), Error> {
2465 let path_query = self.construct_path_query_operations(
2466 drive,
2467 true,
2468 transaction,
2469 drive_operations,
2470 platform_version,
2471 )?;
2472
2473 let proof = drive.grove_get_proved_path_query(
2474 &path_query,
2475 transaction,
2476 drive_operations,
2477 &platform_version.drive,
2478 )?;
2479 self.verify_proof_keep_serialized(proof.as_slice(), platform_version)
2480 }
2481
2482 #[cfg(feature = "server")]
2483 pub fn execute_raw_results_no_proof(
2485 &self,
2486 drive: &Drive,
2487 block_info: Option<BlockInfo>,
2488 transaction: TransactionArg,
2489 platform_version: &PlatformVersion,
2490 ) -> Result<(Vec<Vec<u8>>, u16, u64), Error> {
2491 let mut drive_operations = vec![];
2492 let (items, skipped) = self.execute_raw_results_no_proof_internal(
2493 drive,
2494 transaction,
2495 &mut drive_operations,
2496 platform_version,
2497 )?;
2498 let cost = if let Some(block_info) = block_info {
2499 let fee_result = Drive::calculate_fee(
2500 None,
2501 Some(drive_operations),
2502 &block_info.epoch,
2503 drive.config.epochs_per_era,
2504 platform_version,
2505 None,
2506 )?;
2507 fee_result.processing_fee
2508 } else {
2509 0
2510 };
2511 Ok((items, skipped, cost))
2512 }
2513
2514 #[cfg(feature = "server")]
2515 pub(crate) fn execute_raw_results_no_proof_internal(
2517 &self,
2518 drive: &Drive,
2519 transaction: TransactionArg,
2520 drive_operations: &mut Vec<LowLevelDriveOperation>,
2521 platform_version: &PlatformVersion,
2522 ) -> Result<(Vec<Vec<u8>>, u16), Error> {
2523 {
2531 use dpp::data_contract::document_type::accessors::DocumentTypeV2Getters;
2532 if self.document_type.index_only() {
2533 let (documents, skipped) = self.execute_index_only_documents_no_proof_internal(
2534 drive,
2535 transaction,
2536 drive_operations,
2537 platform_version,
2538 )?;
2539 let serialized = documents
2540 .into_iter()
2541 .map(|document| {
2542 document
2543 .serialize(self.document_type, self.contract, platform_version)
2544 .map_err(|error| match error {
2545 ProtocolError::DataContractError(
2546 dpp::data_contract::errors::DataContractError::MissingRequiredKey(_),
2547 ) => Error::Query(QuerySyntaxError::Unsupported(
2548 "this indexOnly query's index does not cover every required \
2549 property, so the documents it synthesizes cannot be \
2550 serialized into a non-proof response; query through an \
2551 index covering all properties, or use a proved query"
2552 .to_string(),
2553 )),
2554 other => other.into(),
2555 })
2556 })
2557 .collect::<Result<Vec<_>, Error>>()?;
2558 return Ok((serialized, skipped));
2559 }
2560 }
2561
2562 let path_query = self.construct_path_query_operations(
2563 drive,
2564 false,
2565 transaction,
2566 drive_operations,
2567 platform_version,
2568 )?;
2569
2570 let query_result = drive.grove_get_path_query_serialized_results(
2571 &path_query,
2572 transaction,
2573 drive_operations,
2574 &platform_version.drive,
2575 );
2576 match query_result {
2577 Err(Error::GroveDB(e))
2578 if matches!(
2579 e.as_ref(),
2580 GroveError::PathKeyNotFound(_)
2581 | GroveError::PathNotFound(_)
2582 | GroveError::PathParentLayerNotFound(_)
2583 ) =>
2584 {
2585 Ok((Vec::new(), 0))
2586 }
2587 _ => {
2588 let (data, skipped) = query_result?;
2589 {
2590 Ok((data, skipped))
2591 }
2592 }
2593 }
2594 }
2595
2596 #[cfg(feature = "server")]
2597 pub(crate) fn execute_no_proof_internal(
2599 &self,
2600 drive: &Drive,
2601 result_type: QueryResultType,
2602 transaction: TransactionArg,
2603 drive_operations: &mut Vec<LowLevelDriveOperation>,
2604 platform_version: &PlatformVersion,
2605 ) -> Result<(QueryResultElements, u16), Error> {
2606 let path_query = self.construct_path_query_operations(
2607 drive,
2608 false,
2609 transaction,
2610 drive_operations,
2611 platform_version,
2612 )?;
2613 let query_result = drive.grove_get_path_query(
2614 &path_query,
2615 transaction,
2616 result_type,
2617 drive_operations,
2618 &platform_version.drive,
2619 );
2620 match query_result {
2621 Err(Error::GroveDB(e))
2622 if matches!(
2623 e.as_ref(),
2624 GroveError::PathKeyNotFound(_)
2625 | GroveError::PathNotFound(_)
2626 | GroveError::PathParentLayerNotFound(_)
2627 ) =>
2628 {
2629 Ok((QueryResultElements::new(), 0))
2630 }
2631 _ => {
2632 let (data, skipped) = query_result?;
2633 {
2634 Ok((data, skipped))
2635 }
2636 }
2637 }
2638 }
2639}
2640
2641impl<'a> From<&DriveDocumentQuery<'a>> for BTreeMap<String, Value> {
2643 fn from(query: &DriveDocumentQuery<'a>) -> Self {
2644 let mut response = BTreeMap::<String, Value>::new();
2645
2646 response.insert(
2649 "contract_id".to_string(),
2650 Value::Identifier(query.contract.id().to_buffer()),
2651 );
2652
2653 response.insert(
2656 "document_type_name".to_string(),
2657 Value::Text(query.document_type.name().to_string()),
2658 );
2659
2660 let all_where_clauses: Vec<WhereClause> = query.internal_clauses.clone().into();
2662 response.insert(
2663 "where".to_string(),
2664 Value::Array(all_where_clauses.into_iter().map(|v| v.into()).collect()),
2665 );
2666
2667 if let Some(offset) = query.offset {
2669 response.insert("offset".to_string(), Value::U16(offset));
2670 };
2671 if let Some(limit) = query.limit {
2673 response.insert("limit".to_string(), Value::U16(limit));
2674 };
2675 let order_by = &query.order_by;
2677 let value: Vec<Value> = order_by
2678 .into_iter()
2679 .map(|(_k, v)| v.clone().into())
2680 .collect();
2681 response.insert("orderBy".to_string(), Value::Array(value));
2682
2683 if let Some(start_at) = query.start_at {
2685 let v = Value::Identifier(start_at);
2686 if query.start_at_included {
2687 response.insert("startAt".to_string(), v);
2688 } else {
2689 response.insert("startAfter".to_string(), v);
2690 }
2691 };
2692
2693 if let Some(block_time_ms) = query.block_time_ms {
2695 response.insert("blockTime".to_string(), Value::U64(block_time_ms));
2696 };
2697
2698 response
2699 }
2700}
2701
2702#[cfg(feature = "server")]
2703#[cfg(test)]
2704mod tests {
2705
2706 use dpp::data_contract::document_type::accessors::DocumentTypeV0Getters;
2707
2708 use dpp::prelude::Identifier;
2709 use grovedb::Query;
2710 use indexmap::IndexMap;
2711 use rand::prelude::StdRng;
2712 use rand::SeedableRng;
2713 use serde_json::json;
2714 use std::borrow::Cow;
2715 use std::collections::BTreeMap;
2716 use std::option::Option::None;
2717 use tempfile::TempDir;
2718
2719 use crate::drive::Drive;
2720 use crate::query::{
2721 DriveDocumentQuery, InternalClauses, OrderClause, WhereClause, WhereOperator,
2722 };
2723 use crate::util::storage_flags::StorageFlags;
2724
2725 use dpp::data_contract::DataContract;
2726
2727 use serde_json::Value::Null;
2728
2729 use crate::config::DriveConfig;
2730 use crate::util::test_helpers::setup::setup_drive_with_initial_state_structure;
2731 use dpp::block::block_info::BlockInfo;
2732 use dpp::data_contract::accessors::v0::DataContractV0Getters;
2733 use dpp::data_contracts::SystemDataContract;
2734 use dpp::document::DocumentV0;
2735 use dpp::platform_value::string_encoding::Encoding;
2736 use dpp::platform_value::Value;
2737 use dpp::system_data_contracts::load_system_data_contract;
2738 use dpp::tests::fixtures::{get_data_contract_fixture, get_dpns_data_contract_fixture};
2739 use dpp::tests::json_document::json_document_to_contract;
2740 use dpp::util::cbor_serializer;
2741 use dpp::version::PlatformVersion;
2742
2743 fn setup_family_contract() -> (Drive, DataContract) {
2744 let tmp_dir = TempDir::new().unwrap();
2745
2746 let platform_version = PlatformVersion::latest();
2747
2748 let (drive, _) = Drive::open(tmp_dir, None).expect("expected to open Drive successfully");
2749
2750 drive
2751 .create_initial_state_structure(None, platform_version)
2752 .expect("expected to create root tree successfully");
2753
2754 let contract_path = "tests/supporting_files/contract/family/family-contract.json";
2755
2756 let contract = json_document_to_contract(contract_path, false, platform_version)
2758 .expect("expected to get document");
2759
2760 let storage_flags = Some(Cow::Owned(StorageFlags::SingleEpoch(0)));
2761 drive
2762 .apply_contract(
2763 &contract,
2764 BlockInfo::default(),
2765 true,
2766 storage_flags,
2767 None,
2768 platform_version,
2769 )
2770 .expect("expected to apply contract successfully");
2771
2772 (drive, contract)
2773 }
2774
2775 fn setup_withdrawal_contract() -> (Drive, DataContract) {
2776 let tmp_dir = TempDir::new().unwrap();
2777
2778 let platform_version = PlatformVersion::latest();
2779
2780 let (drive, _) = Drive::open(tmp_dir, None).expect("expected to open Drive successfully");
2781
2782 drive
2783 .create_initial_state_structure(None, platform_version)
2784 .expect("expected to create root tree successfully");
2785
2786 let contract = load_system_data_contract(SystemDataContract::Withdrawals, platform_version)
2788 .expect("load system contact");
2789
2790 let storage_flags = Some(Cow::Owned(StorageFlags::SingleEpoch(0)));
2791 drive
2792 .apply_contract(
2793 &contract,
2794 BlockInfo::default(),
2795 true,
2796 storage_flags,
2797 None,
2798 platform_version,
2799 )
2800 .expect("expected to apply contract successfully");
2801
2802 (drive, contract)
2803 }
2804
2805 fn setup_family_birthday_contract() -> (Drive, DataContract) {
2806 let drive = setup_drive_with_initial_state_structure(None);
2807
2808 let platform_version = PlatformVersion::latest();
2809
2810 let contract_path =
2811 "tests/supporting_files/contract/family/family-contract-with-birthday.json";
2812
2813 let contract = json_document_to_contract(contract_path, false, platform_version)
2815 .expect("expected to get document");
2816 let storage_flags = Some(Cow::Owned(StorageFlags::SingleEpoch(0)));
2817 drive
2818 .apply_contract(
2819 &contract,
2820 BlockInfo::default(),
2821 true,
2822 storage_flags,
2823 None,
2824 platform_version,
2825 )
2826 .expect("expected to apply contract successfully");
2827
2828 (drive, contract)
2829 }
2830
2831 #[test]
2832 fn test_drive_query_from_to_cbor() {
2833 let config = DriveConfig::default();
2834 let contract = get_data_contract_fixture(None, 0, 1).data_contract_owned();
2835 let document_type = contract
2836 .document_type_for_name("niceDocument")
2837 .expect("expected to get nice document");
2838 let start_after = Identifier::random();
2839
2840 let query_value = json!({
2841 "contract_id": contract.id(),
2842 "document_type_name": document_type.name(),
2843 "where": [
2844 ["firstName", "<", "Gilligan"],
2845 ["lastName", "=", "Doe"]
2846 ],
2847 "limit": 100u16,
2848 "offset": 10u16,
2849 "orderBy": [
2850 ["firstName", "asc"],
2851 ["lastName", "desc"],
2852 ],
2853 "startAfter": start_after,
2854 "blockTime": 13453432u64,
2855 });
2856
2857 let where_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None)
2858 .expect("expected to serialize to cbor");
2859 let query = DriveDocumentQuery::from_cbor(
2860 where_cbor.as_slice(),
2861 &contract,
2862 document_type,
2863 &config,
2864 PlatformVersion::latest(),
2865 )
2866 .expect("deserialize cbor shouldn't fail");
2867
2868 let cbor = query.to_cbor().expect("should serialize cbor");
2869
2870 let deserialized = DriveDocumentQuery::from_cbor(
2871 &cbor,
2872 &contract,
2873 document_type,
2874 &config,
2875 PlatformVersion::latest(),
2876 )
2877 .expect("should deserialize cbor");
2878
2879 assert_eq!(query, deserialized);
2880
2881 assert_eq!(deserialized.start_at, Some(start_after.to_buffer()));
2882 assert!(!deserialized.start_at_included);
2883 assert_eq!(deserialized.block_time_ms, Some(13453432u64));
2884 }
2885
2886 #[test]
2887 fn test_invalid_query_ranges_different_fields() {
2888 let query_value = json!({
2889 "where": [
2890 ["firstName", "<", "Gilligan"],
2891 ["lastName", "<", "Michelle"],
2892 ],
2893 "limit": 100,
2894 "orderBy": [
2895 ["firstName", "asc"],
2896 ["lastName", "asc"],
2897 ]
2898 });
2899 let contract = get_data_contract_fixture(None, 0, 1).data_contract_owned();
2900 let document_type = contract
2901 .document_type_for_name("niceDocument")
2902 .expect("expected to get nice document");
2903
2904 let where_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None)
2905 .expect("expected to serialize to cbor");
2906 DriveDocumentQuery::from_cbor(
2907 where_cbor.as_slice(),
2908 &contract,
2909 document_type,
2910 &DriveConfig::default(),
2911 PlatformVersion::latest(),
2912 )
2913 .expect_err("all ranges must be on same field");
2914 }
2915
2916 #[test]
2917 fn test_invalid_query_extra_invalid_field() {
2918 let query_value = json!({
2919 "where": [
2920 ["firstName", "<", "Gilligan"],
2921 ],
2922 "limit": 100,
2923 "orderBy": [
2924 ["firstName", "asc"],
2925 ["lastName", "asc"],
2926 ],
2927 "invalid": 0,
2928 });
2929 let contract = get_data_contract_fixture(None, 0, 1).data_contract_owned();
2930 let document_type = contract
2931 .document_type_for_name("niceDocument")
2932 .expect("expected to get nice document");
2933
2934 let where_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None)
2935 .expect("expected to serialize to cbor");
2936 DriveDocumentQuery::from_cbor(
2937 where_cbor.as_slice(),
2938 &contract,
2939 document_type,
2940 &DriveConfig::default(),
2941 PlatformVersion::latest(),
2942 )
2943 .expect_err("fields of queries must of defined supported types (where, limit, orderBy...)");
2944 }
2945
2946 #[test]
2947 fn test_invalid_query_conflicting_clauses() {
2948 let query_value = json!({
2949 "where": [
2950 ["firstName", "<", "Gilligan"],
2951 ["firstName", ">", "Gilligan"],
2952 ],
2953 "limit": 100,
2954 "orderBy": [
2955 ["firstName", "asc"],
2956 ["lastName", "asc"],
2957 ],
2958 });
2959
2960 let contract = get_data_contract_fixture(None, 0, 1).data_contract_owned();
2961 let document_type = contract
2962 .document_type_for_name("niceDocument")
2963 .expect("expected to get nice document");
2964
2965 let where_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None)
2966 .expect("expected to serialize to cbor");
2967 DriveDocumentQuery::from_cbor(
2968 where_cbor.as_slice(),
2969 &contract,
2970 document_type,
2971 &DriveConfig::default(),
2972 PlatformVersion::latest(),
2973 )
2974 .expect_err("the query should not be created");
2975 }
2976
2977 #[test]
2978 fn test_valid_query_groupable_meeting_clauses() {
2979 let query_value = json!({
2980 "where": [
2981 ["firstName", "<=", "Gilligan"],
2982 ["firstName", ">", "Gilligan"],
2983 ],
2984 "limit": 100,
2985 "orderBy": [
2986 ["firstName", "asc"],
2987 ["lastName", "asc"],
2988 ],
2989 });
2990
2991 let contract = get_data_contract_fixture(None, 0, 1).data_contract_owned();
2992 let document_type = contract
2993 .document_type_for_name("niceDocument")
2994 .expect("expected to get nice document");
2995
2996 let where_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None)
2997 .expect("expected to serialize to cbor");
2998 DriveDocumentQuery::from_cbor(
2999 where_cbor.as_slice(),
3000 &contract,
3001 document_type,
3002 &DriveConfig::default(),
3003 PlatformVersion::latest(),
3004 )
3005 .expect("the query should be created");
3006 }
3007
3008 #[test]
3009 fn test_valid_query_query_field_at_max_length() {
3010 let long_string = "t".repeat(255);
3011 let query_value = json!({
3012 "where": [
3013 ["firstName", "<", long_string],
3014 ],
3015 "limit": 100,
3016 "orderBy": [
3017 ["firstName", "asc"],
3018 ["lastName", "asc"],
3019 ],
3020 });
3021 let contract = get_data_contract_fixture(None, 0, 1).data_contract_owned();
3022 let document_type = contract
3023 .document_type_for_name("niceDocument")
3024 .expect("expected to get nice document");
3025
3026 let where_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None)
3027 .expect("expected to serialize to cbor");
3028 DriveDocumentQuery::from_cbor(
3029 where_cbor.as_slice(),
3030 &contract,
3031 document_type,
3032 &DriveConfig::default(),
3033 PlatformVersion::latest(),
3034 )
3035 .expect("query should be fine for a 255 byte long string");
3036 }
3037
3038 #[test]
3039 fn test_valid_query_drive_document_query() {
3040 let platform_version = PlatformVersion::latest();
3041 let mut rng = StdRng::seed_from_u64(5);
3042 let contract =
3043 get_dpns_data_contract_fixture(Some(Identifier::random_with_rng(&mut rng)), 0, 1)
3044 .data_contract_owned();
3045 let domain = contract
3046 .document_type_for_name("domain")
3047 .expect("expected to get domain");
3048
3049 let query_asc = DriveDocumentQuery {
3050 contract: &contract,
3051 document_type: domain,
3052 internal_clauses: InternalClauses {
3053 primary_key_in_clause: None,
3054 primary_key_equal_clause: None,
3055 in_clauses: Vec::new(),
3056 range_clause: Some(WhereClause {
3057 field: "records.identity".to_string(),
3058 operator: WhereOperator::LessThan,
3059 value: Value::Identifier(
3060 Identifier::from_string(
3061 "AYN4srupPWDrp833iG5qtmaAsbapNvaV7svAdncLN5Rh",
3062 Encoding::Base58,
3063 )
3064 .unwrap()
3065 .to_buffer(),
3066 ),
3067 }),
3068 equal_clauses: BTreeMap::new(),
3069 },
3070 offset: None,
3071 limit: Some(6),
3072 order_by: vec![(
3073 "records.identity".to_string(),
3074 OrderClause {
3075 field: "records.identity".to_string(),
3076 ascending: false,
3077 },
3078 )]
3079 .into_iter()
3080 .collect(),
3081 start_at: None,
3082 start_at_included: false,
3083 block_time_ms: None,
3084 resolved_time_ranges: vec![],
3085 };
3086
3087 let path_query = query_asc
3088 .construct_path_query(None, platform_version)
3089 .expect("expected to create path query");
3090
3091 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 } }");
3092
3093 let encoded = bincode::encode_to_vec(&path_query, bincode::config::standard())
3095 .expect("Failed to serialize PathQuery");
3096
3097 let hex_string = hex::encode(encoded);
3099
3100 assert_eq!(hex_string, "050140201da29f488023e306ff9a680bc9837153fb0778c8ee9c934a87dc0de1d69abd3c010106646f6d61696e107265636f7264732e6964656e74697479010105208dc201fd7ad7905f8a84d66218e2b387daea7fe4739ae0e21e8c3ee755e6a2c00101010001010103000000000001010000010101000101010300000000000000010600");
3104 }
3105
3106 #[test]
3107 fn test_invalid_query_field_too_long() {
3108 let (drive, contract) = setup_family_contract();
3109
3110 let platform_version = PlatformVersion::latest();
3111
3112 let document_type = contract
3113 .document_type_for_name("person")
3114 .expect("expected to get a document type");
3115
3116 let too_long_string = "t".repeat(256);
3117 let query_value = json!({
3118 "where": [
3119 ["firstName", "<", too_long_string],
3120 ],
3121 "limit": 100,
3122 "orderBy": [
3123 ["firstName", "asc"],
3124 ["lastName", "asc"],
3125 ],
3126 });
3127
3128 let where_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None)
3129 .expect("expected to serialize to cbor");
3130 let query = DriveDocumentQuery::from_cbor(
3131 where_cbor.as_slice(),
3132 &contract,
3133 document_type,
3134 &DriveConfig::default(),
3135 PlatformVersion::latest(),
3136 )
3137 .expect("fields of queries length must be under 256 bytes long");
3138 query
3139 .execute_raw_results_no_proof(&drive, None, None, platform_version)
3140 .expect_err("fields of queries length must be under 256 bytes long");
3141 }
3142
3143 #[test]
3199 fn test_valid_query_timestamp_field_with_null_value() {
3200 let (drive, contract) = setup_family_birthday_contract();
3201
3202 let platform_version = PlatformVersion::latest();
3203
3204 let document_type = contract
3205 .document_type_for_name("person")
3206 .expect("expected to get a document type");
3207
3208 let query_value = json!({
3209 "where": [
3210 ["birthday", ">=", Null],
3211 ],
3212 "limit": 100,
3213 "orderBy": [
3214 ["birthday", "asc"],
3215 ],
3216 });
3217
3218 let where_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None)
3219 .expect("expected to serialize to cbor");
3220 let query = DriveDocumentQuery::from_cbor(
3221 where_cbor.as_slice(),
3222 &contract,
3223 document_type,
3224 &DriveConfig::default(),
3225 PlatformVersion::latest(),
3226 )
3227 .expect("The query itself should be valid for a null type");
3228 query
3229 .execute_raw_results_no_proof(&drive, None, None, platform_version)
3230 .expect("a Null value doesn't make sense for a float");
3231 }
3232
3233 #[test]
3234 fn test_invalid_query_in_with_empty_array() {
3235 let (drive, contract) = setup_family_contract();
3236
3237 let platform_version = PlatformVersion::latest();
3238
3239 let document_type = contract
3240 .document_type_for_name("person")
3241 .expect("expected to get a document type");
3242
3243 let query_value = json!({
3244 "where": [
3245 ["firstName", "in", []],
3246 ],
3247 "limit": 100,
3248 "orderBy": [
3249 ["firstName", "asc"],
3250 ],
3251 });
3252
3253 let where_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None)
3254 .expect("expected to serialize to cbor");
3255 let query = DriveDocumentQuery::from_cbor(
3256 where_cbor.as_slice(),
3257 &contract,
3258 document_type,
3259 &DriveConfig::default(),
3260 PlatformVersion::latest(),
3261 )
3262 .expect("query should be valid for empty array");
3263
3264 query
3265 .execute_raw_results_no_proof(&drive, None, None, platform_version)
3266 .expect_err("query should not be able to execute for empty array");
3267 }
3268
3269 #[test]
3270 fn test_invalid_query_in_too_many_elements() {
3271 let (drive, contract) = setup_family_contract();
3272
3273 let platform_version = PlatformVersion::latest();
3274
3275 let document_type = contract
3276 .document_type_for_name("person")
3277 .expect("expected to get a document type");
3278
3279 let mut array: Vec<String> = Vec::with_capacity(101);
3280 for _ in 0..array.capacity() {
3281 array.push(String::from("a"));
3282 }
3283 let query_value = json!({
3284 "where": [
3285 ["firstName", "in", array],
3286 ],
3287 "limit": 100,
3288 "orderBy": [
3289 ["firstName", "asc"],
3290 ],
3291 });
3292
3293 let where_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None)
3294 .expect("expected to serialize to cbor");
3295 let query = DriveDocumentQuery::from_cbor(
3296 where_cbor.as_slice(),
3297 &contract,
3298 document_type,
3299 &DriveConfig::default(),
3300 PlatformVersion::latest(),
3301 )
3302 .expect("query is valid for too many elements");
3303
3304 query
3305 .execute_raw_results_no_proof(&drive, None, None, platform_version)
3306 .expect_err("query should not be able to execute with too many elements");
3307 }
3308
3309 #[test]
3310 fn test_invalid_query_in_unique_elements() {
3311 let (drive, contract) = setup_family_contract();
3312
3313 let platform_version = PlatformVersion::latest();
3314
3315 let document_type = contract
3316 .document_type_for_name("person")
3317 .expect("expected to get a document type");
3318
3319 let query_value = json!({
3320 "where": [
3321 ["firstName", "in", ["a", "a"]],
3322 ],
3323 "limit": 100,
3324 "orderBy": [
3325 ["firstName", "asc"],
3326 ],
3327 });
3328
3329 let where_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None)
3330 .expect("expected to serialize to cbor");
3331
3332 let query = DriveDocumentQuery::from_cbor(
3336 where_cbor.as_slice(),
3337 &contract,
3338 document_type,
3339 &DriveConfig::default(),
3340 PlatformVersion::latest(),
3341 )
3342 .expect("the query should be created");
3343
3344 query
3345 .execute_raw_results_no_proof(&drive, None, None, platform_version)
3346 .expect_err("there should be no duplicates values for In query");
3347 }
3348
3349 #[test]
3350 fn test_invalid_query_starts_with_empty_string() {
3351 let query_value = json!({
3352 "where": [
3353 ["firstName", "startsWith", ""],
3354 ],
3355 "limit": 100,
3356 "orderBy": [
3357 ["firstName", "asc"],
3358 ],
3359 });
3360
3361 let contract = get_data_contract_fixture(None, 0, 1).data_contract_owned();
3362 let document_type = contract
3363 .document_type_for_name("niceDocument")
3364 .expect("expected to get nice document");
3365
3366 let where_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None)
3367 .expect("expected to serialize to cbor");
3368 DriveDocumentQuery::from_cbor(
3369 where_cbor.as_slice(),
3370 &contract,
3371 document_type,
3372 &DriveConfig::default(),
3373 PlatformVersion::latest(),
3374 )
3375 .expect_err("starts with can not start with an empty string");
3376 }
3377
3378 #[test]
3379 fn test_invalid_query_limit_too_high() {
3380 let query_value = json!({
3381 "where": [
3382 ["firstName", "startsWith", "a"],
3383 ],
3384 "limit": 101,
3385 "orderBy": [
3386 ["firstName", "asc"],
3387 ],
3388 });
3389
3390 let contract = get_data_contract_fixture(None, 0, 1).data_contract_owned();
3391 let document_type = contract
3392 .document_type_for_name("niceDocument")
3393 .expect("expected to get nice document");
3394
3395 let where_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None)
3396 .expect("expected to serialize to cbor");
3397 DriveDocumentQuery::from_cbor(
3398 where_cbor.as_slice(),
3399 &contract,
3400 document_type,
3401 &DriveConfig::default(),
3402 PlatformVersion::latest(),
3403 )
3404 .expect_err("starts with can not start with an empty string");
3405 }
3406
3407 #[test]
3408 fn test_invalid_query_limit_too_low() {
3409 let query_value = json!({
3410 "where": [
3411 ["firstName", "startsWith", "a"],
3412 ],
3413 "limit": -1,
3414 "orderBy": [
3415 ["firstName", "asc"],
3416 ],
3417 });
3418
3419 let contract = get_data_contract_fixture(None, 0, 1).data_contract_owned();
3420 let document_type = contract
3421 .document_type_for_name("niceDocument")
3422 .expect("expected to get nice document");
3423
3424 let where_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None)
3425 .expect("expected to serialize to cbor");
3426 DriveDocumentQuery::from_cbor(
3427 where_cbor.as_slice(),
3428 &contract,
3429 document_type,
3430 &DriveConfig::default(),
3431 PlatformVersion::latest(),
3432 )
3433 .expect_err("starts with can not start with an empty string");
3434 }
3435
3436 #[test]
3437 fn test_invalid_query_limit_zero() {
3438 let query_value = json!({
3439 "where": [
3440 ["firstName", "startsWith", "a"],
3441 ],
3442 "limit": 0,
3443 "orderBy": [
3444 ["firstName", "asc"],
3445 ],
3446 });
3447
3448 let contract = get_data_contract_fixture(None, 0, 1).data_contract_owned();
3449 let document_type = contract
3450 .document_type_for_name("niceDocument")
3451 .expect("expected to get nice document");
3452
3453 let where_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None)
3454 .expect("expected to serialize to cbor");
3455 DriveDocumentQuery::from_cbor(
3456 where_cbor.as_slice(),
3457 &contract,
3458 document_type,
3459 &DriveConfig::default(),
3460 PlatformVersion::latest(),
3461 )
3462 .expect_err("starts with can not start with an empty string");
3463 }
3464
3465 #[test]
3466 fn resolved_time_range_shape_guard_accepts_only_the_single_resolution_equality() {
3467 use crate::query::{validate_resolved_time_range_clause_shapes, ResolvedTimeRange};
3468 use dpp::data_contract::document_type::TimeRangeTransform;
3469
3470 let resolved = vec![ResolvedTimeRange {
3471 transform: TimeRangeTransform {
3472 source: "$createdAt".to_string(),
3473 range_seconds: 21_600,
3474 step_seconds: 7_200,
3475 phase_seconds: 0,
3476 },
3477 }];
3478 let equality = WhereClause {
3479 field: "$createdAt".to_string(),
3480 operator: WhereOperator::Equal,
3481 value: Value::U64(21_600_000),
3482 };
3483 let other = WhereClause {
3484 field: "hashtag".to_string(),
3485 operator: WhereOperator::Equal,
3486 value: Value::Text("ibiza".to_string()),
3487 };
3488
3489 validate_resolved_time_range_clause_shapes(&[equality.clone(), other.clone()], &resolved)
3490 .expect("one equality on the resolved field is the resolution shape");
3491
3492 let in_clause = WhereClause {
3495 field: "$createdAt".to_string(),
3496 operator: WhereOperator::In,
3497 value: Value::Array(vec![Value::U64(0), Value::U64(7_200_000)]),
3498 };
3499 validate_resolved_time_range_clause_shapes(&[in_clause, other.clone()], &resolved)
3500 .expect_err("an In clause on a resolved field must be rejected");
3501
3502 let range_clause = WhereClause {
3503 field: "$createdAt".to_string(),
3504 operator: WhereOperator::GreaterThan,
3505 value: Value::U64(0),
3506 };
3507 validate_resolved_time_range_clause_shapes(&[equality.clone(), range_clause], &resolved)
3508 .expect_err("a range clause riding along on a resolved field must be rejected");
3509
3510 validate_resolved_time_range_clause_shapes(&[other], &resolved)
3511 .expect_err("a resolved field with no equality at all must be rejected");
3512 }
3513
3514 #[test]
3515 fn test_withdrawal_query_with_missing_transaction_index() {
3516 let (_, contract) = setup_withdrawal_contract();
3518 let platform_version = PlatformVersion::latest();
3519
3520 let document_type_name = "withdrawal";
3521 let document_type = contract
3522 .document_type_for_name(document_type_name)
3523 .expect("expected to get document type");
3524
3525 let drive_document_query = DriveDocumentQuery {
3527 contract: &contract,
3528 document_type,
3529 internal_clauses: InternalClauses {
3530 primary_key_in_clause: None,
3531 primary_key_equal_clause: None,
3532 in_clauses: vec![WhereClause {
3533 field: "status".to_string(),
3534 operator: WhereOperator::In,
3535 value: Value::Array(vec![
3536 Value::U64(0),
3537 Value::U64(1),
3538 Value::U64(2),
3539 Value::U64(3),
3540 Value::U64(4),
3541 ]),
3542 }],
3543 range_clause: None,
3544 equal_clauses: BTreeMap::default(),
3545 },
3546 offset: None,
3547 limit: Some(3),
3548 order_by: IndexMap::from([
3549 (
3550 "status".to_string(),
3551 OrderClause {
3552 field: "status".to_string(),
3553 ascending: true,
3554 },
3555 ),
3556 (
3557 "transactionIndex".to_string(),
3558 OrderClause {
3559 field: "transactionIndex".to_string(),
3560 ascending: true,
3561 },
3562 ),
3563 ]),
3564 start_at: Some([3u8; 32]),
3565 start_at_included: false,
3566 block_time_ms: None,
3567 resolved_time_ranges: vec![],
3568 };
3569
3570 let mut properties = BTreeMap::new();
3572 properties.insert("status".to_string(), Value::U64(0));
3573 let starts_at_document = DocumentV0 {
3576 contract_version: None,
3577 id: Identifier::from([3u8; 32]), owner_id: Identifier::random(),
3579 properties,
3580 revision: None,
3581 created_at: None,
3582 updated_at: None,
3583 transferred_at: None,
3584 created_at_block_height: None,
3585 updated_at_block_height: None,
3586 transferred_at_block_height: None,
3587 created_at_core_block_height: None,
3588 updated_at_core_block_height: None,
3589 transferred_at_core_block_height: None,
3590 creator_id: None,
3591 }
3592 .into();
3593
3594 let result = drive_document_query
3596 .construct_path_query(Some(starts_at_document), platform_version)
3597 .expect("expected to construct a path query");
3598
3599 assert_eq!(
3600 result
3601 .clone()
3602 .query
3603 .query
3604 .default_subquery_branch
3605 .subquery
3606 .expect("expected subquery")
3607 .items,
3608 Query::new_range_full().items
3609 );
3610 }
3611
3612 mod multiple_in_clause_lowering {
3619 use super::*;
3620 use crate::error::query::QuerySyntaxError;
3621 use crate::error::Error;
3622
3623 fn family_contract() -> DataContract {
3624 json_document_to_contract(
3625 "tests/supporting_files/contract/family/family-contract.json",
3626 false,
3627 PlatformVersion::latest(),
3628 )
3629 .expect("expected to load family contract")
3630 }
3631
3632 fn text_array(values: &[&str]) -> Value {
3633 Value::Array(
3634 values
3635 .iter()
3636 .map(|value| Value::Text(value.to_string()))
3637 .collect(),
3638 )
3639 }
3640
3641 fn in_clause(field: &str, values: &[&str]) -> WhereClause {
3642 WhereClause {
3643 field: field.to_string(),
3644 operator: WhereOperator::In,
3645 value: text_array(values),
3646 }
3647 }
3648
3649 fn ascending_order_by(fields: &[&str]) -> IndexMap<String, OrderClause> {
3650 fields
3651 .iter()
3652 .map(|field| {
3653 (
3654 field.to_string(),
3655 OrderClause {
3656 field: field.to_string(),
3657 ascending: true,
3658 },
3659 )
3660 })
3661 .collect()
3662 }
3663
3664 fn person_query<'a>(
3665 contract: &'a DataContract,
3666 where_clauses: Vec<WhereClause>,
3667 order_by_fields: &[&str],
3668 ) -> DriveDocumentQuery<'a> {
3669 let internal_clauses =
3670 InternalClauses::extract_from_clauses(where_clauses, PlatformVersion::latest())
3671 .expect("clauses should group structurally");
3672 DriveDocumentQuery {
3673 contract,
3674 document_type: contract
3675 .document_type_for_name("person")
3676 .expect("person document type should exist"),
3677 internal_clauses,
3678 offset: None,
3679 limit: Some(100),
3680 order_by: ascending_order_by(order_by_fields),
3681 start_at: None,
3682 start_at_included: false,
3683 block_time_ms: None,
3684 resolved_time_ranges: vec![],
3685 }
3686 }
3687
3688 #[test]
3689 fn two_in_clauses_lower_to_nested_key_sets() {
3690 let contract = family_contract();
3691 let platform_version = PlatformVersion::latest();
3692 let query = person_query(
3693 &contract,
3694 vec![
3695 in_clause("firstName", &["Adey", "Briney"]),
3696 in_clause("lastName", &["Kriskov", "Randolf"]),
3697 ],
3698 &["firstName", "lastName"],
3699 );
3700
3701 let path_query = query
3702 .construct_path_query(None, platform_version)
3703 .expect("two in clauses should lower at protocol version 14");
3704
3705 assert_eq!(
3708 path_query.path.last().expect("path should not be empty"),
3709 &b"firstName".to_vec()
3710 );
3711
3712 let outer = &path_query.query.query;
3714 assert_eq!(outer.items.len(), 2);
3715 assert!(outer.left_to_right);
3716
3717 assert_eq!(
3720 outer.default_subquery_branch.subquery_path,
3721 Some(vec![b"lastName".to_vec()])
3722 );
3723 let inner = outer
3724 .default_subquery_branch
3725 .subquery
3726 .as_deref()
3727 .expect("expected a lastName subquery");
3728 assert_eq!(inner.items.len(), 2);
3729
3730 assert_eq!(
3732 inner.default_subquery_branch.subquery_path,
3733 Some(vec![vec![0]])
3734 );
3735 }
3736
3737 #[test]
3738 #[cfg(feature = "cbor_query")]
3739 fn two_in_clauses_survive_cbor_round_trip() {
3740 let contract = family_contract();
3741 let mut query = person_query(
3742 &contract,
3743 vec![
3744 in_clause("firstName", &["Adey", "Briney"]),
3745 in_clause("lastName", &["Kriskov", "Randolf"]),
3746 ],
3747 &["firstName", "lastName"],
3748 );
3749 query.start_at_included = true;
3752
3753 let cbor = query.to_cbor().expect("should serialize cbor");
3754 let deserialized = DriveDocumentQuery::from_cbor(
3755 &cbor,
3756 &contract,
3757 contract
3758 .document_type_for_name("person")
3759 .expect("person document type should exist"),
3760 &DriveConfig::default(),
3761 PlatformVersion::latest(),
3762 )
3763 .expect("should deserialize cbor");
3764
3765 assert_eq!(query, deserialized);
3766 assert_eq!(
3767 deserialized
3768 .internal_clauses
3769 .in_clauses
3770 .iter()
3771 .map(|in_clause| in_clause.field.as_str())
3772 .collect::<Vec<_>>(),
3773 vec!["firstName", "lastName"],
3774 "both in clauses must survive the round trip in order"
3775 );
3776 }
3777
3778 #[test]
3779 fn descending_order_by_on_left_over_property_is_honored() {
3780 let contract = family_contract();
3781 let platform_version = PlatformVersion::latest();
3782 let mut query = person_query(
3785 &contract,
3786 vec![
3787 in_clause("firstName", &["Adey", "Briney"]),
3788 in_clause("middleName", &["Ivanna", "Evangeline"]),
3789 ],
3790 &["firstName", "middleName"],
3791 );
3792 query.order_by.insert(
3793 "lastName".to_string(),
3794 OrderClause {
3795 field: "lastName".to_string(),
3796 ascending: false,
3797 },
3798 );
3799
3800 let path_query = query
3801 .construct_path_query(None, platform_version)
3802 .expect("two in clauses with a left-over order should lower");
3803
3804 let outer = &path_query.query.query;
3805 let middle = outer
3806 .default_subquery_branch
3807 .subquery
3808 .as_deref()
3809 .expect("expected a middleName subquery");
3810 assert_eq!(
3811 middle.default_subquery_branch.subquery_path,
3812 Some(vec![b"lastName".to_vec()])
3813 );
3814 let left_over_level = middle
3815 .default_subquery_branch
3816 .subquery
3817 .as_deref()
3818 .expect("expected a lastName subquery");
3819 assert!(
3820 !left_over_level.left_to_right,
3821 "left-over lastName level must honor the descending order by"
3822 );
3823
3824 query.order_by.shift_remove("lastName");
3827 let path_query = query
3828 .construct_path_query(None, platform_version)
3829 .expect("two in clauses should lower");
3830 let left_over_level = path_query
3831 .query
3832 .query
3833 .default_subquery_branch
3834 .subquery
3835 .as_deref()
3836 .expect("expected a middleName subquery")
3837 .default_subquery_branch
3838 .subquery
3839 .as_deref()
3840 .expect("expected a lastName subquery");
3841 assert!(left_over_level.left_to_right);
3842 }
3843
3844 #[test]
3845 fn two_in_clauses_rejected_at_protocol_version_13() {
3846 let contract = family_contract();
3847 let platform_version_13 =
3848 PlatformVersion::get(13).expect("protocol version 13 should exist");
3849 let query = person_query(
3850 &contract,
3851 vec![
3852 in_clause("firstName", &["Adey", "Briney"]),
3853 in_clause("lastName", &["Kriskov", "Randolf"]),
3854 ],
3855 &["firstName", "lastName"],
3856 );
3857
3858 let error = query
3859 .construct_path_query(None, platform_version_13)
3860 .expect_err("multiple in clauses must be rejected before protocol version 14");
3861 assert!(
3862 matches!(error, Error::Query(QuerySyntaxError::MultipleInClauses(_))),
3863 "expected MultipleInClauses, got {error:?}"
3864 );
3865
3866 query
3867 .construct_path_query(None, PlatformVersion::latest())
3868 .expect("the same query should lower at protocol version 14");
3869 }
3870
3871 #[test]
3872 fn equality_prefix_two_in_clauses_and_trailing_range_lowering() {
3873 let contract = family_contract();
3874 let platform_version = PlatformVersion::latest();
3875 let mut query = person_query(
3876 &contract,
3877 vec![
3878 WhereClause {
3879 field: "age".to_string(),
3880 operator: WhereOperator::Equal,
3881 value: Value::U8(30),
3882 },
3883 in_clause("firstName", &["Adey", "Briney"]),
3884 in_clause("middleName", &["Ivanna", "Evangeline"]),
3885 WhereClause {
3886 field: "lastName".to_string(),
3887 operator: WhereOperator::GreaterThan,
3888 value: Value::Text("M".to_string()),
3889 },
3890 ],
3891 &["firstName", "middleName", "lastName"],
3892 );
3893 query.limit = Some(50);
3894
3895 let path_query = query
3899 .construct_path_query(None, platform_version)
3900 .expect("equality + in + in + range should lower");
3901
3902 let path_len = path_query.path.len();
3903 assert_eq!(path_query.path[path_len - 3], b"age".to_vec());
3904 assert_eq!(
3905 path_query.path.last().expect("path should not be empty"),
3906 &b"firstName".to_vec()
3907 );
3908
3909 let outer = &path_query.query.query;
3910 assert_eq!(outer.items.len(), 2);
3911 assert_eq!(
3912 outer.default_subquery_branch.subquery_path,
3913 Some(vec![b"middleName".to_vec()])
3914 );
3915 let middle = outer
3916 .default_subquery_branch
3917 .subquery
3918 .as_deref()
3919 .expect("expected a middleName subquery");
3920 assert_eq!(middle.items.len(), 2);
3921 assert_eq!(
3922 middle.default_subquery_branch.subquery_path,
3923 Some(vec![b"lastName".to_vec()])
3924 );
3925 let range_level = middle
3926 .default_subquery_branch
3927 .subquery
3928 .as_deref()
3929 .expect("expected a lastName subquery");
3930 assert_eq!(range_level.items.len(), 1);
3932 assert_eq!(
3933 range_level.default_subquery_branch.subquery_path,
3934 Some(vec![vec![0]])
3935 );
3936 }
3937
3938 #[test]
3939 fn cross_product_above_cap_is_rejected() {
3940 let contract = family_contract();
3941 let first_names: Vec<String> = (0..20).map(|i| format!("First{i:02}")).collect();
3942 let last_names: Vec<String> = (0..6).map(|i| format!("Last{i}")).collect();
3943 let query = person_query(
3944 &contract,
3945 vec![
3946 WhereClause {
3947 field: "firstName".to_string(),
3948 operator: WhereOperator::In,
3949 value: Value::Array(first_names.iter().cloned().map(Value::Text).collect()),
3950 },
3951 WhereClause {
3952 field: "lastName".to_string(),
3953 operator: WhereOperator::In,
3954 value: Value::Array(last_names.iter().cloned().map(Value::Text).collect()),
3955 },
3956 ],
3957 &["firstName", "lastName"],
3958 );
3959
3960 let error = query
3961 .construct_path_query(None, PlatformVersion::latest())
3962 .expect_err("a 120-branch cross product must be rejected");
3963 assert!(
3964 matches!(error, Error::Query(QuerySyntaxError::InvalidInClause(_))),
3965 "expected InvalidInClause, got {error:?}"
3966 );
3967 }
3968
3969 #[test]
3970 fn non_consecutive_in_fields_are_rejected() {
3971 let contract = family_contract();
3972 let query = person_query(
3976 &contract,
3977 vec![
3978 in_clause("middleName", &["Ivanna", "Evangeline"]),
3979 in_clause("lastName", &["Kriskov", "Randolf"]),
3980 ],
3981 &["middleName", "lastName"],
3982 );
3983
3984 let error = query
3985 .construct_path_query(None, PlatformVersion::latest())
3986 .expect_err("non-consecutive in clauses must be rejected");
3987 assert!(
3988 matches!(
3989 error,
3990 Error::Query(QuerySyntaxError::WhereClauseOnNonIndexedProperty(_))
3991 ),
3992 "expected WhereClauseOnNonIndexedProperty, got {error:?}"
3993 );
3994 }
3995
3996 #[test]
3997 fn cursor_pagination_is_rejected() {
3998 let contract = family_contract();
3999 let mut query = person_query(
4000 &contract,
4001 vec![
4002 in_clause("firstName", &["Adey", "Briney"]),
4003 in_clause("lastName", &["Kriskov", "Randolf"]),
4004 ],
4005 &["firstName", "lastName"],
4006 );
4007 query.start_at = Some([5u8; 32]);
4008 query.start_at_included = false;
4009
4010 let error = query
4011 .construct_path_query(None, PlatformVersion::latest())
4012 .expect_err("cursor pagination with multiple in clauses must be rejected");
4013 assert!(
4014 matches!(error, Error::Query(QuerySyntaxError::Unsupported(_))),
4015 "expected Unsupported, got {error:?}"
4016 );
4017 }
4018
4019 #[test]
4020 fn missing_order_by_on_an_in_field_is_rejected() {
4021 let contract = family_contract();
4022 let query = person_query(
4023 &contract,
4024 vec![
4025 in_clause("firstName", &["Adey", "Briney"]),
4026 in_clause("lastName", &["Kriskov", "Randolf"]),
4027 ],
4028 &["firstName"],
4029 );
4030
4031 let error = query
4032 .construct_path_query(None, PlatformVersion::latest())
4033 .expect_err("missing order by on an in field must be rejected");
4034 assert!(
4039 matches!(
4040 error,
4041 Error::Query(QuerySyntaxError::WhereClauseOnNonIndexedProperty(_))
4042 ),
4043 "expected WhereClauseOnNonIndexedProperty, got {error:?}"
4044 );
4045 }
4046 }
4047}