refactor(8.0): remove the 4 deprecated query-operator aliases (clean break)

8.0 keeps the canonical operators (eq/ne/gt/gte/lt/lte) and their clean
long-form aliases (equals/notEquals/greaterThan/greaterThanOrEqual/lessThan/
lessThanOrEqual), and drops the four redundant deprecated spellings:
  is → eq,  isNot → ne,  greaterEqual → gte,  lessEqual → lte

Removed from every evaluator (metadataIndex criteria + range switches,
metadataFilter, the db whereMatcher egress path) and from the
BrainyFieldOperators type, the unsupported-operator error message, the docs
(QUERY_OPERATORS / api README / VFS projection + semantic guides), and the
whereMatcher alias tests. Also migrated Brainy's own internal use — the VFS
TemporalProjection queried with greaterEqual/lessEqual, which would have
silently broken — to gte/lte.

Full gate green: build, unit 1512, integration 607.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
David Snelling 2026-06-29 10:29:20 -07:00
parent b9369f260b
commit ddcc0c723d
9 changed files with 45 additions and 68 deletions

View file

@ -39,9 +39,9 @@ export class UnsupportedWhereOperatorError extends Error {
constructor(operator: string) {
super(
`The where-operator '${operator}' is not supported for historical/speculative ` +
`in-memory evaluation. Supported: eq/equals/is, ne/notEquals/isNot, in/oneOf, ` +
`gt/greaterThan, gte/greaterThanOrEqual/greaterEqual, lt/lessThan, ` +
`lte/lessThanOrEqual/lessEqual, between, contains, exists, missing, ` +
`in-memory evaluation. Supported: eq/equals, ne/notEquals, in/oneOf, ` +
`gt/greaterThan, gte/greaterThanOrEqual, lt/lessThan, ` +
`lte/lessThanOrEqual, between, contains, exists, missing, ` +
`plus allOf/anyOf/not.`
)
this.name = 'UnsupportedWhereOperatorError'
@ -150,12 +150,10 @@ function fieldConditionMatches(value: unknown, condition: unknown): boolean {
for (const [op, operand] of Object.entries(condition as Record<string, unknown>)) {
let matches: boolean
switch (op) {
case 'is':
case 'equals':
case 'eq':
matches = eqMatches(value, operand)
break
case 'isNot':
case 'notEquals':
case 'ne':
matches = !eqMatches(value, operand)
@ -170,7 +168,6 @@ function fieldConditionMatches(value: unknown, condition: unknown): boolean {
matches = cmp !== null && cmp > 0
break
}
case 'greaterEqual':
case 'greaterThanOrEqual':
case 'gte': {
const cmp = compare(value, operand)
@ -183,7 +180,6 @@ function fieldConditionMatches(value: unknown, condition: unknown): boolean {
matches = cmp !== null && cmp < 0
break
}
case 'lessEqual':
case 'lessThanOrEqual':
case 'lte': {
const cmp = compare(value, operand)

View file

@ -11,17 +11,21 @@ import { SearchResult, HNSWNoun, HNSWNounWithMetadata } from '../coreTypes.js'
* Designed for performance, clarity, and patent independence
*/
export interface BrainyFieldOperators {
// Equality operators
// Equality operators (canonical + long-form aliases)
eq?: any
equals?: any
ne?: any
notEquals?: any
is?: any
isNot?: any
// Comparison operators
// Comparison operators (canonical + long-form aliases)
greaterThan?: any
greaterEqual?: any
gt?: any
greaterThanOrEqual?: any
gte?: any
lessThan?: any
lessEqual?: any
lt?: any
lessThanOrEqual?: any
lte?: any
between?: [any, any]
// Array/Set operators
@ -45,14 +49,6 @@ export interface BrainyFieldOperators {
allOf?: MetadataFilter[]
anyOf?: MetadataFilter[]
not?: MetadataFilter
// Short aliases for common operations
eq?: any
ne?: any
gt?: any
gte?: any
lt?: any
lte?: any
}
/**
@ -88,12 +84,10 @@ function matchesQuery(value: any, query: any): boolean {
switch (op) {
// Equality operators
case 'equals':
case 'is':
case 'eq':
if (value !== operand) return false
break
case 'notEquals':
case 'isNot':
case 'ne':
// Special handling: if value is undefined and operand is not undefined,
// they are not equal (so the condition passes)
@ -108,7 +102,6 @@ function matchesQuery(value: any, query: any): boolean {
case 'gt':
if (typeof value !== 'number' || typeof operand !== 'number' || !(value > operand)) return false
break
case 'greaterEqual':
case 'gte':
if (typeof value !== 'number' || typeof operand !== 'number' || !(value >= operand)) return false
break
@ -116,7 +109,6 @@ function matchesQuery(value: any, query: any): boolean {
case 'lt':
if (typeof value !== 'number' || typeof operand !== 'number' || !(value < operand)) return false
break
case 'lessEqual':
case 'lte':
if (typeof value !== 'number' || typeof operand !== 'number' || !(value <= operand)) return false
break

View file

@ -1760,7 +1760,6 @@ export class MetadataIndexManager implements MetadataIndexProvider {
}
break
case 'equals':
case 'is':
case 'eq':
criteria.push({ field: key, values: [operand] })
break
@ -1770,8 +1769,6 @@ export class MetadataIndexManager implements MetadataIndexProvider {
break
case 'greaterThan':
case 'lessThan':
case 'greaterEqual':
case 'lessEqual':
case 'between':
// Range queries will be handled separately
// Sorted index will be created/loaded when needed in getIdsForRange
@ -1881,16 +1878,14 @@ export class MetadataIndexManager implements MetadataIndexProvider {
fieldResults = []
switch (op) {
// ===== EQUALITY OPERATORS =====
// Canonical: 'eq' | Alias: 'equals' | Deprecated: 'is'
case 'is': // DEPRECATED: Use 'eq' instead
// Canonical: 'eq' | Alias: 'equals'
case 'equals': // Alias for 'eq'
case 'eq':
fieldResults = await this.getIds(field, operand)
break
// ===== NEGATION OPERATORS =====
// Canonical: 'ne' | Alias: 'notEquals' | Deprecated: 'isNot'
case 'isNot': // DEPRECATED: Use 'ne' instead
// Canonical: 'ne' | Alias: 'notEquals'
case 'notEquals': // Alias for 'ne'
case 'ne': {
// For notEquals, we need all IDs EXCEPT those matching the value
@ -1931,8 +1926,7 @@ export class MetadataIndexManager implements MetadataIndexProvider {
break
// ===== GREATER THAN OR EQUAL OPERATORS =====
// Canonical: 'gte' | Alias: 'greaterThanOrEqual' | Deprecated: 'greaterEqual'
case 'greaterEqual': // DEPRECATED: Use 'gte' instead
// Canonical: 'gte' | Alias: 'greaterThanOrEqual'
case 'greaterThanOrEqual': // Alias for 'gte'
case 'gte':
fieldResults = await this.getIdsForRange(field, operand, undefined, true, true)
@ -1946,8 +1940,7 @@ export class MetadataIndexManager implements MetadataIndexProvider {
break
// ===== LESS THAN OR EQUAL OPERATORS =====
// Canonical: 'lte' | Alias: 'lessThanOrEqual' | Deprecated: 'lessEqual'
case 'lessEqual': // DEPRECATED: Use 'lte' instead
// Canonical: 'lte' | Alias: 'lessThanOrEqual'
case 'lessThanOrEqual': // Alias for 'lte'
case 'lte':
fieldResults = await this.getIdsForRange(field, undefined, operand, true, true)

View file

@ -37,8 +37,8 @@ export class TemporalProjection extends BaseProjectionStrategy {
where: {
vfsType: 'file',
modified: {
greaterEqual: startOfDay.getTime(), // BFO operator
lessEqual: endOfDay.getTime() // BFO operator
gte: startOfDay.getTime(), // BFO operator
lte: endOfDay.getTime() // BFO operator
}
},
limit: 1000
@ -74,8 +74,8 @@ export class TemporalProjection extends BaseProjectionStrategy {
where: {
vfsType: 'file',
modified: {
greaterEqual: startOfDay.getTime(),
lessEqual: endOfDay.getTime()
gte: startOfDay.getTime(),
lte: endOfDay.getTime()
}
},
limit: 1000
@ -93,7 +93,7 @@ export class TemporalProjection extends BaseProjectionStrategy {
const results = await brain.find({
where: {
vfsType: 'file',
modified: { greaterEqual: oneDayAgo }
modified: { gte: oneDayAgo }
},
limit
})