@@ -14,19 +14,18 @@ import { rebuildCursorConditionsToPredicateTree } from "./rebuildNestedPredicate
1414 * @returns {Promise<Array> } - Filtered results based on conditions.
1515 */
1616export async function runCursorQuery ( db , table , conditions , queryAdditions , yieldedPrimaryKeys , compoundKeys ) {
17- var test = rebuildCursorConditionsToPredicateTree ( conditions ) ;
18- debugLog ( test ) ;
19- //t4
20- //debugLog(conditionsoks);
21- debugLog ( "Running Cursor Query with Conditions" , { conditions, queryAdditions } ) ;
17+
18+ const structuredPredicateTree = rebuildCursorConditionsToPredicateTree ( conditions ) ;
19+
20+ debugLog ( "Running Cursor Query with Conditions" , { structuredPredicateTree, queryAdditions } ) ;
2221
2322 const requiresMetaProcessing = queryAdditions . some ( a =>
2423 [ QUERY_ADDITIONS . TAKE , QUERY_ADDITIONS . SKIP , QUERY_ADDITIONS . FIRST , QUERY_ADDITIONS . LAST , QUERY_ADDITIONS . TAKE_LAST ] . includes ( a . additionFunction )
2524 ) ;
2625
2726 if ( requiresMetaProcessing ) {
2827 // **Metadata Path: Extract primary keys and sorting properties**
29- let primaryKeyList = await runMetaDataCursorQuery ( db , table , conditions , queryAdditions , yieldedPrimaryKeys , compoundKeys ) ;
28+ let primaryKeyList = await runMetaDataCursorQuery ( db , table , structuredPredicateTree , queryAdditions , yieldedPrimaryKeys , compoundKeys ) ;
3029
3130 // **Apply sorting, take, and skip operations**
3231 let finalPrimaryKeys = applyCursorQueryAdditions ( primaryKeyList , queryAdditions , compoundKeys ) ;
@@ -38,7 +37,7 @@ export async function runCursorQuery(db, table, conditions, queryAdditions, yiel
3837 return finalRecords ; // Ready for yielding
3938 } else {
4039 // **Direct Retrieval Path: Skip metadata processing & fetch full records immediately**
41- return await runDirectCursorQuery ( db , table , conditions , yieldedPrimaryKeys , compoundKeys ) ;
40+ return await runDirectCursorQuery ( db , table , structuredPredicateTree , yieldedPrimaryKeys , compoundKeys ) ;
4241 }
4342}
4443
@@ -48,54 +47,77 @@ let lastCursorWarningTime = null;
4847 * Generalized cursor processing function for both metadata extraction and direct record retrieval.
4948 * @param {Function } recordHandler - Callback function to process each record.
5049 */
51- async function processCursorRecords ( db , table , conditions , yieldedPrimaryKeys , compoundKeys , recordHandler ) {
50+ async function processCursorRecords ( db , table , predicateTree , yieldedPrimaryKeys , compoundKeys , recordHandler ) {
5251 debugLog ( "Processing Cursor Records" ) ;
5352
54- let now = Date . now ( ) ;
53+ const now = Date . now ( ) ;
5554 let shouldLogWarning = ! lastCursorWarningTime || now - lastCursorWarningTime > 10 * 60 * 1000 ;
56- let optimizedConditions = conditions . map ( optimizeConditions ) ;
57- let requiredPropertiesFiltered = [ ...new Set ( conditions . flatMap ( group => group . map ( c => c . property ) ) ) ] ;
55+
56+ // Dynamically extract all required properties from the predicate tree
57+ const requiredPropertiesFiltered = new Set ( ) ;
58+ collectPropertiesFromTree ( predicateTree , requiredPropertiesFiltered ) ;
5859
5960 await db . transaction ( 'r' , table , async ( ) => {
6061 await table . orderBy ( compoundKeys [ 0 ] ) . each ( ( record ) => {
61- let missingProperties = null ;
62-
63- // **Check for missing required properties**
62+ // Skip if required property is missing
6463 for ( const prop of requiredPropertiesFiltered ) {
6564 if ( record [ prop ] === undefined ) {
66- if ( ! missingProperties ) missingProperties = [ ] ;
67- missingProperties . push ( prop ) ;
68- break ;
69- }
70- }
71-
72- if ( missingProperties ) {
73- if ( shouldLogWarning ) {
74- console . warn ( `[IndexedDB Cursor Warning] Skipping record due to missing properties: ${ missingProperties . join ( ", " ) } ` ) ;
75- lastCursorWarningTime = now ;
76- shouldLogWarning = false ;
65+ if ( shouldLogWarning ) {
66+ console . warn ( `[IndexedDB Cursor Warning] Skipping record due to missing property: ${ prop } ` ) ;
67+ lastCursorWarningTime = now ;
68+ shouldLogWarning = false ;
69+ }
70+ return ;
7771 }
78- return ;
7972 }
8073
81- let recordKey = normalizeCompoundKey ( compoundKeys , record ) ;
82-
74+ const recordKey = normalizeCompoundKey ( compoundKeys , record ) ;
8375 if ( hasYieldedKey ( yieldedPrimaryKeys , recordKey ) ) {
8476 return ;
8577 }
8678
87- // **Apply filtering conditions using early exit**
88- let passesConditions = optimizedConditions . some ( andConditions =>
89- andConditions . every ( condition => applyCondition ( record , condition ) )
90- ) ;
91- if ( ! passesConditions ) return ;
79+ // Evaluate the structured predicate tree
80+ if ( ! evaluatePredicateTree ( predicateTree , record ) ) return ;
9281
93- // **Delegate to the handler (metadata or direct retrieval)**
9482 recordHandler ( record , recordKey ) ;
9583 } ) ;
9684 } ) ;
9785}
9886
87+ function collectPropertiesFromTree ( node , propertySet ) {
88+ if ( node . nodeType === "condition" ) {
89+ propertySet . add ( node . condition . property ) ;
90+ return ;
91+ }
92+ for ( const child of node . children ) {
93+ collectPropertiesFromTree ( child , propertySet ) ;
94+ }
95+ }
96+
97+ function evaluatePredicateTree ( node , record ) {
98+ if ( node . nodeType === "condition" ) {
99+ const condition = optimizeSingleCondition ( node . condition ) ;
100+ return applyCondition ( record , condition ) ;
101+ }
102+
103+ const results = node . children . map ( child => evaluatePredicateTree ( child , record ) ) ;
104+ return node . operator === "And"
105+ ? results . every ( r => r )
106+ : results . some ( r => r ) ;
107+ }
108+
109+ function optimizeSingleCondition ( condition ) {
110+ let optimized = { ...condition } ;
111+
112+ if ( ! condition . caseSensitive && typeof condition . value === "string" ) {
113+ optimized . value = condition . value . toLowerCase ( ) ;
114+ }
115+
116+ optimized . comparisonFunction = getComparisonFunction ( condition . operation ) ;
117+ return optimized ;
118+ }
119+
120+
99121/**
100122 * Directly retrieves records that match the conditions without metadata processing.
101123 */
0 commit comments