Skip to content

Issue/62 orm adapter pattern #339

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 13 commits into
base: master
Choose a base branch
from
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,8 @@ Gemfile.lock

## PROJECT::SPECIFIC
data.sqlite3
mock.sqlite3
sequel_data.sqlite3

## DEBUG
.rspec-local
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ branches:
matrix:
include:
- rvm: 1.8.7
env: RAILS_VERSION=3.2.0 SEQUEL_VERSION=4.0
env: RAILS_VERSION=3.2.0 SEQUEL_VERSION=4.0 MONGOID_VERSION=2.4
- rvm: 1.9.3
env: RAILS_VERSION=3.2.0
- rvm: 1.9.3
Expand Down
2 changes: 2 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ group :test do

sequel_version = ENV['SEQUEL_VERSION'] ? "~> #{ENV['SEQUEL_VERSION']}" : '>= 4.0'
gem 'sequel', sequel_version
mongoid_version = ENV['MONGOID_VERSION'] ? "~> #{ENV['MONGOID_VERSION']}" : '>= 3.0'
gem 'mongoid', mongoid_version
end

group :development do
Expand Down
165 changes: 13 additions & 152 deletions lib/algoliasearch-rails.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
require 'algoliasearch'

require 'algoliasearch/database_adapter'
require 'algoliasearch/version'
require 'algoliasearch/utilities'

Expand Down Expand Up @@ -120,43 +121,10 @@ def add_attribute(*names, &block)
end
alias :add_attributes :add_attribute

def is_mongoid?(object)
defined?(::Mongoid::Document) && object.class.include?(::Mongoid::Document)
end

def is_sequel?(object)
defined?(::Sequel) && object.class < ::Sequel::Model
end

def is_active_record?(object)
!is_mongoid?(object) && !is_sequel?(object)
end

def get_default_attributes(object)
if is_mongoid?(object)
# work-around mongoid 2.4's unscoped method, not accepting a block
object.attributes
elsif is_sequel?(object)
object.to_hash
else
object.class.unscoped do
object.attributes
end
end
end

def get_attribute_names(object)
get_attributes(object).keys
end

def attributes_to_hash(attributes, object)
if attributes
Hash[attributes.map { |name, value| [name.to_s, value.call(object) ] }]
else
{}
end
end

def get_attributes(object)
# If a serializer is set, we ignore attributes
# everything should be done via the serializer
Expand All @@ -165,20 +133,14 @@ def get_attributes(object)
else
if @attributes.nil? || @attributes.length == 0
# no `attribute ...` have been configured, use the default attributes of the model
attributes = get_default_attributes(object)
attributes = DatabaseAdapter.get_default_attributes(object)
else
# at least 1 `attribute ...` has been configured, therefore use ONLY the one configured
if is_active_record?(object)
object.class.unscoped do
attributes = attributes_to_hash(@attributes, object)
end
else
attributes = attributes_to_hash(@attributes, object)
end
attributes = DatabaseAdapter.get_attributes(@attributes, object)
end
end

attributes.merge!(attributes_to_hash(@additional_attributes, object)) if @additional_attributes
attributes.merge!(DatabaseAdapter.attributes_to_hash(@additional_attributes, object)) if @additional_attributes

if @options[:sanitize]
sanitizer = begin
Expand Down Expand Up @@ -394,20 +356,7 @@ def algoliasearch(options = {}, &block)

attr_accessor :highlight_result, :snippet_result

if options[:synchronous] == true
if defined?(::Sequel) && self < Sequel::Model
class_eval do
copy_after_validation = instance_method(:after_validation)
define_method(:after_validation) do |*args|
super(*args)
copy_after_validation.bind(self).call
algolia_mark_synchronous
end
end
else
after_validation :algolia_mark_synchronous if respond_to?(:after_validation)
end
end
DatabaseAdapter.prepare_for_synchronous(self) if options[:synchronous] == true
if options[:enqueue]
raise ArgumentError.new("Cannot use a enqueue if the `synchronous` option if set") if options[:synchronous]
proc = if options[:enqueue] == true
Expand All @@ -425,68 +374,9 @@ def algoliasearch(options = {}, &block)
proc.call(record, remove) unless algolia_without_auto_index_scope
end
end
unless options[:auto_index] == false
if defined?(::Sequel) && self < Sequel::Model
class_eval do
copy_after_validation = instance_method(:after_validation)
copy_before_save = instance_method(:before_save)

define_method(:after_validation) do |*args|
super(*args)
copy_after_validation.bind(self).call
algolia_mark_must_reindex
end

define_method(:before_save) do |*args|
copy_before_save.bind(self).call
algolia_mark_for_auto_indexing
super(*args)
end

sequel_version = Gem::Version.new(Sequel.version)
if sequel_version >= Gem::Version.new('4.0.0') && sequel_version < Gem::Version.new('5.0.0')
copy_after_commit = instance_method(:after_commit)
define_method(:after_commit) do |*args|
super(*args)
copy_after_commit.bind(self).call
algolia_perform_index_tasks
end
else
copy_after_save = instance_method(:after_save)
define_method(:after_save) do |*args|
super(*args)
copy_after_save.bind(self).call
self.db.after_commit do
algolia_perform_index_tasks
end
end
end
end
else
after_validation :algolia_mark_must_reindex if respond_to?(:after_validation)
before_save :algolia_mark_for_auto_indexing if respond_to?(:before_save)
if respond_to?(:after_commit)
after_commit :algolia_perform_index_tasks
elsif respond_to?(:after_save)
after_save :algolia_perform_index_tasks
end
end
end
unless options[:auto_remove] == false
if defined?(::Sequel) && self < Sequel::Model
class_eval do
copy_after_destroy = instance_method(:after_destroy)

define_method(:after_destroy) do |*args|
copy_after_destroy.bind(self).call
algolia_enqueue_remove_from_index!(algolia_synchronous?)
super(*args)
end
end
else
after_destroy { |searchable| searchable.algolia_enqueue_remove_from_index!(algolia_synchronous?) } if respond_to?(:after_destroy)
end
end
DatabaseAdapter.prepare_for_auto_index(self) unless options[:auto_index] == false
DatabaseAdapter.prepare_for_auto_remove(self) unless options[:auto_remove] == false
end

def algolia_without_auto_index(&block)
Expand Down Expand Up @@ -742,15 +632,15 @@ def algolia_must_reindex?(object)
algolia_configurations.each do |options, settings|
next if options[:slave] || options[:replica]
return true if algolia_object_id_changed?(object, options)
settings.get_attribute_names(object).each do |k|
changed_method = attribute_changed_method(k)
settings.get_attribute_names(object).each do |attribute_name|
changed_method = DatabaseAdapter.attribute_changed_method(object, attribute_name)
return true if !object.respond_to?(changed_method) || object.send(changed_method)
end
[options[:if], options[:unless]].each do |condition|
case condition
when nil
when String, Symbol
changed_method = attribute_changed_method(condition)
changed_method = DatabaseAdapter.attribute_changed_method(object, condition)
return true if !object.respond_to?(changed_method) || object.send(changed_method)
else
# if the :if, :unless condition is a anything else,
Expand Down Expand Up @@ -825,7 +715,7 @@ def algolia_object_id_of(o, options = nil)
end

def algolia_object_id_changed?(o, options = nil)
m = attribute_changed_method(algolia_object_id_method(options))
m = DatabaseAdapter.attribute_changed_method(o, algolia_object_id_method(options))
o.respond_to?(m) ? o.send(m) : false
end

Expand Down Expand Up @@ -902,31 +792,7 @@ def algolia_indexing_disabled?(options = nil)
end

def algolia_find_in_batches(batch_size, &block)
if (defined?(::ActiveRecord) && ancestors.include?(::ActiveRecord::Base)) || respond_to?(:find_in_batches)
find_in_batches(:batch_size => batch_size, &block)
elsif defined?(::Sequel) && self < Sequel::Model
dataset.extension(:pagination).each_page(batch_size, &block)
else
# don't worry, mongoid has its own underlying cursor/streaming mechanism
items = []
all.each do |item|
items << item
if items.length % batch_size == 0
yield items
items = []
end
end
yield items unless items.empty?
end
end

def attribute_changed_method(attr)
if defined?(::ActiveRecord) && ActiveRecord::VERSION::MAJOR >= 5 && ActiveRecord::VERSION::MINOR >= 1 ||
(defined?(::ActiveRecord) && ActiveRecord::VERSION::MAJOR > 5)
"will_save_change_to_#{attr}?"
else
"#{attr}_changed?"
end
DatabaseAdapter.find_in_batches(self, batch_size, &block)
end
end

Expand Down Expand Up @@ -979,12 +845,7 @@ def algolia_mark_for_auto_indexing
end

def algolia_mark_must_reindex
@algolia_must_reindex =
if defined?(::Sequel) && is_a?(Sequel::Model)
new? || self.class.algolia_must_reindex?(self)
else
new_record? || self.class.algolia_must_reindex?(self)
end
@algolia_must_reindex = DatabaseAdapter.mark_must_reindex(self)
true
end

Expand Down
Loading