daedal 0.0.2 → 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +169 -2
- data/daedal.gemspec +5 -1
- data/lib/daedal.rb +1 -0
- data/lib/daedal/attributes.rb +4 -88
- data/lib/daedal/attributes/match_type.rb +17 -0
- data/lib/daedal/attributes/operator.rb +17 -0
- data/lib/daedal/attributes/query_array.rb +16 -0
- data/lib/daedal/attributes/score_mode.rb +17 -0
- data/lib/daedal/filters.rb +1 -0
- data/lib/daedal/filters/term_filter.rb +1 -1
- data/lib/daedal/filters/terms_filter.rb +18 -0
- data/lib/daedal/queries.rb +1 -0
- data/lib/daedal/queries/base_query.rb +9 -0
- data/lib/daedal/queries/bool_query.rb +9 -26
- data/lib/daedal/queries/constant_score_query.rb +5 -3
- data/lib/daedal/queries/dis_max_query.rb +2 -13
- data/lib/daedal/queries/filtered_query.rb +3 -3
- data/lib/daedal/queries/match_all_query.rb +1 -1
- data/lib/daedal/queries/match_query.rb +1 -1
- data/lib/daedal/queries/multi_match_query.rb +2 -1
- data/lib/daedal/queries/nested_query.rb +26 -0
- data/spec/unit/daedal/filters/terms_filter_spec.rb +49 -0
- data/spec/unit/daedal/queries/bool_query_spec.rb +13 -12
- data/spec/unit/daedal/queries/constant_score_query_spec.rb +12 -0
- data/spec/unit/daedal/queries/dis_max_query_spec.rb +4 -4
- data/spec/unit/daedal/queries/filtered_query_spec.rb +13 -0
- data/spec/unit/daedal/queries/nested_query_spec.rb +82 -0
- metadata +24 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 01d15eb052c93f8a9dedb824873a533e876c5eee
|
4
|
+
data.tar.gz: d3408e2da2b82d8c35bf1cb07330fdb62e09c547
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1d850b9dd24946209c622306d762e8aa228994de8bdb303e19a0f572b118f42d7a6ee7df0c4ca87c17d32c512ed53f68f541e13c49bf8b28037d42072626762a
|
7
|
+
data.tar.gz: 3eb44d37d68e10dc6cec2c3a5a76b3cf9e146a8c612ed4628c36818aec056a45ab587f94577380a522c484bc60db3b9ad0df4c3b97a9e2bc545f92ef7e15b701
|
data/README.md
CHANGED
@@ -1,4 +1,171 @@
|
|
1
1
|
Daedal
|
2
|
-
|
2
|
+
======
|
3
3
|
|
4
|
-
Ruby classes
|
4
|
+
This repository contains a set of Ruby classes designed to make ElasticSearch
|
5
|
+
query creation simpler and easier to debug. The goal is to reproduce all
|
6
|
+
components of the ElasticSearch [Query DSL](http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/query-dsl.html)
|
7
|
+
to aid in the construction of complex queries. Type checking and attribute
|
8
|
+
coercion are handled using [Virtus](https://github.com/solnic/virtus) to make
|
9
|
+
it harder to construct invalid ElasticSearch queries before sending them to the server.
|
10
|
+
|
11
|
+
The ElasticSearch Query DSL is huge! There are also a ton of different options within each
|
12
|
+
component. My goal is to include as much of that functionality and flexibility as possible, but
|
13
|
+
also maintain as high of test coverage as possible. That means it'll take some time for this project
|
14
|
+
to reach full coverage of the Query DSL, so please feel free to contribute or be patient :)
|
15
|
+
|
16
|
+
Installation
|
17
|
+
------------
|
18
|
+
|
19
|
+
``` terminal
|
20
|
+
$ gem install daedal
|
21
|
+
```
|
22
|
+
|
23
|
+
or in your `Gemfile`
|
24
|
+
|
25
|
+
``` ruby
|
26
|
+
gem 'daedal'
|
27
|
+
```
|
28
|
+
|
29
|
+
Usage
|
30
|
+
--------
|
31
|
+
|
32
|
+
### ElasticSearch Query DSL
|
33
|
+
|
34
|
+
Other Ruby packages for ElasticSearch allow you to create queries either as
|
35
|
+
hashes or by constructing raw JSON:
|
36
|
+
|
37
|
+
``` ruby
|
38
|
+
match_query = {'match' => {'foo' => {'query' => 'bar'}}}
|
39
|
+
```
|
40
|
+
|
41
|
+
For more complicated queries, dealing with the resulting large nested hash can be
|
42
|
+
frustrating. Inspired by ElasticSearch's built in
|
43
|
+
[Java API](http://www.elasticsearch.org/guide/en/elasticsearch/client/java-api/current/),
|
44
|
+
Daedal contains Ruby classes designed to make query construction more Ruby-like.
|
45
|
+
|
46
|
+
### Queries
|
47
|
+
|
48
|
+
Queries are contained within the `Queries` module. You can construct query components like:
|
49
|
+
|
50
|
+
``` ruby
|
51
|
+
require 'daedal'
|
52
|
+
|
53
|
+
# creates the basic match query
|
54
|
+
match_query = Daedal::Queries::MatchQuery.new(field: 'foo', query: 'bar')
|
55
|
+
```
|
56
|
+
Each query object has `#to_json` defined for easy conversion for use with any of the Ruby
|
57
|
+
ElasticSearch clients out there:
|
58
|
+
``` ruby
|
59
|
+
match_query.to_json # => "{\"match\":{\"foo\":{\"query\":\"bar\"}}}"
|
60
|
+
```
|
61
|
+
|
62
|
+
To date (12/8/2013), I have implemented the following queries:
|
63
|
+
* [bool query](http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/query-dsl-bool-query.html)
|
64
|
+
* [constant score query](http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/query-dsl-constant-score-query.html)
|
65
|
+
* [dis max query](http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/query-dsl-dis-max-query.html)
|
66
|
+
* [filtered query](http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/query-dsl-filtered-query.html)
|
67
|
+
* [match all query](http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/query-dsl-match-all-query.html)
|
68
|
+
* [match query](http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/query-dsl-match-query.html)
|
69
|
+
* [multi match query](http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/query-dsl-multi-match-query.html)
|
70
|
+
|
71
|
+
### Filters
|
72
|
+
|
73
|
+
Filters are contained within the `Filters` module. You can construct filter components
|
74
|
+
in the same way as queries:
|
75
|
+
|
76
|
+
``` ruby
|
77
|
+
require 'daedal'
|
78
|
+
|
79
|
+
term_filter = Daedal::Filters::TermFilter.new(field: 'foo', term: 'bar')
|
80
|
+
|
81
|
+
term_filter.to_json # => "{\"term\":{\"foo\":\"bar\"}}"
|
82
|
+
```
|
83
|
+
|
84
|
+
To date (12/8/2013), I have implemented the following filters:
|
85
|
+
* [term filter](http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/query-dsl-term-filter.html)
|
86
|
+
|
87
|
+
### Type checking and attribute coercion
|
88
|
+
|
89
|
+
When creating ElasticSearch queries via nested hashes, it is all too easy to
|
90
|
+
assign an invalid value to a specific field, which would then result in
|
91
|
+
an error response when sending the query to the server. For instance, the query:
|
92
|
+
|
93
|
+
``` ruby
|
94
|
+
constant_score_query = {'constant_score' => {'boost' => 'foo', 'query': {'match_all': {}}}}
|
95
|
+
```
|
96
|
+
|
97
|
+
would yield a server error, since the `boost` parameter must be a number.
|
98
|
+
|
99
|
+
Daedal uses [Virtus](https://github.com/solnic/virtus) to perform data-type coercions.
|
100
|
+
That way, invalid query parameters are surfaced at runtime, making debugging easier.
|
101
|
+
The previous `constant_score_query` example in Daedal would raise an error:
|
102
|
+
|
103
|
+
``` ruby
|
104
|
+
match_all_query = Daedal::Queries::MatchAllQuery.new()
|
105
|
+
constant_score_query = Daedal::Queries::ConstantScoreQuery.new(boost: 'foo', query: match_all_query)
|
106
|
+
|
107
|
+
# Virtus::CoercionError: Failed to coerce "foo" into Float
|
108
|
+
```
|
109
|
+
|
110
|
+
### Creating your own queries
|
111
|
+
|
112
|
+
Currently, I've only made it through a fraction of the entire Query DSL, but will be working to
|
113
|
+
achieve complete coverage as quickly as possible. If you need to use a query that
|
114
|
+
I haven't gotten to yet, or if you want to create your own more specialized queries within
|
115
|
+
your own project, defining the query classes is relatively straightforward - just make
|
116
|
+
your new class a sublass of the `Daedal::Queries::BaseQuery` or `Daedal::Filters::BaseFilter`
|
117
|
+
classes, and define the `to_hash` method. All methods made available by including `Virtus.model` in your
|
118
|
+
class will be available to you, as well.
|
119
|
+
|
120
|
+
Example:
|
121
|
+
``` ruby
|
122
|
+
class MyQuery < Daedal::Queries::BaseQuery
|
123
|
+
|
124
|
+
# define the attributes that you need in your query
|
125
|
+
attribute :foo, String
|
126
|
+
attribute :bar, String
|
127
|
+
|
128
|
+
# define the to_hash method to convert for use in ElasticSearch
|
129
|
+
def to_hash
|
130
|
+
...
|
131
|
+
end
|
132
|
+
end
|
133
|
+
```
|
134
|
+
|
135
|
+
Contributing
|
136
|
+
-------------
|
137
|
+
|
138
|
+
The ElasticSearch Query DSL is pretty large and includes a ton of nuance. I'm starting with the
|
139
|
+
most basic parts of the DSL (and the parts I use for work), so if you want to help out with the project
|
140
|
+
to meet your needs please feel free to contribute! I just ask that you:
|
141
|
+
|
142
|
+
* Fork the project.
|
143
|
+
* Make your changes or additions.
|
144
|
+
* Add tests! My goal is complete test coverage, so please take the effort to make them pretty comprehensive.
|
145
|
+
* Send me a pull request.
|
146
|
+
|
147
|
+
Feedback or suggestions are also always welcome.
|
148
|
+
|
149
|
+
License
|
150
|
+
-------
|
151
|
+
|
152
|
+
The MIT License (MIT)
|
153
|
+
|
154
|
+
Copyright (c) 2013 Christopher Schuch
|
155
|
+
|
156
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
157
|
+
this software and associated documentation files (the "Software"), to deal in
|
158
|
+
the Software without restriction, including without limitation the rights to
|
159
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
160
|
+
the Software, and to permit persons to whom the Software is furnished to do so,
|
161
|
+
subject to the following conditions:
|
162
|
+
|
163
|
+
The above copyright notice and this permission notice shall be included in all
|
164
|
+
copies or substantial portions of the Software.
|
165
|
+
|
166
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
167
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
168
|
+
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
169
|
+
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
170
|
+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
171
|
+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/daedal.gemspec
CHANGED
@@ -1,6 +1,8 @@
|
|
1
|
+
require File.expand_path('../lib/daedal/version', __FILE__)
|
2
|
+
|
1
3
|
Gem::Specification.new do |s|
|
2
4
|
s.name = 'daedal'
|
3
|
-
s.version =
|
5
|
+
s.version = Daedal::VERSION
|
4
6
|
s.date = '2013-12-06'
|
5
7
|
s.summary = "ElasticSearch Query DSL Builders"
|
6
8
|
s.description = "Classes for easier ElasticSearch query creation"
|
@@ -11,4 +13,6 @@ Gem::Specification.new do |s|
|
|
11
13
|
s.license = 'MIT'
|
12
14
|
s.homepage =
|
13
15
|
'https://github.com/cschuch/daedal'
|
16
|
+
|
17
|
+
s.add_dependency('virtus', '~> 1.0.0')
|
14
18
|
end
|
data/lib/daedal.rb
CHANGED
data/lib/daedal/attributes.rb
CHANGED
@@ -1,94 +1,10 @@
|
|
1
1
|
require 'virtus'
|
2
|
-
require 'daedal/
|
3
|
-
require 'daedal/
|
2
|
+
require 'daedal/attributes/operator'
|
3
|
+
require 'daedal/attributes/match_type'
|
4
|
+
require 'daedal/attributes/query_array'
|
5
|
+
require 'daedal/attributes/score_mode'
|
4
6
|
|
5
7
|
module Daedal
|
6
8
|
module Attributes
|
7
|
-
|
8
|
-
"""Custom coercer for a query, allowing nil"""
|
9
|
-
class QueryOrNil < Virtus::Attribute
|
10
|
-
def coerce(value)
|
11
|
-
unless value.is_a? Daedal::Queries::BaseQuery or value.nil?
|
12
|
-
raise "Invalid query"
|
13
|
-
end
|
14
|
-
value
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
"""Custom coercer for a filter, allowing nil"""
|
19
|
-
class FilterOrNil < Virtus::Attribute
|
20
|
-
def coerce(value)
|
21
|
-
unless value.is_a? Daedal::Filters::BaseFilter or value.nil?
|
22
|
-
raise "Invalid filter"
|
23
|
-
end
|
24
|
-
value
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
"""Custom coercer for a query"""
|
29
|
-
class Query < Virtus::Attribute
|
30
|
-
def coerce(value)
|
31
|
-
unless value.is_a? Daedal::Queries::BaseQuery
|
32
|
-
raise "Must give a query"
|
33
|
-
end
|
34
|
-
value
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
"""Custom coercer for a filter"""
|
39
|
-
class Filter < Virtus::Attribute
|
40
|
-
def coerce(value)
|
41
|
-
unless value.is_a? Daedal::Filters::BaseFilter
|
42
|
-
raise "Must give a filter"
|
43
|
-
end
|
44
|
-
value
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
"""Custom coercer for an array of queries"""
|
49
|
-
class QueryArray < Virtus::Attribute
|
50
|
-
def coerce(value)
|
51
|
-
unless value.is_a? Array
|
52
|
-
value = [value]
|
53
|
-
end
|
54
|
-
|
55
|
-
value.each do |q|
|
56
|
-
unless q.is_a? Daedal::Queries::BaseQuery
|
57
|
-
raise "Must give an array of queries"
|
58
|
-
end
|
59
|
-
end
|
60
|
-
|
61
|
-
value
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
|
-
"""Custom coercer for the operator attribute"""
|
66
|
-
class Operator < Virtus::Attribute
|
67
|
-
ALLOWED_MATCH_OPERATORS = [:or, :and]
|
68
|
-
def coerce(value)
|
69
|
-
unless value.nil?
|
70
|
-
value = value.to_sym
|
71
|
-
unless ALLOWED_MATCH_OPERATORS.include? value
|
72
|
-
raise "#{value} is not a valid operator. Allowed values are #{ALLOWED_MATCH_OPERATORS}."
|
73
|
-
end
|
74
|
-
end
|
75
|
-
value
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
"""Custom coercer for the type attribute"""
|
80
|
-
class MatchType < Virtus::Attribute
|
81
|
-
ALLOWED_MATCH_TYPES = [:phrase, :phrase_prefix]
|
82
|
-
def coerce(value)
|
83
|
-
unless value.nil?
|
84
|
-
value = value.to_sym
|
85
|
-
unless ALLOWED_MATCH_TYPES.include? value
|
86
|
-
raise "#{value} is not a valid type. Allowed values are #{ALLOWED_MATCH_TYPES}."
|
87
|
-
end
|
88
|
-
end
|
89
|
-
value
|
90
|
-
end
|
91
|
-
end
|
92
|
-
|
93
9
|
end
|
94
10
|
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Daedal
|
2
|
+
module Attributes
|
3
|
+
"""Custom coercer for the type attribute"""
|
4
|
+
class MatchType < Virtus::Attribute
|
5
|
+
ALLOWED_MATCH_TYPES = [:phrase, :phrase_prefix]
|
6
|
+
def coerce(value)
|
7
|
+
unless value.nil?
|
8
|
+
value = value.to_sym
|
9
|
+
unless ALLOWED_MATCH_TYPES.include? value
|
10
|
+
raise Virtus::CoercionError.new(value, 'Daedal::Attributes::MatchType')
|
11
|
+
end
|
12
|
+
end
|
13
|
+
value
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Daedal
|
2
|
+
module Attributes
|
3
|
+
"""Custom coercer for the operator attribute"""
|
4
|
+
class Operator < Virtus::Attribute
|
5
|
+
ALLOWED_MATCH_OPERATORS = [:or, :and]
|
6
|
+
def coerce(value)
|
7
|
+
unless value.nil?
|
8
|
+
value = value.to_sym
|
9
|
+
unless ALLOWED_MATCH_OPERATORS.include? value
|
10
|
+
raise Virtus::CoercionError.new(value, 'Daedal::Attributes::Operator')
|
11
|
+
end
|
12
|
+
end
|
13
|
+
value
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Daedal
|
2
|
+
module Attributes
|
3
|
+
"""Custom attribute for an array of queries"""
|
4
|
+
class QueryArray < Array
|
5
|
+
# override the << method so that you throw
|
6
|
+
# an error if you don't try to append a query
|
7
|
+
def <<(q)
|
8
|
+
if q.is_a? Daedal::Queries::BaseQuery
|
9
|
+
super q
|
10
|
+
else
|
11
|
+
raise Virtus::CoercionError.new(q, 'Daedal::Queries::BaseQuery')
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Daedal
|
2
|
+
module Attributes
|
3
|
+
"""Custom coercer for the type attribute"""
|
4
|
+
class ScoreMode < Virtus::Attribute
|
5
|
+
ALLOWED_SCORE_MODES = [:avg, :total, :max, :none]
|
6
|
+
def coerce(value)
|
7
|
+
unless value.nil?
|
8
|
+
value = value.to_sym
|
9
|
+
unless ALLOWED_SCORE_MODES.include? value
|
10
|
+
raise Virtus::CoercionError.new(value, 'Daedal::Attributes::MatchType')
|
11
|
+
end
|
12
|
+
end
|
13
|
+
value
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
data/lib/daedal/filters.rb
CHANGED
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'daedal/filters/base_filter'
|
2
|
+
require 'daedal/attributes'
|
3
|
+
|
4
|
+
module Daedal
|
5
|
+
module Filters
|
6
|
+
"""Class for the basic term filter"""
|
7
|
+
class TermsFilter < BaseFilter
|
8
|
+
|
9
|
+
# required attributes
|
10
|
+
attribute :field, Symbol
|
11
|
+
attribute :terms, Array[Symbol]
|
12
|
+
|
13
|
+
def to_hash
|
14
|
+
{terms: {field => terms}}
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
data/lib/daedal/queries.rb
CHANGED
@@ -2,9 +2,18 @@ require 'virtus'
|
|
2
2
|
|
3
3
|
module Daedal
|
4
4
|
module Queries
|
5
|
+
|
6
|
+
"""Base class for queries. All other queries
|
7
|
+
should inherit from this class directly in order to
|
8
|
+
allow for data-type coercion for compound queries
|
9
|
+
like the bool or dis max query"""
|
5
10
|
class BaseQuery
|
11
|
+
# Virtus coercion is set to strict so that errors
|
12
|
+
# are returned when supplied fields cannot be properly
|
13
|
+
# coerced.
|
6
14
|
include Virtus.model strict: true
|
7
15
|
|
16
|
+
# requires the subclasses to define #to_hash
|
8
17
|
def to_json
|
9
18
|
to_hash.to_json
|
10
19
|
end
|
@@ -3,42 +3,25 @@ require 'daedal/attributes'
|
|
3
3
|
|
4
4
|
module Daedal
|
5
5
|
module Queries
|
6
|
-
"""Class for the
|
6
|
+
"""Class for the bool query"""
|
7
7
|
class BoolQuery < BaseQuery
|
8
8
|
|
9
9
|
# required attributes
|
10
|
-
|
11
|
-
|
12
|
-
|
10
|
+
|
11
|
+
# should, must, and must_not must be an array of queries
|
12
|
+
# these queries must inherit from the BaseQuery class
|
13
|
+
attribute :should, Attributes::QueryArray[Daedal::Queries::BaseQuery], default: Array.new
|
14
|
+
attribute :must, Attributes::QueryArray[Daedal::Queries::BaseQuery], default: Array.new
|
15
|
+
attribute :must_not, Attributes::QueryArray[Daedal::Queries::BaseQuery], default: Array.new
|
13
16
|
|
14
17
|
# non required attributes
|
15
18
|
attribute :minimum_should_match, Integer, required: false
|
16
19
|
attribute :boost, Integer, required: false
|
17
|
-
|
18
|
-
def verify_query(q)
|
19
|
-
unless q.is_a? Daedal::Queries::BaseQuery
|
20
|
-
raise "Must give a valid query"
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
def add_should_query(q)
|
25
|
-
verify_query(q)
|
26
|
-
should << q
|
27
|
-
end
|
28
|
-
|
29
|
-
def add_must_query(q)
|
30
|
-
verify_query(q)
|
31
|
-
must << q
|
32
|
-
end
|
33
|
-
|
34
|
-
def add_must_not_query(q)
|
35
|
-
verify_query(q)
|
36
|
-
must_not << q
|
37
|
-
end
|
20
|
+
attribute :name, Symbol, required: false
|
38
21
|
|
39
22
|
def to_hash
|
40
23
|
result = {bool: {should: should.map {|q| q.to_hash}, must: must.map {|q| q.to_hash}, must_not: must_not.map {|q| q.to_hash}}}
|
41
|
-
options = {minimum_should_match: minimum_should_match, boost: boost}
|
24
|
+
options = {minimum_should_match: minimum_should_match, boost: boost, _name: name}
|
42
25
|
result[:bool].merge!(options.select { |k,v| !v.nil? })
|
43
26
|
|
44
27
|
result
|
@@ -1,18 +1,20 @@
|
|
1
1
|
require 'daedal/queries/base_query'
|
2
|
+
require 'daedal/filters/base_filter'
|
2
3
|
require 'daedal/attributes'
|
3
4
|
|
4
5
|
module Daedal
|
5
6
|
module Queries
|
6
|
-
"""Class for the
|
7
|
+
"""Class for the constant score query"""
|
7
8
|
class ConstantScoreQuery < BaseQuery
|
8
9
|
|
9
10
|
# required attributes
|
10
11
|
attribute :boost, Float
|
11
12
|
|
12
13
|
# non required attributes, but one must be required of the two
|
13
|
-
attribute :query,
|
14
|
-
attribute :filter,
|
14
|
+
attribute :query, Daedal::Queries::BaseQuery, required: false
|
15
|
+
attribute :filter, Daedal::Filters::BaseFilter, required: false
|
15
16
|
|
17
|
+
# you must require *one of* query or filter in order for this to be valid
|
16
18
|
def initialize(options={})
|
17
19
|
super options
|
18
20
|
if query.nil? && filter.nil?
|
@@ -4,27 +4,16 @@ require 'daedal/attributes'
|
|
4
4
|
module Daedal
|
5
5
|
module Queries
|
6
6
|
|
7
|
-
"""Class for the
|
7
|
+
"""Class for the dis max query"""
|
8
8
|
class DisMaxQuery < BaseQuery
|
9
9
|
|
10
10
|
# required attributes
|
11
|
-
attribute :queries, Attributes::QueryArray, default: Array.new
|
11
|
+
attribute :queries, Attributes::QueryArray[Daedal::Queries::BaseQuery], default: Array.new
|
12
12
|
|
13
13
|
# non required attributes
|
14
14
|
attribute :tie_breaker, Float, required: false
|
15
15
|
attribute :boost, Integer, required: false
|
16
16
|
|
17
|
-
def verify_query(q)
|
18
|
-
unless q.is_a? Daedal::Queries::BaseQuery
|
19
|
-
raise "Must give a valid query"
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
def add_query(q)
|
24
|
-
verify_query(q)
|
25
|
-
queries << q
|
26
|
-
end
|
27
|
-
|
28
17
|
def to_hash
|
29
18
|
result = {dis_max: {queries: queries.map {|q| q.to_hash }}}
|
30
19
|
options = {tie_breaker: tie_breaker, boost: boost}
|
@@ -5,12 +5,12 @@ require 'daedal/attributes'
|
|
5
5
|
|
6
6
|
module Daedal
|
7
7
|
module Queries
|
8
|
-
"""Class for the
|
8
|
+
"""Class for the filtered query"""
|
9
9
|
class FilteredQuery < BaseQuery
|
10
10
|
|
11
11
|
# required attributes
|
12
|
-
attribute :query,
|
13
|
-
attribute :filter,
|
12
|
+
attribute :query, Daedal::Queries::BaseQuery, default: Daedal::Queries::MatchAllQuery.new
|
13
|
+
attribute :filter, Daedal::Filters::BaseFilter, default: Daedal::Filters::BaseFilter.new
|
14
14
|
|
15
15
|
def to_hash
|
16
16
|
{filtered: {query: query.to_hash, filter: filter.to_hash}}
|
@@ -4,7 +4,7 @@ require 'daedal/attributes'
|
|
4
4
|
module Daedal
|
5
5
|
module Queries
|
6
6
|
|
7
|
-
"""Class for the
|
7
|
+
"""Class for the multi match query"""
|
8
8
|
class MultiMatchQuery < BaseQuery
|
9
9
|
|
10
10
|
# required attributes
|
@@ -22,6 +22,7 @@ module Daedal
|
|
22
22
|
attribute :boost, Integer, required: false
|
23
23
|
attribute :fuzziness, Float, required: false
|
24
24
|
|
25
|
+
# Fields cannot be an empty array... should eventually refactor this kind of thing out of initialize
|
25
26
|
def initialize(options={})
|
26
27
|
super options
|
27
28
|
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'daedal/queries/base_query'
|
2
|
+
require 'daedal/attributes'
|
3
|
+
|
4
|
+
module Daedal
|
5
|
+
module Queries
|
6
|
+
"""Class for the bool query"""
|
7
|
+
class NestedQuery < BaseQuery
|
8
|
+
|
9
|
+
# required attributes
|
10
|
+
attribute :path, Symbol
|
11
|
+
attribute :query, Daedal::Queries::BaseQuery
|
12
|
+
|
13
|
+
# non required attributes
|
14
|
+
attribute :score_mode, Attributes::ScoreMode, required: false
|
15
|
+
|
16
|
+
def to_hash
|
17
|
+
result = {nested: {path: path, query: query.to_hash}}
|
18
|
+
unless score_mode.nil?
|
19
|
+
result[:nested][:score_mode] = score_mode
|
20
|
+
end
|
21
|
+
|
22
|
+
result
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'daedal/filters'
|
3
|
+
|
4
|
+
describe Daedal::Filters::TermsFilter do
|
5
|
+
|
6
|
+
subject do
|
7
|
+
Daedal::Filters::TermsFilter
|
8
|
+
end
|
9
|
+
|
10
|
+
let(:field) do
|
11
|
+
:foo
|
12
|
+
end
|
13
|
+
|
14
|
+
let(:terms) do
|
15
|
+
[:foo, :bar]
|
16
|
+
end
|
17
|
+
|
18
|
+
let(:hash_filter) do
|
19
|
+
{terms: {field => terms}}
|
20
|
+
end
|
21
|
+
|
22
|
+
context 'without a field or a list of terms specified' do
|
23
|
+
it 'will raise an error' do
|
24
|
+
expect {subject.new}.to raise_error
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
context 'without a field specified' do
|
29
|
+
it 'will raise an error' do
|
30
|
+
expect {subject.new(terms: terms)}.to raise_error
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
context 'with a field and a list of terms specified' do
|
35
|
+
let(:filter) do
|
36
|
+
subject.new(field: field, terms: terms.map {|t| t.to_s})
|
37
|
+
end
|
38
|
+
it 'will populate the field and term attributes appropriately' do
|
39
|
+
expect(filter.field).to eq field
|
40
|
+
expect(filter.terms).to eq terms
|
41
|
+
end
|
42
|
+
it 'will have the correct hash representation' do
|
43
|
+
expect(filter.to_hash).to eq hash_filter
|
44
|
+
end
|
45
|
+
it 'will have the correct json representation' do
|
46
|
+
expect(filter.to_json).to eq hash_filter.to_json
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
require 'daedal/queries'
|
3
|
+
require 'debugger'
|
3
4
|
|
4
5
|
describe Daedal::Queries::BoolQuery do
|
5
6
|
|
@@ -136,9 +137,9 @@ describe Daedal::Queries::BoolQuery do
|
|
136
137
|
match_query.new(field: :a, query: :b)
|
137
138
|
end
|
138
139
|
|
139
|
-
context 'with the
|
140
|
+
context 'with the should.<< method' do
|
140
141
|
before do
|
141
|
-
query.
|
142
|
+
query.should << mq
|
142
143
|
end
|
143
144
|
it 'will add a should query' do
|
144
145
|
expect(query.should).to eq [mq]
|
@@ -146,7 +147,7 @@ describe Daedal::Queries::BoolQuery do
|
|
146
147
|
|
147
148
|
context 'twice' do
|
148
149
|
before do
|
149
|
-
query.
|
150
|
+
query.should << mq
|
150
151
|
end
|
151
152
|
it 'will append the second query' do
|
152
153
|
expect(query.should).to eq [mq, mq]
|
@@ -155,14 +156,14 @@ describe Daedal::Queries::BoolQuery do
|
|
155
156
|
|
156
157
|
context 'with a non-valid query' do
|
157
158
|
it 'will raise an error' do
|
158
|
-
expect{query.
|
159
|
+
expect{query.should << :foo}.to raise_error
|
159
160
|
end
|
160
161
|
end
|
161
162
|
end
|
162
163
|
|
163
|
-
context 'with the
|
164
|
+
context 'with the must.<< method' do
|
164
165
|
before do
|
165
|
-
query.
|
166
|
+
query.must << mq
|
166
167
|
end
|
167
168
|
|
168
169
|
it 'will add a should query' do
|
@@ -171,7 +172,7 @@ describe Daedal::Queries::BoolQuery do
|
|
171
172
|
|
172
173
|
context 'twice' do
|
173
174
|
before do
|
174
|
-
query.
|
175
|
+
query.must << mq
|
175
176
|
end
|
176
177
|
it 'will append the second query' do
|
177
178
|
expect(query.must).to eq [mq, mq]
|
@@ -180,15 +181,15 @@ describe Daedal::Queries::BoolQuery do
|
|
180
181
|
|
181
182
|
context 'with a non-valid query' do
|
182
183
|
it 'will raise an error' do
|
183
|
-
expect {query.
|
184
|
+
expect {query.must << :foo}.to raise_error
|
184
185
|
end
|
185
186
|
end
|
186
187
|
|
187
188
|
end
|
188
189
|
|
189
|
-
context 'with the
|
190
|
+
context 'with the must_not.<< method' do
|
190
191
|
before do
|
191
|
-
query.
|
192
|
+
query.must_not << mq
|
192
193
|
end
|
193
194
|
|
194
195
|
it 'will add a must_not query' do
|
@@ -197,7 +198,7 @@ describe Daedal::Queries::BoolQuery do
|
|
197
198
|
|
198
199
|
context 'twice' do
|
199
200
|
before do
|
200
|
-
query.
|
201
|
+
query.must_not << mq
|
201
202
|
end
|
202
203
|
it 'will append the second query' do
|
203
204
|
expect(query.must_not).to eq [mq, mq]
|
@@ -206,7 +207,7 @@ describe Daedal::Queries::BoolQuery do
|
|
206
207
|
|
207
208
|
context 'with a non-valid query' do
|
208
209
|
it 'will raise an error' do
|
209
|
-
expect {query.
|
210
|
+
expect {query.must_not << :foo}.to raise_error
|
210
211
|
end
|
211
212
|
end
|
212
213
|
end
|
@@ -36,6 +36,18 @@ describe Daedal::Queries::ConstantScoreQuery do
|
|
36
36
|
end
|
37
37
|
end
|
38
38
|
|
39
|
+
context 'with a boost but an invalid query specified' do
|
40
|
+
it 'will raise an error' do
|
41
|
+
expect {subject.new(boost: 5, query: :foo)}.to raise_error
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
context 'with a boost but an invalid filter specified' do
|
46
|
+
it 'will raise an error' do
|
47
|
+
expect {subject.new(boost: 5, filter: :foo)}.to raise_error
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
39
51
|
context 'with a query and a boost specified' do
|
40
52
|
let(:query) do
|
41
53
|
subject.new(query: match_query, boost: 5)
|
@@ -124,9 +124,9 @@ describe Daedal::Queries::DisMaxQuery do
|
|
124
124
|
match_query.new(field: :a, query: :b)
|
125
125
|
end
|
126
126
|
|
127
|
-
context 'with the
|
127
|
+
context 'with the queries.<< method' do
|
128
128
|
before do
|
129
|
-
query.
|
129
|
+
query.queries << mq
|
130
130
|
end
|
131
131
|
it 'will add a query' do
|
132
132
|
expect(query.queries).to eq [mq]
|
@@ -134,7 +134,7 @@ describe Daedal::Queries::DisMaxQuery do
|
|
134
134
|
|
135
135
|
context 'twice' do
|
136
136
|
before do
|
137
|
-
query.
|
137
|
+
query.queries << mq
|
138
138
|
end
|
139
139
|
it 'will append the second query' do
|
140
140
|
expect(query.queries).to eq [mq, mq]
|
@@ -143,7 +143,7 @@ describe Daedal::Queries::DisMaxQuery do
|
|
143
143
|
|
144
144
|
context 'with a non-valid query' do
|
145
145
|
it 'will raise an error' do
|
146
|
-
expect{query.
|
146
|
+
expect{query.queries << :foo}.to raise_error
|
147
147
|
end
|
148
148
|
end
|
149
149
|
end
|
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
require 'daedal/queries'
|
3
|
+
require 'daedal/filters'
|
3
4
|
|
4
5
|
describe Daedal::Queries::FilteredQuery do
|
5
6
|
|
@@ -40,6 +41,18 @@ describe Daedal::Queries::FilteredQuery do
|
|
40
41
|
end
|
41
42
|
end
|
42
43
|
|
44
|
+
context 'with an invalid query specified' do
|
45
|
+
it 'will raise an error' do
|
46
|
+
expect{subject.new(query: :foo)}.to raise_error
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
context 'with an invalid filter specified' do
|
51
|
+
it 'will raise an error' do
|
52
|
+
expect{subject.new(filter: :foo)}.to raise_error
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
43
56
|
context 'with a query and a filter specified' do
|
44
57
|
let(:query) do
|
45
58
|
subject.new(query: match_query, filter: term_filter)
|
@@ -0,0 +1,82 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'daedal/queries'
|
3
|
+
require 'daedal/filters'
|
4
|
+
|
5
|
+
describe Daedal::Queries::NestedQuery do
|
6
|
+
|
7
|
+
subject do
|
8
|
+
Daedal::Queries::NestedQuery
|
9
|
+
end
|
10
|
+
|
11
|
+
let(:match_all_query) do
|
12
|
+
Daedal::Queries::MatchAllQuery.new
|
13
|
+
end
|
14
|
+
|
15
|
+
context 'with no path specified' do
|
16
|
+
it 'will raise an error' do
|
17
|
+
expect{subject.new(query: match_all_query)}.to raise_error
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
context 'with no query specified' do
|
22
|
+
it 'will raise an error' do
|
23
|
+
expect{subject.new(path: 'foo')}.to raise_error
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
context 'with an invalid query specified' do
|
28
|
+
it 'will raise an error' do
|
29
|
+
expect{subject.new(query: :foo)}.to raise_error
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
context 'with a query and a path specified' do
|
34
|
+
let(:query) do
|
35
|
+
subject.new query: match_all_query, path: :foo
|
36
|
+
end
|
37
|
+
let(:hash_query) do
|
38
|
+
{nested: {path: :foo, query: match_all_query.to_hash}}
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'will create a nested query with the appropriate fields' do
|
42
|
+
expect(query.query).to eq match_all_query
|
43
|
+
expect(query.path).to eq :foo
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'will have the correct hash representation' do
|
47
|
+
expect(query.to_hash).to eq hash_query
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'will have the correct json representation' do
|
51
|
+
expect(query.to_json).to eq hash_query.to_json
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
context 'with score_mode specified' do
|
56
|
+
let(:query) do
|
57
|
+
subject.new query: match_all_query, path: :foo, score_mode: :avg
|
58
|
+
end
|
59
|
+
let(:hash_query) do
|
60
|
+
{nested: {path: :foo, query: match_all_query.to_hash, score_mode: :avg}}
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'will create a nested query with the appropriate fields' do
|
64
|
+
expect(query.query).to eq match_all_query
|
65
|
+
expect(query.path).to eq :foo
|
66
|
+
expect(query.score_mode).to eq :avg
|
67
|
+
end
|
68
|
+
|
69
|
+
it 'will have the correct hash representation' do
|
70
|
+
expect(query.to_hash).to eq hash_query
|
71
|
+
end
|
72
|
+
it 'will have the correct json representation' do
|
73
|
+
expect(query.to_json).to eq hash_query.to_json
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
context 'with an invalid score_mode specified' do
|
78
|
+
it 'will raise an error' do
|
79
|
+
expect{subject.new(query: match_all_query, path: :foo, score_mode: 'foo')}.to raise_error
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: daedal
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Christopher Schuch
|
@@ -9,7 +9,21 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
date: 2013-12-06 00:00:00.000000000 Z
|
12
|
-
dependencies:
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: virtus
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 1.0.0
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 1.0.0
|
13
27
|
description: Classes for easier ElasticSearch query creation
|
14
28
|
email: cas13091@gmail.com
|
15
29
|
executables: []
|
@@ -26,9 +40,14 @@ files:
|
|
26
40
|
- daedal.gemspec
|
27
41
|
- lib/daedal.rb
|
28
42
|
- lib/daedal/attributes.rb
|
43
|
+
- lib/daedal/attributes/match_type.rb
|
44
|
+
- lib/daedal/attributes/operator.rb
|
45
|
+
- lib/daedal/attributes/query_array.rb
|
46
|
+
- lib/daedal/attributes/score_mode.rb
|
29
47
|
- lib/daedal/filters.rb
|
30
48
|
- lib/daedal/filters/base_filter.rb
|
31
49
|
- lib/daedal/filters/term_filter.rb
|
50
|
+
- lib/daedal/filters/terms_filter.rb
|
32
51
|
- lib/daedal/queries.rb
|
33
52
|
- lib/daedal/queries/base_query.rb
|
34
53
|
- lib/daedal/queries/bool_query.rb
|
@@ -38,8 +57,10 @@ files:
|
|
38
57
|
- lib/daedal/queries/match_all_query.rb
|
39
58
|
- lib/daedal/queries/match_query.rb
|
40
59
|
- lib/daedal/queries/multi_match_query.rb
|
60
|
+
- lib/daedal/queries/nested_query.rb
|
41
61
|
- spec/spec_helper.rb
|
42
62
|
- spec/unit/daedal/filters/term_filter_spec.rb
|
63
|
+
- spec/unit/daedal/filters/terms_filter_spec.rb
|
43
64
|
- spec/unit/daedal/queries/bool_query_spec.rb
|
44
65
|
- spec/unit/daedal/queries/constant_score_query_spec.rb
|
45
66
|
- spec/unit/daedal/queries/dis_max_query_spec.rb
|
@@ -47,6 +68,7 @@ files:
|
|
47
68
|
- spec/unit/daedal/queries/match_all_query_spec.rb
|
48
69
|
- spec/unit/daedal/queries/match_query_spec.rb
|
49
70
|
- spec/unit/daedal/queries/multi_match_query_spec.rb
|
71
|
+
- spec/unit/daedal/queries/nested_query_spec.rb
|
50
72
|
homepage: https://github.com/cschuch/daedal
|
51
73
|
licenses:
|
52
74
|
- MIT
|