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:
parent
b9369f260b
commit
ddcc0c723d
9 changed files with 45 additions and 68 deletions
|
|
@ -10,8 +10,8 @@ All operators work with `find({ where: { ... } })` and filter on **metadata fiel
|
||||||
|
|
||||||
| Operator | Alias | Description | Example |
|
| Operator | Alias | Description | Example |
|
||||||
|----------|-------|-------------|---------|
|
|----------|-------|-------------|---------|
|
||||||
| `equals` | `eq`, `is` | Exact match | `{ status: { equals: 'active' } }` |
|
| `eq` | `equals` | Exact match | `{ status: { eq: 'active' } }` |
|
||||||
| `notEquals` | `ne`, `isNot` | Not equal | `{ status: { notEquals: 'deleted' } }` |
|
| `ne` | `notEquals` | Not equal | `{ status: { ne: 'deleted' } }` |
|
||||||
|
|
||||||
**Shorthand:** A bare value is treated as `equals`:
|
**Shorthand:** A bare value is treated as `equals`:
|
||||||
|
|
||||||
|
|
@ -27,10 +27,10 @@ brain.find({ where: { status: { equals: 'active' } } })
|
||||||
|
|
||||||
| Operator | Alias | Description | Example |
|
| Operator | Alias | Description | Example |
|
||||||
|----------|-------|-------------|---------|
|
|----------|-------|-------------|---------|
|
||||||
| `greaterThan` | `gt` | Greater than | `{ age: { greaterThan: 18 } }` |
|
| `gt` | `greaterThan` | Greater than | `{ age: { gt: 18 } }` |
|
||||||
| `greaterEqual` | `gte` | Greater or equal | `{ score: { greaterEqual: 90 } }` |
|
| `gte` | `greaterThanOrEqual` | Greater or equal | `{ score: { gte: 90 } }` |
|
||||||
| `lessThan` | `lt` | Less than | `{ price: { lessThan: 100 } }` |
|
| `lt` | `lessThan` | Less than | `{ price: { lt: 100 } }` |
|
||||||
| `lessEqual` | `lte` | Less or equal | `{ rating: { lessEqual: 3 } }` |
|
| `lte` | `lessThanOrEqual` | Less or equal | `{ rating: { lte: 3 } }` |
|
||||||
| `between` | — | Inclusive range `[min, max]` | `{ year: { between: [2020, 2025] } }` |
|
| `between` | — | Inclusive range `[min, max]` | `{ year: { between: [2020, 2025] } }` |
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
|
|
@ -160,9 +160,9 @@ Brainy's MetadataIndex supports a subset of operators natively for O(1) field lo
|
||||||
| `equals` / `eq` | Yes | Yes |
|
| `equals` / `eq` | Yes | Yes |
|
||||||
| `notEquals` / `ne` | — | Yes |
|
| `notEquals` / `ne` | — | Yes |
|
||||||
| `greaterThan` / `gt` | Yes | Yes |
|
| `greaterThan` / `gt` | Yes | Yes |
|
||||||
| `greaterEqual` / `gte` | Yes | Yes |
|
| `greaterThanOrEqual` / `gte` | Yes | Yes |
|
||||||
| `lessThan` / `lt` | Yes | Yes |
|
| `lessThan` / `lt` | Yes | Yes |
|
||||||
| `lessEqual` / `lte` | Yes | Yes |
|
| `lessThanOrEqual` / `lte` | Yes | Yes |
|
||||||
| `between` | Yes | Yes |
|
| `between` | Yes | Yes |
|
||||||
| `oneOf` / `in` | Yes | Yes |
|
| `oneOf` / `in` | Yes | Yes |
|
||||||
| `noneOf` | — | Yes |
|
| `noneOf` | — | Yes |
|
||||||
|
|
|
||||||
|
|
@ -413,9 +413,9 @@ Brainy uses clean, readable operators (BFO — Brainy Field Operators):
|
||||||
| `equals` / `eq` | Exact match | `{age: {equals: 25}}` |
|
| `equals` / `eq` | Exact match | `{age: {equals: 25}}` |
|
||||||
| `notEquals` / `ne` | Not equal | `{status: {notEquals: 'deleted'}}` |
|
| `notEquals` / `ne` | Not equal | `{status: {notEquals: 'deleted'}}` |
|
||||||
| `greaterThan` / `gt` | Greater than | `{age: {greaterThan: 18}}` |
|
| `greaterThan` / `gt` | Greater than | `{age: {greaterThan: 18}}` |
|
||||||
| `greaterEqual` / `gte` | Greater or equal | `{score: {greaterEqual: 90}}` |
|
| `gte` / `greaterThanOrEqual` | Greater or equal | `{score: {gte: 90}}` |
|
||||||
| `lessThan` / `lt` | Less than | `{price: {lessThan: 100}}` |
|
| `lessThan` / `lt` | Less than | `{price: {lessThan: 100}}` |
|
||||||
| `lessEqual` / `lte` | Less or equal | `{rating: {lessEqual: 3}}` |
|
| `lte` / `lessThanOrEqual` | Less or equal | `{rating: {lte: 3}}` |
|
||||||
| `between` | Inclusive range | `{year: {between: [2020, 2025]}}` |
|
| `between` | Inclusive range | `{year: {between: [2020, 2025]}}` |
|
||||||
| `oneOf` / `in` | In array | `{color: {oneOf: ['red', 'blue']}}` |
|
| `oneOf` / `in` | In array | `{color: {oneOf: ['red', 'blue']}}` |
|
||||||
| `noneOf` | Not in array | `{status: {noneOf: ['deleted']}}` |
|
| `noneOf` | Not in array | `{status: {noneOf: ['deleted']}}` |
|
||||||
|
|
|
||||||
|
|
@ -289,7 +289,7 @@ export class SizeProjection extends BaseProjectionStrategy {
|
||||||
where: {
|
where: {
|
||||||
vfsType: 'file',
|
vfsType: 'file',
|
||||||
size: {
|
size: {
|
||||||
greaterEqual: min,
|
gte: min,
|
||||||
lessThan: max
|
lessThan: max
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
@ -305,7 +305,7 @@ export class SizeProjection extends BaseProjectionStrategy {
|
||||||
where: {
|
where: {
|
||||||
vfsType: 'file',
|
vfsType: 'file',
|
||||||
size: {
|
size: {
|
||||||
greaterEqual: min,
|
gte: min,
|
||||||
lessThan: max
|
lessThan: max
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
@ -359,7 +359,7 @@ export class StatusProjection extends BaseProjectionStrategy {
|
||||||
const results = await brain.find({
|
const results = await brain.find({
|
||||||
where: {
|
where: {
|
||||||
vfsType: 'file',
|
vfsType: 'file',
|
||||||
modified: { greaterEqual: oneDayAgo },
|
modified: { gte: oneDayAgo },
|
||||||
reviewStatus: { missing: true } // No review status set
|
reviewStatus: { missing: true } // No review status set
|
||||||
},
|
},
|
||||||
limit: 1000
|
limit: 1000
|
||||||
|
|
@ -387,7 +387,7 @@ export class StatusProjection extends BaseProjectionStrategy {
|
||||||
vfsType: 'file',
|
vfsType: 'file',
|
||||||
anyOf: [
|
anyOf: [
|
||||||
{ reviewStatus: { exists: true } },
|
{ reviewStatus: { exists: true } },
|
||||||
{ modified: { greaterEqual: Date.now() - 86400000 } }
|
{ modified: { gte: Date.now() - 86400000 } }
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
limit
|
limit
|
||||||
|
|
@ -415,7 +415,7 @@ Projection strategies use **Brainy Field Operators** (BFO), not MongoDB-style op
|
||||||
{ size: { $gte: 1000, $lte: 5000 } }
|
{ size: { $gte: 1000, $lte: 5000 } }
|
||||||
|
|
||||||
// ✅ BFO style (CORRECT)
|
// ✅ BFO style (CORRECT)
|
||||||
{ size: { greaterEqual: 1000, lessEqual: 5000 } }
|
{ size: { gte: 1000, lte: 5000 } }
|
||||||
```
|
```
|
||||||
|
|
||||||
### Logical Operators
|
### Logical Operators
|
||||||
|
|
@ -451,9 +451,9 @@ Projection strategies use **Brainy Field Operators** (BFO), not MongoDB-style op
|
||||||
// Comparison
|
// Comparison
|
||||||
{ field: value } // Exact match
|
{ field: value } // Exact match
|
||||||
{ field: { greaterThan: 10 } } // >
|
{ field: { greaterThan: 10 } } // >
|
||||||
{ field: { greaterEqual: 10 } } // >=
|
{ field: { gte: 10 } } // >=
|
||||||
{ field: { lessThan: 10 } } // <
|
{ field: { lessThan: 10 } } // <
|
||||||
{ field: { lessEqual: 10 } } // <=
|
{ field: { lte: 10 } } // <=
|
||||||
{ field: { not: value } } // !=
|
{ field: { not: value } } // !=
|
||||||
|
|
||||||
// Logical
|
// Logical
|
||||||
|
|
@ -485,7 +485,7 @@ All metadata fields are automatically indexed. Use direct equality or range quer
|
||||||
```typescript
|
```typescript
|
||||||
// ✅ Fast: Direct index lookup (O(log n))
|
// ✅ Fast: Direct index lookup (O(log n))
|
||||||
{ priority: 'high' }
|
{ priority: 'high' }
|
||||||
{ size: { greaterEqual: 1000 } }
|
{ size: { gte: 1000 } }
|
||||||
|
|
||||||
// ⚠️ Slower: Must scan results
|
// ⚠️ Slower: Must scan results
|
||||||
{ path: { matches: /complex-regex/ } }
|
{ path: { matches: /complex-regex/ } }
|
||||||
|
|
@ -668,7 +668,7 @@ async resolve(brain, vfs, period: string) {
|
||||||
|
|
||||||
const results = await brain.find({
|
const results = await brain.find({
|
||||||
where: {
|
where: {
|
||||||
modified: { greaterEqual: since }
|
modified: { gte: since }
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
return this.extractIds(results)
|
return this.extractIds(results)
|
||||||
|
|
|
||||||
|
|
@ -127,7 +127,7 @@ await vfs.readFile('/as-of/2024-03-15/auth.ts')
|
||||||
// the path only resolves if auth.ts was modified that day
|
// the path only resolves if auth.ts was modified that day
|
||||||
```
|
```
|
||||||
|
|
||||||
**How it works:** Tracks the `modified` timestamp on every file and runs a range query (`greaterEqual`/`lessEqual`) over one 24-hour window for O(log n) performance. The VFS does not store historical file contents — `/as-of/` filters by *when a file last changed*; reads return the current bytes. For point-in-time state, use the Db API (`brain.asOf(generation)`).
|
**How it works:** Tracks the `modified` timestamp on every file and runs a range query (`gte`/`lte`) over one 24-hour window for O(log n) performance. The VFS does not store historical file contents — `/as-of/` filters by *when a file last changed*; reads return the current bytes. For point-in-time state, use the Db API (`brain.asOf(generation)`).
|
||||||
|
|
||||||
**Status:** ✅ Fully implemented and tested at 10K file scale
|
**Status:** ✅ Fully implemented and tested at 10K file scale
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -39,9 +39,9 @@ export class UnsupportedWhereOperatorError extends Error {
|
||||||
constructor(operator: string) {
|
constructor(operator: string) {
|
||||||
super(
|
super(
|
||||||
`The where-operator '${operator}' is not supported for historical/speculative ` +
|
`The where-operator '${operator}' is not supported for historical/speculative ` +
|
||||||
`in-memory evaluation. Supported: eq/equals/is, ne/notEquals/isNot, in/oneOf, ` +
|
`in-memory evaluation. Supported: eq/equals, ne/notEquals, in/oneOf, ` +
|
||||||
`gt/greaterThan, gte/greaterThanOrEqual/greaterEqual, lt/lessThan, ` +
|
`gt/greaterThan, gte/greaterThanOrEqual, lt/lessThan, ` +
|
||||||
`lte/lessThanOrEqual/lessEqual, between, contains, exists, missing, ` +
|
`lte/lessThanOrEqual, between, contains, exists, missing, ` +
|
||||||
`plus allOf/anyOf/not.`
|
`plus allOf/anyOf/not.`
|
||||||
)
|
)
|
||||||
this.name = 'UnsupportedWhereOperatorError'
|
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>)) {
|
for (const [op, operand] of Object.entries(condition as Record<string, unknown>)) {
|
||||||
let matches: boolean
|
let matches: boolean
|
||||||
switch (op) {
|
switch (op) {
|
||||||
case 'is':
|
|
||||||
case 'equals':
|
case 'equals':
|
||||||
case 'eq':
|
case 'eq':
|
||||||
matches = eqMatches(value, operand)
|
matches = eqMatches(value, operand)
|
||||||
break
|
break
|
||||||
case 'isNot':
|
|
||||||
case 'notEquals':
|
case 'notEquals':
|
||||||
case 'ne':
|
case 'ne':
|
||||||
matches = !eqMatches(value, operand)
|
matches = !eqMatches(value, operand)
|
||||||
|
|
@ -170,7 +168,6 @@ function fieldConditionMatches(value: unknown, condition: unknown): boolean {
|
||||||
matches = cmp !== null && cmp > 0
|
matches = cmp !== null && cmp > 0
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
case 'greaterEqual':
|
|
||||||
case 'greaterThanOrEqual':
|
case 'greaterThanOrEqual':
|
||||||
case 'gte': {
|
case 'gte': {
|
||||||
const cmp = compare(value, operand)
|
const cmp = compare(value, operand)
|
||||||
|
|
@ -183,7 +180,6 @@ function fieldConditionMatches(value: unknown, condition: unknown): boolean {
|
||||||
matches = cmp !== null && cmp < 0
|
matches = cmp !== null && cmp < 0
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
case 'lessEqual':
|
|
||||||
case 'lessThanOrEqual':
|
case 'lessThanOrEqual':
|
||||||
case 'lte': {
|
case 'lte': {
|
||||||
const cmp = compare(value, operand)
|
const cmp = compare(value, operand)
|
||||||
|
|
|
||||||
|
|
@ -11,17 +11,21 @@ import { SearchResult, HNSWNoun, HNSWNounWithMetadata } from '../coreTypes.js'
|
||||||
* Designed for performance, clarity, and patent independence
|
* Designed for performance, clarity, and patent independence
|
||||||
*/
|
*/
|
||||||
export interface BrainyFieldOperators {
|
export interface BrainyFieldOperators {
|
||||||
// Equality operators
|
// Equality operators (canonical + long-form aliases)
|
||||||
|
eq?: any
|
||||||
equals?: any
|
equals?: any
|
||||||
|
ne?: any
|
||||||
notEquals?: any
|
notEquals?: any
|
||||||
is?: any
|
|
||||||
isNot?: any
|
|
||||||
|
|
||||||
// Comparison operators
|
// Comparison operators (canonical + long-form aliases)
|
||||||
greaterThan?: any
|
greaterThan?: any
|
||||||
greaterEqual?: any
|
gt?: any
|
||||||
|
greaterThanOrEqual?: any
|
||||||
|
gte?: any
|
||||||
lessThan?: any
|
lessThan?: any
|
||||||
lessEqual?: any
|
lt?: any
|
||||||
|
lessThanOrEqual?: any
|
||||||
|
lte?: any
|
||||||
between?: [any, any]
|
between?: [any, any]
|
||||||
|
|
||||||
// Array/Set operators
|
// Array/Set operators
|
||||||
|
|
@ -45,14 +49,6 @@ export interface BrainyFieldOperators {
|
||||||
allOf?: MetadataFilter[]
|
allOf?: MetadataFilter[]
|
||||||
anyOf?: MetadataFilter[]
|
anyOf?: MetadataFilter[]
|
||||||
not?: 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) {
|
switch (op) {
|
||||||
// Equality operators
|
// Equality operators
|
||||||
case 'equals':
|
case 'equals':
|
||||||
case 'is':
|
|
||||||
case 'eq':
|
case 'eq':
|
||||||
if (value !== operand) return false
|
if (value !== operand) return false
|
||||||
break
|
break
|
||||||
case 'notEquals':
|
case 'notEquals':
|
||||||
case 'isNot':
|
|
||||||
case 'ne':
|
case 'ne':
|
||||||
// Special handling: if value is undefined and operand is not undefined,
|
// Special handling: if value is undefined and operand is not undefined,
|
||||||
// they are not equal (so the condition passes)
|
// they are not equal (so the condition passes)
|
||||||
|
|
@ -108,7 +102,6 @@ function matchesQuery(value: any, query: any): boolean {
|
||||||
case 'gt':
|
case 'gt':
|
||||||
if (typeof value !== 'number' || typeof operand !== 'number' || !(value > operand)) return false
|
if (typeof value !== 'number' || typeof operand !== 'number' || !(value > operand)) return false
|
||||||
break
|
break
|
||||||
case 'greaterEqual':
|
|
||||||
case 'gte':
|
case 'gte':
|
||||||
if (typeof value !== 'number' || typeof operand !== 'number' || !(value >= operand)) return false
|
if (typeof value !== 'number' || typeof operand !== 'number' || !(value >= operand)) return false
|
||||||
break
|
break
|
||||||
|
|
@ -116,7 +109,6 @@ function matchesQuery(value: any, query: any): boolean {
|
||||||
case 'lt':
|
case 'lt':
|
||||||
if (typeof value !== 'number' || typeof operand !== 'number' || !(value < operand)) return false
|
if (typeof value !== 'number' || typeof operand !== 'number' || !(value < operand)) return false
|
||||||
break
|
break
|
||||||
case 'lessEqual':
|
|
||||||
case 'lte':
|
case 'lte':
|
||||||
if (typeof value !== 'number' || typeof operand !== 'number' || !(value <= operand)) return false
|
if (typeof value !== 'number' || typeof operand !== 'number' || !(value <= operand)) return false
|
||||||
break
|
break
|
||||||
|
|
|
||||||
|
|
@ -1760,7 +1760,6 @@ export class MetadataIndexManager implements MetadataIndexProvider {
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
case 'equals':
|
case 'equals':
|
||||||
case 'is':
|
|
||||||
case 'eq':
|
case 'eq':
|
||||||
criteria.push({ field: key, values: [operand] })
|
criteria.push({ field: key, values: [operand] })
|
||||||
break
|
break
|
||||||
|
|
@ -1770,8 +1769,6 @@ export class MetadataIndexManager implements MetadataIndexProvider {
|
||||||
break
|
break
|
||||||
case 'greaterThan':
|
case 'greaterThan':
|
||||||
case 'lessThan':
|
case 'lessThan':
|
||||||
case 'greaterEqual':
|
|
||||||
case 'lessEqual':
|
|
||||||
case 'between':
|
case 'between':
|
||||||
// Range queries will be handled separately
|
// Range queries will be handled separately
|
||||||
// Sorted index will be created/loaded when needed in getIdsForRange
|
// Sorted index will be created/loaded when needed in getIdsForRange
|
||||||
|
|
@ -1881,16 +1878,14 @@ export class MetadataIndexManager implements MetadataIndexProvider {
|
||||||
fieldResults = []
|
fieldResults = []
|
||||||
switch (op) {
|
switch (op) {
|
||||||
// ===== EQUALITY OPERATORS =====
|
// ===== EQUALITY OPERATORS =====
|
||||||
// Canonical: 'eq' | Alias: 'equals' | Deprecated: 'is'
|
// Canonical: 'eq' | Alias: 'equals'
|
||||||
case 'is': // DEPRECATED: Use 'eq' instead
|
|
||||||
case 'equals': // Alias for 'eq'
|
case 'equals': // Alias for 'eq'
|
||||||
case 'eq':
|
case 'eq':
|
||||||
fieldResults = await this.getIds(field, operand)
|
fieldResults = await this.getIds(field, operand)
|
||||||
break
|
break
|
||||||
|
|
||||||
// ===== NEGATION OPERATORS =====
|
// ===== NEGATION OPERATORS =====
|
||||||
// Canonical: 'ne' | Alias: 'notEquals' | Deprecated: 'isNot'
|
// Canonical: 'ne' | Alias: 'notEquals'
|
||||||
case 'isNot': // DEPRECATED: Use 'ne' instead
|
|
||||||
case 'notEquals': // Alias for 'ne'
|
case 'notEquals': // Alias for 'ne'
|
||||||
case 'ne': {
|
case 'ne': {
|
||||||
// For notEquals, we need all IDs EXCEPT those matching the value
|
// For notEquals, we need all IDs EXCEPT those matching the value
|
||||||
|
|
@ -1931,8 +1926,7 @@ export class MetadataIndexManager implements MetadataIndexProvider {
|
||||||
break
|
break
|
||||||
|
|
||||||
// ===== GREATER THAN OR EQUAL OPERATORS =====
|
// ===== GREATER THAN OR EQUAL OPERATORS =====
|
||||||
// Canonical: 'gte' | Alias: 'greaterThanOrEqual' | Deprecated: 'greaterEqual'
|
// Canonical: 'gte' | Alias: 'greaterThanOrEqual'
|
||||||
case 'greaterEqual': // DEPRECATED: Use 'gte' instead
|
|
||||||
case 'greaterThanOrEqual': // Alias for 'gte'
|
case 'greaterThanOrEqual': // Alias for 'gte'
|
||||||
case 'gte':
|
case 'gte':
|
||||||
fieldResults = await this.getIdsForRange(field, operand, undefined, true, true)
|
fieldResults = await this.getIdsForRange(field, operand, undefined, true, true)
|
||||||
|
|
@ -1946,8 +1940,7 @@ export class MetadataIndexManager implements MetadataIndexProvider {
|
||||||
break
|
break
|
||||||
|
|
||||||
// ===== LESS THAN OR EQUAL OPERATORS =====
|
// ===== LESS THAN OR EQUAL OPERATORS =====
|
||||||
// Canonical: 'lte' | Alias: 'lessThanOrEqual' | Deprecated: 'lessEqual'
|
// Canonical: 'lte' | Alias: 'lessThanOrEqual'
|
||||||
case 'lessEqual': // DEPRECATED: Use 'lte' instead
|
|
||||||
case 'lessThanOrEqual': // Alias for 'lte'
|
case 'lessThanOrEqual': // Alias for 'lte'
|
||||||
case 'lte':
|
case 'lte':
|
||||||
fieldResults = await this.getIdsForRange(field, undefined, operand, true, true)
|
fieldResults = await this.getIdsForRange(field, undefined, operand, true, true)
|
||||||
|
|
|
||||||
|
|
@ -37,8 +37,8 @@ export class TemporalProjection extends BaseProjectionStrategy {
|
||||||
where: {
|
where: {
|
||||||
vfsType: 'file',
|
vfsType: 'file',
|
||||||
modified: {
|
modified: {
|
||||||
greaterEqual: startOfDay.getTime(), // BFO operator
|
gte: startOfDay.getTime(), // BFO operator
|
||||||
lessEqual: endOfDay.getTime() // BFO operator
|
lte: endOfDay.getTime() // BFO operator
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
limit: 1000
|
limit: 1000
|
||||||
|
|
@ -74,8 +74,8 @@ export class TemporalProjection extends BaseProjectionStrategy {
|
||||||
where: {
|
where: {
|
||||||
vfsType: 'file',
|
vfsType: 'file',
|
||||||
modified: {
|
modified: {
|
||||||
greaterEqual: startOfDay.getTime(),
|
gte: startOfDay.getTime(),
|
||||||
lessEqual: endOfDay.getTime()
|
lte: endOfDay.getTime()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
limit: 1000
|
limit: 1000
|
||||||
|
|
@ -93,7 +93,7 @@ export class TemporalProjection extends BaseProjectionStrategy {
|
||||||
const results = await brain.find({
|
const results = await brain.find({
|
||||||
where: {
|
where: {
|
||||||
vfsType: 'file',
|
vfsType: 'file',
|
||||||
modified: { greaterEqual: oneDayAgo }
|
modified: { gte: oneDayAgo }
|
||||||
},
|
},
|
||||||
limit
|
limit
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -80,10 +80,9 @@ describe('db/whereMatcher — operators', () => {
|
||||||
expect(whereMatches(e, { status: 'closed' })).toBe(false)
|
expect(whereMatches(e, { status: 'closed' })).toBe(false)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('eq / equals / is aliases', () => {
|
it('eq / equals aliases', () => {
|
||||||
expect(whereMatches(e, { amount: { eq: 250 } })).toBe(true)
|
expect(whereMatches(e, { amount: { eq: 250 } })).toBe(true)
|
||||||
expect(whereMatches(e, { amount: { equals: 250 } })).toBe(true)
|
expect(whereMatches(e, { amount: { equals: 250 } })).toBe(true)
|
||||||
expect(whereMatches(e, { amount: { is: 250 } })).toBe(true)
|
|
||||||
expect(whereMatches(e, { amount: { eq: 99 } })).toBe(false)
|
expect(whereMatches(e, { amount: { eq: 99 } })).toBe(false)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
@ -93,10 +92,9 @@ describe('db/whereMatcher — operators', () => {
|
||||||
expect(whereMatches(e, { tags: 'missing-tag' })).toBe(false)
|
expect(whereMatches(e, { tags: 'missing-tag' })).toBe(false)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('ne / notEquals / isNot aliases', () => {
|
it('ne / notEquals aliases', () => {
|
||||||
expect(whereMatches(e, { status: { ne: 'closed' } })).toBe(true)
|
expect(whereMatches(e, { status: { ne: 'closed' } })).toBe(true)
|
||||||
expect(whereMatches(e, { status: { notEquals: 'open' } })).toBe(false)
|
expect(whereMatches(e, { status: { notEquals: 'open' } })).toBe(false)
|
||||||
expect(whereMatches(e, { status: { isNot: 'open' } })).toBe(false)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it('in / oneOf set membership', () => {
|
it('in / oneOf set membership', () => {
|
||||||
|
|
@ -109,12 +107,10 @@ describe('db/whereMatcher — operators', () => {
|
||||||
expect(whereMatches(e, { amount: { greaterThan: 250 } })).toBe(false)
|
expect(whereMatches(e, { amount: { greaterThan: 250 } })).toBe(false)
|
||||||
expect(whereMatches(e, { amount: { gte: 250 } })).toBe(true)
|
expect(whereMatches(e, { amount: { gte: 250 } })).toBe(true)
|
||||||
expect(whereMatches(e, { amount: { greaterThanOrEqual: 251 } })).toBe(false)
|
expect(whereMatches(e, { amount: { greaterThanOrEqual: 251 } })).toBe(false)
|
||||||
expect(whereMatches(e, { amount: { greaterEqual: 250 } })).toBe(true)
|
|
||||||
expect(whereMatches(e, { amount: { lt: 251 } })).toBe(true)
|
expect(whereMatches(e, { amount: { lt: 251 } })).toBe(true)
|
||||||
expect(whereMatches(e, { amount: { lessThan: 250 } })).toBe(false)
|
expect(whereMatches(e, { amount: { lessThan: 250 } })).toBe(false)
|
||||||
expect(whereMatches(e, { amount: { lte: 250 } })).toBe(true)
|
expect(whereMatches(e, { amount: { lte: 250 } })).toBe(true)
|
||||||
expect(whereMatches(e, { amount: { lessThanOrEqual: 249 } })).toBe(false)
|
expect(whereMatches(e, { amount: { lessThanOrEqual: 249 } })).toBe(false)
|
||||||
expect(whereMatches(e, { amount: { lessEqual: 250 } })).toBe(true)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it('string range comparison is lexicographic', () => {
|
it('string range comparison is lexicographic', () => {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue