require 'ensurance/version' require 'active_support' require 'ensurance/date_ensure' require 'ensurance/time_ensure' require 'ensurance/hash_ensure' require 'ensurance/array_ensure' module Ensurance extend ActiveSupport::Concern class_methods do @_additional_ensure_by = [] @_ensure_order = nil @_ensure_by = [] def ensure_by(*args, order: nil) @_additional_ensure_by = args if (::ActiveRecord::Base.connection rescue false) @_ensure_order = (order || self.primary_key).to_s @_ensure_by = [@_additional_ensure_by || primary_key].flatten.compact.uniq end # ap "Ensure By: #{self}.#{@_ensure_by} Order: #{self}.#{@_ensure_order}" end def ensure(thing = nil) return nil unless thing.present? if thing.is_a?(self) return thing elsif thing.is_a?(GlobalID) return GlobalID::Locator.locate(thing) elsif thing.is_a?(Hash) && thing['_aj_globalid'] && (found = GlobalID::Locator.locate(thing['_aj_globalid'])) return found elsif thing.is_a?(String) && (found = GlobalID::Locator.locate(thing)) return found end @_ensure_by ||= [@_additional_ensure_by || self.primary_key].flatten.compact.uniq @_ensure_order ||= primary_key found = [] things = [thing].flatten things.each do |thing| record = nil @_ensure_by.each do |ensure_field| value = thing if thing.is_a?(Hash) value = thing.fetch(ensure_field.to_sym, nil) || thing.fetch(ensure_field.to_s, nil) end if ensure_field.to_sym == :id begin # Always return the most recent record that matches query = where(ensure_field => value) query = query.order("#{@_ensure_order}" => 'desc') record = query.first rescue ActiveRecord::RecordNotFound nil end else record = find_by(ensure_field => value) if value.present? && !value.is_a?(Hash) end record = nil if record&.__send__(ensure_field).to_s != value.to_s break if record end found << record end found.compact! thing.is_a?(Array) ? found : found.first end def ensure!(thing = nil) return nil unless thing.present? result = self.ensure(thing) raise ActiveRecord::RecordNotFound, "#{self} not found" unless result result end end end