stretchy-model 0.4.0 → 0.6.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.
Files changed (71) hide show
  1. checksums.yaml +4 -4
  2. data/.rspec +1 -1
  3. data/README.md +19 -84
  4. data/lib/rails/instrumentation/railtie.rb +2 -0
  5. data/lib/stretchy/associations.rb +155 -15
  6. data/lib/stretchy/attributes/type/array.rb +20 -0
  7. data/lib/stretchy/attributes/type/base.rb +42 -0
  8. data/lib/stretchy/attributes/type/binary.rb +45 -0
  9. data/lib/stretchy/attributes/type/boolean.rb +48 -0
  10. data/lib/stretchy/attributes/type/completion.rb +25 -0
  11. data/lib/stretchy/attributes/type/constant_keyword.rb +38 -0
  12. data/lib/stretchy/attributes/type/date_time.rb +35 -0
  13. data/lib/stretchy/attributes/type/dense_vector.rb +59 -0
  14. data/lib/stretchy/attributes/type/flattened.rb +31 -0
  15. data/lib/stretchy/attributes/type/geo_point.rb +27 -0
  16. data/lib/stretchy/attributes/type/geo_shape.rb +27 -0
  17. data/lib/stretchy/attributes/type/hash.rb +40 -0
  18. data/lib/stretchy/attributes/type/histogram.rb +7 -0
  19. data/lib/stretchy/attributes/type/ip.rb +29 -0
  20. data/lib/stretchy/attributes/type/join.rb +22 -0
  21. data/lib/stretchy/attributes/type/keyword.rb +36 -10
  22. data/lib/stretchy/attributes/type/match_only_text.rb +8 -0
  23. data/lib/stretchy/attributes/type/nested.rb +25 -0
  24. data/lib/stretchy/attributes/type/numeric/base.rb +32 -0
  25. data/lib/stretchy/attributes/type/numeric/byte.rb +7 -0
  26. data/lib/stretchy/attributes/type/numeric/double.rb +7 -0
  27. data/lib/stretchy/attributes/type/numeric/float.rb +7 -0
  28. data/lib/stretchy/attributes/type/numeric/half_float.rb +7 -0
  29. data/lib/stretchy/attributes/type/numeric/integer.rb +7 -0
  30. data/lib/stretchy/attributes/type/numeric/long.rb +7 -0
  31. data/lib/stretchy/attributes/type/numeric/scaled_float.rb +23 -0
  32. data/lib/stretchy/attributes/type/numeric/short.rb +7 -0
  33. data/lib/stretchy/attributes/type/numeric/unsigned_long.rb +7 -0
  34. data/lib/stretchy/attributes/type/percolator.rb +23 -0
  35. data/lib/stretchy/attributes/type/point.rb +24 -0
  36. data/lib/stretchy/attributes/type/range/base.rb +9 -0
  37. data/lib/stretchy/attributes/type/range/date_range.rb +17 -0
  38. data/lib/stretchy/attributes/type/range/double_range.rb +17 -0
  39. data/lib/stretchy/attributes/type/range/float_range.rb +16 -0
  40. data/lib/stretchy/attributes/type/range/integer_range.rb +16 -0
  41. data/lib/stretchy/attributes/type/range/ip_range.rb +16 -0
  42. data/lib/stretchy/attributes/type/range/long_range.rb +16 -0
  43. data/lib/stretchy/attributes/type/rank_feature.rb +21 -0
  44. data/lib/stretchy/attributes/type/rank_features.rb +24 -0
  45. data/lib/stretchy/attributes/type/search_as_you_type.rb +30 -0
  46. data/lib/stretchy/attributes/type/shape.rb +24 -0
  47. data/lib/stretchy/attributes/type/sparse_vector.rb +37 -0
  48. data/lib/stretchy/attributes/type/string.rb +7 -0
  49. data/lib/stretchy/attributes/type/text.rb +51 -0
  50. data/lib/stretchy/attributes/type/token_count.rb +26 -0
  51. data/lib/stretchy/attributes/type/version.rb +21 -0
  52. data/lib/stretchy/attributes/type/wildcard.rb +35 -0
  53. data/lib/stretchy/attributes.rb +68 -2
  54. data/lib/stretchy/common.rb +5 -5
  55. data/lib/stretchy/delegation/gateway_delegation.rb +9 -5
  56. data/lib/stretchy/model/serialization.rb +1 -0
  57. data/lib/stretchy/querying.rb +4 -4
  58. data/lib/stretchy/record.rb +9 -10
  59. data/lib/stretchy/relation.rb +11 -17
  60. data/lib/stretchy/relations/finder_methods.rb +19 -2
  61. data/lib/stretchy/relations/merger.rb +5 -1
  62. data/lib/stretchy/relations/query_builder.rb +32 -3
  63. data/lib/stretchy/relations/query_methods.rb +66 -2
  64. data/lib/stretchy/scoping/named.rb +1 -1
  65. data/lib/stretchy/shared_scopes.rb +1 -1
  66. data/lib/stretchy/version.rb +1 -1
  67. data/lib/stretchy.rb +5 -3
  68. data/lib/stretchy_model.rb +9 -0
  69. metadata +49 -4
  70. data/lib/active_model/type/array.rb +0 -13
  71. data/lib/active_model/type/hash.rb +0 -15
@@ -2,11 +2,12 @@ module Stretchy
2
2
  module Relations
3
3
  class QueryBuilder
4
4
 
5
- attr_reader :structure, :values, :attribute_types
5
+ attr_reader :structure, :values, :attribute_types, :default_size
6
6
 
7
7
  def initialize(values, attribute_types = nil)
8
8
  @attribute_types = attribute_types
9
9
  @structure = Jbuilder.new ignore_nil: true
10
+ @default_size = values.delete(:default_size)
10
11
  @values = values
11
12
  end
12
13
 
@@ -38,6 +39,10 @@ module Stretchy
38
39
  @shoulds ||= compact_where(values[:should])
39
40
  end
40
41
 
42
+ def regexes
43
+ @regexes ||= values[:regexp]
44
+ end
45
+
41
46
  def fields
42
47
  values[:field]
43
48
  end
@@ -88,7 +93,7 @@ module Stretchy
88
93
  private
89
94
 
90
95
  def missing_bool_query?
91
- query.nil? && must_nots.nil? && shoulds.nil?
96
+ query.nil? && must_nots.nil? && shoulds.nil? && regexes.nil?
92
97
  end
93
98
 
94
99
  def missing_query_string?
@@ -102,7 +107,12 @@ module Stretchy
102
107
  def build_query
103
108
  return if missing_bool_query? && missing_query_string? && missing_query_filter?
104
109
  structure.query do
110
+ structure.regexp do
111
+ build_regexp unless regexes.nil?
112
+ end
113
+
105
114
  structure.bool do
115
+
106
116
  structure.must query unless missing_bool_query?
107
117
  structure.must_not must_nots unless must_nots.nil?
108
118
  structure.set! :should, shoulds unless shoulds.nil?
@@ -120,6 +130,14 @@ module Stretchy
120
130
  end.with_indifferent_access
121
131
  end
122
132
 
133
+ def build_regexp
134
+ regexes.each do |args|
135
+ target_field = args.first.keys.first
136
+ value_field = args.first.values.first
137
+ structure.set! target_field, args.last.merge(value: value_field)
138
+ end
139
+ end
140
+
123
141
  def build_filtered_query
124
142
  structure.filter do
125
143
  structure.or do
@@ -157,7 +175,13 @@ module Stretchy
157
175
  structure.highlight do
158
176
  structure.fields do
159
177
  highlights.each do |highlight|
160
- structure.set! highlight, extract_highlighter(highlight)
178
+ if highlight.is_a?(String) || highlight.is_a?(Symbol)
179
+ structure.set! highlight, {}
180
+ elsif highlight.is_a?(Hash)
181
+ highlight.each_pair do |k,v|
182
+ structure.set! k, v
183
+ end
184
+ end
161
185
  end
162
186
  end
163
187
  end
@@ -185,6 +209,11 @@ module Stretchy
185
209
  end
186
210
 
187
211
  def extra_search_options
212
+ unless self.count?
213
+ values[:size] = size.present? ? size : values[:default_size]
214
+ else
215
+ values[:size] = nil
216
+ end
188
217
  [:size].inject(Hash.new) { |h,k| h[k] = self.send(k) unless self.send(k).nil?; h}
189
218
  end
190
219
 
@@ -18,7 +18,8 @@ module Stretchy
18
18
  :filter_query,
19
19
  :or_filter,
20
20
  :extending,
21
- :skip_callbacks
21
+ :skip_callbacks,
22
+ :regexp
22
23
  ]
23
24
 
24
25
  SINGLE_VALUE_METHODS = [:size]
@@ -173,6 +174,16 @@ module Stretchy
173
174
  # }
174
175
  # }
175
176
  #
177
+ # .where acts as a convienence method for adding conditions to the query. It can also be used to add
178
+ # range , regex, terms, and id queries through shorthand parameters.
179
+ #
180
+ # @example
181
+ # Model.where(price: {gte: 10, lte: 20})
182
+ # Model.where(age: 19..33)
183
+ # Model.where(color: /gr(a|e)y/)
184
+ # Model.where(id: [10, 22, 18])
185
+ # Model.where(names: ['John', 'Jane'])
186
+ #
176
187
  # @return [ActiveRecord::Relation, WhereChain] a new relation, which reflects the conditions, or a WhereChain if opts is :chain
177
188
  # @see #must
178
189
  def where(opts = :chain, *rest)
@@ -181,7 +192,28 @@ module Stretchy
181
192
  elsif opts.blank?
182
193
  self
183
194
  else
184
- spawn.where!(opts, *rest)
195
+ opts.each do |key, value|
196
+ case value
197
+ when Range
198
+ between(value, key)
199
+ when Hash
200
+ filter_query(:range, key => value) if value.keys.any? { |k| [:gte, :lte, :gt, :lt].include?(k) }
201
+ when Regexp
202
+ regexp(Hash[key, value])
203
+ when Array
204
+ # handle ID queries
205
+ # if [:id, :_id].include?(key)
206
+
207
+ # else
208
+ spawn.where!(opts, *rest)
209
+ # end
210
+ else
211
+ spawn.where!(opts, *rest)
212
+ end
213
+ end
214
+
215
+ self
216
+
185
217
  end
186
218
  end
187
219
 
@@ -199,6 +231,38 @@ module Stretchy
199
231
  # @see #where
200
232
  alias :must :where
201
233
 
234
+ # Adds a regexp condition to the query.
235
+ #
236
+ # @param field [Hash] the field to filter by and the Regexp to match
237
+ # @param opts [Hash] additional options for the regexp query
238
+ # - :flags [String] the flags to use for the regexp query (e.g. 'ALL')
239
+ # - :use_keyword [Boolean] whether to use the .keyword field for the regexp query. Default: true
240
+ # - :case_insensitive [Boolean] whether to use case insensitive matching. If the regexp has ignore case flag `/regex/i`, this is automatically set to true
241
+ # - :max_determinized_states [Integer] the maximum number of states that the regexp query can produce
242
+ # - :rewrite [String] the rewrite method to use for the regexp query
243
+ #
244
+ #
245
+ # @example
246
+ # Model.regexp(:name, /john|jane/)
247
+ # Model.regexp(:name, /john|jane/i)
248
+ # Model.regexp(:name, /john|jane/i, flags: 'ALL')
249
+ #
250
+ # @return [Stretchy::Relation] a new relation, which reflects the regexp condition
251
+ # @see #where
252
+ def regexp(args)
253
+ spawn.regexp!(args)
254
+ end
255
+
256
+ def regexp!(args) # :nodoc:
257
+ args = args.to_a
258
+ target_field, regex = args.shift
259
+ opts = args.to_h
260
+ opts.reverse_merge!(use_keyword: true)
261
+ target_field = "#{target_field}.keyword" if opts.delete(:use_keyword)
262
+ opts.merge!(case_insensitive: true) if regex.casefold?
263
+ self.regexp_values += [[Hash[target_field, regex.source], opts]]
264
+ self
265
+ end
202
266
 
203
267
 
204
268
 
@@ -8,7 +8,7 @@ module Stretchy
8
8
  if current_scope
9
9
  current_scope.clone
10
10
  else
11
- default_scoped.size(default_size)
11
+ default_scoped
12
12
  end
13
13
  end
14
14
 
@@ -4,7 +4,7 @@ module Stretchy
4
4
 
5
5
  included do
6
6
 
7
- scope :between, lambda { |range| filter(:range, "date" => {gte: range.begin, lte: range.end}) }
7
+ scope :between, ->(range, range_field = "created_at") { filter_query(:range, range_field => {gte: range.begin, lte: range.end}) }
8
8
  scope :using_time_based_indices, lambda { |range| search_options(index: time_based_indices(range)) }
9
9
 
10
10
  end
@@ -1,3 +1,3 @@
1
1
  module Stretchy
2
- VERSION = '0.4.0'
2
+ VERSION = '0.6.0'
3
3
  end
data/lib/stretchy.rb CHANGED
@@ -7,14 +7,11 @@ require 'elasticsearch/model'
7
7
  require 'elasticsearch/persistence'
8
8
  require 'active_model'
9
9
  require 'active_support/all'
10
- require 'active_model/type/array'
11
- require 'active_model/type/hash'
12
10
 
13
11
  require_relative "stretchy/version"
14
12
  require_relative "rails/instrumentation/railtie" if defined?(Rails)
15
13
 
16
14
 
17
-
18
15
  module Stretchy
19
16
 
20
17
  def self.loader
@@ -23,6 +20,7 @@ module Stretchy
23
20
  loader.tag = File.basename(__FILE__, ".rb")
24
21
  loader.inflector = Zeitwerk::GemInflector.new(__FILE__)
25
22
  loader.push_dir(__dir__)
23
+ loader.inflector.inflect("ip" => "IP")
26
24
  loader
27
25
  end
28
26
  end
@@ -32,6 +30,10 @@ module Stretchy
32
30
  Stretchy::Attributes.register!
33
31
  end
34
32
 
33
+ def self.instrument!
34
+ Stretchy::Delegation::GatewayDelegation.send(:include, Rails::Instrumentation::Publishers::Record)
35
+ end
36
+
35
37
  module Errors
36
38
  class QueryOptionMissing < StandardError; end
37
39
  end
@@ -0,0 +1,9 @@
1
+ # This is a simple model that inherits from Stretchy::Record
2
+ # for aesthetic purposes.
3
+ #
4
+ # In Rails applications, you can use this model as a base class
5
+ # for your models.
6
+ #
7
+ class StretchyModel < Stretchy::Record
8
+
9
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: stretchy-model
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Spencer Markowski
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-03-10 00:00:00.000000000 Z
11
+ date: 2024-03-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: zeitwerk
@@ -224,8 +224,6 @@ files:
224
224
  - containers/Dockerfile.elasticsearch
225
225
  - containers/Dockerfile.opensearch
226
226
  - docker-compose.yml
227
- - lib/active_model/type/array.rb
228
- - lib/active_model/type/hash.rb
229
227
  - lib/rails/instrumentation/publishers.rb
230
228
  - lib/rails/instrumentation/railtie.rb
231
229
  - lib/stretchy.rb
@@ -234,7 +232,53 @@ files:
234
232
  - lib/stretchy/associations/elastic_relation.rb
235
233
  - lib/stretchy/attributes.rb
236
234
  - lib/stretchy/attributes/transformers/keyword_transformer.rb
235
+ - lib/stretchy/attributes/type/array.rb
236
+ - lib/stretchy/attributes/type/base.rb
237
+ - lib/stretchy/attributes/type/binary.rb
238
+ - lib/stretchy/attributes/type/boolean.rb
239
+ - lib/stretchy/attributes/type/completion.rb
240
+ - lib/stretchy/attributes/type/constant_keyword.rb
241
+ - lib/stretchy/attributes/type/date_time.rb
242
+ - lib/stretchy/attributes/type/dense_vector.rb
243
+ - lib/stretchy/attributes/type/flattened.rb
244
+ - lib/stretchy/attributes/type/geo_point.rb
245
+ - lib/stretchy/attributes/type/geo_shape.rb
246
+ - lib/stretchy/attributes/type/hash.rb
247
+ - lib/stretchy/attributes/type/histogram.rb
248
+ - lib/stretchy/attributes/type/ip.rb
249
+ - lib/stretchy/attributes/type/join.rb
237
250
  - lib/stretchy/attributes/type/keyword.rb
251
+ - lib/stretchy/attributes/type/match_only_text.rb
252
+ - lib/stretchy/attributes/type/nested.rb
253
+ - lib/stretchy/attributes/type/numeric/base.rb
254
+ - lib/stretchy/attributes/type/numeric/byte.rb
255
+ - lib/stretchy/attributes/type/numeric/double.rb
256
+ - lib/stretchy/attributes/type/numeric/float.rb
257
+ - lib/stretchy/attributes/type/numeric/half_float.rb
258
+ - lib/stretchy/attributes/type/numeric/integer.rb
259
+ - lib/stretchy/attributes/type/numeric/long.rb
260
+ - lib/stretchy/attributes/type/numeric/scaled_float.rb
261
+ - lib/stretchy/attributes/type/numeric/short.rb
262
+ - lib/stretchy/attributes/type/numeric/unsigned_long.rb
263
+ - lib/stretchy/attributes/type/percolator.rb
264
+ - lib/stretchy/attributes/type/point.rb
265
+ - lib/stretchy/attributes/type/range/base.rb
266
+ - lib/stretchy/attributes/type/range/date_range.rb
267
+ - lib/stretchy/attributes/type/range/double_range.rb
268
+ - lib/stretchy/attributes/type/range/float_range.rb
269
+ - lib/stretchy/attributes/type/range/integer_range.rb
270
+ - lib/stretchy/attributes/type/range/ip_range.rb
271
+ - lib/stretchy/attributes/type/range/long_range.rb
272
+ - lib/stretchy/attributes/type/rank_feature.rb
273
+ - lib/stretchy/attributes/type/rank_features.rb
274
+ - lib/stretchy/attributes/type/search_as_you_type.rb
275
+ - lib/stretchy/attributes/type/shape.rb
276
+ - lib/stretchy/attributes/type/sparse_vector.rb
277
+ - lib/stretchy/attributes/type/string.rb
278
+ - lib/stretchy/attributes/type/text.rb
279
+ - lib/stretchy/attributes/type/token_count.rb
280
+ - lib/stretchy/attributes/type/version.rb
281
+ - lib/stretchy/attributes/type/wildcard.rb
238
282
  - lib/stretchy/common.rb
239
283
  - lib/stretchy/delegation/delegate_cache.rb
240
284
  - lib/stretchy/delegation/gateway_delegation.rb
@@ -263,6 +307,7 @@ files:
263
307
  - lib/stretchy/shared_scopes.rb
264
308
  - lib/stretchy/utils.rb
265
309
  - lib/stretchy/version.rb
310
+ - lib/stretchy_model.rb
266
311
  - sig/stretchy.rbs
267
312
  - stretchy-model/lib/stretchy-model.rb
268
313
  - stretchy.logo.png
@@ -1,13 +0,0 @@
1
- module ActiveModel
2
- module Type
3
-
4
- class Array < Value # :nodoc:
5
-
6
- def type
7
- :array
8
- end
9
-
10
- end
11
-
12
- end
13
- end
@@ -1,15 +0,0 @@
1
- module ActiveModel
2
- module Type
3
- class Hash < Value # :nodoc:
4
- def type
5
- :hash
6
- end
7
-
8
- private
9
-
10
- def cast_value(value)
11
- Elasticsearch::Model::HashWrapper[value]
12
- end
13
- end
14
- end
15
- end