lsolr 0.0.5 → 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (3) hide show
  1. checksums.yaml +5 -5
  2. data/lib/lsolr.rb +113 -8
  3. metadata +2 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: c54840a14b31fc2c85a73294fd6617dd5e918584
4
- data.tar.gz: 68f92d1fce16534895aaf287eaa33ab6c407f041
2
+ SHA256:
3
+ metadata.gz: 5e5ca288040ec046e3df00c273dcd6c3ccc6bd31e6db172bb652ff377dddaaf4
4
+ data.tar.gz: d87df9ae56c1aa37c1b92e11c00c82b0a3afb44abdd7e918e48ab88cce69a7e8
5
5
  SHA512:
6
- metadata.gz: ffd1a3501680882574ff40442680ee588cdbc539f5906d6d25863e21aeda24777a1d34677dc99cbe67bdc0144595f73bf08687da2d1727eddaefce184d90f043
7
- data.tar.gz: 28cae9bcbf02b498c0ebaadfdb77ba0bbf8cff4476fd7c035d546eca45b43ecec28d4e99148dacfa576b132eba53c68158bfde5cd75df6e5ea396e9faef6eed7
6
+ metadata.gz: 4da503d0ce9a2627630c35848d8e3dc0d1b5fdacbf60839d9973f82a7ac2cd79d29a73a57a4583ed2ebf3a98de9bd14a5488da55f77cc41f24010cb76c091e70
7
+ data.tar.gz: b0ad4353b239b32cfdaf828cfc201dae3b917f21f861c4c460787b575d0630ec60276ff9cd6a36d3daa8d9ee0cc24730df68206a11ae83ea8d283c83453de95c
data/lib/lsolr.rb CHANGED
@@ -1,8 +1,40 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'date'
4
+
3
5
  # A query builder of Apache Solr standard Lucene type query for Ruby.
4
6
  #
5
- # @example How to use.
7
+ # @example How to use. Part 1:
8
+ # LSolr.build(term1: 'hoge', term2: true).to_s
9
+ # #=> 'term1:hoge AND term2:true'
10
+ #
11
+ # @example How to use. Part 2:
12
+ # params = {
13
+ # term01: 'hoge',
14
+ # term02: :fuga,
15
+ # term03: 14,
16
+ # term04: 7.3,
17
+ # term05: true,
18
+ # term06: false,
19
+ # term07: Date.new(7000, 7, 1),
20
+ # term08: DateTime.new(6000, 5, 31, 6, 31, 43),
21
+ # term09: Time.new(5000, 6, 30, 12, 59, 3),
22
+ # term10: LSolr.new(:term10).fuzzy_match('foo'),
23
+ # term11: [1, 2, 3],
24
+ # term12: 1..10,
25
+ # term13: 20...40,
26
+ # term14: Date.new(3000, 1, 1)..Date.new(4000, 12, 31),
27
+ # term15: (3.0..4.0).step(0.1)
28
+ # }
29
+ #
30
+ # LSolr.build(params).to_s
31
+ # #=> 'term01:hoge AND term02:fuga AND term03:14 AND term04:7.3 AND term05:true
32
+ # # AND term06:false AND term07:"7000-07-01T00:00:00Z" AND term08:"6000-05-31T06:31:43Z"
33
+ # # AND term09:"5000-06-30T12:59:03Z" AND term10:foo~2.0 AND (term11:1 OR term11:2 OR term11:3)
34
+ # # AND term12:[1 TO 10] AND term13:[20 TO 40} AND term14:[3000-01-01T00:00:00Z TO 4000-12-31T00:00:00Z]
35
+ # # AND term15:[3.0 TO 4.0]'
36
+ #
37
+ # @example How to use. Part 3:
6
38
  # monoclinic = LSolr.new(:crystal_system).match(:monoclinic)
7
39
  # cubic = LSolr.new(:crystal_system).match(:cubic)
8
40
  # soft = LSolr.new(:mohs_scale).greater_than_or_equal_to('*').less_than(5.0)
@@ -27,7 +59,12 @@ class LSolr
27
59
  WILD_CARD = '*'
28
60
  PROXIMITY = '~'
29
61
  BOOST = '^'
62
+ PHRASE_MATCH_DELIMITER = ' '
30
63
  FUZZY_MATCH_DISTANCE_RANGE = (0.0..2.0).freeze
64
+ FORMAT_DATE_TIME = '%Y-%m-%dT%H:%M:%SZ'
65
+ FORMAT_MILLISECOND_FOR_DATE_TYPE = '%Q'
66
+ FORMAT_MILLISECOND_FOR_TIME_TYPE = '%L'
67
+ FORMAT_SECOND = '%s'
31
68
 
32
69
  PARENTHESIS_LEFT = '('
33
70
  PARENTHESIS_RIGHT = ')'
@@ -38,6 +75,49 @@ class LSolr
38
75
 
39
76
  attr_accessor :prev, :operator, :left_parentheses, :right_parentheses
40
77
 
78
+ class << self
79
+ # Builds composite query and returns builder instance.
80
+ #
81
+ # @param params [Hash{Symbol => String, Integer, Float, true, false, Range, Date, Time}] query terms
82
+ #
83
+ # @return [LSolr] a instance
84
+ def build(params)
85
+ params.map { |f, v| build_query(f, v) }.reduce { |a, e| a.and(e) }
86
+ end
87
+
88
+ private
89
+
90
+ def build_query(field, value) # rubocop:disable Metrics/CyclomaticComplexity
91
+ case value
92
+ when String, Symbol, Integer, Float, true, false then new(field).match(value)
93
+ when Date, Time then new(field).date_time_match(value)
94
+ when LSolr then value
95
+ when Array then build_array_query(field, value)
96
+ when Range then build_range_query(field, value)
97
+ when Enumerator then build_enumerator_query(field, value)
98
+ else raise ArgumentError, "Could not build solr query. field: #{field}, value: #{value.inspect}"
99
+ end
100
+ end
101
+
102
+ def build_array_query(field, values)
103
+ values.map { |v| build_query(field, v) }.reduce { |a, e| a.or(e) }.wrap
104
+ end
105
+
106
+ def build_range_query(field, value)
107
+ if value.exclude_end?
108
+ new(field).greater_than_or_equal_to(value.first).less_than(value.last)
109
+ else
110
+ new(field).greater_than_or_equal_to(value.first).less_than_or_equal_to(value.last)
111
+ end
112
+ end
113
+
114
+ def build_enumerator_query(field, values)
115
+ last = nil
116
+ values.each { |v| last = v }
117
+ new(field).greater_than_or_equal_to(values.first).less_than_or_equal_to(last)
118
+ end
119
+ end
120
+
41
121
  # Create a new query builder instance.
42
122
  #
43
123
  # @param field [String] a field name
@@ -125,6 +205,7 @@ class LSolr
125
205
  # @return [LSolr] self instance
126
206
  def match(value)
127
207
  values = clean(value).split
208
+
128
209
  if values.size > 1
129
210
  phrase_match(values)
130
211
  else
@@ -135,11 +216,19 @@ class LSolr
135
216
 
136
217
  # Builds a normal query expression with dates and times.
137
218
  #
138
- # @param value [String] a filter value
219
+ # @see https://lucene.apache.org/solr/guide/6_6/working-with-dates.html Working with Dates
220
+ #
221
+ # @param value [String, Date, Time] a filter value
139
222
  #
140
223
  # @return [LSolr] self instance
141
224
  def date_time_match(value)
142
- @value = clean(value, symbols: RESERVED_SYMBOLS - %w[- : . / +])
225
+ value = if value.is_a?(Date) || value.is_a?(Time)
226
+ format_date(value)
227
+ else
228
+ clean(value, symbols: RESERVED_SYMBOLS - %w[- : . / +])
229
+ end
230
+
231
+ @value = %("#{value}")
143
232
  self
144
233
  end
145
234
 
@@ -165,7 +254,7 @@ class LSolr
165
254
  #
166
255
  # @return [LSolr] self instance
167
256
  def phrase_match(values, distance: 0)
168
- value = values.map { |v| clean(v).split }.flatten.join(REPLACEMENT_CHAR)
257
+ value = values.map { |v| clean(v).split }.flatten.join(PHRASE_MATCH_DELIMITER)
169
258
  proximity_match = distance > 0 ? "#{PROXIMITY}#{distance}" : ''
170
259
  @value = %("#{value}"#{proximity_match})
171
260
  self
@@ -189,10 +278,11 @@ class LSolr
189
278
  #
190
279
  # @see https://lucene.apache.org/solr/guide/7_1/the-standard-query-parser.html#range-searches Range Searches
191
280
  #
192
- # @param value [String, Integer] a filter value
281
+ # @param value [String, Integer, Date, Time] a filter value
193
282
  #
194
283
  # @return [LSolr] self instance
195
284
  def greater_than(value)
285
+ value = format_date(value) if value.is_a?(Date) || value.is_a?(Time)
196
286
  @range_first = "#{GREATER_THAN}#{value}"
197
287
  self
198
288
  end
@@ -201,10 +291,11 @@ class LSolr
201
291
  #
202
292
  # @see https://lucene.apache.org/solr/guide/7_1/the-standard-query-parser.html#range-searches Range Searches
203
293
  #
204
- # @param value [String, Integer] a filter value
294
+ # @param value [String, Integer, Date, Time] a filter value
205
295
  #
206
296
  # @return [LSolr] self instance
207
297
  def less_than(value)
298
+ value = format_date(value) if value.is_a?(Date) || value.is_a?(Time)
208
299
  @range_last = "#{value}#{LESS_THAN}"
209
300
  self
210
301
  end
@@ -213,10 +304,11 @@ class LSolr
213
304
  #
214
305
  # @see https://lucene.apache.org/solr/guide/7_1/the-standard-query-parser.html#range-searches Range Searches
215
306
  #
216
- # @param value [String, Integer] a filter value
307
+ # @param value [String, Integer, Date, Time] a filter value
217
308
  #
218
309
  # @return [LSolr] self instance
219
310
  def greater_than_or_equal_to(value)
311
+ value = format_date(value) if value.is_a?(Date) || value.is_a?(Time)
220
312
  @range_first = "#{GREATER_THAN_OR_EQUAL_TO}#{value}"
221
313
  self
222
314
  end
@@ -225,10 +317,11 @@ class LSolr
225
317
  #
226
318
  # @see https://lucene.apache.org/solr/guide/7_1/the-standard-query-parser.html#range-searches Range Searches
227
319
  #
228
- # @param value [String, Integer] a filter value
320
+ # @param value [String, Integer, Date, Time] a filter value
229
321
  #
230
322
  # @return [LSolr] self instance
231
323
  def less_than_or_equal_to(value)
324
+ value = format_date(value) if value.is_a?(Date) || value.is_a?(Time)
232
325
  @range_last = "#{value}#{LESS_THAN_OR_EQUAL_TO}"
233
326
  self
234
327
  end
@@ -287,4 +380,16 @@ class LSolr
287
380
  while !element.prev.nil? && element.prev.present? do element = element.prev end
288
381
  element
289
382
  end
383
+
384
+ def format_date(date)
385
+ msec_str = case date
386
+ when Date then date.strftime(FORMAT_MILLISECOND_FOR_DATE_TYPE).gsub(date.strftime(FORMAT_SECOND), '')
387
+ when Time then date.strftime(FORMAT_MILLISECOND_FOR_TIME_TYPE)
388
+ else raise ArgumentError, "Unknown type #{date.inspect}"
389
+ end
390
+
391
+ return date.strftime(FORMAT_DATE_TIME) if msec_str == '000'
392
+
393
+ "#{date.strftime('%Y-%m-%dT%H:%M:%S')}.#{msec_str}Z"
394
+ end
290
395
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lsolr
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.5
4
+ version: 0.0.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Taishi Kasuga
@@ -38,7 +38,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
38
38
  version: '0'
39
39
  requirements: []
40
40
  rubyforge_project:
41
- rubygems_version: 2.6.13
41
+ rubygems_version: 2.7.3
42
42
  signing_key:
43
43
  specification_version: 4
44
44
  summary: A query builder of Apache Solr for Ruby