@@ -11,6 +11,7 @@ mod val_prop_sub_index;
1111use std:: {
1212 collections:: { HashMap , HashSet } ,
1313 sync:: { Arc , Mutex } ,
14+ vec,
1415} ;
1516
1617use tracing:: { info, instrument} ;
@@ -19,7 +20,10 @@ use crate::{
1920 agents:: ForAgent ,
2021 atoms:: IndexAtom ,
2122 commit:: CommitResponse ,
22- db:: { query_index:: NO_VALUE , val_prop_sub_index:: find_in_val_prop_sub_index} ,
23+ db:: {
24+ query_index:: { requires_query_index, NO_VALUE } ,
25+ val_prop_sub_index:: find_in_val_prop_sub_index,
26+ } ,
2327 endpoints:: { default_endpoints, Endpoint , HandleGetContext } ,
2428 errors:: { AtomicError , AtomicResult } ,
2529 resources:: PropVals ,
@@ -35,8 +39,8 @@ use self::{
3539 remove_atom_from_prop_val_sub_index,
3640 } ,
3741 query_index:: {
38- check_if_atom_matches_watched_query_filters, query_indexed , update_indexed_member ,
39- IndexIterator , QueryFilter ,
42+ check_if_atom_matches_watched_query_filters, query_sorted_indexed , should_include_resource ,
43+ update_indexed_member , IndexIterator , QueryFilter ,
4044 } ,
4145 val_prop_sub_index:: { add_atom_to_reference_index, remove_atom_from_reference_index} ,
4246} ;
@@ -209,6 +213,110 @@ impl Db {
209213
210214 Some ( Resource :: from_propvals ( propvals, subject) )
211215 }
216+
217+ fn build_index_for_atom (
218+ & self ,
219+ atom : & IndexAtom ,
220+ query_filter : & QueryFilter ,
221+ ) -> AtomicResult < ( ) > {
222+ // Get the SortableValue either from the Atom or the Resource.
223+ let sort_val: SortableValue = if let Some ( sort) = & query_filter. sort_by {
224+ if & atom. property == sort {
225+ atom. sort_value . clone ( )
226+ } else {
227+ // Find the sort value in the store
228+ match self . get_value ( & atom. subject , sort) {
229+ Ok ( val) => val. to_sortable_string ( ) ,
230+ // If we try sorting on a value that does not exist,
231+ // we'll use an empty string as the sortable value.
232+ Err ( _) => NO_VALUE . to_string ( ) ,
233+ }
234+ }
235+ } else {
236+ atom. sort_value . clone ( )
237+ } ;
238+
239+ update_indexed_member ( self , query_filter, & atom. subject , & sort_val, false ) ?;
240+ Ok ( ( ) )
241+ }
242+
243+ fn get_index_iterator_for_query ( & self , q : & Query ) -> IndexIterator {
244+ match ( & q. property , q. value . as_ref ( ) ) {
245+ ( Some ( prop) , val) => find_in_prop_val_sub_index ( self , prop, val) ,
246+ ( None , None ) => self . all_index_atoms ( q. include_external ) ,
247+ ( None , Some ( val) ) => find_in_val_prop_sub_index ( self , val, None ) ,
248+ }
249+ }
250+
251+ fn query_basic ( & self , q : & Query ) -> AtomicResult < QueryResult > {
252+ let self_url = self
253+ . get_self_url ( )
254+ . ok_or ( "No self_url set, required for Queries" ) ?;
255+
256+ let mut subjects: Vec < String > = vec ! [ ] ;
257+ let mut resources: Vec < Resource > = vec ! [ ] ;
258+ let mut total_count = 0 ;
259+
260+ let atoms = self . get_index_iterator_for_query ( q) ;
261+
262+ for ( i, atom_res) in atoms. enumerate ( ) {
263+ let atom = atom_res?;
264+
265+ if q. offset > i {
266+ continue ;
267+ }
268+
269+ if !q. include_external && !atom. subject . starts_with ( & self_url) {
270+ continue ;
271+ }
272+ if q. limit . is_none ( ) || subjects. len ( ) < q. limit . unwrap ( ) {
273+ if !should_include_resource ( q) {
274+ subjects. push ( atom. subject . clone ( ) ) ;
275+ total_count += 1 ;
276+ continue ;
277+ }
278+
279+ if let Ok ( resource) = self . get_resource_extended ( & atom. subject , true , & q. for_agent )
280+ {
281+ subjects. push ( atom. subject . clone ( ) ) ;
282+ resources. push ( resource) ;
283+ }
284+ }
285+
286+ total_count += 1 ;
287+ }
288+
289+ Ok ( QueryResult {
290+ subjects,
291+ resources,
292+ count : total_count,
293+ } )
294+ }
295+
296+ fn query_complex ( & self , q : & Query ) -> AtomicResult < QueryResult > {
297+ let ( mut subjects, mut resources, mut total_count) = query_sorted_indexed ( self , q) ?;
298+ let q_filter: QueryFilter = q. into ( ) ;
299+
300+ if total_count == 0 && !q_filter. is_watched ( self ) {
301+ info ! ( filter = ?q_filter, "Building query index" ) ;
302+ let atoms = self . get_index_iterator_for_query ( q) ;
303+ q_filter. watch ( self ) ?;
304+
305+ // Build indexes
306+ for atom in atoms. flatten ( ) {
307+ self . build_index_for_atom ( & atom, & q_filter) ?;
308+ }
309+
310+ // Query through the new indexes.
311+ ( subjects, resources, total_count) = query_sorted_indexed ( self , q) ?;
312+ }
313+
314+ Ok ( QueryResult {
315+ subjects,
316+ resources,
317+ count : total_count,
318+ } )
319+ }
212320}
213321
214322impl Storelike for Db {
@@ -468,50 +576,11 @@ impl Storelike for Db {
468576 /// Tries `query_cache`, which you should implement yourself.
469577 #[ instrument( skip( self ) ) ]
470578 fn query ( & self , q : & Query ) -> AtomicResult < QueryResult > {
471- let q_filter: QueryFilter = q. into ( ) ;
472- if let Ok ( res) = query_indexed ( self , q) {
473- if res. count > 0 || q_filter. is_watched ( self ) {
474- // Yay, we have a cache hit!
475- // We don't have to create the indexes, so we can return early.
476- return Ok ( res) ;
477- }
478- }
479-
480- // Maybe make this optional?
481- q_filter. watch ( self ) ?;
482-
483- info ! ( filter = ?q_filter, "Building query index" ) ;
484-
485- let atoms: IndexIterator = match ( & q. property , q. value . as_ref ( ) ) {
486- ( Some ( prop) , val) => find_in_prop_val_sub_index ( self , prop, val) ,
487- ( None , None ) => self . all_index_atoms ( q. include_external ) ,
488- ( None , Some ( val) ) => find_in_val_prop_sub_index ( self , val, None ) ,
489- } ;
490-
491- for a in atoms {
492- let atom = a?;
493- // Get the SortableValue either from the Atom or the Resource.
494- let sort_val: SortableValue = if let Some ( sort) = & q_filter. sort_by {
495- if & atom. property == sort {
496- atom. sort_value
497- } else {
498- // Find the sort value in the store
499- match self . get_value ( & atom. subject , sort) {
500- Ok ( val) => val. to_sortable_string ( ) ,
501- // If we try sorting on a value that does not exist,
502- // we'll use an empty string as the sortable value.
503- Err ( _) => NO_VALUE . to_string ( ) ,
504- }
505- }
506- } else {
507- atom. sort_value
508- } ;
509-
510- update_indexed_member ( self , & q_filter, & atom. subject , & sort_val, false ) ?;
579+ if requires_query_index ( q) {
580+ return self . query_complex ( q) ;
511581 }
512582
513- // Retry the same query!
514- query_indexed ( self , q)
583+ self . query_basic ( q)
515584 }
516585
517586 #[ instrument( skip( self ) ) ]
0 commit comments