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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ee41dfa3c33abb94b45a246a59dd12b9ed45a278
4
- data.tar.gz: 4ec21b922bb6b1e9fcd5cb94f6effad2159d8d70
3
+ metadata.gz: 01d15eb052c93f8a9dedb824873a533e876c5eee
4
+ data.tar.gz: d3408e2da2b82d8c35bf1cb07330fdb62e09c547
5
5
  SHA512:
6
- metadata.gz: 0676d06f03db74a4cf9fe0fa016f0d7197d75fc1a1c2acb21780e5b22191ff9a487f9022580a412943b62f968b8d19f9264b3a3ece0cc719475e5a70a74c47d2
7
- data.tar.gz: c7a4f7ece2fa6d1aebc00fdad3b095ff22b529a84aba9440124b6d5b607da38ce62c117cad8905a1b476fb8cfdee085e94dc27a3e9b86f09c446224f7279c0b8
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 for easier ElasticSearch query building
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.
@@ -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 = '0.0.2'
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
@@ -1,4 +1,5 @@
1
1
  require 'json'
2
+
2
3
  require 'daedal/queries'
3
4
  require 'daedal/filters'
4
5
  require 'daedal/attributes'
@@ -1,94 +1,10 @@
1
1
  require 'virtus'
2
- require 'daedal/queries/base_query'
3
- require 'daedal/filters/base_filter'
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
@@ -1,5 +1,6 @@
1
1
  require 'daedal/filters/base_filter'
2
2
  require 'daedal/filters/term_filter'
3
+ require 'daedal/filters/terms_filter'
3
4
 
4
5
  module Daedal
5
6
  module Filters
@@ -3,7 +3,7 @@ require 'daedal/attributes'
3
3
 
4
4
  module Daedal
5
5
  module Filters
6
- """Class for the basic match query"""
6
+ """Class for the basic term filter"""
7
7
  class TermFilter < BaseFilter
8
8
 
9
9
  # required attributes
@@ -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
@@ -6,6 +6,7 @@ require 'daedal/queries/filtered_query'
6
6
  require 'daedal/queries/match_all_query'
7
7
  require 'daedal/queries/match_query'
8
8
  require 'daedal/queries/multi_match_query'
9
+ require 'daedal/queries/nested_query'
9
10
 
10
11
  module Daedal
11
12
  module Queries
@@ -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 basic match query"""
6
+ """Class for the bool query"""
7
7
  class BoolQuery < BaseQuery
8
8
 
9
9
  # required attributes
10
- attribute :should, Attributes::QueryArray, default: Array.new
11
- attribute :must, Attributes::QueryArray, default: Array.new
12
- attribute :must_not, Attributes::QueryArray, default: Array.new
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 basic match query"""
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, Attributes::QueryOrNil
14
- attribute :filter, Attributes::FilterOrNil
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 basic match query"""
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 basic match query"""
8
+ """Class for the filtered query"""
9
9
  class FilteredQuery < BaseQuery
10
10
 
11
11
  # required attributes
12
- attribute :query, Attributes::Query, default: Daedal::Queries::MatchAllQuery.new
13
- attribute :filter, Attributes::Filter, default: Daedal::Filters::BaseFilter.new
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}}
@@ -2,7 +2,7 @@ require 'daedal/queries/base_query'
2
2
 
3
3
  module Daedal
4
4
  module Queries
5
- """Class for the basic match query"""
5
+ """Class for the match all query"""
6
6
  class MatchAllQuery < BaseQuery
7
7
  def to_hash
8
8
  {match_all: {}}
@@ -4,7 +4,7 @@ require 'daedal/attributes'
4
4
  module Daedal
5
5
  module Queries
6
6
 
7
- """Class for the basic match query"""
7
+ """Class for the match query"""
8
8
  class MatchQuery < BaseQuery
9
9
 
10
10
  # required attributes
@@ -4,7 +4,7 @@ require 'daedal/attributes'
4
4
  module Daedal
5
5
  module Queries
6
6
 
7
- """Class for the multi_match query"""
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 #add_should_query method' do
140
+ context 'with the should.<< method' do
140
141
  before do
141
- query.add_should_query mq
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.add_should_query mq
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.add_should_query :foo}.to raise_error
159
+ expect{query.should << :foo}.to raise_error
159
160
  end
160
161
  end
161
162
  end
162
163
 
163
- context 'with the #add_must_query method' do
164
+ context 'with the must.<< method' do
164
165
  before do
165
- query.add_must_query mq
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.add_must_query mq
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.add_must_query :foo}.to raise_error
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 #add_must_not_query method' do
190
+ context 'with the must_not.<< method' do
190
191
  before do
191
- query.add_must_not_query mq
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.add_must_not_query mq
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.add_must_not_query :foo}.to raise_error
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 #add_query method' do
127
+ context 'with the queries.<< method' do
128
128
  before do
129
- query.add_query mq
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.add_query mq
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.add_query :foo}.to raise_error
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.2
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