lib/isomorfeus/data/object_accelerator.rb in isomorfeus-data-2.5.5 vs lib/isomorfeus/data/object_accelerator.rb in isomorfeus-data-22.9.0.rc1

- old
+ new

@@ -9,149 +9,141 @@ attr_accessor :store def initialize(ruby_class) @object_class = ruby_class @object_class_name = ruby_class.name - @class_cache = Isomorfeus.production? + @class_cache = !Isomorfeus.development? @store_path = File.expand_path(File.join(Isomorfeus.data_documents_path, "#{@object_class_name.underscore}")) open_store ObjectSpace.define_finalizer(self, self.class.finalize(self)) end - def object_from_ref(ref, already_loaded) - return nil if !ref || ref.empty? - _, iso, type_class_name, key = ref.split('---') - raise "not a valid object reference '#{ref}'" unless iso == "iso-object-reference" - raise "invalid data class #{type_class_name}" unless Isomorfeus.valid_data_class_name?(type_class_name) - type_class = Isomorfeus.cached_data_class(type_class_name) - type_class.load(key: key, _already_loaded: already_loaded) + def serialize(o) + Oj.dump(o, mode: :strict) end - def serialize(obj) - Oj.dump(obj, mode: :object, circular: true, class_cache: @class_cache) + def unserialize(s) + Oj.load(s, mode: :strict) end - def unserialize(v) - Oj.load(v, mode: :object, circular: true, class_cache: @class_cache) - end - def destroy_store - close_store + close_store rescue nil FileUtils.rm_rf(@store_path) end def close_store @store.close end + def exist?(sid_s:) + !!get_object_id(sid_s) + end + + def exist_by_field?(field:, value:) + top_docs = @store.search("#{field}:\"#{serialize(value)}\"") + top_docs.total_hits > 0 + end + def search_each(query, options, &block) @store.search_each(query, options, &block) + rescue => e + return nil if e.message.include?('frt_sort.c') + raise e end def each(&block) - ft = @object_class.field_types - @store.each do |doc| - hash = doc.to_h do |k, v| - [k, unserialize_or_load(v, ft[k], {})] - end - block.call hash - end + @store.each { |doc| block.call(doc[:key]) } end - def create_object(key, fields, already_saved) - ft = @object_class.field_types - hash = fields.to_h do |k, v| - [k, serialize_or_save(v, ft[k], already_saved)] + def create(sid_s:, fields:, level: 10) + id = get_object_id(sid_s) + return false if id + data = fields.to_h do |k, v| + [k, serialize(v)] end - @store.add_document(hash.merge!({key: key})) + data[:_revision] = serialize(1) + data[:key] = sid_s + @store.add_document(data) + true + rescue => e + @store.flush + raise e if level < 1 + create(sid_s: sid_s, fields: fields, level: level - 1) end - def destroy_object(key) - id = get_object_id(key) + def destroy(sid_s:) + id = get_object_id(sid_s) @store.delete(id) if id end - def load_object(key: nil, id: nil, already_loaded: {}) - hash = nil - id = get_object_id(key) if key - if id - ft = @object_class.field_types - hash = @store.doc(id)&.to_h do |k, v| - [k, unserialize_or_load(v, ft[k], already_loaded)] + def load(sid_s: nil, id: nil) + id = get_object_id(sid_s) if sid_s + return nil unless id + data = @store.doc(id)&.to_h + if data + data.delete(:key) + data = data.to_h do |k, v| + [k, unserialize(v)] end end - hash + data end - def save_object(key, fields, already_saved) - id = get_object_id(key) - return create_object(key, fields, already_saved) unless id - ft = @object_class.field_types - hash = fields.to_h do |k, v| - [k, serialize_or_save(v, ft[k], already_saved)] - end - @store.update(id, hash.merge!({key: key})) - true + def field(sid_s:, field:) + id = get_object_id(sid_s) if sid_s + return nil unless id + doc = @store.doc(id) + v = doc[field] + unserialize(v) if v end - private - - def unserialize_or_load(v, t, already_loaded) - return unserialize(v) if t == :attribute - if t == :object && v - if v.is_a?(Array) - v = v.map { |e| object_from_ref(e, already_loaded) } - v.compact! - return v - else - return nil if v.empty? - return object_from_ref(v, already_loaded) - end - end - v + def load_sid_s(id:) + doc = @store.doc(id) + return doc[:key] if doc end - def serialize_or_save(v, t, already_saved) - return serialize(v) if t == :attribute - if t == :object && v - if v.is_a?(Array) - v = v.compact - v.map! { |e| create_or_save(e, already_saved) } - v.compact! - return v - else - return create_or_save(v, already_saved) - end - end - v + def revision(sid_s:) + id = get_object_id(sid_s) + doc = @store.doc(id) if id + return unserialize(doc[:_revision]) if doc end - def create_or_save(v, already_saved) - if get_object_id(v.key) - v.save(_already_saved: already_saved) - else - v.create + def save(sid_s:, fields:, revision:, id: nil, level: 10) + id = get_object_id(sid_s) unless id + return false unless id + data = fields.to_h do |k, v| + [k, serialize(v)] end - v.ref_s + data[:key] = sid_s + data[:_revision] = serialize(revision) + @store.update(id, data) + true + rescue => e + @store.flush + raise e if level < 1 + save(sid_s: sid_s, fields: fields, revision: revision, id: id, level: level - 1) end - def get_object_id(key) + def escape(string) # special characters must be escaped, characters taken from the ferret query parser documentation - escaped_key = key.gsub(/([\\\&\:\(\)\[\]\{\}\!\"\~\^\|\<\>\=\*\?\+\-\s])/, '\\\\\1') - top_docs = @store.search("key:\"#{escaped_key}\"", limit: 1) - id = top_docs.hits[0].doc if top_docs.total_hits == 1 + string.gsub(/([\\\&\:\(\)\[\]\{\}\!\"\~\^\|\<\>\=\*\?\+\-\s])/, '\\\\\1') end + private + + def get_object_id(sid_s) + top_docs = @store.search("key:\"#{sid_s}\"", limit: 1) + top_docs.hits[0].doc if top_docs.total_hits == 1 + end + def open_store FileUtils.mkdir_p(Isomorfeus.data_documents_path) unless Dir.exist?(Isomorfeus.data_documents_path) - field_infos = Isomorfeus::Ferret::Index::FieldInfos.new(store: :yes, index: :yes, term_vector: :no) + field_infos = Isomorfeus::Ferret::Index::FieldInfos.new(store: :yes, index: :no, term_vector: :no) + @object_class.field_options.each { |field, options| field_infos.add_field(field, options) } + field_infos.add_field(:key, store: :yes, index: :yes, term_vector: :yes) @store = Isomorfeus::Ferret::Index::Index.new(path: @store_path, key: :key, auto_flush: true, lock_retry_time: 5, field_infos: field_infos) - @store.field_infos.add_field(:key, store: :yes, index: :yes, term_vector: :yes) unless @store.field_infos[:key] - @object_class.field_options.each do |field, options| - @store.field_infos.add_field(field, options) unless @store.field_infos[field] - end end end end end