Module: Esse::Repository::ClassMethods
- Included in:
- Esse::Repository
- Defined in:
- lib/esse/repository/actions.rb,
lib/esse/repository/documents.rb,
lib/esse/repository/object_document_mapper.rb,
lib/esse/repository/lazy_document_attributes.rb
Instance Method Summary collapse
- #action(name, options = {}, &block) ⇒ Object
-
#collection(collection_klass = nil, **_, &block) ⇒ void
Used to define the source of data.
-
#collection_class ⇒ Class?
Expose the collection class to let external plugins and extensions to access it.
-
#document(klass = nil, &block) ⇒ Object
Define the document type that will be used to serialize the data.
-
#documents(**kwargs) ⇒ Enumerator
Wrap collection data into serialized documents.
- #documents_for_lazy_attribute(name, ids_or_doc_headers) ⇒ Object
-
#each_serialized_batch(eager_load_lazy_attributes: false, preload_lazy_attributes: false, **kwargs) {|Array, **context| ... } ⇒ Enumerator
Wrap collection data into serialized batches.
- #fetch_lazy_document_attribute(attr_name) ⇒ Object
- #import(**kwargs) ⇒ Object
- #lazy_document_attribute(attr_name, klass = nil, **kwargs, &block) ⇒ Object
- #lazy_document_attribute_names(all = true) ⇒ Object
- #lazy_document_attributes ⇒ Object
- #retrieve_lazy_attribute_values(name, ids_or_doc_headers) ⇒ Object
-
#serialize(model, **kwargs) ⇒ Esse::Document
Convert ruby object to json by using the document of the given document type.
- #update_documents_attribute(name, ids_or_doc_headers = [], kwargs = {}) ⇒ Object
Instance Method Details
#action(name, options = {}, &block) ⇒ Object
6 7 |
# File 'lib/esse/repository/actions.rb', line 6 def action(name, = {}, &block) end |
#collection(collection_klass = nil, **_, &block) ⇒ void
This method returns an undefined value.
Used to define the source of data. A block is required. And its content should yield an array of each object that should be serialized. The list of arguments will be passed throught the document method.
Example:
collection AdminStore
collection do |**conditions, &block|
User.where(conditions).find_in_batches(batch_size: 5000) do |batch|
block.call(batch, conditions)
end
end
57 58 59 60 61 62 63 64 65 66 67 68 69 70 |
# File 'lib/esse/repository/object_document_mapper.rb', line 57 def collection(collection_klass = nil, **_, &block) if collection_klass.nil? && block.nil? raise ArgumentError, 'a document type, followed by a collection class or block that stream the data ' \ 'is required to define the collection' end if block.nil? && collection_klass.is_a?(Class) && !collection_klass.include?(Enumerable) msg = '%<arg>p is not a valid collection class.' \ ' Collections should implement the Enumerable interface.' raise ArgumentError, format(msg, arg: collection_klass) end @collection_proc = collection_klass || block end |
#collection_class ⇒ Class?
Expose the collection class to let external plugins and extensions to access it. IDEA: When collection is defined as a block, it should setup a class with the block content.
75 76 77 78 79 |
# File 'lib/esse/repository/object_document_mapper.rb', line 75 def collection_class return unless @collection_proc.is_a?(Class) @collection_proc end |
#document(klass = nil, &block) ⇒ Object
Define the document type that will be used to serialize the data. Arguments will be same of passed through the collection. It’s allowed a block or a class with the ‘to_h` instance method. Example with block
document do |model, **context|
{
id: model.id,
admin: context[:is_admin],
}
end
Example with document class
document UserDocument
20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
# File 'lib/esse/repository/object_document_mapper.rb', line 20 def document(klass = nil, &block) if @document_proc raise ArgumentError, format('Document for %p already defined', repo_name) end if block @document_proc = ->(model, **kwargs) { coerce_to_document(block.call(model, **kwargs)) } elsif klass.is_a?(Class) && klass <= Esse::Document @document_proc = ->(model, **kwargs) { klass.new(model, **kwargs) } elsif klass.is_a?(Class) && klass.instance_methods.include?(:to_h) @document_proc = ->(model, **kwargs) { coerce_to_document(klass.new(model, **kwargs).to_h) } elsif klass.is_a?(Class) && klass.instance_methods.include?(:as_json) # backward compatibility @document_proc = ->(model, **kwargs) { coerce_to_document(klass.new(model, **kwargs).as_json) } elsif klass.is_a?(Class) && klass.instance_methods.include?(:call) @document_proc = ->(model, **kwargs) { coerce_to_document(klass.new(model, **kwargs).call) } else msg = format("%<arg>p is not a valid document. The document should inherit from Esse::Document or respond to `to_h'", arg: klass) raise ArgumentError, msg end end |
#documents(**kwargs) ⇒ Enumerator
Wrap collection data into serialized documents
Example:
GeosIndex.documents(id: 1).first
140 141 142 143 144 145 146 |
# File 'lib/esse/repository/object_document_mapper.rb', line 140 def documents(**kwargs) Enumerator.new do |yielder| each_serialized_batch(**kwargs) do |docs| docs.each { |document| yielder.yield(document) } end end end |
#documents_for_lazy_attribute(name, ids_or_doc_headers) ⇒ Object
17 18 19 20 21 |
# File 'lib/esse/repository/documents.rb', line 17 def documents_for_lazy_attribute(name, ids_or_doc_headers) retrieve_lazy_attribute_values(name, ids_or_doc_headers).map do |doc_header, datum| doc_header.document_for_partial_update(name => datum) end end |
#each_serialized_batch(eager_load_lazy_attributes: false, preload_lazy_attributes: false, **kwargs) {|Array, **context| ... } ⇒ Enumerator
Wrap collection data into serialized batches
86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 |
# File 'lib/esse/repository/object_document_mapper.rb', line 86 def each_serialized_batch(eager_load_lazy_attributes: false, preload_lazy_attributes: false, **kwargs) if kwargs.key?(:lazy_attributes) warn 'The `lazy_attributes` option is deprecated. Use `eager_load_lazy_attributes` instead.' eager_load_lazy_attributes = kwargs.delete(:lazy_attributes) end lazy_attrs_to_eager_load = lazy_document_attribute_names(eager_load_lazy_attributes) lazy_attrs_to_search_preload = lazy_document_attribute_names(preload_lazy_attributes) lazy_attrs_to_search_preload -= lazy_attrs_to_eager_load each_batch(**kwargs) do |*args| batch, collection_context = args collection_context ||= {} entries = [*batch].map { |entry| serialize(entry, **collection_context) }.compact lazy_attrs_to_eager_load.each do |attr_name| retrieve_lazy_attribute_values(attr_name, entries).each do |doc_header, value| doc = entries.find { |d| d.eql?(doc_header, match_lazy_doc_header: true) } doc&.mutate(attr_name) { value } end end if lazy_attrs_to_search_preload.any? entries.group_by(&:routing).each do |routing, docs| search_request = { query: { ids: { values: docs.map(&:id) } }, size: docs.size, _source: lazy_attrs_to_search_preload } search_request[:routing] = routing if routing index.search(**search_request).response.hits.each do |hit| header = [hit['_id'], hit['_routing'], hit['_type']] next if header[0].nil? hit.dig('_source')&.each do |attr_name, attr_value| real_attr_name = lazy_document_attribute_names(attr_name).first next if real_attr_name.nil? doc = entries.find { |d| Esse.document_match_with_header?(d, *header) } doc&.mutate(real_attr_name) { attr_value } end end end end yield entries end end |
#fetch_lazy_document_attribute(attr_name) ⇒ Object
23 24 25 26 27 28 |
# File 'lib/esse/repository/lazy_document_attributes.rb', line 23 def fetch_lazy_document_attribute(attr_name) klass, kwargs = lazy_document_attributes.fetch(attr_name) klass.new(**kwargs) rescue KeyError raise ArgumentError, format('Attribute %<attr>p is not defined as a lazy document attribute', attr: attr_name) end |
#import(**kwargs) ⇒ Object
6 7 8 |
# File 'lib/esse/repository/documents.rb', line 6 def import(**kwargs) index.import(repo_name, **kwargs) end |
#lazy_document_attribute(attr_name, klass = nil, **kwargs, &block) ⇒ Object
30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
# File 'lib/esse/repository/lazy_document_attributes.rb', line 30 def lazy_document_attribute(attr_name, klass = nil, **kwargs, &block) if attr_name.nil? raise ArgumentError, 'Attribute name is required to define a lazy document attribute' end if lazy_document_attribute?(attr_name.to_sym) || lazy_document_attribute?(attr_name.to_s) raise ArgumentError, format('Attribute %<attr>p is already defined as a lazy document attribute', attr: attr_name) end @lazy_document_attributes = lazy_document_attributes.dup if block klass = Class.new(Esse::DocumentLazyAttribute) do define_method(:call, &block) end @lazy_document_attributes[attr_name] = [klass, kwargs] elsif klass.is_a?(Class) && klass <= Esse::DocumentLazyAttribute @lazy_document_attributes[attr_name] = [klass, kwargs] elsif klass.is_a?(Class) && klass.instance_methods.include?(:call) @lazy_document_attributes[attr_name] = [klass, kwargs] elsif klass.nil? raise ArgumentError, format('A block or a class that responds to `call` is required to define a lazy document attribute') else raise ArgumentError, format('%<arg>p is not a valid lazy document attribute. Class should inherit from Esse::DocumentLazyAttribute or respond to `call`', arg: klass) end ensure @lazy_document_attributes&.freeze end |
#lazy_document_attribute_names(all = true) ⇒ Object
11 12 13 14 15 16 17 18 19 20 21 |
# File 'lib/esse/repository/lazy_document_attributes.rb', line 11 def lazy_document_attribute_names(all = true) case all when false [] when true lazy_document_attributes.keys else filtered = Array(all).map(&:to_s) lazy_document_attributes.keys.select { |name| filtered.include?(name.to_s) } end end |
#lazy_document_attributes ⇒ Object
7 8 9 |
# File 'lib/esse/repository/lazy_document_attributes.rb', line 7 def lazy_document_attributes @lazy_document_attributes ||= {}.freeze end |
#retrieve_lazy_attribute_values(name, ids_or_doc_headers) ⇒ Object
23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
# File 'lib/esse/repository/documents.rb', line 23 def retrieve_lazy_attribute_values(name, ids_or_doc_headers) unless lazy_document_attribute?(name) raise ArgumentError, <<~MSG The attribute `#{name}` is not defined as a lazy document attribute. Define the attribute as a lazy document attribute using the `lazy_document_attribute` method. MSG end docs = LazyDocumentHeader.coerce_each(ids_or_doc_headers) return [] if docs.empty? result = fetch_lazy_document_attribute(name).call(docs) return [] unless result.is_a?(Hash) result.each_with_object({}) do |(key, value), memo| val = docs.find { |doc| doc.eql?(key, match_lazy_doc_header: true) || doc.id == key } next unless val memo[val] = value end end |
#serialize(model, **kwargs) ⇒ Esse::Document
Convert ruby object to json by using the document of the given document type.
152 153 154 155 156 157 158 |
# File 'lib/esse/repository/object_document_mapper.rb', line 152 def serialize(model, **kwargs) if @document_proc.nil? raise NotImplementedError, format('there is no %<t>p document defined for the %<k>p index', t: repo_name, k: index.to_s) end @document_proc.call(model, **kwargs) end |
#update_documents_attribute(name, ids_or_doc_headers = [], kwargs = {}) ⇒ Object
10 11 12 13 14 15 |
# File 'lib/esse/repository/documents.rb', line 10 def update_documents_attribute(name, ids_or_doc_headers = [], kwargs = {}) batch = documents_for_lazy_attribute(name, ids_or_doc_headers) return if batch.empty? index.bulk(**kwargs.transform_keys(&:to_sym), update: batch) end |