elasticsearch_record 1.8.0 → 1.8.2

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
  SHA256:
3
- metadata.gz: 401d762b20a8e30d4a1b75231e1f3b10f9740ddaad711314fb9a83956442a49c
4
- data.tar.gz: 1d8b9eb52e869e2b2ac7f9f2805d7aa95e36414335aca58bc5785b6983548cb2
3
+ metadata.gz: bbb80c1852041338e02e17314a2a70e852db077e2724383fe05d1990dc5c601e
4
+ data.tar.gz: 5d1f2b445e83e602b16ac571b8b3824784490f9c365a304b4be06aaa02620cb2
5
5
  SHA512:
6
- metadata.gz: e8369142becb328fc7ea2c52f45e7b86c4b38405123ff7b39e57fbefb5d8c8fac4e13fbda4416181200f8c789e4fcfbcbf57f29d212bb1ff2f8d4d2974e9176c
7
- data.tar.gz: 9cd8458bfd6583d665544310f57c1bbf45468ff431c9597656258db427495185a67a0cb0c0a03f963f315b88e2181167df8dbac5cc9d5d3db32eecd96dce8511
6
+ metadata.gz: 80ac0419ba02c1d7cc563446067caff43f7ee5b1a92c1155b5d3c2871652b06d5a8998aae4da6ee5c44289c7579a87b1346c15ae15630c11ab8cded34412e524
7
+ data.tar.gz: 1559d1ab3873e002c867c88726358a4d1c3f875e087f8b37ec58d9c8ee196fc757490c246409c1bc32871e9210b617e6c48473c7fe6fe68e97ab47e66da010ec
data/README.md CHANGED
@@ -14,8 +14,10 @@ _ElasticsearchRecord is a ActiveRecord adapter and provides similar functionalit
14
14
 
15
15
  **PLEASE NOTE:**
16
16
 
17
- - This is the `main`-branch, which only supports rails **7.1** _(see section 'Rails_Versions' for supported versions)_
17
+ - This is the `main`-branch, which currently supports rails **7.1** _(see section 'Rails_Versions' for supported versions)_
18
18
  - supports ActiveRecord ~> 7.1 + Elasticsearch >= 7.17
19
+ - added features up to Elasticsearch `8.16.1`
20
+ - tested with Elasticsearch `8.15.2`
19
21
 
20
22
  -----
21
23
 
@@ -44,11 +46,11 @@ https://github.com/ruby-smart/elasticsearch_record/tree/rails-7-0-stable
44
46
  Add this line to your application's Gemfile:
45
47
 
46
48
  ```ruby
47
- gem 'elasticsearch_record'
49
+ gem 'elasticsearch_record', '~> 1.8'
48
50
 
49
- # alternatives
51
+ # alternative
50
52
  gem 'elasticsearch_record', git: 'https://github.com/ruby-smart/elasticsearch_record', branch: 'rails-7-1-stable'
51
- gem 'elasticsearch_record', git: 'https://github.com/ruby-smart/elasticsearch_record', branch: 'rails-7-0-stable'
53
+ gem 'elasticsearch_record', git: 'https://github.com/ruby-smart/elasticsearch_record', branch: 'rails-70-stable'
52
54
 
53
55
  ```
54
56
 
@@ -88,7 +90,7 @@ To raise an exception while using transactions on a ElasticsearchRecord model, t
88
90
  However enabling this flag will surely fail transactional tests _(prevent this with 'use_transactional_tests=false')_
89
91
 
90
92
  ```ruby
91
- # config/initializers/elasticsearch_record.yml
93
+ # config/initializers/elasticsearch_record.rb
92
94
 
93
95
  # enable transactional exceptions
94
96
  ElasticsearchRecord.error_on_transaction = true
data/docs/CHANGELOG.md CHANGED
@@ -1,10 +1,30 @@
1
1
  # ElasticsearchRecord - CHANGELOG
2
2
 
3
+ ## [1.8.2] - 2024-11-26
4
+ * [fix] `ElasticsearchRecord::Relation::QueryMethods#build_query_clause` to raise an exception on `nil` assignments
5
+ * [fix] `Arel::Visitors::ElasticsearchBase#compile` to always reset temporary assignments _(causes missing assignments after a query-build-exception)_
6
+ * [fix] `Arel::Nodes::SelectAgg` to not merge nil-values
7
+ * [add] elasticsearch mapping type _(semantic_text)_
8
+
9
+ ## [1.8.1] - 2024-05-07
10
+ * [add] new elasticsearch mapping types _(percolator, geo, vector, texts, ...)_
11
+ * [ref] `ElasticsearchRecord::Relation#limit` to detect `Float::INFINITY` to also set the **max_result_window**
12
+ * [fix] `ElasticsearchRecord::SchemaMigration` only returning the first ten migrations (broke migrated migrations)
13
+ * [fix] `ElasticsearchRecord::Relation::CalculationMethods#calculate` method incompatibility - renamed to `#calculate_aggregation` (+ alias to `#calculate`)
14
+ * [fix] `ElasticsearchRecord::ModelApi#bulk` method not correctly generating data for 'delete'
15
+
3
16
  ## [1.8.0] - 2024-01-10
4
17
  * [ref] major method & dependency refactoring for `rails 7.1` - _(Does **NOT** work with rails 7.0)_
5
18
  * [add] new repository branch `rails-7-1-stable` to support different rails version
6
19
  * [ref] gemspec to lock on rails 7.1
7
20
 
21
+ ## [1.7.3] - 2024-05-07 _(no gem release)_
22
+ * [add] new elasticsearch mapping types _(percolator, geo, vector, texts, ...)_
23
+ * [ref] `ElasticsearchRecord::Relation#limit` to detect `Float::INFINITY` to also set the **max_result_window**
24
+ * [fix] `ElasticsearchRecord::SchemaMigration` only returning the first ten migrations (broke migrated migrations)
25
+ * [fix] `ElasticsearchRecord::Relation::CalculationMethods#calculate` method incompatibility - renamed to `#calculate_aggregation` (+ alias to `#calculate`)
26
+ * [fix] `ElasticsearchRecord::ModelApi#bulk` method not correctly generating data for 'delete'
27
+
8
28
  ## [1.7.2] - 2024-01-10
9
29
  * [ref] gemspec to lock on rails 7.0
10
30
 
@@ -8,11 +8,20 @@ module ActiveRecord
8
8
 
9
9
  included do
10
10
  # see @ ::ActiveRecord::ConnectionAdapters::ElasticsearchAdapter::NATIVE_DATABASE_TYPES.keys
11
- define_column_methods :string, :blob, :datetime, :bigint, :json, :binary, :boolean, :keyword,
12
- :constant_keyword, :wildcard, :long, :integer, :short, :byte, :double, :float,
13
- :half_float, :scaled_float, :unsigned_long, :date, :object, :flattened, :nested,
11
+ define_column_methods :string, :blob, :datetime, :bigint, :json,
12
+ :binary, :boolean,
13
+ :keyword, :constant_keyword, :wildcard,
14
+ :long, :integer, :short, :byte, :double, :float, :half_float, :scaled_float, :unsigned_long,
15
+ :date, :date_nanos,
16
+ :alias,
17
+ :object, :flattened, :nested, :join,
14
18
  :integer_range, :float_range, :long_range, :double_range, :date_range, :ip_range,
15
- :ip, :version, :text
19
+ :ip, :version, :murmur3,
20
+ :aggregate_metric_double, :histogram,
21
+ :text, :match_only_text, :completion, :search_as_you_type, :token_count, :semantic_text,
22
+ :dense_vector, :sparse_vector, :rank_feature, :rank_features,
23
+ :geo_point, :geo_shape, :point, :shape,
24
+ :percolator
16
25
 
17
26
  # Appends a primary key definition to the table definition.
18
27
  # Can be called multiple times, but this is probably not a good idea.
@@ -9,7 +9,7 @@ module Arel # :nodoc: all
9
9
  end
10
10
 
11
11
  def right
12
- return expr[1].reduce({}) { |m, data| m.merge(data) } if expr[1].is_a?(Array)
12
+ return expr[1].reduce({}) { |m, data| data ? m.merge(data) : m } if expr[1].is_a?(Array)
13
13
 
14
14
  expr[1]
15
15
  end
@@ -27,11 +27,6 @@ module Arel # :nodoc: all
27
27
  def initialize(connection)
28
28
  super()
29
29
  @connection = connection
30
-
31
- # required for nested assignment.
32
- # see +#assign+ method
33
- @nested = false
34
- @nested_args = []
35
30
  end
36
31
 
37
32
  def dispatch_as(mode)
@@ -45,6 +40,13 @@ module Arel # :nodoc: all
45
40
  end
46
41
 
47
42
  def compile(node, collector = Arel::Collectors::ElasticsearchQuery.new)
43
+ # IMPORTANT: To prevent persistent assigned variables due *accept* exceptions, those must be 'reset' before each compile.
44
+ #
45
+ # required for nested assignment.
46
+ # see +#assign+ method
47
+ @nested = false
48
+ @nested_args = []
49
+
48
50
  # we don't need to forward the collector each time - we just set it and always access it, when we need.
49
51
  self.collector = collector
50
52
 
@@ -9,7 +9,7 @@ module ElasticsearchRecord
9
9
  module VERSION
10
10
  MAJOR = 1
11
11
  MINOR = 8
12
- TINY = 0
12
+ TINY = 2
13
13
  PRE = nil
14
14
 
15
15
  STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
@@ -269,8 +269,11 @@ module ElasticsearchRecord
269
269
 
270
270
  _connection.api(:core, :bulk, {
271
271
  index: _index_name,
272
- body: if operation == :update
273
- data.map { |item| { operation => { _id: (item[:_id].presence || item['_id']), data: { doc: item.except(:_id, '_id') } } } }
272
+ body: case operation
273
+ when :update
274
+ data.map { |item| { update: { _id: (item[:_id].presence || item['_id']), data: { doc: item.except(:_id, '_id') } } } }
275
+ when :delete
276
+ data.map { |item| { delete: { _id: (item[:_id].presence || item['_id']) } } }
274
277
  else
275
278
  data.map { |item| { operation => { _id: (item[:_id].presence || item['_id']), data: item.except(:_id, '_id') } } }
276
279
  end,
@@ -64,9 +64,12 @@ module ElasticsearchRecord
64
64
  #
65
65
  # @see https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-metrics-boxplot-aggregation.html
66
66
  #
67
+ # @note returns *nil* on a *NullRelation*
68
+ #
67
69
  # @param [Symbol, String] column_name
70
+ # @return [Hash,nil]
68
71
  def boxplot(column_name)
69
- calculate(:boxplot, column_name)
72
+ calculate_aggregation(:boxplot, column_name)
70
73
  end
71
74
 
72
75
  # A multi-value metrics aggregation that computes stats over numeric values extracted from the aggregated documents. #
@@ -83,9 +86,12 @@ module ElasticsearchRecord
83
86
  #
84
87
  # @see https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-metrics-stats-aggregation.html
85
88
  #
89
+ # @note returns *nil* on a *NullRelation*
90
+ #
86
91
  # @param [Symbol, String] column_name
92
+ # @return [Hash,nil]
87
93
  def stats(column_name)
88
- calculate(:stats, column_name)
94
+ calculate_aggregation(:stats, column_name)
89
95
  end
90
96
 
91
97
  # A multi-value metrics aggregation that computes statistics over string values extracted from the aggregated documents.
@@ -102,9 +108,12 @@ module ElasticsearchRecord
102
108
  #
103
109
  # @see https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-metrics-string-stats-aggregation.html
104
110
  #
111
+ # @note returns *nil* on a *NullRelation*
112
+ #
105
113
  # @param [Symbol, String] column_name
114
+ # @return [Hash,nil]
106
115
  def string_stats(column_name)
107
- calculate(:string_stats, column_name)
116
+ calculate_aggregation(:string_stats, column_name)
108
117
  end
109
118
 
110
119
  # The matrix_stats aggregation is a numeric aggregation that computes the following statistics over a set of document fields:
@@ -118,9 +127,12 @@ module ElasticsearchRecord
118
127
  #
119
128
  # @see https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-matrix-stats-aggregation.html
120
129
  #
130
+ # @note returns *nil* on a *NullRelation*
131
+ #
121
132
  # @param [Array<Symbol|String>] column_names
133
+ # @return [Hash,nil]
122
134
  def matrix_stats(*column_names)
123
- calculate(:matrix_stats, *column_names)
135
+ calculate_aggregation(:matrix_stats, *column_names)
124
136
  end
125
137
 
126
138
  # A multi-value metrics aggregation that calculates one or more
@@ -140,9 +152,12 @@ module ElasticsearchRecord
140
152
  #
141
153
  # @see https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-metrics-percentile-aggregation.html
142
154
  #
155
+ # @note returns *nil* on a *NullRelation*
156
+ #
143
157
  # @param [Symbol, String] column_name
158
+ # @return [Hash,nil]
144
159
  def percentiles(column_name)
145
- calculate(:percentiles, column_name, node: :values)
160
+ calculate_aggregation(:percentiles, column_name, node: :values)
146
161
  end
147
162
 
148
163
  # A multi-value metrics aggregation that calculates one or more
@@ -165,10 +180,13 @@ module ElasticsearchRecord
165
180
  #
166
181
  # @see https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-metrics-percentile-rank-aggregation.html
167
182
  #
183
+ # @note returns *nil* on a *NullRelation*
184
+ #
168
185
  # @param [Symbol, String] column_name
169
186
  # @param [Array] values
187
+ # @return [Hash,nil]
170
188
  def percentile_ranks(column_name, values)
171
- calculate(:percentile_ranks, column_name, opts: { values: values }, node: :values)
189
+ calculate_aggregation(:percentile_ranks, column_name, opts: { values: values }, node: :values)
172
190
  end
173
191
 
174
192
  # Calculates the cardinality on a given column. Returns +0+ if there's no row.
@@ -178,9 +196,12 @@ module ElasticsearchRecord
178
196
  #
179
197
  # @see https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-metrics-cardinality-aggregation.html
180
198
  #
199
+ # @note returns *nil* on a *NullRelation*
200
+ #
181
201
  # @param [Symbol, String] column_name
202
+ # @return [Integer,nil]
182
203
  def cardinality(column_name)
183
- calculate(:cardinality, column_name, node: :value)
204
+ calculate_aggregation(:cardinality, column_name, node: :value)
184
205
  end
185
206
 
186
207
  # Calculates the average value on a given column. Returns +nil+ if there's no row. See #calculate for examples with options.
@@ -189,9 +210,12 @@ module ElasticsearchRecord
189
210
  #
190
211
  # @see https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-metrics-avg-aggregation.html
191
212
  #
213
+ # @note returns *nil* on a *NullRelation*
214
+ #
192
215
  # @param [Symbol, String] column_name
216
+ # @return [Float,nil]
193
217
  def average(column_name)
194
- calculate(:avg, column_name, node: :value)
218
+ calculate_aggregation(:avg, column_name, node: :value)
195
219
  end
196
220
 
197
221
  # Calculates the minimum value on a given column. The value is returned
@@ -202,9 +226,12 @@ module ElasticsearchRecord
202
226
  #
203
227
  # @see https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-metrics-min-aggregation.html
204
228
  #
229
+ # @note returns *nil* on a *NullRelation*
230
+ #
205
231
  # @param [Symbol, String] column_name
232
+ # @return [Float,nil]
206
233
  def minimum(column_name)
207
- calculate(:min, column_name, node: :value)
234
+ calculate_aggregation(:min, column_name, node: :value)
208
235
  end
209
236
 
210
237
  # Calculates the maximum value on a given column. The value is returned
@@ -215,9 +242,12 @@ module ElasticsearchRecord
215
242
  #
216
243
  # @see https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-metrics-max-aggregation.html
217
244
  #
245
+ # @note returns *nil* on a *NullRelation*
246
+ #
218
247
  # @param [Symbol, String] column_name
248
+ # @return [Float,nil]
219
249
  def maximum(column_name)
220
- calculate(:max, column_name, node: :value)
250
+ calculate_aggregation(:max, column_name, node: :value)
221
251
  end
222
252
 
223
253
  # This single-value aggregation approximates the median absolute deviation of its search results.
@@ -232,9 +262,12 @@ module ElasticsearchRecord
232
262
  #
233
263
  # @see https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-metrics-median-absolute-deviation-aggregation.html
234
264
  #
265
+ # @note returns *nil* on a *NullRelation*
266
+ #
235
267
  # @param [Symbol, String] column_name
268
+ # @return [Float,nil]
236
269
  def median_absolute_deviation(column_name)
237
- calculate(:median_absolute_deviation, column_name)
270
+ calculate_aggregation(:median_absolute_deviation, column_name)
238
271
  end
239
272
 
240
273
  # Calculates the sum of values on a given column. The value is returned
@@ -245,18 +278,27 @@ module ElasticsearchRecord
245
278
  #
246
279
  # @see https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-metrics-sum-aggregation.html
247
280
  #
281
+ # @note returns *nil* on a *NullRelation*
282
+ #
248
283
  # @param [Symbol, String] column_name (optional)
284
+ # @return [Float,nil]
249
285
  def sum(column_name)
250
- calculate(:sum, column_name, node: :value)
286
+ calculate_aggregation(:sum, column_name, node: :value)
251
287
  end
252
288
 
253
289
  # creates a aggregation with the provided metric (e.g. :sum) and columns.
254
290
  # returns the metric node (default: :value) from the aggregations result.
291
+ #
292
+ # @note returns *nil* on a *NullRelation*
293
+ #
255
294
  # @param [Symbol, String] metric
256
295
  # @param [Array<Symbol|String>] columns
257
296
  # @param [Hash] opts - additional arguments that get merged with the metric definition
258
297
  # @param [Symbol] node (default: nil)
259
- def calculate(metric, *columns, opts: {}, node: nil)
298
+ def calculate_aggregation(metric, *columns, opts: {}, node: nil)
299
+ # prevent execution on a *NullRelation*
300
+ return if null_relation?
301
+
260
302
  metric_key = "calculate_#{metric}"
261
303
 
262
304
  # spawn a new aggregation and return the aggs
@@ -272,6 +314,8 @@ module ElasticsearchRecord
272
314
  response[metric_key]
273
315
  end
274
316
  end
317
+
318
+ alias_method :calculate, :calculate_aggregation
275
319
  end
276
320
  end
277
321
  end
@@ -316,6 +316,12 @@ module ElasticsearchRecord
316
316
  end
317
317
 
318
318
  def build_query_clause(kind, data, rest = [])
319
+ # prevent empty data clauses
320
+ # e.g. [nil] - which will cause possible query-exceptions
321
+ if data.blank? || (data.is_a?(Array) && data.all?(&:blank?))
322
+ raise ArgumentError, "Unable to build query clause for '#{kind}' without any data @ #{klass.name}!"
323
+ end
324
+
319
325
  ElasticsearchRecord::Relation::QueryClause.new(kind, Array.wrap(data), rest.extract_options!)
320
326
  end
321
327
 
@@ -132,11 +132,10 @@ module ElasticsearchRecord
132
132
  # resolve only data from hits->hits[{_source}]
133
133
  current_results = if ids_only
134
134
  current_response['hits']['hits'].map { |result| result['_id'] }
135
- # future with helper
136
- # current_response['hits']['hits'].map.from_hash('_id')
137
135
  else
138
136
  current_response['hits']['hits'].map { |result| result['_source'].merge('_id' => result['_id']) }
139
137
  end
138
+
140
139
  current_results_length = current_results.length
141
140
 
142
141
  # check if we reached the required offset
@@ -45,7 +45,7 @@ module ElasticsearchRecord
45
45
 
46
46
  # overwrite the limit_value setter, to provide a special behaviour of auto-setting the +max_result_window+.
47
47
  def limit_value=(limit)
48
- if limit == '__max__' || (limit.nil? && delegate_query_nil_limit?)
48
+ if limit == '__max__' || limit == Float::INFINITY || (limit.nil? && delegate_query_nil_limit?)
49
49
  super(max_result_window)
50
50
  else
51
51
  super(limit)
@@ -8,5 +8,15 @@ module ElasticsearchRecord
8
8
  def table_name
9
9
  "#{ElasticsearchRecord::Base.table_name_prefix}#{ElasticsearchRecord::Base.schema_migrations_table_name}#{ElasticsearchRecord::Base.table_name_suffix}"
10
10
  end
11
+
12
+ # overwrite method to fix the default limit (= 10) to support returning more than 10 migrations
13
+ def versions
14
+ sm = Arel::SelectManager.new(arel_table)
15
+ sm.project(arel_table[primary_key])
16
+ sm.order(arel_table[primary_key].asc)
17
+ sm.take(connection.max_result_window(table_name))
18
+
19
+ connection.select_values(sm, "#{self.class} Load")
20
+ end
11
21
  end
12
22
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: elasticsearch_record
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.8.0
4
+ version: 1.8.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tobias Gonsior
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-01-10 00:00:00.000000000 Z
11
+ date: 2024-11-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -221,7 +221,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
221
221
  - !ruby/object:Gem::Version
222
222
  version: '0'
223
223
  requirements: []
224
- rubygems_version: 3.3.26
224
+ rubygems_version: 3.4.19
225
225
  signing_key:
226
226
  specification_version: 4
227
227
  summary: ActiveRecord adapter for Elasticsearch