qiita-elasticsearch 0.3.0 → 0.4.0

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: cc0094615455695aa7148b67052af7b154c5e31e
4
- data.tar.gz: 64562e5f4139f14eb727062d7caf39cf706f92eb
3
+ metadata.gz: 133b6b66d4231ea9d97e516812cc58b232981319
4
+ data.tar.gz: b70d9f047d78e461e4cd81a076e5f09418982682
5
5
  SHA512:
6
- metadata.gz: 183fabc234d8480455a5804eb80a8ccca40cc0b0e39fc5f6ee2f75800958875170203063f76303c88ea68e45388f347aa000f14c13d204eb6f2f8317c213b5d7
7
- data.tar.gz: 857a39fb54f660ed9a3edf6c74b45212589ba558586bd0966f2b388454099ce5aad322a7b77949d1a4129b10ae6e755eacf377b8c2eecf3e6a0f43a042637ba6
6
+ metadata.gz: 3d9776c15e61239299ec17682c62930e2fddade09934cccf08f236a8e85f38bb8788fc34703323a4e49d66094bc19c494a4b8e7cd6c3a567bdebab0a5b564e68
7
+ data.tar.gz: 93d80c35c9135c8f3cb0837731fccd55b60cca6a912e9a36e1f641f71984b7f815b1d945c2a9836295fad9389ecec433566a5c457907759f0157c027caeb7b7d
data/.rubocop.yml CHANGED
@@ -39,3 +39,7 @@ Style/StringLiterals:
39
39
 
40
40
  Style/TrailingComma:
41
41
  Enabled: false
42
+
43
+ Metrics/ParameterLists:
44
+ Max: 5
45
+ CountKeywordArgs: false
data/CHANGELOG.md CHANGED
@@ -1,3 +1,10 @@
1
+ ## 0.4.0
2
+ - Change range fields to use integer
3
+ - Support date fields
4
+ - Support time_zone parameter
5
+ - Rename range_fields parameter as int_fields
6
+ - Return a null query if an invalid query string is given
7
+
1
8
  ## 0.3.0
2
9
  - Add downcased_fields options and update case rule
3
10
 
data/README.md CHANGED
@@ -60,15 +60,36 @@ query_builder.build("tag:ruby")
60
60
  #=> {"filtered"=>{"filter"=>{"bool"=>{"should"=>[{"prefix"=>{"tag"=>"ruby/"}}, {"term"=>{"tag"=>"ruby"}}]}}}}
61
61
  ```
62
62
 
63
- ### range_fields
64
- Pass `:range_fields` option with `:filterable_fields` to enable range filtered queries.
65
- With this option, `created_at:<2015-04-16` will hit documents created before 2015-04-16.
63
+ ### int_fields
64
+ Pass `:int_fields` option with `:filterable_fields` to enable range filtered queries.
65
+ With this option, `stocks:>100` will hit documents stocked by greater than 100 users.
66
66
 
67
67
  ```rb
68
- query_builder = Qiita::Elasticsearch::QueryBuilder.new(filterable_fields: ["created_at"], range_fields: ["created_at"])
68
+ query_builder = Qiita::Elasticsearch::QueryBuilder.new(filterable_fields: ["stocks"], int_fields: ["stocks"])
69
+
70
+ query_builder.build("stocks:>100")
71
+ #=> {"filtered"=>{"filter"=>{"range"=>{"stocks"=>{"gt"=>100}}}}}
72
+ ```
73
+
74
+ ### date_fields
75
+ Pass `:date_fields` option with `:filterable_fields` to enable date filtered queries.
76
+ With this option, `created_at:<2015-04-01` will hit documents created before 2015-04-01.
77
+
78
+ ```rb
79
+ query_builder = Qiita::Elasticsearch::QueryBuilder.new(filterable_fields: ["created_at"], date_fields: ["created_at"])
80
+
81
+ query_builder.build("created_at:<2015-04-01")
82
+ #=> {"filtered"=>{"filter"=>{"range"=>{"created_at"=>{"lt"=>"2015-04-01"}}}}}
83
+ ```
84
+
85
+ ### time_zone
86
+ Pass `:time_zone` option to tell how move range field's input to UTC time based date.
87
+
88
+ ```rb
89
+ query_builder = Qiita::Elasticsearch::QueryBuilder.new(filterable_fields: ["created_at"], date_fields: ["created_at"], time_zone: "+09:00")
69
90
 
70
91
  query_builder.build("created_at:<2015-04-16")
71
- #=> {"filtered"=>{"filter"=>{"range"=>{"created_at"=>{"lt"=>"2015-04-16"}}}}}
92
+ #=> {"filtered"=>{"filter"=>{"range"=>{"created_at"=>{"lt"=>"2015-04-16","time_zone"=>"+09:00"}}}}}
72
93
  ```
73
94
 
74
95
  ### downcased_fields
@@ -0,0 +1,42 @@
1
+ require "active_support/concern"
2
+
3
+ module Qiita
4
+ module Elasticsearch
5
+ module Concerns
6
+ module RangeOperandIncludable
7
+ extend ActiveSupport::Concern
8
+
9
+ RANGE_TERM_REGEXP = /\A(?<operand>\<=|\<|\>=|\>)(?<query>.*)\z/
10
+
11
+ private
12
+
13
+ # @return [String, nil]
14
+ # @example Suppose @term is "created_at:>=2015-04-16"
15
+ # range_parameter #=> "gte"
16
+ def range_parameter
17
+ range_match[:operand] ? operand_map[range_match[:operand]] : nil
18
+ end
19
+
20
+ # @return [String, nil]
21
+ # @example Suppose @term is "created_at:>=2015-04-16"
22
+ # range_query #=> "2015-04-16"
23
+ def range_query
24
+ range_match[:query]
25
+ end
26
+
27
+ def range_match
28
+ @range_match ||= RANGE_TERM_REGEXP.match(@term) || {}
29
+ end
30
+
31
+ def operand_map
32
+ {
33
+ ">" => "gt",
34
+ ">=" => "gte",
35
+ "<" => "lt",
36
+ "<=" => "lte",
37
+ }
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,93 @@
1
+ require "active_support/core_ext/date"
2
+ require "active_support/core_ext/integer"
3
+ require "qiita/elasticsearch/concerns/range_operand_includable"
4
+ require "qiita/elasticsearch/errors"
5
+ require "qiita/elasticsearch/token"
6
+
7
+ module Qiita
8
+ module Elasticsearch
9
+ class DateToken < Token
10
+ include Concerns::RangeOperandIncludable
11
+
12
+ # @note Matches to "YYYY", "YYYY-MM" and "YYYY-MM-DD"
13
+ DATE_PATTERN = /\A
14
+ (?<year>\d{4})
15
+ (?:
16
+ -
17
+ (?<month>\d{1,2})
18
+ (?:
19
+ -
20
+ (?<day>\d{1,2})
21
+ )?
22
+ )?
23
+ \z/x
24
+
25
+ attr_writer :time_zone
26
+
27
+ # @return [Hash]
28
+ # @raise [InvalidQuery]
29
+ def to_hash
30
+ if date_match
31
+ if range_parameter
32
+ {
33
+ "range" => {
34
+ @field_name => {
35
+ range_parameter => range_query,
36
+ "time_zone" => @time_zone,
37
+ }.reject do |key, value|
38
+ key == "time_zone" && value.nil?
39
+ end,
40
+ },
41
+ }
42
+ else
43
+ {
44
+ "range" => {
45
+ @field_name => {
46
+ "gte" => beginning_of_range.to_s,
47
+ "lt" => end_of_range.to_s,
48
+ "time_zone" => @time_zone,
49
+ }.reject do |key, value|
50
+ key == "time_zone" && value.nil?
51
+ end,
52
+ },
53
+ }
54
+ end
55
+ else
56
+ fail InvalidQuery
57
+ end
58
+ end
59
+
60
+ private
61
+
62
+ def date_match
63
+ @date_match ||= DATE_PATTERN.match(range_query || @term)
64
+ end
65
+
66
+ # @return [Date]
67
+ def beginning_of_range
68
+ @beginning_of_range ||=
69
+ case
70
+ when date_match[:day]
71
+ Date.new(date_match[:year].to_i, date_match[:month].to_i, date_match[:day].to_i)
72
+ when date_match[:month]
73
+ Date.new(date_match[:year].to_i, date_match[:month].to_i)
74
+ else
75
+ Date.new(date_match[:year].to_i)
76
+ end
77
+ end
78
+
79
+ # @return [Date]
80
+ def end_of_range
81
+ @end_of_range ||=
82
+ case
83
+ when date_match[:day]
84
+ beginning_of_range + 1.day
85
+ when date_match[:month]
86
+ beginning_of_range + 1.month
87
+ else
88
+ beginning_of_range + 1.year
89
+ end
90
+ end
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,10 @@
1
+ module Qiita
2
+ module Elasticsearch
3
+ # @note Custom error class for rescuing from all Qiita::Elasticsearch errors.
4
+ class Error < StandardError
5
+ end
6
+
7
+ class InvalidQuery < Error
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,35 @@
1
+ require "qiita/elasticsearch/concerns/range_operand_includable"
2
+ require "qiita/elasticsearch/errors"
3
+ require "qiita/elasticsearch/token"
4
+
5
+ module Qiita
6
+ module Elasticsearch
7
+ class IntToken < Token
8
+ include Concerns::RangeOperandIncludable
9
+
10
+ INT_PATTERN = /\A\d+\z/
11
+
12
+ # @return [Hash]
13
+ # @raise [InvalidQuery]
14
+ def to_hash
15
+ if range_parameter && INT_PATTERN =~ range_query
16
+ {
17
+ "range" => {
18
+ @field_name => {
19
+ range_parameter => range_query.to_i,
20
+ },
21
+ },
22
+ }
23
+ elsif INT_PATTERN =~ @term
24
+ {
25
+ "term" => {
26
+ @field_name => @term.to_i,
27
+ },
28
+ }
29
+ else
30
+ fail InvalidQuery
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -1,3 +1,4 @@
1
+ require "qiita/elasticsearch/errors"
1
2
  require "qiita/elasticsearch/nodes/null_node"
2
3
  require "qiita/elasticsearch/nodes/or_separatable_node"
3
4
  require "qiita/elasticsearch/tokenizer"
@@ -5,17 +6,21 @@ require "qiita/elasticsearch/tokenizer"
5
6
  module Qiita
6
7
  module Elasticsearch
7
8
  class QueryBuilder
9
+ # @param [Array<String>, nil] date_fields
8
10
  # @param [Array<String>, nil] downcased_fields
9
11
  # @param [Array<String>, nil] filterable_fields
10
12
  # @param [Array<String>, nil] hierarchal_fields
13
+ # @param [Array<String>, nil] int_fields
11
14
  # @param [Array<String>, nil] matchable_fields
12
- # @param [Array<String>, nil] range_fields
13
- def initialize(downcased_fields: nil, hierarchal_fields: nil, filterable_fields: nil, matchable_fields: nil, range_fields: nil)
15
+ # @param [String, nil] time_zone
16
+ def initialize(date_fields: nil, downcased_fields: nil, hierarchal_fields: nil, filterable_fields: nil, int_fields: nil, matchable_fields: nil, time_zone: nil)
17
+ @date_fields = date_fields
14
18
  @downcased_fields = downcased_fields
15
- @hierarchal_fields = hierarchal_fields
16
19
  @filterable_fields = filterable_fields
20
+ @hierarchal_fields = hierarchal_fields
21
+ @int_fields = int_fields
17
22
  @matchable_fields = matchable_fields
18
- @range_fields = range_fields
23
+ @time_zone = time_zone
19
24
  end
20
25
 
21
26
  # @param [String] query_string Raw query string
@@ -27,17 +32,21 @@ module Qiita
27
32
  else
28
33
  Nodes::OrSeparatableNode.new(tokens).to_hash
29
34
  end
35
+ rescue Error
36
+ Nodes::NullNode.new.to_hash
30
37
  end
31
38
 
32
39
  private
33
40
 
34
41
  def tokenizer
35
42
  @tokenizer ||= Tokenizer.new(
43
+ date_fields: @date_fields,
36
44
  downcased_fields: @downcased_fields,
37
- hierarchal_fields: @hierarchal_fields,
38
45
  filterable_fields: @filterable_fields,
46
+ hierarchal_fields: @hierarchal_fields,
47
+ int_fields: @int_fields,
39
48
  matchable_fields: @matchable_fields,
40
- range_fields: @range_fields,
49
+ time_zone: @time_zone,
41
50
  )
42
51
  end
43
52
  end
@@ -3,7 +3,7 @@ require "qiita/elasticsearch/token"
3
3
  module Qiita
4
4
  module Elasticsearch
5
5
  class RangeToken < Token
6
- RANGE_TERM_REGEXP = /\A(?<operand>\<|\<=|\>|\>=)(?<query>.*)\z/
6
+ RANGE_TERM_REGEXP = /\A(?<operand>\<=|\<|\>=|\>)(?<query>.*)\z/
7
7
 
8
8
  # @return [Hash]
9
9
  def to_hash
@@ -11,14 +11,14 @@ module Qiita
11
11
  {
12
12
  "range" => {
13
13
  @field_name => {
14
- range_parameter => range_query,
14
+ range_parameter => range_query.to_i,
15
15
  },
16
16
  },
17
17
  }
18
18
  else
19
19
  {
20
20
  "term" => {
21
- @field_name => proper_cased_term,
21
+ @field_name => proper_cased_term.to_i,
22
22
  },
23
23
  }
24
24
  end
@@ -1,15 +1,17 @@
1
+ require "qiita/elasticsearch/date_token"
1
2
  require "qiita/elasticsearch/filterable_token"
2
3
  require "qiita/elasticsearch/hierarchal_token"
3
4
  require "qiita/elasticsearch/matchable_token"
4
- require "qiita/elasticsearch/range_token"
5
+ require "qiita/elasticsearch/int_token"
5
6
 
6
7
  module Qiita
7
8
  module Elasticsearch
8
9
  class Tokenizer
10
+ DEFAULT_DATE_FIELDS = []
9
11
  DEFAULT_DOWNCASED_FIELDS = []
10
12
  DEFAULT_FILTERABLE_FIELDS = []
11
13
  DEFAULT_HIERARCHAL_FIELDS = []
12
- DEFAULT_RANGE_FIELDS = []
14
+ DEFAULT_INT_FIELDS = []
13
15
 
14
16
  TOKEN_PATTERN = /
15
17
  (?<token_string>
@@ -23,17 +25,21 @@ module Qiita
23
25
  )
24
26
  /x
25
27
 
28
+ # @param [Array<String>, nil] date_fields
26
29
  # @param [Array<String>, nil] downcased_fields
27
30
  # @param [Array<String>, nil] filterable_fields
28
31
  # @param [Array<String>, nil] hierarchal_fields
32
+ # @param [Array<String>, nil] int_fields
29
33
  # @param [Array<String>, nil] matchable_fields
30
- # @param [Array<String>, nil] range_fields
31
- def initialize(downcased_fields: nil, filterable_fields: nil, hierarchal_fields: nil, matchable_fields: nil, range_fields: nil)
34
+ # @param [String, nil] time_zone
35
+ def initialize(date_fields: nil, downcased_fields: nil, filterable_fields: nil, hierarchal_fields: nil, int_fields: nil, matchable_fields: nil, time_zone: nil)
36
+ @date_fields = date_fields
32
37
  @downcased_fields = downcased_fields
33
38
  @filterable_fields = filterable_fields
34
39
  @hierarchal_fields = hierarchal_fields
40
+ @int_fields = int_fields
35
41
  @matchable_fields = matchable_fields
36
- @range_fields = range_fields
42
+ @time_zone = time_zone
37
43
  end
38
44
 
39
45
  # @param [String] query_string Raw query string
@@ -54,12 +60,17 @@ module Qiita
54
60
  token_string: token_string,
55
61
  )
56
62
  token.matchable_fields = @matchable_fields if token.is_a?(MatchableToken)
63
+ token.time_zone = @time_zone if token.is_a?(DateToken)
57
64
  token
58
65
  end
59
66
  end
60
67
 
61
68
  private
62
69
 
70
+ def date_fields
71
+ @date_fields || DEFAULT_DATE_FIELDS
72
+ end
73
+
63
74
  def downcased_fields
64
75
  @downcased_fields || DEFAULT_DOWNCASED_FIELDS
65
76
  end
@@ -72,14 +83,16 @@ module Qiita
72
83
  @hierarchal_fields || DEFAULT_HIERARCHAL_FIELDS
73
84
  end
74
85
 
75
- def range_fields
76
- @range_fields || DEFAULT_RANGE_FIELDS
86
+ def int_fields
87
+ @int_fields || DEFAULT_INT_FIELDS
77
88
  end
78
89
 
79
90
  def token_class(field_name)
80
91
  case
81
- when range_fields.include?(field_name)
82
- RangeToken
92
+ when date_fields.include?(field_name)
93
+ DateToken
94
+ when int_fields.include?(field_name)
95
+ IntToken
83
96
  when hierarchal_fields.include?(field_name)
84
97
  HierarchalToken
85
98
  when filterable_fields.include?(field_name)
@@ -1,5 +1,5 @@
1
1
  module Qiita
2
2
  module Elasticsearch
3
- VERSION = "0.3.0"
3
+ VERSION = "0.4.0"
4
4
  end
5
5
  end
@@ -14,6 +14,7 @@ Gem::Specification.new do |spec|
14
14
  spec.bindir = "bin"
15
15
  spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
16
16
  spec.require_paths = ["lib"]
17
+ spec.add_dependency "activesupport"
17
18
  spec.add_development_dependency "bundler", ">= 1.7"
18
19
  spec.add_development_dependency "codeclimate-test-reporter"
19
20
  spec.add_development_dependency "rake", "~> 10.0"
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: qiita-elasticsearch
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ryo Nakamura
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-04-22 00:00:00.000000000 Z
11
+ date: 2015-04-23 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activesupport
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: bundler
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -97,8 +111,12 @@ files:
97
111
  - README.md
98
112
  - Rakefile
99
113
  - lib/qiita/elasticsearch.rb
114
+ - lib/qiita/elasticsearch/concerns/range_operand_includable.rb
115
+ - lib/qiita/elasticsearch/date_token.rb
116
+ - lib/qiita/elasticsearch/errors.rb
100
117
  - lib/qiita/elasticsearch/filterable_token.rb
101
118
  - lib/qiita/elasticsearch/hierarchal_token.rb
119
+ - lib/qiita/elasticsearch/int_token.rb
102
120
  - lib/qiita/elasticsearch/matchable_token.rb
103
121
  - lib/qiita/elasticsearch/nodes/filter_node.rb
104
122
  - lib/qiita/elasticsearch/nodes/filterable_node.rb
@@ -134,7 +152,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
134
152
  version: '0'
135
153
  requirements: []
136
154
  rubyforge_project:
137
- rubygems_version: 2.4.5
155
+ rubygems_version: 2.2.2
138
156
  signing_key:
139
157
  specification_version: 4
140
158
  summary: Elasticsearch client helper for Qiita.