Compare commits

..

No commits in common. "8844f326b0741144b54d351337930fdc1efe72a7" and "d9ebc1e875b7d4f6369d563b626f66d6b55009cb" have entirely different histories.

6 changed files with 30 additions and 70 deletions

View file

@ -1,4 +1,4 @@
import { curry, is, last, mergeRightDeep, path } from '../fn.js'
import { assocPath, curry, identity, is, last, mergeRightDeep, path } from '../fn.js'
import { Stream } from '../stream.js'
class Value {
@ -97,11 +97,11 @@ export class Function {
#pop(stack) {
const result = []
let n = Math.min(this.length, stack.length)
const len = stack.length - 1
const n = Math.min(this.length, len)
while(n > 0) {
for(let i = len; i >= len - n; i--) {
result.push(stack.pop())
n--
}
result.reverse()
@ -122,14 +122,14 @@ const Associativity = Object.freeze({
export class Operator extends Function {
constructor(name, fn, priority, associativity = Associativity.Left, length = fn.length) {
super(name, fn, length)
this.precedence = priority
this.priority = priority
this.associativity = associativity
}
compare(other) {
if (other.precedence < this.precedence) {
if (other.priority > this.priority) {
return 1
} else if (other.precedence === this.precedence) {
} else if (other.priority === this.priority) {
if (this.associativity === Associativity.Left) {
return 1
} else {
@ -185,10 +185,9 @@ export class Filter {
const next = stream.next()
if (is(Function, next)) {
if (is(Operator, next)) {
const ops = this.#takeWhile(op => !leftParen(op) && next.compare(op) > 0, operators)
const ops = this.#takeUntil(op => leftParen(op) && next.compare(op) <= 0, operators)
output.push.apply(output, ops)
}
operators.push(next)
} else if (comma(next)) {
output.push.apply(output, this.#takeUntil(leftParen, operators))
@ -197,11 +196,9 @@ export class Filter {
} else if (rightParen(next)) {
const ops = this.#takeUntil(leftParen, operators)
output.push.apply(output, ops)
if (!leftParen(operators.pop())) {
throw new SyntaxError('mismatched parenthesis')
}
if (is(Function, last(operators))) {
output.push(operators.pop())
}
@ -229,13 +226,13 @@ export class Filter {
const next = stream.next()
if (is(Operator, next)) {
const result = next.apply(stack)
stack.push(result)
stack.unshift(result)
} else {
stack.push(next)
}
}
return stack[0]
return stack.every(identity)
})
}
}

View file

@ -40,7 +40,7 @@ export class Iterator {
let accumulator = []
for (let i = 0; i < n; i++) {
if (this.done()) {
if(this.done()) {
break
}
accumulator.push(this.next())
@ -49,37 +49,10 @@ export class Iterator {
return accumulator
}
takeWhile(fn) {
const accumulator = []
while (!this.done() || fn(this.peek())) {
accumulator.push(this.next())
}
return accumulator
}
takeUntil(fn) {
return this.takeWhile(x => !fn(x))
}
drop(n) {
this.take(n)
return this
}
dropWhile(fn) {
while(!this.done() || fn(this.peek())) {
this.next()
}
return this
}
dropUntil(fn) {
this.dropWhile(x => !fn(x))
return this
}
}
class ArrayIterator extends Iterator {

View file

@ -1,6 +1,6 @@
import { describe, it } from 'node:test'
import assert from '../assert.js'
import { Alias, Identifier, Literal, ObjectPath, Property } from '../../src/query-parser/types.js'
import { Alias, Identifier, Literal, ObjectPath } from '../../src/query-parser/types.js'
import { baseValue, literal, value } from '../../src/query-parser/common.js'
describe('common parser library', () => {
@ -38,7 +38,7 @@ describe('common parser library', () => {
})
assert.parseOk(baseValue, 'ginger.snaps', ([actual]) => {
assert.deepEqual(actual, new ObjectPath(new Identifier('ginger'), new Property(new Identifier('snaps'))))
assert.deepEqual(actual, new ObjectPath(new Identifier('ginger'), new Identifier('snaps')))
})
})
@ -56,7 +56,7 @@ describe('common parser library', () => {
})
assert.parseOk(baseValue, 'monster.girl', ([actual]) => {
assert.deepEqual(actual, new ObjectPath(new Identifier('monster'), new Property(new Identifier('girl'))))
assert.deepEqual(actual, new ObjectPath(new Identifier('monster'), new Identifier('girl')))
})
})
@ -74,7 +74,7 @@ describe('common parser library', () => {
})
assert.parseOk(value, 'rowan.containment.isBreached AS rawrnEscaped', ([actual]) => {
const obj = new ObjectPath(new Identifier('rowan'), new Property(new Identifier('containment')), new Property(new Identifier('isBreached')))
const obj = new ObjectPath(new Identifier('rowan'), new Identifier('containment'), new Identifier('isBreached'))
const alias = new Alias(obj, new Identifier('rawrnEscaped'))
assert.deepEqual(actual, alias)
})

View file

@ -1,13 +1,11 @@
import util from 'node:util'
import { describe, it } from 'node:test'
import assert from '../assert.js'
import { query } from '../../src/query-parser/index.js'
import { Alias, Identifier, Match, ObjectPath, Property, Query, ReturnValues, SelectedGraph } from '../../src/query-parser/types.js'
import { Alias, Identifier, Match, ObjectPath, Query, ReturnValues, SelectedGraph } from '../../src/query-parser/types.js'
import { makeNode, makeRelationship, makeRightEdge } from '../utils.js'
import { map } from '../../src/fn.js'
const path = (...args) => new ObjectPath(identifier(args[0]), ...args.slice(1).map(prop))
const prop = x => new Property(identifier(x))
const path = (...x) => new ObjectPath(...x)
const alias = (...x) => new Alias(...x)
const identifier = n => new Identifier(n)
const graph = n => new SelectedGraph(identifier(n))
@ -70,13 +68,11 @@ describe('query', () => {
)),
[],
returnVals(
alias(path('kbity', 'name'), identifier('name')),
alias(path(identifier('kbity'), identifier('name')), identifier('name')),
alias(identifier('snacc'), identifier('food'))
)
)
console.log(util.inspect(actual, { depth: null }))
console.log(util.inspect(expected, { depth: null }))
assert.deepEqual(actual, expected)
})
})

View file

@ -85,21 +85,21 @@ describe('WHERE keyword', () => {
it('handles complex filters', () => {
assert.parseOk(whereClause, 'WHERE h.max > 500 AND (h.current < 250 OR a.value = 10) OR a.value <= 2', ([actual]) => {
const expected = [
new ObjectPath(new Identifier('h'), new Property(new Identifier('max'))),
new ObjectPath(new Identifier('h'), new Property('max')),
new Literal(500),
GreaterThan,
new ObjectPath(new Identifier('h'), new Property(new Identifier('current'))),
new ObjectPath(new Identifier('h'), new Property('current')),
new Literal(250),
LesserThan,
new ObjectPath(new Identifier('a'), new Property(new Identifier('value'))),
new ObjectPath(new Identifier('a'), new Property('value')),
Or,
new Literal(10),
Equal,
Or,
And,
new ObjectPath(new Identifier('a'), new Property(new Identifier('value'))),
new Literal(2),
LesserThanEqual,
new ObjectPath(new Identifier('a'), new Property('value')),
Or,
new Literal(2),
LesserThanEqual
]
assert.deepEqual(actual.values, expected)
})

View file

@ -121,18 +121,12 @@ describe('query', () => {
)
assert.deepEqual(
query('MATCH (e, h:Health) WHERE h.max = 50 OR h.current > 45 RETURN e, h.max AS maxHealth', engine).unwrap(),
query('MATCH (e, h:Health) WHERE h.max = 50 OR h.current < 50 RETURN e, h.max AS maxHealth', engine).unwrap(),
[
{ e: 12, maxHealth: 50 },
{ e: 13, maxHealth: 50 }
]
)
assert.deepEqual(
query('MATCH (e, :Player, h:Health) WHERE (h.max = 50 OR h.current > 45) AND e = 12 RETURN e, h.max AS maxHealth', engine).unwrap(),
[
{ e: 12, maxHealth: 50 }
]
)
})
})