lsolr 0.0.5 → 0.0.6

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.
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