Skip to content

Commit 233f0bc

Browse files
committed
edit: parseQueryEXP passes almost same tests as parseQuery
there should be no breaking changes
1 parent 61b45dc commit 233f0bc

File tree

8 files changed

+107
-54
lines changed

8 files changed

+107
-54
lines changed

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@hp4k1h5/aqlquerybuilder.js",
3-
"version": "0.1.3",
3+
"version": "0.1.4",
44
"license": "MIT",
55
"main": "built/index.js",
66
"types": "built/index.d.ts",

src/filter.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import { aql } from 'arangojs'
2-
import { filter } from './lib/structs'
2+
import { Filter } from './lib/structs'
33

4-
export function buildFilters(filters: filter[]) {
4+
export function buildFilters(filters: Filter[]) {
55
if (!filters.length) return
66

77
let _filters = filters.map(
8-
(f: filter) => aql`doc.${f.field} ${aql.literal(f.op)} ${f.val}`,
8+
(f: Filter) => aql`doc.${f.field} ${aql.literal(f.op)} ${f.val}`,
99
)
1010

1111
return aql`FILTER ${aql.join(_filters, ' && ')}`

src/lib/structs.ts

+19-2
Original file line numberDiff line numberDiff line change
@@ -85,8 +85,8 @@ export interface Term {
8585
}
8686

8787
export enum Type {
88-
phrase = 'phrase',
89-
token = 'token',
88+
phrase = 'phr',
89+
token = 'tok',
9090
}
9191

9292
export enum Operator {
@@ -109,3 +109,20 @@ export interface Filter {
109109
/** the query string to filter with */
110110
val: string | number | Date
111111
}
112+
113+
export class Char {
114+
char: string
115+
constructor(ch: string) {
116+
this.char = ch
117+
}
118+
119+
isSpace() {
120+
return /\s/.test(this.char)
121+
}
122+
isOperator() {
123+
return /[+-?]/.test(this.char)
124+
}
125+
isQuote() {
126+
return /"|'/.test(this.char)
127+
}
128+
}

src/parse.ts

+4-27
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Term, Type, Operator } from './lib/structs'
1+
import { Term, Type, Operator, Char } from './lib/structs'
22

33
export function parseQuery(queryString: string): Term[] {
44
const queryRgx: RegExp = /[+?-]?(["'(]).+?(\1|\))|[^"'()\s]+/g
@@ -34,25 +34,8 @@ export function parseQueryEXP(queryString: string): Term[] {
3434
return lex(queryString)
3535
}
3636

37-
class Char {
38-
char: string
39-
constructor(ch: string) {
40-
this.char = ch
41-
}
42-
43-
isSpace() {
44-
return /\s/.test(this.char)
45-
}
46-
isOperator() {
47-
return /[+-?]/.test(this.char)
48-
}
49-
isQuote() {
50-
return /"|'/.test(this.char)
51-
}
52-
}
53-
5437
function lex(queryString: string) {
55-
const tokens = []
38+
const lexes = []
5639
let curToken = ''
5740
let curTokenType: Type = Type.token
5841
let curOperator: Operator = Operator.OR
@@ -96,7 +79,7 @@ function lex(queryString: string) {
9679
}
9780

9881
function resetCur() {
99-
tokens.push({
82+
lexes.push({
10083
type: curTokenType,
10184
val: curToken,
10285
op: curOperator,
@@ -107,7 +90,7 @@ function lex(queryString: string) {
10790
isToken = false
10891
}
10992

110-
return tokens
93+
return lexes
11194
}
11295

11396
export class ParseError extends Error {
@@ -125,9 +108,3 @@ export class ParseError extends Error {
125108
// U+201C “
126109
// U+201D ”
127110
}
128-
129-
try {
130-
console.log(parseQueryEXP('"+hello -there" -apple'))
131-
} catch (e) {
132-
console.error(e)
133-
}

src/search.ts

+8-8
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { aql } from 'arangojs'
2-
import { query, collection, term } from './lib/structs'
2+
import { query, collection, Term, Type } from './lib/structs'
33
import { parseQuery } from './parse'
44

55
export function buildSearch(query: query): any {
@@ -36,14 +36,14 @@ export function buildSearch(query: query): any {
3636
OPTIONS { collections: ${cols} }
3737
SORT TFIDF(doc) DESC`
3838
}
39-
function buildOps(collections: collection[], terms: term[], op: string): any {
39+
function buildOps(collections: collection[], terms: Term[], op: string): any {
4040
const opWord: string = op == '+' ? ' AND ' : ' OR '
4141

42-
let queryTerms: any = terms.filter((t: term) => t.op == op)
42+
let queryTerms: any = terms.filter((t: Term) => t.op == op)
4343
if (!queryTerms.length) return
4444

4545
/* phrases */
46-
let phrases = queryTerms.filter((qT: term) => qT.type == 'phr')
46+
let phrases = queryTerms.filter((qT: Term) => qT.type == Type.phrase)
4747
phrases = buildPhrases(phrases, collections, opWord)
4848

4949
/* tokens */
@@ -57,7 +57,7 @@ function buildOps(collections: collection[], terms: term[], op: string): any {
5757
}
5858

5959
function buildPhrases(
60-
phrases: term[],
60+
phrases: Term[],
6161
collections: collection[],
6262
opWord: string,
6363
): any {
@@ -69,7 +69,7 @@ function buildPhrases(
6969
)
7070
}
7171

72-
function buildPhrase(phrase: term, collections: collection[]): any {
72+
function buildPhrase(phrase: Term, collections: collection[]): any {
7373
const phrases = []
7474
collections.forEach((coll) =>
7575
coll.keys.forEach((k: string) =>
@@ -81,7 +81,7 @@ function buildPhrase(phrase: term, collections: collection[]): any {
8181
return aql`(${aql.join(phrases, ' OR ')})`
8282
}
8383

84-
function buildTokens(tokens: term[], collections: collection[]): any {
84+
function buildTokens(tokens: Term[], collections: collection[]): any {
8585
if (!tokens.length) return
8686

8787
const opWordMap = {
@@ -97,7 +97,7 @@ function buildTokens(tokens: term[], collections: collection[]): any {
9797
}, {})
9898

9999
const makeTokenAnalyzers = (
100-
tokens: term[],
100+
tokens: Term[],
101101
op: string,
102102
analyzer: string,
103103
keys: string[],

tests/bool.ts

+1-2
Original file line numberDiff line numberDiff line change
@@ -211,8 +211,7 @@ describe('boolean search logic', () => {
211211
expect(result[0].title).to.equal('doc B')
212212
})
213213

214-
it(`should bring back only results matching AND'ed values
215-
when +'ed TOKEN's are passed`, async () => {
214+
it(`should bring back only results matching AND'ed values when +'ed TOKEN's are passed`, async () => {
216215
const info = await view.get()
217216
expect(info.name).to.be.a('string')
218217
let query = {

tests/parse.ts

+11-11
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,14 @@ describe('parse.ts', () => {
1515
when a string is passed with no op hints`, () => {
1616
const parsedQuery = parseQuery('terms "a and b" c')
1717
expect(parsedQuery).to.be.an('array').that.has.lengthOf(3)
18-
expect(parsedQuery[ 0 ]).to.deep.equal({
19-
op: "?",
20-
type: "tok",
21-
val: "terms",
18+
expect(parsedQuery[0]).to.deep.equal({
19+
op: '?',
20+
type: 'tok',
21+
val: 'terms',
2222
})
23-
expect(parsedQuery[ 1 ]).to.deep.equal({
24-
op: "?",
25-
type: "phr",
23+
expect(parsedQuery[1]).to.deep.equal({
24+
op: '?',
25+
type: 'phr',
2626
val: '"a and b"',
2727
})
2828
})
@@ -33,25 +33,25 @@ describe('parse.ts', () => {
3333

3434
expect(parsedQuery).to.be.an('array').that.has.lengthOf(4)
3535

36-
expect(parsedQuery[ 0 ]).to.deep.equal({
36+
expect(parsedQuery[0]).to.deep.equal({
3737
op: '?',
3838
type: 'tok',
3939
val: 'terms',
4040
})
4141

42-
expect(parsedQuery[ 1 ]).to.deep.equal({
42+
expect(parsedQuery[1]).to.deep.equal({
4343
op: '+',
4444
type: 'phr',
4545
val: '"must have"',
4646
})
4747

48-
expect(parsedQuery[ 2 ]).to.deep.equal({
48+
expect(parsedQuery[2]).to.deep.equal({
4949
op: '-',
5050
type: 'tok',
5151
val: 'cannot',
5252
})
5353

54-
expect(parsedQuery[ 3 ]).to.deep.equal({
54+
expect(parsedQuery[3]).to.deep.equal({
5555
op: '-',
5656
type: 'phr',
5757
val: '"have this"',

tests/parseEXP.ts

+60
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import { expect } from 'chai'
2+
import { parseQueryEXP } from '../src/parse'
3+
4+
describe('parse.ts', () => {
5+
it('should export a function parseQueryEXP', () => {
6+
expect(parseQueryEXP).to.be.a('function')
7+
})
8+
9+
it(`should return an an empty array
10+
when an empty string is passed`, () => {
11+
expect(parseQueryEXP('')).to.be.an('array')
12+
})
13+
14+
it(`should return an array of parsed optional term objects
15+
when a string is passed with no op hints`, () => {
16+
const parsedQuery = parseQueryEXP('terms "a and b" c')
17+
expect(parsedQuery).to.be.an('array').that.has.lengthOf(3)
18+
expect(parsedQuery[0]).to.deep.equal({
19+
op: '?',
20+
type: 'tok',
21+
val: 'terms',
22+
})
23+
expect(parsedQuery[1]).to.deep.equal({
24+
op: '?',
25+
type: 'phr',
26+
val: 'a and b',
27+
})
28+
})
29+
30+
it(`should return an array of parsed term objects
31+
when a complex string is passed`, () => {
32+
const parsedQuery = parseQueryEXP('terms +"must have" -cannot -"have this"')
33+
34+
expect(parsedQuery).to.be.an('array').that.has.lengthOf(4)
35+
36+
expect(parsedQuery[0]).to.deep.equal({
37+
op: '?',
38+
type: 'tok',
39+
val: 'terms',
40+
})
41+
42+
expect(parsedQuery[1]).to.deep.equal({
43+
op: '+',
44+
type: 'phr',
45+
val: 'must have',
46+
})
47+
48+
expect(parsedQuery[2]).to.deep.equal({
49+
op: '-',
50+
type: 'tok',
51+
val: 'cannot',
52+
})
53+
54+
expect(parsedQuery[3]).to.deep.equal({
55+
op: '-',
56+
type: 'phr',
57+
val: 'have this',
58+
})
59+
})
60+
})

0 commit comments

Comments
 (0)