Skip to content

Commit b94b732

Browse files
committedOct 11, 2021
Use tape for tests
Add tests section to readme.
1 parent 0bbf043 commit b94b732

File tree

6 files changed

+1363
-5427
lines changed

6 files changed

+1363
-5427
lines changed
 

‎.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
node_modules
2+
.nyc_output

‎README.md

+80-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
# Lucene Query String Builder
22

3-
[![Tests](https://github.com/bas080/lucene-query-string-builder/workflows/Node.js%20CI/badge.svg)](https://github.com/bas080/lucene-query-string-builder/actions)
4-
53
Easily build your lucene string queries using small and pure functions.
64

75
Imagine having an API that leverages lucene for performing queries on the
@@ -131,6 +129,86 @@ https://lucene.apache.org/core/2_9_4/queryparsersyntax.html#Terms
131129

132130
```
133131

132+
## Tests
133+
134+
```bash bash
135+
set -eo pipefail
136+
137+
npm i
138+
npm prune
139+
140+
npx standard --fix
141+
npx nyc npm t
142+
```
143+
```
144+
145+
up to date, audited 72 packages in 604ms
146+
147+
44 packages are looking for funding
148+
run `npm fund` for details
149+
150+
found 0 vulnerabilities
151+
152+
up to date, audited 72 packages in 553ms
153+
154+
44 packages are looking for funding
155+
run `npm fund` for details
156+
157+
found 0 vulnerabilities
158+
159+
> lucene-query-string-builder@1.0.5 test
160+
> tape ./test/index.js
161+
162+
TAP version 13
163+
# builder
164+
ok 1 should be strictly equal
165+
# range
166+
ok 2 should be strictly equal
167+
ok 3 should be strictly equal
168+
ok 4 should be strictly equal
169+
ok 5 should be strictly equal
170+
# group
171+
ok 6 should be strictly equal
172+
# term
173+
ok 7 should be strictly equal
174+
ok 8 should be strictly equal
175+
# fuzzy
176+
ok 9 should throw
177+
ok 10 should be strictly equal
178+
ok 11 should be strictly equal
179+
ok 12 should be strictly equal
180+
ok 13 should be strictly equal
181+
ok 14 should be strictly equal
182+
ok 15 should be strictly equal
183+
# proximity
184+
ok 16 should be strictly equal
185+
ok 17 should throw
186+
ok 18 should throw
187+
ok 19 should throw
188+
ok 20 should throw
189+
ok 21 should throw
190+
# or/and/not
191+
ok 22 should be strictly equal
192+
ok 23 should be strictly equal
193+
ok 24 should be strictly equal
194+
ok 25 should be strictly equal
195+
ok 26 should be strictly equal
196+
ok 27 should be strictly equal
197+
198+
1..27
199+
# tests 27
200+
# pass 27
201+
202+
# ok
203+
204+
----------|---------|----------|---------|---------|-------------------
205+
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
206+
----------|---------|----------|---------|---------|-------------------
207+
All files | 90.32 | 94.44 | 88.24 | 90.91 |
208+
index.js | 90.32 | 94.44 | 88.24 | 90.91 | 69-72,165-167
209+
----------|---------|----------|---------|---------|-------------------
210+
```
211+
134212
## Contributing
135213

136214
I have not gotten the chance to use this lib in my own projects. Please share

‎README.mz

+173
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
# Lucene Query String Builder
2+
3+
Easily build your lucene string queries using small and pure functions.
4+
5+
Imagine having an API that leverages lucene for performing queries on the
6+
(indexed) database. In that case you might want to generate lucene query strings on
7+
the client/front end.
8+
9+
The usage section shows how you can leverage this lib for your purposes.
10+
11+
## Setup
12+
13+
```bash
14+
npm install lucene-query-string-builder --save
15+
```
16+
17+
## Features
18+
19+
- escapes lucene special chars when creating a term string
20+
- contains all the operators lucene uses
21+
- simple lucene.builder function for defining a lucene query builder
22+
23+
## Usage
24+
25+
Let's see how you can use lucene query string builder to define lucene query
26+
strings with simple JavaScript functions.
27+
28+
Assuming that the lucene global variable contains the lucene functions. This
29+
would be the default when loaded into a browser.
30+
31+
```JavaScript
32+
33+
var findUserLuceneQueryString = lucene.builder(function(data){
34+
35+
// just to make the example more readable;
36+
var _ = lucene;
37+
38+
return _.group(_.and(
39+
_.field('eye-color', _.term(data.eye.color)),
40+
_.field('age', _.range(data.age.min, data.age.max))
41+
));
42+
43+
});
44+
45+
var luceneQueryString = findUserLuceneQueryString({
46+
eye: { color: 'brown'},
47+
age: {
48+
min: 10,
49+
max: 20
50+
}
51+
});
52+
53+
luceneQueryString === '( eye-color: "brown" AND age:{ 10 TO 20 } )' // => true
54+
55+
```
56+
The functions are based on the lucene specifications found here:
57+
https://lucene.apache.org/core/2_9_4/queryparsersyntax.html#Terms
58+
59+
```JavaScript
60+
61+
var _ = lucene;
62+
63+
/***
64+
* terms or term
65+
*/
66+
67+
_.term('hello'); // => '"hello"'
68+
69+
_.terms('hello world'); // => '"hello world"'
70+
71+
72+
/***
73+
* field
74+
*/
75+
76+
_.field('hello', _.term('world')); // => 'hello: "world"'
77+
78+
79+
/***
80+
* or/and/not
81+
*
82+
* These functions are variadic and all work the same way. This example only
83+
shows the or but ot works similar with and and not
84+
*/
85+
86+
_.or(_.term('hello'), _.term('world')); // => '"hello" OR "world"'
87+
88+
_.or(_.term('hello'), _.term('you'), _.term('world')); // => '"hello" OR "you" OR "world"'
89+
90+
91+
/***
92+
* group
93+
*
94+
* Is a variadic function too
95+
*/
96+
97+
_.group(_.term('hello'), _.term('you'), _.term('world')); // => '( "hello" "you" "world" )'
98+
99+
100+
/***
101+
* range
102+
*
103+
* Takes two strings and 2 booleans.
104+
*/
105+
106+
/* combined with the field function to query for ages between 10 and 20 */
107+
_.field('age', _.range(10, 20)); // => 'age: { 10 TO 20 }'
108+
109+
110+
/***
111+
* fuzzy
112+
*/
113+
114+
_.fuzzy(_.term('hello'), 0.2); // => '"hello"~0.2'
115+
116+
117+
/***
118+
* proximity
119+
*/
120+
121+
_.proximity("a", "c", 2); // => '"a b"'~2
122+
123+
124+
/***
125+
* required
126+
*/
127+
128+
_.required(_.term('required')); // => '+"required"'
129+
130+
```
131+
132+
## Tests
133+
134+
```bash bash
135+
set -eo pipefail
136+
137+
npm i
138+
npm prune
139+
140+
npx standard --fix
141+
npx nyc npm t
142+
```
143+
144+
## Contributing
145+
146+
I have not gotten the chance to use this lib in my own projects. Please share
147+
your thoughts, issues and improvements.
148+
149+
- Make sure your dependencies are installed by running: `npm run-script setup`
150+
- Then start editing the index.js
151+
- You should add and/or edit the tests in test/index.js
152+
- Run your tests and see what happens
153+
154+
When performing pull request make sure to not add the **dist** files. This is left
155+
to the maintainers(s) of the library. They are responsible to version and avoid
156+
code breakages.
157+
158+
You can perform your own build with `npm run-script` build to make a *lucine.js* and
159+
a *lucine.min.js*
160+
161+
**notice**
162+
163+
I am currently not using this repository in any of my projects. Therefore I am looking
164+
for people that are able to make LQSB more useful for them and others.
165+
166+
## Road map
167+
168+
- split all functions into separate files
169+
- tasks for running tests on dist/lucene.js and dist/lucene.min.js
170+
171+
## License
172+
173+
The MIT License (MIT)

‎package-lock.json

+1,054-5,335
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎package.json

+3-6
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,14 @@
11
{
22
"name": "lucene-query-string-builder",
3-
"version": "1.0.4",
3+
"version": "1.0.5",
44
"description": "Build Lucene queries by defining lucene query builders",
55
"main": "index.js",
66
"repository": {
77
"type": "git",
88
"url": "https://github.com/bas080/lucene-query-string-builder.git"
99
},
1010
"scripts": {
11-
"test": "mocha -b",
12-
"posttest": "standard"
11+
"test": "tape ./test/index.js"
1312
},
1413
"keywords": [
1514
"lucene",
@@ -19,9 +18,7 @@
1918
"author": "Bas Huis <bas080@hotmail.com>",
2019
"license": "MIT",
2120
"devDependencies": {
22-
"chai": "~4.3.0",
23-
"mocha": "^8.3.0",
24-
"standard": "^16.0.3"
21+
"tape": "^5.3.1"
2522
},
2623
"standard": {
2724
"env": [

‎test/index.js

+52-84
Original file line numberDiff line numberDiff line change
@@ -1,111 +1,79 @@
11
'use strict'
22

3-
const expect = require('chai').expect
3+
const test = require('tape')
44
const l = require('../index.js')
55

6-
describe('builder', () => {
7-
it('generates a string', () => {
8-
const helloWorldQuery = l.builder((data) => {
9-
return l.field(data.hello, l.term(data.world))
10-
})
11-
12-
expect(helloWorldQuery({
13-
hello: 'hello',
14-
world: 'world'
15-
})).to.equal('hello: "world"')
6+
test('builder', t => {
7+
const helloWorldQuery = l.builder((data) => {
8+
return l.field(data.hello, l.term(data.world))
169
})
10+
t.equal(helloWorldQuery({
11+
hello: 'hello',
12+
world: 'world'
13+
}), 'hello: "world"')
14+
t.end()
1715
})
1816

19-
describe('range', () => {
20-
it('includes both the left and right equal cases', () => {
21-
expect(l.range('a', 'b', true, true)).to.equal('[ a TO b ]')
22-
})
23-
24-
it('includes the left equal case', () => {
25-
expect(l.range('a', 'b', true)).to.equal('[ a TO b }')
26-
})
27-
28-
it('includes the left equal case', () => {
29-
expect(l.range('a', 'b', false, true)).to.equal('{ a TO b ]')
30-
})
31-
32-
it('excludes the equal cases by default', () => {
33-
expect(l.range('a', 'b')).to.equal('{ a TO b }')
34-
})
17+
test('range', t => {
18+
t.equal(l.range('a', 'b', true, true), '[ a TO b ]')
19+
t.equal(l.range('a', 'b', true), '[ a TO b }')
20+
t.equal(l.range('a', 'b', false, true), '{ a TO b ]')
21+
t.equal(l.range('a', 'b'), '{ a TO b }')
22+
t.end()
3523
})
3624

37-
describe('group', () => {
38-
it('group', () => {
39-
expect(l.group.apply(null, ['red', 'white', 'blue'].map(l.term)))
40-
.to.equal('( "red" "white" "blue" )')
41-
})
25+
test('group', t => {
26+
t.equal(
27+
l.group.apply(null, ['red', 'white', 'blue'].map(l.term)),
28+
'( "red" "white" "blue" )')
29+
t.end()
4230
})
4331

44-
describe('term', () => {
45-
it('creates a term query', function () {
46-
expect(l.terms('hello world')).to.equal('"hello world"')
47-
})
48-
49-
it('escapes query syntax characters', function () {
50-
expect(l.terms('()')).to.equal('"\\(\\)"')
51-
})
32+
test('term', t => {
33+
t.equal(l.terms('hello world'), '"hello world"')
34+
t.equal(l.terms('()'), '"\\(\\)"')
35+
t.end()
5236
})
5337

54-
describe('fuzzy', () => {
55-
it('throws a RangeError when similarity is out of range', () => {
56-
expect(
57-
l.fuzzy.bind(null, l.term('lucene'), 200)
58-
).to.throw(RangeError)
59-
})
60-
61-
it('returns a valid fuzzy search when similarity is not defined', () => {
62-
expect(l.fuzzy('hello')).to.equal('hello~')
63-
expect(l.fuzzy('hello')).to.equal('hello~')
64-
expect(l.fuzzy('hello')).to.equal('hello~')
65-
})
66-
67-
it('returns a valid fuzzy search when similarity param is passed', () => {
68-
expect(l.fuzzy('hello', 1)).to.equal('hello~1')
69-
expect(l.fuzzy('hello', 0)).to.equal('hello~0')
70-
expect(l.fuzzy('hello', 0.5)).to.equal('hello~0.5')
71-
})
38+
test('fuzzy', t => {
39+
t.throws(l.fuzzy.bind(null, l.term('lucene'), 200), RangeError)
40+
t.equal(l.fuzzy('hello'), 'hello~')
41+
t.equal(l.fuzzy('hello'), 'hello~')
42+
t.equal(l.fuzzy('hello'), 'hello~')
43+
t.equal(l.fuzzy('hello', 1), 'hello~1')
44+
t.equal(l.fuzzy('hello', 0), 'hello~0')
45+
t.equal(l.fuzzy('hello', 0.5), 'hello~0.5')
46+
t.end()
7247
})
7348

74-
describe('proximity', () => {
75-
it('returns a valid proximity query', () => {
76-
expect(l.proximity('hello', 'world', 10)).to.equal('"hello world"~10')
77-
// expect(l.proximity('hello', 'world', Infinity)).to.equal('"hello world"~Infinity');
78-
})
49+
test('proximity', t => {
50+
t.equal(l.proximity('hello', 'world', 10), '"hello world"~10')
7951

80-
it('throw when arguments are invalid', () => {
81-
expect(l.proximity.bind(null, 'lucene')).to.throw(TypeError)
82-
expect(l.proximity.bind(null, 'lucene', 'hello')).to.throw(TypeError)
83-
expect(l.proximity.bind(null, 'lucene', 'hello', Infinity)).to.throw(RangeError)
84-
expect(l.proximity.bind(null, 'lucene', 'hello', -1)).to.throw(RangeError)
85-
expect(l.proximity.bind(null, 'lucene', 'hello', -Infinity)).to.throw(RangeError)
86-
})
52+
t.throws(l.proximity.bind(null, 'lucene'), TypeError)
53+
t.throws(l.proximity.bind(null, 'lucene', 'hello'), TypeError)
54+
t.throws(l.proximity.bind(null, 'lucene', 'hello', Infinity), RangeError)
55+
t.throws(l.proximity.bind(null, 'lucene', 'hello', -1), RangeError)
56+
t.throws(l.proximity.bind(null, 'lucene', 'hello', -Infinity), RangeError)
57+
t.end()
8758
})
8859

8960
/***
9061
* These are combined as they use the same function to be bootstrapped
9162
*/
92-
describe('or/and/not', () => {
63+
test('or/and/not', t => {
9364
['or', 'and', 'not'].forEach(function (operator) {
9465
const uppered = operator.toUpperCase()
9566

96-
it('places the operator in the middle of the other operators', () => {
97-
expect(l[operator](
98-
l.terms('hello'),
99-
l.terms('world')
100-
)).to.equal(`"hello" ${uppered} "world"`)
101-
})
67+
t.equal(l[operator](
68+
l.terms('hello'),
69+
l.terms('world')
70+
), `"hello" ${uppered} "world"`)
10271

103-
it('takes a variadic amount of args', () => {
104-
expect(l[operator](
105-
l.terms('hello'),
106-
l.terms('world'),
107-
l.terms('red')
108-
)).to.equal(`"hello" ${uppered} "world" ${uppered} "red"`)
109-
})
72+
t.equal(l[operator](
73+
l.terms('hello'),
74+
l.terms('world'),
75+
l.terms('red')
76+
), `"hello" ${uppered} "world" ${uppered} "red"`)
11077
})
78+
t.end()
11179
})

0 commit comments

Comments
 (0)
Please sign in to comment.