esse 0.2.0 → 0.2.3

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 (98) hide show
  1. checksums.yaml +4 -4
  2. data/lib/esse/cli/event_listener.rb +13 -0
  3. data/lib/esse/cli/generate.rb +53 -14
  4. data/lib/esse/cli/index/base_operation.rb +5 -13
  5. data/lib/esse/cli/index/close.rb +1 -1
  6. data/lib/esse/cli/index/create.rb +1 -1
  7. data/lib/esse/cli/index/delete.rb +1 -1
  8. data/lib/esse/cli/index/import.rb +6 -2
  9. data/lib/esse/cli/index/open.rb +1 -1
  10. data/lib/esse/cli/index/reset.rb +1 -1
  11. data/lib/esse/cli/index/update_aliases.rb +2 -2
  12. data/lib/esse/cli/index/update_mapping.rb +9 -5
  13. data/lib/esse/cli/index/update_settings.rb +1 -1
  14. data/lib/esse/cli/index.rb +11 -4
  15. data/lib/esse/cli/templates/collection.rb.erb +29 -0
  16. data/lib/esse/cli/templates/config.rb.erb +13 -3
  17. data/lib/esse/cli/templates/document.rb.erb +34 -0
  18. data/lib/esse/cli/templates/index.rb.erb +63 -114
  19. data/lib/esse/cli/templates/mappings.json +27 -0
  20. data/lib/esse/cli/templates/settings.json +62 -0
  21. data/lib/esse/cli.rb +5 -0
  22. data/lib/esse/cluster.rb +93 -12
  23. data/lib/esse/cluster_engine.rb +42 -0
  24. data/lib/esse/collection.rb +18 -0
  25. data/lib/esse/config.rb +14 -2
  26. data/lib/esse/core.rb +28 -7
  27. data/lib/esse/deprecations/cluster.rb +27 -0
  28. data/lib/esse/deprecations/deprecate.rb +29 -0
  29. data/lib/esse/deprecations/index.rb +37 -0
  30. data/lib/esse/deprecations/index_backend_delegator.rb +217 -0
  31. data/lib/esse/deprecations/repository.rb +34 -0
  32. data/lib/esse/deprecations/repository_backend_delegator.rb +110 -0
  33. data/lib/esse/deprecations/serializer.rb +14 -0
  34. data/lib/esse/deprecations.rb +7 -0
  35. data/lib/esse/document.rb +91 -0
  36. data/lib/esse/dynamic_template.rb +43 -0
  37. data/lib/esse/errors.rb +60 -2
  38. data/lib/esse/events/event.rb +4 -19
  39. data/lib/esse/events.rb +13 -2
  40. data/lib/esse/hash_document.rb +38 -0
  41. data/lib/esse/import/bulk.rb +106 -0
  42. data/lib/esse/import/request_body.rb +60 -0
  43. data/lib/esse/index/aliases.rb +50 -0
  44. data/lib/esse/index/attributes.rb +107 -0
  45. data/lib/esse/index/base.rb +17 -53
  46. data/lib/esse/index/documents.rb +236 -0
  47. data/lib/esse/index/indices.rb +171 -0
  48. data/lib/esse/index/inheritance.rb +30 -0
  49. data/lib/esse/index/mappings.rb +6 -19
  50. data/lib/esse/index/object_document_mapper.rb +36 -0
  51. data/lib/esse/index/plugins.rb +42 -0
  52. data/lib/esse/index/search.rb +27 -0
  53. data/lib/esse/index/settings.rb +2 -2
  54. data/lib/esse/index/type.rb +51 -11
  55. data/lib/esse/index.rb +14 -9
  56. data/lib/esse/index_mapping.rb +10 -2
  57. data/lib/esse/index_setting.rb +3 -1
  58. data/lib/esse/null_document.rb +35 -0
  59. data/lib/esse/plugins.rb +12 -0
  60. data/lib/esse/primitives/hstring.rb +1 -1
  61. data/lib/esse/{index_type → repository}/actions.rb +1 -1
  62. data/lib/esse/repository/documents.rb +13 -0
  63. data/lib/esse/repository/object_document_mapper.rb +157 -0
  64. data/lib/esse/repository.rb +17 -0
  65. data/lib/esse/search/query.rb +105 -0
  66. data/lib/esse/search/response.rb +46 -0
  67. data/lib/esse/template_loader.rb +1 -1
  68. data/lib/esse/transport/aliases.rb +36 -0
  69. data/lib/esse/transport/documents.rb +199 -0
  70. data/lib/esse/transport/health.rb +30 -0
  71. data/lib/esse/transport/indices.rb +192 -0
  72. data/lib/esse/transport/search.rb +48 -0
  73. data/lib/esse/transport.rb +44 -0
  74. data/lib/esse/version.rb +1 -1
  75. data/lib/esse.rb +20 -5
  76. metadata +55 -50
  77. data/lib/esse/backend/index/aliases.rb +0 -73
  78. data/lib/esse/backend/index/close.rb +0 -54
  79. data/lib/esse/backend/index/create.rb +0 -67
  80. data/lib/esse/backend/index/delete.rb +0 -39
  81. data/lib/esse/backend/index/documents.rb +0 -23
  82. data/lib/esse/backend/index/existance.rb +0 -22
  83. data/lib/esse/backend/index/open.rb +0 -54
  84. data/lib/esse/backend/index/refresh.rb +0 -43
  85. data/lib/esse/backend/index/reset.rb +0 -33
  86. data/lib/esse/backend/index/update.rb +0 -143
  87. data/lib/esse/backend/index.rb +0 -54
  88. data/lib/esse/backend/index_type/documents.rb +0 -214
  89. data/lib/esse/backend/index_type.rb +0 -37
  90. data/lib/esse/cli/templates/type_collection.rb.erb +0 -41
  91. data/lib/esse/cli/templates/type_mappings.json +0 -6
  92. data/lib/esse/cli/templates/type_serializer.rb.erb +0 -23
  93. data/lib/esse/index/backend.rb +0 -14
  94. data/lib/esse/index/naming.rb +0 -64
  95. data/lib/esse/index_type/backend.rb +0 -14
  96. data/lib/esse/index_type/mappings.rb +0 -42
  97. data/lib/esse/index_type.rb +0 -15
  98. data/lib/esse/object_document_mapper.rb +0 -110
@@ -1,214 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Esse
4
- module Backend
5
- class IndexType
6
- module InstanceMethods
7
- # Resolve collection and index data
8
- #
9
- # @param options [Hash] Hash of paramenters that will be passed along to elasticsearch request
10
- # @option [String, nil] :suffix The index suffix. Defaults to the nil.
11
- # @option [Hash] :context The collection context. This value will be passed as argument to the collection
12
- # May be SQL condition or any other filter you have defined on the collection.
13
- def import(context: {}, suffix: nil, **options)
14
- each_serialized_batch(**(context || {})) do |batch|
15
- bulk(index: batch, suffix: suffix, **options)
16
- end
17
- end
18
- alias_method :import!, :import
19
-
20
- # Performs multiple indexing or delete operations in a single API call.
21
- # This reduces overhead and can greatly increase indexing speed.
22
- #
23
- # @param options [Hash] Hash of paramenters that will be passed along to elasticsearch request
24
- # @option [String, nil] :suffix The index suffix. Defaults to the nil.
25
- # @option [Array] :index list of serialized documents to be indexed(Optional)
26
- # @option [Array] :delete list of serialized documents to be deleted(Optional)
27
- # @option [Array] :create list of serialized documents to be created(Optional)
28
- # @return [Hash, nil] the elasticsearch response or nil if there is no data.
29
- #
30
- # @see https://www.elastic.co/guide/en/elasticsearch/reference/7.5/docs-bulk.html
31
- def bulk(index: nil, delete: nil, create: nil, suffix: nil, **options)
32
- body = []
33
- Array(index).each do |entry|
34
- id, data = Esse.doc_id!(entry)
35
- body << { index: { _id: id, data: data } } if id
36
- end
37
- Array(create).each do |entry|
38
- id, data = Esse.doc_id!(entry)
39
- body << { create: { _id: id, data: data } } if id
40
- end
41
- Array(delete).each do |entry|
42
- id, _data = Esse.doc_id!(entry, delete: [], keep: %w[_id id])
43
- body << { delete: { _id: id } } if id
44
- end
45
-
46
- return if body.empty?
47
-
48
- definition = {
49
- index: index_name(suffix: suffix),
50
- type: type_name,
51
- body: body,
52
- }.merge(options)
53
-
54
- client.bulk(definition)
55
- end
56
- alias_method :bulk!, :bulk
57
-
58
- # Adds a JSON document to the specified index and makes it searchable. If the document
59
- # already exists, updates the document and increments its version.
60
- #
61
- # UsersIndex::User.index(id: 1, body: { name: 'name' }) # { '_id' => 1, ...}
62
- #
63
- # @param options [Hash] Hash of paramenters that will be passed along to elasticsearch request
64
- # @option [String, Integer] :id The `_id` of the elasticsearch document
65
- # @option [Hash] :body The JSON document that will be indexed (Required)
66
- # @option [String, nil] :suffix The index suffix. Defaults to the nil.
67
- # @return [Hash] the elasticsearch response Hash
68
- #
69
- # @see https://www.elastic.co/guide/en/elasticsearch/reference/7.5/docs-index_.html
70
- def index(id:, body:, suffix: nil, **options)
71
- client.index(
72
- index: index_name(suffix: suffix), type: type_name, id: id, body: body, **options
73
- )
74
- end
75
- alias_method :index!, :index
76
-
77
- # Updates a document using the specified script.
78
- #
79
- # UsersIndex::User.update!(id: 1, body: { doc: { ... } }) # { '_id' => 1, ...}
80
- #
81
- # @param options [Hash] Hash of paramenters that will be passed along to elasticsearch request
82
- # @option [String, Integer] :id The `_id` of the elasticsearch document
83
- # @option [Hash] :body the body of the request
84
- # @option [String, nil] :suffix The index suffix. Defaults to the nil.
85
- # @raise [Elasticsearch::Transport::Transport::Errors::NotFound] when the doc does not exist
86
- # @return [Hash] elasticsearch response hash
87
- #
88
- # @see https://www.elastic.co/guide/en/elasticsearch/reference/7.5/docs-update.html
89
- def update!(id:, body:, suffix: nil, **options)
90
- client.update(
91
- index: index_name(suffix: suffix), type: type_name, id: id, body: body, **options
92
- )
93
- end
94
-
95
- # Updates a document using the specified script.
96
- #
97
- # UsersIndex::User.update(id: 1, body: { doc: { ... } }) # { '_id' => 1, ...}
98
- #
99
- # @param options [Hash] Hash of paramenters that will be passed along to elasticsearch request
100
- # @option [String, Integer] :id The `_id` of the elasticsearch document
101
- # @option [Hash] :body the body of the request
102
- # @option [String, nil] :suffix The index suffix. Defaults to the nil.
103
- # @return [Hash] the elasticsearch response, or an hash with 'errors' as true in case of failure
104
- #
105
- # @see https://www.elastic.co/guide/en/elasticsearch/reference/7.5/docs-update.html
106
- def update(id:, body:, suffix: nil, **options)
107
- update!(id: id, body: body, suffix: suffix, **options)
108
- rescue Elasticsearch::Transport::Transport::Errors::NotFound
109
- { 'errors' => true }
110
- end
111
-
112
- # Removes a JSON document from the specified index.
113
- #
114
- # UsersIndex::User.delete!(id: 1) # true
115
- # UsersIndex::User.delete!(id: 'missing') # raise Elasticsearch::Transport::Transport::Errors::NotFound
116
- #
117
- # @param options [Hash] Hash of paramenters that will be passed along to elasticsearch request
118
- # @option [String, Integer] :id The `_id` of the elasticsearch document
119
- # @option [String, nil] :suffix The index suffix. Defaults to the nil.
120
- # @raise [Elasticsearch::Transport::Transport::Errors::NotFound] when the doc does not exist
121
- # @return [Boolean] true when the operation is successfully completed
122
- #
123
- # @see https://www.elastic.co/guide/en/elasticsearch/reference/7.5/docs-delete.html
124
- def delete!(id:, suffix: nil, **options)
125
- client.delete(options.merge(index: index_name(suffix: suffix), type: type_name, id: id))
126
- end
127
-
128
- # Removes a JSON document from the specified index.
129
- #
130
- # UsersIndex::User.delete(id: 1) # true
131
- # UsersIndex::User.delete(id: 'missing') # false
132
- #
133
- # @param options [Hash] Hash of paramenters that will be passed along to elasticsearch request
134
- # @option [String, Integer] :id The `_id` of the elasticsearch document
135
- # @option [String, nil] :suffix The index suffix. Defaults to the nil.
136
- # @raise [Elasticsearch::Transport::Transport::Errors::NotFound] when the doc does not exist
137
- # @return [Boolean] true when the operation is successfully completed
138
- #
139
- # @see https://www.elastic.co/guide/en/elasticsearch/reference/7.5/docs-delete.html
140
- def delete(id:, suffix: nil, **options)
141
- delete!(id: id, suffix: suffix, **options)
142
- rescue Elasticsearch::Transport::Transport::Errors::NotFound
143
- false
144
- end
145
-
146
- # Gets the number of matches for a search query.
147
- #
148
- # UsersIndex::User.count # 999
149
- # UsersIndex::User.count(body: { ... }) # 32
150
- #
151
- # @param options [Hash] Hash of paramenters that will be passed along to elasticsearch request
152
- # @option [Hash] :body A query to restrict the results specified with the Query DSL (optional)
153
- # @option [String, nil] :suffix The index suffix. Defaults to the nil.
154
- # @return [Integer] amount of documents found
155
- #
156
- # @see https://www.elastic.co/guide/en/elasticsearch/reference/7.5/search-count.html
157
- def count(suffix: nil, **options)
158
- response = client.count(options.merge(index: index_name(suffix: suffix), type: type_name))
159
- response['count']
160
- rescue Elasticsearch::Transport::Transport::Errors::NotFound
161
- 0
162
- end
163
-
164
- # Check if a JSON document exists
165
- #
166
- # UsersIndex::User.exist?(id: 1) # true
167
- # UsersIndex::User.exist?(id: 'missing') # false
168
- #
169
- # @param options [Hash] Hash of paramenters that will be passed along to elasticsearch request
170
- # @option [String, Integer] :id The `_id` of the elasticsearch document
171
- # @option [String, nil] :suffix The index suffix. Defaults to the nil.
172
- # @return [Boolean] true if the document exists
173
- def exist?(id:, suffix: nil, **options)
174
- client.exists(options.merge(index: index_name(suffix: suffix), type: type_name, id: id))
175
- end
176
-
177
- # Retrieves the specified JSON document from an index.
178
- #
179
- # UsersIndex::User.find!(id: 1) # { '_id' => 1, ... }
180
- # UsersIndex::User.find!(id: 'missing') # raise Elasticsearch::Transport::Transport::Errors::NotFound
181
- #
182
- # @param options [Hash] Hash of paramenters that will be passed along to elasticsearch request
183
- # @option [String, Integer] :id The `_id` of the elasticsearch document
184
- # @option [String, nil] :suffix The index suffix. Defaults to the nil.
185
- # @raise [Elasticsearch::Transport::Transport::Errors::NotFound] when the doc does not exist
186
- # @return [Hash] The elasticsearch document.
187
- #
188
- # @see https://www.elastic.co/guide/en/elasticsearch/reference/7.5/docs-get.html
189
- def find!(id:, suffix: nil, **options)
190
- client.get(options.merge(index: index_name(suffix: suffix), type: type_name, id: id))
191
- end
192
-
193
- # Retrieves the specified JSON document from an index.
194
- #
195
- # UsersIndex::User.find(id: 1) # { '_id' => 1, ... }
196
- # UsersIndex::User.find(id: 'missing') # nil
197
- #
198
- # @param options [Hash] Hash of paramenters that will be passed along to elasticsearch request
199
- # @option [String, Integer] :id The `_id` of the elasticsearch document
200
- # @option [String, nil] :suffix The index suffix. Defaults to the nil.
201
- # @return [Hash, nil] The elasticsearch document
202
- #
203
- # @see https://www.elastic.co/guide/en/elasticsearch/reference/7.5/docs-get.html
204
- def find(id:, suffix: nil, **options)
205
- find!(id: id, suffix: suffix, **options)
206
- rescue Elasticsearch::Transport::Transport::Errors::NotFound
207
- nil
208
- end
209
- end
210
-
211
- include InstanceMethods
212
- end
213
- end
214
- end
@@ -1,37 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'forwardable'
4
-
5
- module Esse
6
- module Backend
7
- class IndexType
8
- require_relative 'index_type/documents'
9
-
10
- extend Forwardable
11
-
12
- # Type delegators
13
- def_delegators :@index_type, :type_name, :each_serialized_batch, :serialize
14
-
15
- def initialize(type)
16
- @index_type = type
17
- end
18
-
19
- protected
20
-
21
- def index_name(suffix: nil)
22
- suffix = Hstring.new(suffix).underscore.presence
23
- return index_class.index_name unless suffix
24
-
25
- [index_class.index_name, suffix].join('_')
26
- end
27
-
28
- def index_class
29
- @index_type.index
30
- end
31
-
32
- def client
33
- index_class.cluster.client
34
- end
35
- end
36
- end
37
- end
@@ -1,41 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class <%= @index_name %> < <%= @base_class %>
4
- module Collections
5
- class <%= @type.camelize %>Collection
6
- include Enumerable
7
-
8
- # @param params [Hash] List of parameters
9
- def initialize(**params)
10
- @params = params
11
- end
12
-
13
- # Find all <%= @type %> in batches
14
- #
15
- # @yield [Array<<%= @type.camelize %>>]
16
- # @see <%= @index_name %>::<%= @type.camelize %>#collection
17
- def each
18
- offset = 0
19
- while (rows = find_all(offset))
20
- break if rows.none?
21
-
22
- # You may preload associations before serialize them
23
- # associations = preload_associations!(rows)
24
- # yield(row, associations)
25
- offset += 1
26
-
27
- yield(rows, **params)
28
- end
29
- end
30
-
31
- protected
32
-
33
- attr_reader :params
34
-
35
- # @param offset [Number] Offset to start from
36
- def find_all(offset)
37
- # @TODO load data from persistent store
38
- end
39
- end
40
- end
41
- end
@@ -1,6 +0,0 @@
1
- {
2
- "name": {
3
- "type": "string",
4
- "index": "analyzed"
5
- }
6
- }
@@ -1,23 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class <%= @index_name %> < <%= @base_class %>
4
- module Serializers
5
- class <%= @type.camelize %>Serializer
6
- def initialize(<%= @type %>, **params)
7
- @entity = <%= @type %>
8
- @params = params
9
- end
10
-
11
- def to_h
12
- {
13
- id: entity.id, # This field is required
14
- name: entity.name,
15
- }
16
- end
17
-
18
- protected
19
-
20
- attr_reader :entity, :params
21
- end
22
- end
23
- end
@@ -1,14 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Esse
4
- class Index
5
- module ClassMethods
6
- def elasticsearch
7
- Esse::Backend::Index.new(self)
8
- end
9
- alias_method :backend, :elasticsearch
10
- end
11
-
12
- extend ClassMethods
13
- end
14
- end
@@ -1,64 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Esse
4
- class Index
5
- module ClassMethods
6
- TEMPLATE_DIRS = [
7
- '%<dirname>s/templates',
8
- '%<dirname>s'
9
- ].freeze
10
-
11
- def index_name=(value)
12
- @index_name = index_prefixed_name(value)
13
- end
14
-
15
- def index_name
16
- @index_name || index_prefixed_name(normalized_name)
17
- end
18
-
19
- def index_name?
20
- !index_name.nil?
21
- end
22
-
23
- def index_version=(value)
24
- @index_version = Hstring.new(value.to_s).underscore.presence
25
- end
26
-
27
- def index_version
28
- @index_version
29
- end
30
-
31
- def uname
32
- Hstring.new(name).underscore.presence
33
- end
34
-
35
- def index_directory
36
- return unless uname
37
- return if uname == 'Esse::Index'
38
-
39
- Esse.config.indices_directory.join(uname).to_s
40
- end
41
-
42
- def template_dirs
43
- return [] unless index_directory
44
-
45
- TEMPLATE_DIRS.map { |term| format(term, dirname: index_directory) }
46
- end
47
-
48
- protected
49
-
50
- def index_prefixed_name(value)
51
- return if value == '' || value.nil?
52
- return value.to_s unless cluster.index_prefix
53
-
54
- [cluster.index_prefix, value].join('_')
55
- end
56
-
57
- def normalized_name
58
- Hstring.new(name).demodulize.underscore.sub(/_(index)$/, '')
59
- end
60
- end
61
-
62
- extend ClassMethods
63
- end
64
- end
@@ -1,14 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Esse
4
- class IndexType
5
- module ClassMethods
6
- def elasticsearch
7
- Esse::Backend::IndexType.new(self)
8
- end
9
- alias_method :backend, :elasticsearch
10
- end
11
-
12
- extend ClassMethods
13
- end
14
- end
@@ -1,42 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Esse
4
- class IndexType
5
- # https://www.elastic.co/guide/en/elasticsearch/reference/master/indices-put-mapping.html
6
- module ClassMethods
7
- # This method is only used to define mapping
8
- def mappings(hash = {}, &block)
9
- @mapping = Esse::IndexMapping.new(body: hash, paths: template_dirs, filenames: mapping_filenames)
10
- return unless block
11
-
12
- @mapping.define_singleton_method(:to_h, &block)
13
- end
14
-
15
- # This is the actually content that will be passed through the ES api
16
- def mappings_hash
17
- hash = mapping.body
18
- {
19
- type_name => (hash.key?('properties') ? hash : { 'properties' => hash }),
20
- }
21
- end
22
-
23
- private
24
-
25
- def mapping
26
- @mapping ||= Esse::IndexMapping.new(paths: template_dirs, filenames: mapping_filenames)
27
- end
28
-
29
- def template_dirs
30
- return [] unless respond_to?(:index)
31
-
32
- index.template_dirs
33
- end
34
-
35
- def mapping_filenames
36
- Esse::IndexMapping::FILENAMES.map { |str| [type_name, str].join('_') }
37
- end
38
- end
39
-
40
- extend ClassMethods
41
- end
42
- end
@@ -1,15 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative 'object_document_mapper'
4
-
5
- module Esse
6
- # Type is actually deprecated. Elasticsearch today uses _doc instead of type
7
- # And in upcoming release it will be totally removed.
8
- # But I want to keep compatibility with old versions of es.
9
- class IndexType
10
- require_relative 'index_type/actions'
11
- require_relative 'index_type/mappings'
12
- require_relative 'index_type/backend'
13
- extend ObjectDocumentMapper
14
- end
15
- end
@@ -1,110 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Esse
4
- module ObjectDocumentMapper
5
- # Convert ruby object to json. Arguments will be same of passed through the
6
- # collection. It's allowed a block or a class with the `to_h` instance method.
7
- # Example with block
8
- # serializer do |model, **context|
9
- # {
10
- # id: model.id,
11
- # admin: context[:is_admin],
12
- # }
13
- # end
14
- # Example with serializer class
15
- # serializer UserSerializer
16
- def serializer(klass = nil, &block)
17
- if block
18
- @serializer_proc = block
19
- elsif klass.is_a?(Class) && klass.instance_methods.include?(:to_h)
20
- @serializer_proc = proc { |*args, **kwargs| klass.new(*args, **kwargs).to_h }
21
- elsif klass.is_a?(Class) && klass.instance_methods.include?(:as_json) # backward compatibility
22
- @serializer_proc = proc { |*args, **kwargs| klass.new(*args, **kwargs).as_json }
23
- elsif klass.is_a?(Class) && klass.instance_methods.include?(:call)
24
- @serializer_proc = proc { |*args, **kwargs| klass.new(*args, **kwargs).call }
25
- else
26
- msg = format('%<arg>p is not a valid serializer. The serializer should ' \
27
- 'respond with `to_h` instance method.', arg: klass,)
28
- raise ArgumentError, msg
29
- end
30
- end
31
-
32
- def serialize(model, *args, **kwargs)
33
- unless @serializer_proc
34
- raise NotImplementedError, format('there is no serializer defined for the %<k>p index', k: to_s)
35
- end
36
-
37
- @serializer_proc.call(model, *args, **kwargs)
38
- end
39
-
40
- # Used to define the source of data. A block is required. And its
41
- # content should yield an array of each object that should be serialized.
42
- # The list of arguments will be passed throught the serializer method.
43
- #
44
- # Here is an example of how this should work:
45
- # collection do |conditions, &block|
46
- # User.where(conditions).find_in_batches(batch_size: 5000) do |batch|
47
- # block.call(batch, conditions)
48
- # end
49
- # end
50
- def collection(collection_class = nil, &block)
51
- raise ArgumentError, 'a collection class or a block is required' if block.nil? && collection_class.nil?
52
-
53
- if block.nil? && collection_class.is_a?(Class) && !collection_class.include?(Enumerable)
54
- msg = '%<arg>p is not a valid collection class.' \
55
- ' Collections should implement the Enumerable interface'
56
- raise ArgumentError, format(msg, arg: collection_class)
57
- end
58
-
59
- @collection_proc = collection_class || block
60
- end
61
-
62
- # Used to fetch all batch of data defined on the collection model.
63
- # Arguments can be anything. They will just be passed through the block.
64
- # Useful when the collection depends on scope or any other conditions
65
- # Example
66
- # each_batch(active: true) do |data, _opts|
67
- # puts data.size
68
- # end
69
- def each_batch(*args, **kwargs, &block)
70
- unless @collection_proc
71
- raise NotImplementedError, format('there is no collection defined for the %<k>p index', k: to_s)
72
- end
73
-
74
- case @collection_proc
75
- when Class
76
- @collection_proc.new(*args, **kwargs).each(&block)
77
- else
78
- @collection_proc.call(*args, **kwargs, &block)
79
- end
80
- rescue LocalJumpError
81
- raise(SyntaxError, 'block must be explicitly declared in the collection definition')
82
- end
83
-
84
- # Wrap collection data into serialized batches
85
- #
86
- # @param args [*Object] Any argument is allowed here. The collection will be called with same arguments.
87
- # And the serializer will be initialized with those arguments too.
88
- # @yield [Array, *Object] serialized collection and method arguments
89
- def each_serialized_batch(**kwargs, &block)
90
- each_batch(**kwargs) do |*batch, **collection_kwargs|
91
- entries = batch.flatten.map { |entry| serialize(entry, **collection_kwargs) }.compact
92
- block.call(entries, **kwargs)
93
- end
94
- end
95
-
96
- # Wrap collection data into serialized documents
97
- #
98
- # Example:
99
- # GeosIndex.documents(id: 1).first
100
- #
101
- # @return [Enumerator] All serialized entries
102
- def documents(**kwargs)
103
- Enumerator.new do |yielder|
104
- each_serialized_batch(**kwargs) do |documents, **_collection_kargs|
105
- documents.each { |document| yielder.yield(document) }
106
- end
107
- end
108
- end
109
- end
110
- end