Skip to content

Commit 3ce7e1b

Browse files
working, but not optimized
1 parent 804b07e commit 3ce7e1b

File tree

2 files changed

+60
-45
lines changed

2 files changed

+60
-45
lines changed

Magic.IndexedDb/wwwroot/utilities/cursorEngine.js

Lines changed: 56 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -14,19 +14,18 @@ import { rebuildCursorConditionsToPredicateTree } from "./rebuildNestedPredicate
1414
* @returns {Promise<Array>} - Filtered results based on conditions.
1515
*/
1616
export 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
*/

Magic.IndexedDb/wwwroot/utilities/rebuildNestedPredicate.js

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -19,20 +19,13 @@ export function rebuildCursorConditionsToPredicateTree(flattened) {
1919
}))
2020
};
2121

22-
// Step 2: Extract grouped conditions dynamically
23-
let branches = orRoot.children.map(andNode => andNode.children);
24-
const intentGroups = extractDynamicIntentGroups(branches);
22+
// Step 2: Simplify redundant ANDs if possible
23+
const simplified = fixpointSimplify(orRoot);
2524

26-
// Step 3: Rebuild AND of ORs (with sub-ANDs if needed)
27-
const top = {
28-
nodeType: "logical",
29-
operator: "And",
30-
children: intentGroups
31-
};
32-
33-
return fixpointSimplify(top);
25+
return simplified;
3426
}
3527

28+
3629
function extractDynamicIntentGroups(branches) {
3730
const conditionMap = new Map();
3831

0 commit comments

Comments
 (0)