amber_odm 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 3fd8519f176d5e86f6ddb8307e77864de6511ee3af28e0f89873bb57a4ac51e7
4
+ data.tar.gz: 3684de6f1e2f52c1da8b04c55fb47b6e5e13da36fbe3eb843c0929cf5ab49dc6
5
+ SHA512:
6
+ metadata.gz: e0fb595ffd51eb627493a777347636200c06713041802d65aa41968140bc0ed361e74e23a0c4d6b73cf8925d2994f4fddcdf52a1fb55541b56572d2912f53da9
7
+ data.tar.gz: 2f36be5406925f55a1f2329518891982da4263543526c1d01e244d853b30207a555be16201c685eeb8caa8a0e5b1faacb07b79ba094d70f77ee843edac0f98bc
data/.gitignore ADDED
@@ -0,0 +1,14 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+ .idea
10
+ *.gem
11
+ .ruby-version
12
+
13
+ # rspec failure tracking
14
+ .rspec_status
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in emerald-orm.gemspec
4
+ gemspec
5
+
data/Gemfile.lock ADDED
@@ -0,0 +1,86 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ amber_odm (1.0.0)
5
+ elasticsearch
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ coderay (1.1.3)
11
+ diff-lcs (1.5.0)
12
+ docile (1.4.0)
13
+ dotenv (2.8.1)
14
+ elastic-transport (8.1.0)
15
+ faraday (< 3)
16
+ multi_json
17
+ elasticsearch (8.6.0)
18
+ elastic-transport (~> 8)
19
+ elasticsearch-api (= 8.6.0)
20
+ elasticsearch-api (8.6.0)
21
+ multi_json
22
+ faraday (1.10.3)
23
+ faraday-em_http (~> 1.0)
24
+ faraday-em_synchrony (~> 1.0)
25
+ faraday-excon (~> 1.1)
26
+ faraday-httpclient (~> 1.0)
27
+ faraday-multipart (~> 1.0)
28
+ faraday-net_http (~> 1.0)
29
+ faraday-net_http_persistent (~> 1.0)
30
+ faraday-patron (~> 1.0)
31
+ faraday-rack (~> 1.0)
32
+ faraday-retry (~> 1.0)
33
+ ruby2_keywords (>= 0.0.4)
34
+ faraday-em_http (1.0.0)
35
+ faraday-em_synchrony (1.0.0)
36
+ faraday-excon (1.1.0)
37
+ faraday-httpclient (1.0.1)
38
+ faraday-multipart (1.0.4)
39
+ multipart-post (~> 2)
40
+ faraday-net_http (1.0.1)
41
+ faraday-net_http_persistent (1.2.0)
42
+ faraday-patron (1.0.0)
43
+ faraday-rack (1.0.0)
44
+ faraday-retry (1.0.3)
45
+ method_source (1.0.0)
46
+ multi_json (1.15.0)
47
+ multipart-post (2.3.0)
48
+ pry (0.14.2)
49
+ coderay (~> 1.1)
50
+ method_source (~> 1.0)
51
+ rake (13.0.6)
52
+ rspec (3.12.0)
53
+ rspec-core (~> 3.12.0)
54
+ rspec-expectations (~> 3.12.0)
55
+ rspec-mocks (~> 3.12.0)
56
+ rspec-core (3.12.0)
57
+ rspec-support (~> 3.12.0)
58
+ rspec-expectations (3.12.2)
59
+ diff-lcs (>= 1.2.0, < 2.0)
60
+ rspec-support (~> 3.12.0)
61
+ rspec-mocks (3.12.3)
62
+ diff-lcs (>= 1.2.0, < 2.0)
63
+ rspec-support (~> 3.12.0)
64
+ rspec-support (3.12.0)
65
+ ruby2_keywords (0.0.5)
66
+ simplecov (0.22.0)
67
+ docile (~> 1.1)
68
+ simplecov-html (~> 0.11)
69
+ simplecov_json_formatter (~> 0.1)
70
+ simplecov-html (0.12.3)
71
+ simplecov_json_formatter (0.1.4)
72
+
73
+ PLATFORMS
74
+ ruby
75
+
76
+ DEPENDENCIES
77
+ amber_odm!
78
+ bundler
79
+ dotenv
80
+ pry
81
+ rake
82
+ rspec
83
+ simplecov
84
+
85
+ BUNDLED WITH
86
+ 1.16.2
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2022 mikael
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,143 @@
1
+ # AmberODM
2
+ A Ruby gem that provides a simple Object Document Mapper (ODM) for Elasticsearch. It allows you to interact with Elasticsearch in a more organized and object-oriented way.
3
+
4
+ ## Installation
5
+ Add this line to your application's Gemfile:
6
+
7
+ ```ruby
8
+ gem 'amber_odm'
9
+ ```
10
+
11
+
12
+ And then execute:
13
+
14
+ $ bundle
15
+
16
+ Or install it yourself as:
17
+
18
+ $ gem install amber_odm
19
+
20
+ # Usage
21
+ Here's a quick example of how to use EmeraldODM to interact with a ElasticSearch database:
22
+
23
+ ## 1. Configuring your Elasticsearch connection
24
+ ```ruby
25
+ require 'amber_odm'
26
+
27
+ AmberODM.databases_settings[:dev] = {
28
+ url: 'http://localhost:9200',
29
+ log: true
30
+ }
31
+
32
+ ```
33
+
34
+ ## 2. Define your model
35
+ ```ruby
36
+ require 'amber_odm'
37
+
38
+ # Define a model for the "users" index
39
+ class User < AmberODM::Document
40
+
41
+ attr_accessor :name, :email, :posts, :keywords_count
42
+
43
+ def self.index_name
44
+ :users
45
+ end
46
+
47
+ def self.db_name
48
+ :dev
49
+ end
50
+
51
+ def self.posts=(posts)
52
+ @posts = posts.map { |post| Post.new(post)}
53
+ end
54
+
55
+ class Post < AmberODM::AttrInitializer
56
+ attr_accessor :id, :title, :body, :created_at, :updated_at
57
+
58
+ def created_at
59
+ Time.parse(@created_at)
60
+ end
61
+
62
+ def updated_at
63
+ Time.parse(@updated_at)
64
+ end
65
+
66
+ def keywords
67
+ body.scan(/\w+/)
68
+ end
69
+ end
70
+
71
+ end
72
+
73
+ ```
74
+
75
+ ## 3. Use it
76
+ ```ruby
77
+ # Find users using a query
78
+ users = User.search(
79
+ {
80
+ bool: {
81
+ must: [
82
+ {match: {name: 'John Doe'}}
83
+ ]
84
+ }
85
+ }, # filter query is required
86
+ _source: %w[name email posts keywords_count], # optional, the default is to return all fields defined in the document
87
+ size: 10, # optional, the default is to return all documents
88
+ )
89
+
90
+ # users is an array of User objects like Array<User>
91
+ bulk_users = []
92
+ users.each do |user|
93
+ posts = user.posts
94
+ all_user_keywords = posts.map(&:keywords).flatten.uniq
95
+ user.keywords_count = all_user_keywords.count
96
+ bulk_hash = user.get_bulk_update_hash(:keywords_count) # returns a hash that can be used to update the document field ':keywords_count' in bulk
97
+
98
+ bulk_users << bulk_hash
99
+ end
100
+
101
+ # Update the documents in bulk
102
+ User.client.bulk(body: bulk_users) unless bulk_users.empty?
103
+ ```
104
+
105
+ # Advanced usage
106
+ ## Pagination
107
+ ```ruby
108
+ # 1. Get the first page of users
109
+ users = User.search(
110
+ { bool: { must: [{match: {name: 'John Doe'}}] } },
111
+ size: 10,
112
+ sort: [{name: 'asc'}],
113
+ )
114
+
115
+ # 2. Get the last sort value
116
+ search_after = users.last&.sort
117
+
118
+ # 3. Loop through the pages
119
+ while users.any?
120
+ users = User.search(
121
+ { bool: { must: [{match: {name: 'John Doe'}}] } },
122
+ size: 10,
123
+ sort: [{name: 'asc'}],
124
+ search_after: search_after
125
+ )
126
+
127
+ # 4. Do something with the users documents...
128
+ puts users.map(&:name).join(', ')
129
+
130
+ # 5. Update the last sort value
131
+ search_after = users.last&.sort
132
+ end
133
+ ```
134
+ ## Accessing the Elasticsearch client
135
+ ```ruby
136
+ User.client # returns the Elasticsearch client from 'elasticsearch-ruby' gem
137
+ ```
138
+
139
+ # Contributing
140
+ Bug reports and pull requests are welcome on GitHub at https://github.com/MikaelSantilio/amber-odm/.
141
+
142
+ # License
143
+ The gem is available as open source under the terms of the MIT License.
data/amber_odm.gemspec ADDED
@@ -0,0 +1,41 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+
5
+ require_relative 'lib/amber_odm/version'
6
+
7
+ Gem::Specification.new do |spec|
8
+ spec.name = 'amber_odm'
9
+ spec.version = AmberODM::VERSION
10
+ spec.authors = ['mikael']
11
+ spec.email = ['mikael.santilio@gmail.com']
12
+
13
+ spec.summary = 'ElasticSearch ODM'
14
+ spec.description = 'Simple ElasticSearch ODM'
15
+ spec.homepage = 'https://github.com/MikaelSantilio/amber-odm'
16
+ spec.required_ruby_version = Gem::Requirement.new('>= 2.5.0')
17
+
18
+ spec.metadata['allowed_push_host'] = 'https://rubygems.org'
19
+
20
+ spec.metadata['homepage_uri'] = spec.homepage
21
+ spec.metadata['source_code_uri'] = 'https://github.com/MikaelSantilio/amber-odm'
22
+
23
+ # Specify which files should be added to the gem when it is released.
24
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
25
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
26
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
27
+ end
28
+ spec.bindir = 'exe'
29
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
30
+ spec.require_paths = ['lib']
31
+
32
+ spec.add_development_dependency 'bundler'
33
+ spec.add_development_dependency 'rake'
34
+ spec.add_development_dependency 'rspec'
35
+ spec.add_development_dependency 'dotenv'
36
+ spec.add_development_dependency 'pry'
37
+ spec.add_development_dependency 'simplecov'
38
+
39
+ spec.add_dependency 'elasticsearch'
40
+
41
+ end
@@ -0,0 +1,3 @@
1
+ module AmberODM
2
+ VERSION = '1.0.0'
3
+ end
data/lib/amber_odm.rb ADDED
@@ -0,0 +1,197 @@
1
+ require 'amber_odm/version'
2
+ require 'elasticsearch'
3
+
4
+ module AmberODM
5
+
6
+ def self.databases_settings
7
+ @databases_settings ||= {}
8
+ end
9
+
10
+ module Connector
11
+
12
+ # @return [Elasticsearch::Client] The database client
13
+ def self.database(db_name)
14
+ if databases_instances[db_name].nil?
15
+ db_settings = AmberODM.databases_settings[db_name]
16
+ raise Exceptions::MissingDatabaseSettings.new("Database settings not found for #{db_name}") if db_settings.nil? || db_settings.empty?
17
+ self.databases_instances[db_name] = Elasticsearch::Client.new(db_settings)
18
+ end
19
+ databases_instances[db_name]
20
+ end
21
+
22
+ def self.databases_instances
23
+ @databases_instances ||= {}
24
+ end
25
+ end
26
+
27
+ class AttrInitializer
28
+ attr_reader :document
29
+
30
+ def initialize(document)
31
+ self.class.fields.each do |field|
32
+ document_value = document&.dig(field).dup
33
+ send("#{field}=", document_value) unless document_value.nil?
34
+ end
35
+ instance_variable_set('@document', document)
36
+ end
37
+
38
+ # @return [Array]
39
+ def self.fields
40
+ public_instance_methods = self.public_instance_methods(false).grep(/=$/)
41
+ rejected_attr_names = %w[document]
42
+ fields = []
43
+ public_instance_methods.each do |attr|
44
+ attr_name = attr.to_s.gsub('=', '')
45
+ next if rejected_attr_names.include?(attr_name)
46
+ fields << attr_name
47
+ end
48
+ fields
49
+ end
50
+
51
+ def nil?
52
+ document.nil? || document.empty?
53
+ end
54
+
55
+ def self.array_to_h(array)
56
+ array.map do |item|
57
+ if item.is_a?(AttrInitializer)
58
+ item.to_h
59
+ elsif item.is_a?(Array)
60
+ array_to_h(item)
61
+ else
62
+ item
63
+ end
64
+ end
65
+ end
66
+
67
+ def to_h
68
+ hash = {}
69
+ known_fields = self.class.fields
70
+ unknown_fields = document.keys - known_fields
71
+ unknown_fields.reject! { |field| field.start_with?('_') }
72
+ known_fields.each do |field|
73
+ value = send(field)
74
+ if value.is_a?(AttrInitializer)
75
+ hash[field] = value.to_h
76
+ elsif value.is_a?(Array)
77
+ hash[field] = self.class.array_to_h(value)
78
+ else
79
+ hash[field] = value
80
+ end
81
+ end
82
+ unknown_fields.each do |field|
83
+ value = document[field]
84
+ hash[field] = value
85
+ end
86
+
87
+ hash
88
+ end
89
+ end
90
+
91
+ class Document < AttrInitializer
92
+
93
+ attr_reader :_id, :_score, :sort
94
+
95
+ def initialize(document)
96
+ @_id = document&.dig('_id').dup
97
+ @_score = document&.dig('_score').dup
98
+ @sort = document&.dig('sort').dup
99
+ self.class.fields.each do |field|
100
+ document_value = document&.dig('_source')&.dig(field).dup
101
+ send("#{field}=", document_value) unless document_value.nil?
102
+ end
103
+ instance_variable_set('@document', document)
104
+ end
105
+
106
+ # @return [Symbol, nil]
107
+ def self.db_name
108
+ nil
109
+ end
110
+
111
+ # @return [Symbol, String, nil]
112
+ def self.index_name
113
+ nil
114
+ end
115
+
116
+ # @return [Elasticsearch::Client] The ES client
117
+ def self.client
118
+ Connector.database(db_name&.to_sym)
119
+ end
120
+
121
+ def self.is_valid_fields?(query_fields)
122
+ (query_fields - fields).count == 0
123
+ end
124
+
125
+ # @param [Hash] query The query
126
+ # @param [Array] _source The _source
127
+ # @param [Hash] sort The sort
128
+ # @param [Integer] size The size
129
+ # @return [Array<self>] The documents
130
+ def search(query, _source: [], sort: [], search_after: [], size: 0)
131
+ # self.class.validate_fields_from_stages(query, _source, sort)
132
+
133
+ if _source.empty?
134
+ _source = self.class.fields
135
+ end
136
+
137
+ if query.empty?
138
+ raise Exceptions::IllegalArgumentException.new
139
+ end
140
+
141
+ body = { _source: _source, query: query }
142
+ body[:sort] = sort unless sort.empty?
143
+ body[:search_after] = search_after unless search_after.empty?
144
+ body[:size] = size unless size.zero?
145
+ response = self.class.client.search(index: self.class.index_name.to_s, body: body)
146
+ response&.dig('hits', 'hits')&.map { |document| self.class.new(document) } || []
147
+ end
148
+
149
+ def self.search(filter, _source: [], sort: {}, search_after: [], size: 0)
150
+ new({}).search(filter, _source: _source, sort: sort, search_after: search_after, size: size)
151
+ end
152
+
153
+ def self.validate_fields(fields_to_validate)
154
+ fields_to_validate.map! { |field| field.to_s }
155
+ if (fields_to_validate - fields).count > 0
156
+ raise Exceptions::UnknownWriteFieldException.new "Unknown fields: #{fields_to_validate - fields}, define them in attr_accessor before using them"
157
+ elsif fields_to_validate.empty?
158
+ raise Exceptions::IllegalArgumentException.new 'Empty fields'
159
+ end
160
+ end
161
+
162
+ def get_bulk_update_hash(*fields)
163
+ self.class.validate_fields(fields)
164
+
165
+ aggregation_hash = {}
166
+ fields.each do |field|
167
+ value = send(field)
168
+ if value.is_a?(AttrInitializer)
169
+ aggregation_hash[field] = value.to_h
170
+ elsif value.is_a?(Array)
171
+ aggregation_hash[field] = AttrInitializer.array_to_h(value)
172
+ else
173
+ aggregation_hash[field] = value
174
+ end
175
+ end
176
+
177
+ {
178
+ update: {
179
+ _index: self.class.index_name&.to_s,
180
+ _id: _id,
181
+ data: { doc: aggregation_hash }
182
+ }
183
+ }
184
+ end
185
+
186
+ end
187
+
188
+ module Exceptions
189
+ class MissingDatabaseSettings < StandardError; end
190
+ class UnknownWriteFieldException < StandardError; end
191
+ class IllegalArgumentException < StandardError
192
+ def initialize(msg = 'query malformed, empty clause')
193
+ super
194
+ end
195
+ end
196
+ end
197
+ end
metadata ADDED
@@ -0,0 +1,153 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: amber_odm
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - mikael
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2023-01-28 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: dotenv
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: pry
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: simplecov
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: elasticsearch
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ description: Simple ElasticSearch ODM
112
+ email:
113
+ - mikael.santilio@gmail.com
114
+ executables: []
115
+ extensions: []
116
+ extra_rdoc_files: []
117
+ files:
118
+ - ".gitignore"
119
+ - ".rspec"
120
+ - Gemfile
121
+ - Gemfile.lock
122
+ - LICENSE.txt
123
+ - README.md
124
+ - amber_odm.gemspec
125
+ - lib/amber_odm.rb
126
+ - lib/amber_odm/version.rb
127
+ homepage: https://github.com/MikaelSantilio/amber-odm
128
+ licenses: []
129
+ metadata:
130
+ allowed_push_host: https://rubygems.org
131
+ homepage_uri: https://github.com/MikaelSantilio/amber-odm
132
+ source_code_uri: https://github.com/MikaelSantilio/amber-odm
133
+ post_install_message:
134
+ rdoc_options: []
135
+ require_paths:
136
+ - lib
137
+ required_ruby_version: !ruby/object:Gem::Requirement
138
+ requirements:
139
+ - - ">="
140
+ - !ruby/object:Gem::Version
141
+ version: 2.5.0
142
+ required_rubygems_version: !ruby/object:Gem::Requirement
143
+ requirements:
144
+ - - ">="
145
+ - !ruby/object:Gem::Version
146
+ version: '0'
147
+ requirements: []
148
+ rubyforge_project:
149
+ rubygems_version: 2.7.7
150
+ signing_key:
151
+ specification_version: 4
152
+ summary: ElasticSearch ODM
153
+ test_files: []