Skip to content

Commit f9d110b

Browse files
committed
Remove unused predicate helper functions
1 parent 54c152c commit f9d110b

File tree

3 files changed

+0
-700
lines changed

3 files changed

+0
-700
lines changed

packages/db/src/query/index.ts

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,14 +61,11 @@ export { type LiveQueryCollectionUtils } from "./live/collection-config-builder.
6161
// Predicate utilities for predicate push-down
6262
export {
6363
isWhereSubset,
64-
intersectWherePredicates,
6564
unionWherePredicates,
6665
minusWherePredicates,
6766
isOrderBySubset,
6867
isLimitSubset,
6968
isPredicateSubset,
70-
intersectPredicates,
71-
unionPredicates,
7269
} from "./predicate-utils.js"
7370

7471
export { DeduplicatedLoadSubset } from "./subset-dedupe.js"

packages/db/src/query/predicate-utils.ts

Lines changed: 0 additions & 320 deletions
Original file line numberDiff line numberDiff line change
@@ -231,34 +231,6 @@ function combineWherePredicates(
231231
} as BasicExpression<boolean>
232232
}
233233

234-
/**
235-
* Combine multiple where predicates with AND logic (intersection).
236-
* Returns a predicate that is satisfied only when all input predicates are satisfied.
237-
* Simplifies when possible (e.g., age > 10 AND age > 20 → age > 20).
238-
* Returns a false literal if predicates are contradictory (empty set).
239-
*
240-
* @example
241-
* // Take most restrictive
242-
* intersectWherePredicates([gt(ref('age'), val(10)), gt(ref('age'), val(20))]) // age > 20
243-
*
244-
* @example
245-
* // Different fields combine with AND
246-
* intersectWherePredicates([gt(ref('age'), val(10)), eq(ref('status'), val('active'))])
247-
* // age > 10 AND status = 'active'
248-
*
249-
* @example
250-
* // Contradictory predicates return false
251-
* intersectWherePredicates([eq(ref('age'), val(5)), eq(ref('age'), val(6))])
252-
* // {type: 'val', value: false}
253-
*
254-
* @param predicates - Array of where predicates to intersect
255-
* @returns Combined predicate representing the intersection, or false literal for empty set
256-
*/
257-
export function intersectWherePredicates(
258-
predicates: Array<BasicExpression<boolean>>
259-
): BasicExpression<boolean> {
260-
return combineWherePredicates(predicates, `and`, intersectSameFieldPredicates)
261-
}
262234

263235
/**
264236
* Combine multiple where predicates with OR logic (union).
@@ -783,84 +755,7 @@ export function isPredicateSubset(
783755
)
784756
}
785757

786-
/**
787-
* Helper to combine predicates (where + orderBy + limit)
788-
*/
789-
function combinePredicates(
790-
predicates: Array<LoadSubsetOptions>,
791-
operation: `intersect` | `union`,
792-
whereFn: (
793-
clauses: Array<BasicExpression<boolean>>
794-
) => BasicExpression<boolean>
795-
): LoadSubsetOptions {
796-
if (predicates.length === 0) {
797-
return {}
798-
}
799-
800-
if (predicates.length === 1) {
801-
return predicates[0]!
802-
}
803-
804-
// Combine where clauses
805-
const whereClauses = predicates
806-
.map((p) => p.where)
807-
.filter((w): w is BasicExpression<boolean> => w !== undefined)
808-
809-
const mergedWhere =
810-
whereClauses.length > 0 ? whereFn(whereClauses) : undefined
811-
812-
// OrderBy logic differs by operation
813-
const mergedOrderBy =
814-
operation === `intersect`
815-
? predicates.find((p) => p.orderBy && p.orderBy.length > 0)?.orderBy
816-
: undefined // Union: different orderings can't be combined
817-
818-
// Limit logic
819-
const limits = predicates
820-
.map((p) => p.limit)
821-
.filter((l): l is number => l !== undefined)
822-
823-
const mergedLimit =
824-
operation === `intersect`
825-
? limits.length === 0
826-
? undefined
827-
: Math.min(...limits) // All unlimited = unlimited, else min
828-
: limits.length === predicates.length && limits.length > 0
829-
? Math.min(...limits)
830-
: undefined // Min only if all have limits
831-
832-
return {
833-
where: mergedWhere,
834-
orderBy: mergedOrderBy,
835-
limit: mergedLimit,
836-
}
837-
}
838-
839-
/**
840-
* Merge multiple predicates by intersecting their where clauses.
841-
* Intersection semantics: returns predicate satisfied by data matching ALL input predicates.
842-
* For limits, this means the MINIMUM (most restrictive) limit.
843-
*
844-
* @param predicates - Array of predicates to merge
845-
* @returns Combined predicate representing the intersection
846-
*/
847-
export function intersectPredicates(
848-
predicates: Array<LoadSubsetOptions>
849-
): LoadSubsetOptions {
850-
return combinePredicates(predicates, `intersect`, intersectWherePredicates)
851-
}
852758

853-
/**
854-
* Merge multiple predicates by unioning their where clauses.
855-
*
856-
* @param predicates - Array of predicates to merge
857-
* @returns Combined predicate
858-
*/
859-
export function unionPredicates(
860-
predicates: Array<LoadSubsetOptions>
861-
): LoadSubsetOptions {
862-
return combinePredicates(predicates, `union`, unionWherePredicates)
863-
}
864759

865760
// ============================================================================
866761
// Helper functions
@@ -1107,25 +1002,6 @@ function arrayIncludesWithSet(
11071002
return array.some((v) => areValuesEqual(v, value))
11081003
}
11091004

1110-
/**
1111-
* Intersect two arrays, with optional pre-built Set for optimization.
1112-
* The set2 is cached in InField during extraction and reused for all operations.
1113-
*/
1114-
function intersectArraysWithSet(
1115-
arr1: Array<any>,
1116-
arr2: Array<any>,
1117-
set2: Set<any> | null
1118-
): Array<any> {
1119-
// Fast path: use pre-built Set for O(n) intersection
1120-
if (set2) {
1121-
// If set2 exists, arr2 contains ONLY primitives (that's when we build the Set).
1122-
// So we can skip non-primitives in arr1 immediately - they can't be in arr2.
1123-
return arr1.filter((v) => isPrimitive(v) && set2.has(v))
1124-
}
1125-
1126-
// Fallback: use areValuesEqual for all comparisons
1127-
return arr1.filter((v) => arr2.some((v2) => areValuesEqual(v, v2)))
1128-
}
11291005

11301006
/**
11311007
* Get the maximum of two values, handling both numbers and Dates
@@ -1334,202 +1210,6 @@ function groupPredicatesByField(
13341210
return groups
13351211
}
13361212

1337-
function intersectSameFieldPredicates(
1338-
predicates: Array<BasicExpression<boolean>>
1339-
): BasicExpression<boolean> {
1340-
if (predicates.length === 1) {
1341-
return predicates[0]!
1342-
}
1343-
1344-
// Try to extract range constraints
1345-
let minGt: number | null = null
1346-
let minGte: number | null = null
1347-
let maxLt: number | null = null
1348-
let maxLte: number | null = null
1349-
const eqValues: Set<any> = new Set()
1350-
const inFields: Array<InField> = [] // Store full InField objects to access cached data
1351-
const otherPredicates: Array<BasicExpression<boolean>> = []
1352-
1353-
for (const pred of predicates) {
1354-
if (pred.type === `func`) {
1355-
const func = pred as Func
1356-
const field = extractComparisonField(func)
1357-
1358-
if (field) {
1359-
const value = field.value
1360-
if (func.name === `gt`) {
1361-
minGt = minGt === null ? value : maxValue(minGt, value)
1362-
} else if (func.name === `gte`) {
1363-
minGte = minGte === null ? value : maxValue(minGte, value)
1364-
} else if (func.name === `lt`) {
1365-
maxLt = maxLt === null ? value : minValue(maxLt, value)
1366-
} else if (func.name === `lte`) {
1367-
maxLte = maxLte === null ? value : minValue(maxLte, value)
1368-
} else if (func.name === `eq`) {
1369-
eqValues.add(value)
1370-
} else {
1371-
otherPredicates.push(pred)
1372-
}
1373-
} else {
1374-
const inField = extractInField(func)
1375-
if (inField) {
1376-
inFields.push(inField) // Store full InField with cached primitiveSet
1377-
} else {
1378-
otherPredicates.push(pred)
1379-
}
1380-
}
1381-
} else {
1382-
otherPredicates.push(pred)
1383-
}
1384-
}
1385-
1386-
// Check for conflicting equality values (field = 5 AND field = 6 → empty set)
1387-
// Need to use areValuesEqual for proper Date/object comparison
1388-
const uniqueEqValues: Array<any> = []
1389-
for (const value of eqValues) {
1390-
if (!uniqueEqValues.some((v) => areValuesEqual(v, value))) {
1391-
uniqueEqValues.push(value)
1392-
}
1393-
}
1394-
if (uniqueEqValues.length > 1) {
1395-
return { type: `val`, value: false } as BasicExpression<boolean>
1396-
}
1397-
1398-
// If we have an equality, that's the most restrictive
1399-
const eqValue = uniqueEqValues.length === 1 ? uniqueEqValues[0] : null
1400-
if (eqValue !== null) {
1401-
// Check if it satisfies the range constraints
1402-
if (minGt !== null && !(eqValue > minGt)) {
1403-
return { type: `val`, value: false } as BasicExpression<boolean>
1404-
}
1405-
if (minGte !== null && !(eqValue >= minGte)) {
1406-
return { type: `val`, value: false } as BasicExpression<boolean>
1407-
}
1408-
if (maxLt !== null && !(eqValue < maxLt)) {
1409-
return { type: `val`, value: false } as BasicExpression<boolean>
1410-
}
1411-
if (maxLte !== null && !(eqValue <= maxLte)) {
1412-
return { type: `val`, value: false } as BasicExpression<boolean>
1413-
}
1414-
1415-
// Check if it's in all IN sets (use cached primitive sets and metadata)
1416-
for (const inField of inFields) {
1417-
if (
1418-
!arrayIncludesWithSet(
1419-
inField.values,
1420-
eqValue,
1421-
inField.primitiveSet ?? null,
1422-
inField.areAllPrimitives
1423-
)
1424-
) {
1425-
return { type: `val`, value: false } as BasicExpression<boolean>
1426-
}
1427-
}
1428-
1429-
// Return just the equality (use areValuesEqual for Date support)
1430-
return predicates.find((p) => {
1431-
if (p.type === `func`) {
1432-
const f = p as Func
1433-
const field = extractComparisonField(f)
1434-
return f.name === `eq` && field && areValuesEqual(field.value, eqValue)
1435-
}
1436-
return false
1437-
})!
1438-
}
1439-
1440-
// Handle intersection of multiple IN clauses (use cached primitive sets)
1441-
let intersectedInValues: Array<any> | null = null
1442-
if (inFields.length > 0) {
1443-
// All primitive sets already cached in inFields from extraction
1444-
intersectedInValues = [...inFields[0]!.values]
1445-
for (let i = 1; i < inFields.length; i++) {
1446-
const currentField = inFields[i]!
1447-
intersectedInValues = intersectArraysWithSet(
1448-
intersectedInValues,
1449-
currentField.values,
1450-
currentField.primitiveSet ?? null
1451-
)
1452-
// Early exit if intersection becomes empty
1453-
if (intersectedInValues.length === 0) {
1454-
return { type: `val`, value: false } as BasicExpression<boolean>
1455-
}
1456-
}
1457-
}
1458-
1459-
// Build the most restrictive range
1460-
const result: Array<BasicExpression<boolean>> = []
1461-
1462-
// Choose the most restrictive lower bound
1463-
if (minGt !== null && minGte !== null) {
1464-
// If we have both > and >=, use > if it's more restrictive
1465-
const pred =
1466-
minGt >= minGte
1467-
? findPredicateWithOperator(predicates, `gt`, minGt)
1468-
: findPredicateWithOperator(predicates, `gte`, minGte)
1469-
if (pred) result.push(pred)
1470-
} else if (minGt !== null) {
1471-
const pred = findPredicateWithOperator(predicates, `gt`, minGt)
1472-
if (pred) result.push(pred)
1473-
} else if (minGte !== null) {
1474-
const pred = findPredicateWithOperator(predicates, `gte`, minGte)
1475-
if (pred) result.push(pred)
1476-
}
1477-
1478-
// Choose the most restrictive upper bound
1479-
if (maxLt !== null && maxLte !== null) {
1480-
const pred =
1481-
maxLt <= maxLte
1482-
? findPredicateWithOperator(predicates, `lt`, maxLt)
1483-
: findPredicateWithOperator(predicates, `lte`, maxLte)
1484-
if (pred) result.push(pred)
1485-
} else if (maxLt !== null) {
1486-
const pred = findPredicateWithOperator(predicates, `lt`, maxLt)
1487-
if (pred) result.push(pred)
1488-
} else if (maxLte !== null) {
1489-
const pred = findPredicateWithOperator(predicates, `lte`, maxLte)
1490-
if (pred) result.push(pred)
1491-
}
1492-
1493-
// Add intersected IN values if present
1494-
if (intersectedInValues !== null && intersectedInValues.length > 0) {
1495-
// Get the ref from one of the original IN predicates
1496-
const firstInPred = predicates.find((p) => {
1497-
if (p.type === `func`) {
1498-
return (p as Func).name === `in`
1499-
}
1500-
return false
1501-
})
1502-
1503-
if (firstInPred && firstInPred.type === `func`) {
1504-
const ref = (firstInPred as Func).args[0]
1505-
result.push({
1506-
type: `func`,
1507-
name: `in`,
1508-
args: [
1509-
ref,
1510-
{ type: `val`, value: intersectedInValues } as BasicExpression,
1511-
],
1512-
} as BasicExpression<boolean>)
1513-
}
1514-
}
1515-
1516-
// Add other predicates
1517-
result.push(...otherPredicates)
1518-
1519-
if (result.length === 0) {
1520-
return { type: `val`, value: true } as BasicExpression<boolean>
1521-
}
1522-
1523-
if (result.length === 1) {
1524-
return result[0]!
1525-
}
1526-
1527-
return {
1528-
type: `func`,
1529-
name: `and`,
1530-
args: result,
1531-
} as BasicExpression<boolean>
1532-
}
15331213

15341214
function unionSameFieldPredicates(
15351215
predicates: Array<BasicExpression<boolean>>

0 commit comments

Comments
 (0)