elasticsearch_record 1.0.0 → 1.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +5 -3
- data/docs/CHANGELOG.md +16 -0
- data/lib/active_record/connection_adapters/elasticsearch/column.rb +27 -3
- data/lib/active_record/connection_adapters/elasticsearch/schema_statements.rb +83 -13
- data/lib/active_record/connection_adapters/elasticsearch/type/multicast_value.rb +1 -1
- data/lib/active_record/connection_adapters/elasticsearch/type/nested.rb +21 -0
- data/lib/active_record/connection_adapters/elasticsearch/type/object.rb +1 -25
- data/lib/active_record/connection_adapters/elasticsearch/type.rb +1 -0
- data/lib/active_record/connection_adapters/elasticsearch_adapter.rb +18 -2
- data/lib/arel/visitors/elasticsearch.rb +4 -3
- data/lib/elasticsearch_record/gem_version.rb +1 -1
- data/lib/elasticsearch_record/model_schema.rb +4 -3
- data/lib/elasticsearch_record/querying.rb +7 -0
- data/lib/elasticsearch_record/relation/calculation_methods.rb +9 -9
- data/lib/elasticsearch_record/relation/result_methods.rb +3 -1
- data/lib/elasticsearch_record/schema_migration.rb +30 -0
- data/lib/elasticsearch_record/statement_cache.rb +1 -1
- data/lib/elasticsearch_record/tasks/elasticsearch_database_tasks.rb +32 -0
- data/lib/elasticsearch_record.rb +9 -0
- metadata +8 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: aee5f9a1e1bc853f7e7648313db47e4b3179f85049baebc364cfce80a3e1dbdf
|
4
|
+
data.tar.gz: c3c17cd41fcc22930d28fdfdaedc69f5d5832d003e53141a0682942b8bb29496
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e81eb876eb78e6133b4c8edc868f1d72fa2d3064d17680c6f0252f05d4c4029e3a6941dc3cd50948fc31ee91da308bb4f899c0744d708c5b4c66873a51985ba7
|
7
|
+
data.tar.gz: 5235d1a1e23ccce634d994fc037a6b15ec0471cbc0cb16e35891f61cd01bad39cedc16c390a569b958677dada149825cdb514d59bb6d85465182b583974deeb7
|
data/README.md
CHANGED
@@ -1,8 +1,10 @@
|
|
1
1
|
# ElasticsearchRecord
|
2
2
|
|
3
|
-
|
3
|
+
[![Gem Version](https://badge.fury.io/rb/elasticsearch_record.svg)](https://badge.fury.io/rb/elasticsearch_record)
|
4
4
|
|
5
|
-
|
5
|
+
ActiveRecord adapter for Elasticsearch
|
6
|
+
|
7
|
+
_ElasticsearchRecord is a ActiveRecord adapter and provides similar functionality for Elasticsearch._
|
6
8
|
|
7
9
|
-----
|
8
10
|
|
@@ -118,7 +120,7 @@ Different to the default where-method you can now use it in different ways.
|
|
118
120
|
|
119
121
|
Using it by default with a Hash, the method decides itself to either add a filter, or must_not query.
|
120
122
|
|
121
|
-
_Hint: If not
|
123
|
+
_Hint: If not provided through ```#kind```-method a default kind **:bool** will be used._
|
122
124
|
```ruby
|
123
125
|
# use it by default
|
124
126
|
Search.where(name: 'A nice object')
|
data/docs/CHANGELOG.md
CHANGED
@@ -1,5 +1,21 @@
|
|
1
1
|
# ElasticsearchRecord - CHANGELOG
|
2
2
|
|
3
|
+
## [1.0.2] - 2022-11-07
|
4
|
+
* [add] ```ActiveRecord::ConnectionAdapters::ElasticsearchAdapter#migrations_paths``` with 'db/migrate_elasticsearch'
|
5
|
+
* [fix] to prevent executing 'primary' migrations to elasticsearch (SchemaDumper may still throw error comments)
|
6
|
+
* [add] temporary workarounds for scheme & migrations until we support it (so bin/rails db:migrate - tasks will now run again)
|
7
|
+
|
8
|
+
## [1.0.1] - 2022-10-19
|
9
|
+
* [add] ```ActiveRecord::ConnectionAdapters::Elasticsearch::Type::Nested``` class to cast nested values
|
10
|
+
* [add] **properties** to column definition (so they are also searchable by _Relation_ conditions)
|
11
|
+
* [add] exception for _Relation_ #pit_results if batch size is too large
|
12
|
+
* [add] a default _#find_by_id_-method to proved a 'fallback' functionality for the primary '_id' column
|
13
|
+
* [fix] nested properties are not cast for column-type "object"
|
14
|
+
* [fix] ```ActiveRecord::ConnectionAdapters::Elasticsearch::SchemaStatements``` fields and property detection
|
15
|
+
* [fix] ```ElasticsearchRecord::StatementCache::PartialQuery``` reference manipulation of cached hash _(missing .deep_dup )_
|
16
|
+
* [ref] ```ActiveRecord::ConnectionAdapters::Elasticsearch::Type::Object``` class to only cast object values
|
17
|
+
* [ref] ```Arel::Visitors::Elasticsearch#visit_Sort``` to detect a random sort with correct keyword: "**\_\_rand\_\_**"
|
18
|
+
|
3
19
|
## [1.0.0] - 2022-10-18
|
4
20
|
* [add] patch for ```ActiveRecord::Relation::Merger``` - to support AR-relations
|
5
21
|
* [add] ```ElasticsearchRecord::Relation#pit_results``` _offset_ & _yield_ support
|
@@ -5,11 +5,12 @@ module ActiveRecord
|
|
5
5
|
module Elasticsearch
|
6
6
|
class Column < ConnectionAdapters::Column # :nodoc:
|
7
7
|
|
8
|
-
attr_reader :virtual, :fields
|
8
|
+
attr_reader :virtual, :fields, :properties
|
9
9
|
|
10
10
|
def initialize(name, default, sql_type_metadata = nil, null = true, default_function = nil, **kwargs)
|
11
|
-
@virtual
|
12
|
-
@fields
|
11
|
+
@virtual = kwargs.delete(:virtual)
|
12
|
+
@fields = kwargs.delete(:fields)
|
13
|
+
@properties = kwargs.delete(:properties)
|
13
14
|
super(name, default, sql_type_metadata, null, default_function, **kwargs)
|
14
15
|
end
|
15
16
|
|
@@ -26,6 +27,29 @@ module ActiveRecord
|
|
26
27
|
def fields?
|
27
28
|
fields.present?
|
28
29
|
end
|
30
|
+
|
31
|
+
# returns true if this column has nested properties
|
32
|
+
# To receive the nested names just call +#properties+ on this object.
|
33
|
+
# @return [Boolean]
|
34
|
+
def properties?
|
35
|
+
properties.present?
|
36
|
+
end
|
37
|
+
|
38
|
+
# returns a array of field names
|
39
|
+
# @return [Array]
|
40
|
+
def field_names
|
41
|
+
return [] unless fields?
|
42
|
+
|
43
|
+
fields.map { |field| field['name'] }
|
44
|
+
end
|
45
|
+
|
46
|
+
# returns a array of property names
|
47
|
+
# @return [Array]
|
48
|
+
def property_names
|
49
|
+
return [] unless properties?
|
50
|
+
|
51
|
+
properties.map { |property| property['name'] }
|
52
|
+
end
|
29
53
|
end
|
30
54
|
end
|
31
55
|
end
|
@@ -4,6 +4,23 @@ module ActiveRecord
|
|
4
4
|
module ConnectionAdapters
|
5
5
|
module Elasticsearch
|
6
6
|
module SchemaStatements # :nodoc:
|
7
|
+
|
8
|
+
# temporary workaround
|
9
|
+
# toDo: fixme
|
10
|
+
def create_table(*args)
|
11
|
+
$stdout.puts "\n>>> 'create_table' elasticsearch is not supported - the following message is insignificant!"
|
12
|
+
end
|
13
|
+
|
14
|
+
# temporary workaround
|
15
|
+
# toDo: fixme
|
16
|
+
def assume_migrated_upto_version(version)
|
17
|
+
$stdout.puts "\n>>> 'assume_migrated_upto_version' elasticsearch is not supported - the following message is insignificant!"
|
18
|
+
end
|
19
|
+
|
20
|
+
|
21
|
+
|
22
|
+
|
23
|
+
|
7
24
|
# Returns the relation names usable to back Active Record models.
|
8
25
|
# For Elasticsearch this means all indices - which also includes system +dot+ '.' indices.
|
9
26
|
# @see ActiveRecord::ConnectionAdapters::SchemaStatements#data_sources
|
@@ -23,7 +40,7 @@ module ActiveRecord
|
|
23
40
|
# @param [String] index_name
|
24
41
|
# @return [Hash]
|
25
42
|
def settings(index_name)
|
26
|
-
api(:indices, :get_settings, { index: index_name }, 'SCHEMA').dig(index_name, 'settings','index')
|
43
|
+
api(:indices, :get_settings, { index: index_name }, 'SCHEMA').dig(index_name, 'settings', 'index')
|
27
44
|
end
|
28
45
|
|
29
46
|
# Returns the list of a table's column names, data types, and default values.
|
@@ -38,12 +55,14 @@ module ActiveRecord
|
|
38
55
|
# since the received mappings do not have the "primary" +_id+-column we manually need to add this here
|
39
56
|
# The BASE_STRUCTURE will also include some meta keys like '_score', '_type', ...
|
40
57
|
ActiveRecord::ConnectionAdapters::ElasticsearchAdapter::BASE_STRUCTURE + structure['properties'].map { |key, prop|
|
41
|
-
#
|
42
|
-
|
43
|
-
|
58
|
+
# resolve (nested) fields and properties
|
59
|
+
fields, properties = resolve_fields_and_properties(key, prop, true)
|
60
|
+
|
61
|
+
# fallback for possible empty type
|
62
|
+
type = prop['type'].presence || (properties.present? ? 'object' : 'nested')
|
44
63
|
|
45
|
-
#
|
46
|
-
prop.merge('name' => key, '
|
64
|
+
# return a new hash
|
65
|
+
prop.merge('name' => key, 'type' => type, 'fields' => fields, 'properties' => properties)
|
47
66
|
}
|
48
67
|
end
|
49
68
|
|
@@ -54,18 +73,16 @@ module ActiveRecord
|
|
54
73
|
# @param [Hash] field
|
55
74
|
# @return [ActiveRecord::ConnectionAdapters::Column]
|
56
75
|
def new_column_from_field(_table_name, field)
|
57
|
-
# fallback for possible empty type
|
58
|
-
field_type = field['type'].presence || (field['properties'].present? ? 'nested' : 'object')
|
59
|
-
|
60
76
|
ActiveRecord::ConnectionAdapters::Elasticsearch::Column.new(
|
61
77
|
field["name"],
|
62
78
|
field["null_value"],
|
63
|
-
fetch_type_metadata(
|
79
|
+
fetch_type_metadata(field["type"]),
|
64
80
|
field['null'].nil? ? true : field['null'],
|
65
81
|
nil,
|
66
|
-
comment:
|
67
|
-
virtual:
|
68
|
-
fields:
|
82
|
+
comment: field['meta'] ? field['meta'].map { |k, v| "#{k}: #{v}" }.join(' | ') : nil,
|
83
|
+
virtual: field['virtual'],
|
84
|
+
fields: field['fields'],
|
85
|
+
properties: field['properties']
|
69
86
|
)
|
70
87
|
end
|
71
88
|
|
@@ -128,6 +145,59 @@ module ActiveRecord
|
|
128
145
|
def max_result_window
|
129
146
|
10000
|
130
147
|
end
|
148
|
+
|
149
|
+
private
|
150
|
+
|
151
|
+
# returns a multidimensional array with fields & properties from the provided +prop+.
|
152
|
+
# Nested fields & properties will be also detected.
|
153
|
+
# .
|
154
|
+
# resolve_fields_and_properties('user', {...})
|
155
|
+
# # > [
|
156
|
+
# # fields
|
157
|
+
# [0] [
|
158
|
+
# [0] {
|
159
|
+
# "name" => "user.name.analyzed",
|
160
|
+
# "type" => "text"
|
161
|
+
# }
|
162
|
+
# ],
|
163
|
+
# # properties
|
164
|
+
# [1] [
|
165
|
+
# [0] {
|
166
|
+
# "name" => "user.id",
|
167
|
+
# "type" => "integer"
|
168
|
+
# },
|
169
|
+
# [1] {
|
170
|
+
# "name" => "user.name",
|
171
|
+
# "type" => "keyword"
|
172
|
+
# }
|
173
|
+
# ]
|
174
|
+
# ]
|
175
|
+
#
|
176
|
+
# @param [String] key
|
177
|
+
# @param [Hash] prop
|
178
|
+
# @param [Boolean] root - provide true, if this is a top property entry (default: false)
|
179
|
+
# @return [[Array, Array]]
|
180
|
+
def resolve_fields_and_properties(key, prop, root = false)
|
181
|
+
# mappings can have +fields+ - we also want them for 'query-conditions'
|
182
|
+
fields = (prop['fields'] || {}).map { |field_key, field_def|
|
183
|
+
{ 'name' => "#{key}.#{field_key}", 'type' => field_def['type'] }
|
184
|
+
}
|
185
|
+
|
186
|
+
# initial empty array
|
187
|
+
properties = []
|
188
|
+
|
189
|
+
if prop['properties'].present?
|
190
|
+
prop['properties'].each do |nested_key, nested_prop|
|
191
|
+
nested_fields, nested_properties = resolve_fields_and_properties("#{key}.#{nested_key}", nested_prop)
|
192
|
+
fields |= nested_fields
|
193
|
+
properties |= nested_properties
|
194
|
+
end
|
195
|
+
elsif !root # don't add the root property as sub-property
|
196
|
+
properties << { 'name' => key, 'type' => prop['type'] }
|
197
|
+
end
|
198
|
+
|
199
|
+
[fields, properties]
|
200
|
+
end
|
131
201
|
end
|
132
202
|
end
|
133
203
|
end
|
@@ -25,7 +25,7 @@ module ActiveRecord
|
|
25
25
|
|
26
26
|
def _deserialize(value)
|
27
27
|
# check for the special +object+ type which is forced to be casted
|
28
|
-
return _deserialize_by_nested_type(value) if nested_type.type == :object
|
28
|
+
return _deserialize_by_nested_type(value) if nested_type.type == :object
|
29
29
|
|
30
30
|
if value.is_a?(Array)
|
31
31
|
value.map { |val| _deserialize_by_nested_type(val) }
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module ConnectionAdapters
|
3
|
+
module Elasticsearch
|
4
|
+
module Type # :nodoc:
|
5
|
+
class Nested < ActiveRecord::Type::Value
|
6
|
+
|
7
|
+
def type
|
8
|
+
:nested
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
# cast value
|
14
|
+
def cast_value(value)
|
15
|
+
value.to_h
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -3,39 +3,15 @@ module ActiveRecord
|
|
3
3
|
module Elasticsearch
|
4
4
|
module Type # :nodoc:
|
5
5
|
class Object < ActiveRecord::Type::Value
|
6
|
-
attr_reader :cast_type, :default
|
7
|
-
|
8
|
-
# creates a new object type which can be natively every value.
|
9
|
-
# Providing a +cast+ will call the value with this method (or callback)
|
10
|
-
# @param [nil, Symbol, String, Proc] cast - the cast type
|
11
|
-
# @param [nil, Object] default
|
12
|
-
# @param [Boolean] force - force value to be casted (used by the MulticastValue type) - (default: false)
|
13
|
-
def initialize(cast: nil, default: nil, force: false, **)
|
14
|
-
@cast_type = cast
|
15
|
-
@default = default
|
16
|
-
@force = force
|
17
|
-
end
|
18
|
-
|
19
6
|
def type
|
20
7
|
:object
|
21
8
|
end
|
22
9
|
|
23
|
-
def forced?
|
24
|
-
@force
|
25
|
-
end
|
26
|
-
|
27
10
|
private
|
28
11
|
|
29
12
|
# cast value by provided cast_method
|
30
13
|
def cast_value(value)
|
31
|
-
|
32
|
-
when Symbol, String
|
33
|
-
value.public_send(self.cast_type) rescue default
|
34
|
-
when Proc
|
35
|
-
self.cast_type.(value) rescue default
|
36
|
-
else
|
37
|
-
value
|
38
|
-
end
|
14
|
+
value.to_h
|
39
15
|
end
|
40
16
|
end
|
41
17
|
end
|
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
require 'active_record/connection_adapters/elasticsearch/type/format_string'
|
4
4
|
require 'active_record/connection_adapters/elasticsearch/type/multicast_value'
|
5
|
+
require 'active_record/connection_adapters/elasticsearch/type/nested'
|
5
6
|
require 'active_record/connection_adapters/elasticsearch/type/object'
|
6
7
|
require 'active_record/connection_adapters/elasticsearch/type/range'
|
7
8
|
|
@@ -88,11 +88,11 @@ module ActiveRecord # :nodoc:
|
|
88
88
|
m.register_type 'date', Type::DateTime.new
|
89
89
|
|
90
90
|
# force a hash
|
91
|
-
m.register_type 'object', ActiveRecord::ConnectionAdapters::Elasticsearch::Type::Object.new
|
91
|
+
m.register_type 'object', ActiveRecord::ConnectionAdapters::Elasticsearch::Type::Object.new
|
92
92
|
m.alias_type 'flattened', "object"
|
93
93
|
|
94
94
|
# array of objects
|
95
|
-
m.register_type 'nested', ActiveRecord::ConnectionAdapters::Elasticsearch::Type::
|
95
|
+
m.register_type 'nested', ActiveRecord::ConnectionAdapters::Elasticsearch::Type::Nested.new
|
96
96
|
|
97
97
|
ip_type = ActiveRecord::ConnectionAdapters::Elasticsearch::Type::FormatString.new(format: /^((25[0-5]|(2[0-4]|1\d|[1-9]|)\d)\.?\b){4}$/)
|
98
98
|
|
@@ -131,6 +131,22 @@ module ActiveRecord # :nodoc:
|
|
131
131
|
@prepared_statements = false
|
132
132
|
end
|
133
133
|
|
134
|
+
def migrations_paths # :nodoc:
|
135
|
+
@config[:migrations_paths] || ['db/migrate_elasticsearch']
|
136
|
+
end
|
137
|
+
|
138
|
+
# temporary workaround
|
139
|
+
# toDo: fixme
|
140
|
+
def use_metadata_table? # :nodoc:
|
141
|
+
false
|
142
|
+
end
|
143
|
+
|
144
|
+
# temporary workaround
|
145
|
+
# toDo: fixme
|
146
|
+
def schema_migration # :nodoc:
|
147
|
+
@schema_migration ||= ElasticsearchRecord::SchemaMigration
|
148
|
+
end
|
149
|
+
|
134
150
|
private
|
135
151
|
|
136
152
|
def type_map
|
@@ -263,7 +263,8 @@ module Arel # :nodoc: all
|
|
263
263
|
# empty / nil columns - instead the nil columns do not exist!!!
|
264
264
|
# This is a big mess, because those missing columns are +not+ editable or savable in any way after we initialize the record...
|
265
265
|
# To prevent NOT-accessible attributes, we need to provide the "full-column-definition" to the query.
|
266
|
-
|
266
|
+
resource_klass = o.source.left.instance_variable_get(:@klass)
|
267
|
+
claim(:columns, resource_klass.source_column_names) if resource_klass.respond_to?(:source_column_names)
|
267
268
|
|
268
269
|
# sets the query
|
269
270
|
resolve(o, :visit_Query) if o.queries.present? || o.wheres.present?
|
@@ -410,8 +411,8 @@ module Arel # :nodoc: all
|
|
410
411
|
key = visit(o.expr)
|
411
412
|
dir = visit(o.direction)
|
412
413
|
|
413
|
-
# we support a special key:
|
414
|
-
if key == '
|
414
|
+
# we support a special key: __rand__ to create a simple random method ...
|
415
|
+
if key == '__rand__'
|
415
416
|
assign({
|
416
417
|
"_script" => {
|
417
418
|
"script" => "Math.random()",
|
@@ -20,12 +20,13 @@ module ElasticsearchRecord
|
|
20
20
|
@source_column_names ||= columns.reject(&:virtual).map(&:name) - ActiveRecord::ConnectionAdapters::ElasticsearchAdapter.base_structure_keys
|
21
21
|
end
|
22
22
|
|
23
|
-
# returns an array with columns names, that are searchable (also includes nested )
|
23
|
+
# returns an array with columns names, that are searchable (also includes nested fields & properties )
|
24
24
|
def searchable_column_names
|
25
25
|
@searchable_column_names ||= columns.reject(&:virtual).reduce([]) { |m, column|
|
26
26
|
m << column.name
|
27
|
-
m += column.
|
28
|
-
m
|
27
|
+
m += column.field_names
|
28
|
+
m += column.property_names
|
29
|
+
m.uniq
|
29
30
|
}
|
30
31
|
end
|
31
32
|
|
@@ -16,6 +16,13 @@ module ElasticsearchRecord
|
|
16
16
|
].freeze # :nodoc:
|
17
17
|
delegate(*ES_QUERYING_METHODS, to: :all)
|
18
18
|
|
19
|
+
# finds a single record by provided id.
|
20
|
+
# This method is overwritten to support the primary key column (+_id+).
|
21
|
+
# @param [Object] id
|
22
|
+
def find_by_id(id)
|
23
|
+
has_attribute?('id') ? super(id) : public_send(:find_by__id, id)
|
24
|
+
end
|
25
|
+
|
19
26
|
# finds records by sql, query-arguments or query-object.
|
20
27
|
#
|
21
28
|
# PLEASE NOTE: This method is used by different other methods:
|
@@ -3,10 +3,10 @@ module ElasticsearchRecord
|
|
3
3
|
module CalculationMethods
|
4
4
|
# Count the records.
|
5
5
|
#
|
6
|
-
# Person.count
|
6
|
+
# Person.all.count
|
7
7
|
# => the total count of all people
|
8
8
|
#
|
9
|
-
# Person.count(:age)
|
9
|
+
# Person.all.count(:age)
|
10
10
|
# => returns the total count of all people whose age is present in database
|
11
11
|
def count(column_name = nil)
|
12
12
|
# fallback to default
|
@@ -46,7 +46,7 @@ module ElasticsearchRecord
|
|
46
46
|
# percentiles over numeric values extracted from the aggregated documents.
|
47
47
|
# Returns a hash with empty values (but keys still exists) if there is no row.
|
48
48
|
#
|
49
|
-
# Person.percentiles(:year)
|
49
|
+
# Person.all.percentiles(:year)
|
50
50
|
# > {
|
51
51
|
# "1.0" => 2016.0,
|
52
52
|
# "5.0" => 2016.0,
|
@@ -68,7 +68,7 @@ module ElasticsearchRecord
|
|
68
68
|
# For example, if a value is greater than or equal to 95% of the observed values it is
|
69
69
|
# said to be at the 95th percentile rank.
|
70
70
|
#
|
71
|
-
# Person.percentile_ranks(:year, [500,600])
|
71
|
+
# Person.all.percentile_ranks(:year, [500,600])
|
72
72
|
# > {
|
73
73
|
# "1.0" => 2016.0,
|
74
74
|
# "5.0" => 2016.0,
|
@@ -86,7 +86,7 @@ module ElasticsearchRecord
|
|
86
86
|
|
87
87
|
# Calculates the cardinality on a given column. Returns +0+ if there's no row.
|
88
88
|
#
|
89
|
-
# Person.cardinality(:age)
|
89
|
+
# Person.all.cardinality(:age)
|
90
90
|
# > 12
|
91
91
|
#
|
92
92
|
# @param [Symbol, String] column_name
|
@@ -96,7 +96,7 @@ module ElasticsearchRecord
|
|
96
96
|
|
97
97
|
# Calculates the average value on a given column. Returns +nil+ if there's no row. See #calculate for examples with options.
|
98
98
|
#
|
99
|
-
# Person.average(:age) # => 35.8
|
99
|
+
# Person.all.average(:age) # => 35.8
|
100
100
|
#
|
101
101
|
# @param [Symbol, String] column_name
|
102
102
|
def average(column_name)
|
@@ -106,7 +106,7 @@ module ElasticsearchRecord
|
|
106
106
|
# Calculates the minimum value on a given column. The value is returned
|
107
107
|
# with the same data type of the column, or +nil+ if there's no row.
|
108
108
|
#
|
109
|
-
# Person.minimum(:age)
|
109
|
+
# Person.all.minimum(:age)
|
110
110
|
# > 7
|
111
111
|
#
|
112
112
|
# @param [Symbol, String] column_name
|
@@ -118,7 +118,7 @@ module ElasticsearchRecord
|
|
118
118
|
# with the same data type of the column, or +nil+ if there's no row. See
|
119
119
|
# #calculate for examples with options.
|
120
120
|
#
|
121
|
-
# Person.maximum(:age) # => 93
|
121
|
+
# Person.all.maximum(:age) # => 93
|
122
122
|
#
|
123
123
|
# @param [Symbol, String] column_name
|
124
124
|
def maximum(column_name)
|
@@ -129,7 +129,7 @@ module ElasticsearchRecord
|
|
129
129
|
# with the same data type of the column, +0+ if there's no row. See
|
130
130
|
# #calculate for examples with options.
|
131
131
|
#
|
132
|
-
# Person.sum(:age) # => 4562
|
132
|
+
# Person.all.sum(:age) # => 4562
|
133
133
|
#
|
134
134
|
# @param [Symbol, String] column_name (optional)
|
135
135
|
def sum(column_name)
|
@@ -89,6 +89,8 @@ module ElasticsearchRecord
|
|
89
89
|
# @param [String] keep_alive - how long to keep alive (for each single request) - default: '1m'
|
90
90
|
# @param [Integer] batch_size - how many results per query (default: 1000 - this means at least 10 queries before reaching the +max_result_window+)
|
91
91
|
def pit_results(keep_alive: '1m', batch_size: 1000)
|
92
|
+
raise ArgumentError, "Batch size cannot be above the 'max_result_window' (#{klass.connection.max_result_window}) !" if batch_size > klass.connection.max_result_window
|
93
|
+
|
92
94
|
# check if a limit or offset values was provided
|
93
95
|
results_limit = limit_value ? limit_value : Float::INFINITY
|
94
96
|
results_offset = offset_value ? offset_value : 0
|
@@ -116,7 +118,7 @@ module ElasticsearchRecord
|
|
116
118
|
current_response = relation.spawn.configure!(current_pit_hash).limit!(batch_size).resolve('Pit').response
|
117
119
|
|
118
120
|
# resolve only data from hits->hits[{_source}]
|
119
|
-
current_results = current_response['hits']['hits'].map { |result| result['_source'] }
|
121
|
+
current_results = current_response['hits']['hits'].map { |result| result['_source'].merge('_id' => result['_id']) }
|
120
122
|
current_results_length = current_results.length
|
121
123
|
|
122
124
|
# check if we reached the required offset
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'active_record/schema_migration'
|
3
|
+
|
4
|
+
module ElasticsearchRecord
|
5
|
+
# temporary workaround
|
6
|
+
# toDo: fixme
|
7
|
+
class SchemaMigration < ActiveRecord::SchemaMigration # :nodoc:
|
8
|
+
class << self
|
9
|
+
def create_table
|
10
|
+
$stdout.puts "\n>>> 'create_table' elasticsearch is not supported - the following message is insignificant!"
|
11
|
+
end
|
12
|
+
|
13
|
+
def drop_table
|
14
|
+
$stdout.puts "\n>>> 'drop_table' elasticsearch is not supported - the following message is insignificant!"
|
15
|
+
end
|
16
|
+
|
17
|
+
def normalized_versions
|
18
|
+
[]
|
19
|
+
end
|
20
|
+
|
21
|
+
def all_versions
|
22
|
+
[]
|
23
|
+
end
|
24
|
+
|
25
|
+
def table_exists?
|
26
|
+
true
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ElasticsearchRecord
|
4
|
+
module Tasks
|
5
|
+
class ElasticsearchDatabaseTasks
|
6
|
+
delegate :connection, :establish_connection, to: ActiveRecord::Base
|
7
|
+
|
8
|
+
def initialize(db_config)
|
9
|
+
@db_config = db_config
|
10
|
+
end
|
11
|
+
|
12
|
+
def create
|
13
|
+
#establish_connection(db_config)
|
14
|
+
$stdout.puts "\n>>> 'create' elasticsearch is not supported - the following message is insignificant!"
|
15
|
+
end
|
16
|
+
|
17
|
+
def drop
|
18
|
+
#establish_connection(db_config)
|
19
|
+
$stdout.puts "\n>>> 'drop' elasticsearch is not supported - the following message is insignificant!"
|
20
|
+
end
|
21
|
+
|
22
|
+
def purge
|
23
|
+
create
|
24
|
+
drop
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
attr_reader :db_config
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
data/lib/elasticsearch_record.rb
CHANGED
@@ -27,6 +27,7 @@ module ElasticsearchRecord
|
|
27
27
|
autoload :Querying
|
28
28
|
autoload :Query
|
29
29
|
autoload :Result
|
30
|
+
autoload :SchemaMigration
|
30
31
|
autoload :StatementCache
|
31
32
|
end
|
32
33
|
|
@@ -47,6 +48,12 @@ module ElasticsearchRecord
|
|
47
48
|
autoload :ResultMethods
|
48
49
|
autoload :ValueMethods
|
49
50
|
end
|
51
|
+
|
52
|
+
module Tasks
|
53
|
+
extend ActiveSupport::Autoload
|
54
|
+
|
55
|
+
autoload :ElasticsearchDatabaseTasks, 'elasticsearch_record/tasks/elasticsearch_database_tasks'
|
56
|
+
end
|
50
57
|
end
|
51
58
|
|
52
59
|
ActiveSupport.on_load(:active_record) do
|
@@ -57,4 +64,6 @@ ActiveSupport.on_load(:active_record) do
|
|
57
64
|
require 'elasticsearch_record/patches/arel/select_statement_patch'
|
58
65
|
require 'elasticsearch_record/patches/arel/update_manager_patch'
|
59
66
|
require 'elasticsearch_record/patches/arel/update_statement_patch'
|
67
|
+
|
68
|
+
ActiveRecord::Tasks::DatabaseTasks.register_task(/elasticsearch/, "ElasticsearchRecord::Tasks::ElasticsearchDatabaseTasks")
|
60
69
|
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.0.
|
4
|
+
version: 1.0.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: 2022-
|
11
|
+
date: 2022-11-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -80,8 +80,8 @@ dependencies:
|
|
80
80
|
- - "~>"
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: '13.0'
|
83
|
-
description: 'ElasticsearchRecord is a ActiveRecord
|
84
|
-
|
83
|
+
description: 'ElasticsearchRecord is a ActiveRecord adapter and provides similar functionality
|
84
|
+
for Elasticsearch.
|
85
85
|
|
86
86
|
'
|
87
87
|
email:
|
@@ -106,6 +106,7 @@ files:
|
|
106
106
|
- lib/active_record/connection_adapters/elasticsearch/type.rb
|
107
107
|
- lib/active_record/connection_adapters/elasticsearch/type/format_string.rb
|
108
108
|
- lib/active_record/connection_adapters/elasticsearch/type/multicast_value.rb
|
109
|
+
- lib/active_record/connection_adapters/elasticsearch/type/nested.rb
|
109
110
|
- lib/active_record/connection_adapters/elasticsearch/type/object.rb
|
110
111
|
- lib/active_record/connection_adapters/elasticsearch/type/range.rb
|
111
112
|
- lib/active_record/connection_adapters/elasticsearch_adapter.rb
|
@@ -142,7 +143,9 @@ files:
|
|
142
143
|
- lib/elasticsearch_record/relation/result_methods.rb
|
143
144
|
- lib/elasticsearch_record/relation/value_methods.rb
|
144
145
|
- lib/elasticsearch_record/result.rb
|
146
|
+
- lib/elasticsearch_record/schema_migration.rb
|
145
147
|
- lib/elasticsearch_record/statement_cache.rb
|
148
|
+
- lib/elasticsearch_record/tasks/elasticsearch_database_tasks.rb
|
146
149
|
- lib/elasticsearch_record/version.rb
|
147
150
|
- sig/elasticsearch_record.rbs
|
148
151
|
homepage: https://github.com/ruby-smart/elasticsearch_record
|
@@ -171,5 +174,5 @@ requirements: []
|
|
171
174
|
rubygems_version: 3.3.7
|
172
175
|
signing_key:
|
173
176
|
specification_version: 4
|
174
|
-
summary: ActiveRecord
|
177
|
+
summary: ActiveRecord adapter for Elasticsearch
|
175
178
|
test_files: []
|