rushdb_query/
point_fields.rs1use crate::planner::{family_id, pids_of};
6use crate::{access, normalize, reconstruct, Expr, FieldPred, Json, QueryError, QuerySnapshot};
7use rushdb_lmpg::reader::TryRead;
8use serde_json::Map;
9
10pub struct PointFields(Vec<(String, Vec<u64>)>);
16
17impl PointFields {
18 pub fn resolve<'n>(
24 snap: &QuerySnapshot,
25 tenant: rushdb_types::ids::TenantId,
26 names: impl IntoIterator<Item = &'n str>,
27 ) -> Result<Option<Self>, QueryError> {
28 let mut fields = Vec::new();
29 for name in names {
30 let Some(pids) = scalar_pids(snap, tenant, name)? else {
31 return Ok(None);
32 };
33 fields.push((name.to_owned(), pids));
34 }
35 Ok(Some(Self(fields)))
36 }
37
38 pub(super) fn for_predicate(
41 snap: &QuerySnapshot,
42 tenant: rushdb_types::ids::TenantId,
43 predicate: &Expr,
44 ) -> Result<Option<Self>, QueryError> {
45 let mut names = std::collections::BTreeSet::new();
46 if !predicate_fields(predicate, &mut names) {
47 return Ok(None);
48 }
49 Self::resolve(snap, tenant, names.iter().map(String::as_str))
50 }
51
52 pub fn row(
59 &self,
60 snap: &QuerySnapshot,
61 tenant: rushdb_types::ids::TenantId,
62 ord: u64,
63 ) -> Result<Map<String, Json>, QueryError> {
64 let mut row = Map::new();
65 for (field, pids) in &self.0 {
66 for &pid in pids.iter().rev() {
68 if let Some(occ) = access::occurrence(
69 snap,
70 tenant,
71 rushdb_types::ids::OwnerKind::Record,
72 ord,
73 pid,
74 0,
75 )? {
76 row.insert(
77 field.clone(),
78 reconstruct::decode_value(occ.value, &occ.payload)?,
79 );
80 break;
81 }
82 }
83 }
84 Ok(row)
85 }
86}
87
88fn predicate_fields(expr: &Expr, out: &mut std::collections::BTreeSet<String>) -> bool {
91 match expr {
92 Expr::And(items) | Expr::Or(items) | Expr::Nor(items) => {
93 items.iter().all(|item| predicate_fields(item, out))
94 }
95 Expr::Xor(a, b) => predicate_fields(a, out) && predicate_fields(b, out),
96 Expr::Not(inner) => predicate_fields(inner, out),
97 Expr::Related(_) | Expr::Field(FieldPred::Id(_)) => false,
98 Expr::Field(
99 FieldPred::Eq(name, _)
100 | FieldPred::Ne(name, _)
101 | FieldPred::Gt(name, _)
102 | FieldPred::Gte(name, _)
103 | FieldPred::Lt(name, _)
104 | FieldPred::Lte(name, _)
105 | FieldPred::Contains(name, _)
106 | FieldPred::StartsWith(name, _)
107 | FieldPred::EndsWith(name, _)
108 | FieldPred::Exists(name, _)
109 | FieldPred::IsNull(name, _)
110 | FieldPred::In(name, _)
111 | FieldPred::Nin(name, _)
112 | FieldPred::Type(name, _)
113 | FieldPred::DatetimeComponent { field: name, .. },
114 ) => {
115 out.insert(name.clone());
116 true
117 }
118 }
119}
120
121fn scalar_pids<R: TryRead>(
126 snap: &R,
127 tenant: rushdb_types::ids::TenantId,
128 name: &str,
129) -> Result<Option<Vec<u64>>, QueryError> {
130 let norm = normalize(name);
131 if norm.is_empty() || rushdb_types::value::is_reserved_name(&norm) {
132 return Ok(None);
133 }
134 let Some(fid) = family_id(snap, tenant, &norm)? else {
135 return Ok(Some(Vec::new()));
136 };
137 let mut pids = pids_of(snap, tenant, fid)?;
138 for &pid in &pids {
139 let (arrays, _) = rushdb_lmpg::derived::array_markers(
140 snap,
141 tenant,
142 rushdb_types::ids::OwnerKind::Record,
143 pid,
144 )?;
145 if arrays {
146 return Ok(None);
147 }
148 }
149 pids.sort_unstable();
150 Ok(Some(pids))
151}