Skip to content

Commit

Permalink
Fixes for embedded touch (#7)
Browse files Browse the repository at this point in the history
* Fixes for embedded touch

* Fix touch loop fix on Mongoid 4 and 5
  • Loading branch information
johnnyshields authored Feb 26, 2017
1 parent 9fca9d8 commit 6a1fadd
Show file tree
Hide file tree
Showing 9 changed files with 151 additions and 38 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@

#### 0.2.5

* Improvements to `:touch` callback support on `:embedded_in`.
* Backport fix to an infinite loop issue related to `:touch` callbacks from Mongoid 6.

#### 0.2.4

* Support aliases for index options.
Expand Down
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ If you would only like some of the patches, please copy and paste the code to yo
| `instrument.rb` | Backport instrumentation change to Moped 1. ||||
| `reorder.rb` | Backport `Criteria#reorder` method from Mongoid 4. ||||
| `only_pluck_localized.rb` | Backport [PR #4299](https://github.com/mongodb/mongoid/pull/4299) from Mongoid 6 which fixes `#only`, `#without`, and `#pluck` with localized fields. || × | × |
| `embedded_touch.rb` | Backport [Issue #3310](https://github.com/mongodb/mongoid/commit/a94c2f43573e58f973913c881ad9d11d62bf857c) from Mongoid 4 to add `:touch` option to `embedded_in`. ||||
| `embedded_touch.rb` (1) | Backport [Issue #3310](https://github.com/mongodb/mongoid/commit/a94c2f43573e58f973913c881ad9d11d62bf857c) from Mongoid 4 to add `:touch` option to `embedded_in`. ||||
| `embedded_touch.rb` (2) | Backport [PR #4392](https://github.com/mongodb/mongoid/pull/4392) from Mongoid 6 to fix an infinite loop issue related to `:touch` callbacks. ||||
| `index_options.rb` | Backport latest index valid index options from Mongoid 6. ||||

### License
Expand Down
99 changes: 79 additions & 20 deletions lib/patches/embedded_touch.rb
Original file line number Diff line number Diff line change
@@ -1,37 +1,96 @@
# Backport Mongoid 4 :touch option for #embedded_in to Mongoid 3.
# Backport support #embedded_in :touch option from Mongoid 4 to Mongoid 3.
# Also support touch callback on update, and fix infinite loop issue.

if Mongoid::VERSION =~ /\A3\./

module Mongoid
module Relations
module Embedded
class In < Relations::One
class << self
def valid_options
[ :autobuild, :cyclic, :polymorphic, :touch ]
module Relations
module Embedded
class In < Relations::One
class << self
def valid_options
[ :autobuild, :cyclic, :polymorphic, :touch ]
end
end
end
end

module Macros
module ClassMethods

def embedded_in(name, options = {}, &block)
if ancestors.include?(Mongoid::Versioning)
raise Errors::VersioningNotOnRoot.new(self)
end
meta = characterize(name, Embedded::In, options, &block)
self.embedded = true
relate(name, meta)
builder(name, meta).creator(name, meta)
touchable(meta)
add_counter_cache_callbacks(meta) if meta.counter_cached?
meta
end
end
end
end

module Macros
module ClassMethods
module Touchable
module ClassMethods

def embedded_in(name, options = {}, &block)
if ancestors.include?(Mongoid::Versioning)
raise Errors::VersioningNotOnRoot.new(self)
def touchable(metadata)
if metadata.touchable?
name = metadata.name
method_name = define_relation_touch_method(name)
after_save method_name
after_destroy method_name
after_touch method_name
end
self
end
meta = characterize(name, Embedded::In, options, &block)
self.embedded = true
relate(name, meta)
builder(name, meta).creator(name, meta)
touchable(meta)
add_counter_cache_callbacks(meta) if meta.counter_cached?
meta
end
end
end

module Callbacks
def cascadable_children(kind, children = Set.new)
embedded_relations.each_pair do |name, metadata|
next unless metadata.cascading_callbacks?
without_autobuild do
delayed_pulls = delayed_atomic_pulls[name]
delayed_unsets = delayed_atomic_unsets[name]
children.merge(delayed_pulls) if delayed_pulls
children.merge(delayed_unsets) if delayed_unsets
relation = send(name)
Array.wrap(relation).each do |child|
next if children.include?(child)
children.add(child) if cascadable_child?(kind, child, metadata)
child.send(:cascadable_children, kind, children)
end
end
end
children.to_a
end

def cascadable_child?(kind, child, metadata)
return false if kind == :initialize || kind == :find || kind == :touch
return false if kind == :validate && metadata.validate?
child.callback_executable?(kind) ? child.in_callback_state?(kind) : false
end
end
end

end

if Mongoid::VERSION =~ /\A[45]\./

module Mongoid

module Interceptable
def cascadable_child?(kind, child, metadata)
return false if kind == :initialize || kind == :find || kind == :touch
return false if kind == :validate && metadata.validate?
child.callback_executable?(kind) ? child.in_callback_state?(kind) : false
end
end
end

end
2 changes: 1 addition & 1 deletion lib/version.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
module MongoidMonkey
VERSION = '0.2.4'
VERSION = '0.2.5'
end
6 changes: 6 additions & 0 deletions spec/app/models/book.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
class Book
include Mongoid::Document
include Mongoid::Timestamps

embeds_many :pages, cascade_callbacks: true
end
5 changes: 5 additions & 0 deletions spec/app/models/edit.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class Edit
include Mongoid::Document
include Mongoid::Timestamps::Updated
embedded_in :wiki_page, touch: true
end
6 changes: 6 additions & 0 deletions spec/app/models/page.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
class Page
include Mongoid::Document

embedded_in :book, touch: true
field :content, :type => String
end
8 changes: 8 additions & 0 deletions spec/app/models/wiki_page.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
class WikiPage
include Mongoid::Document
include Mongoid::Timestamps

field :title, type: String

embeds_many :edits, validate: false
end
55 changes: 39 additions & 16 deletions spec/unit/embedded_touch_spec.rb
Original file line number Diff line number Diff line change
@@ -1,21 +1,6 @@
require "spec_helper"

if Mongoid::VERSION =~ /\A3\./

class Edit
include Mongoid::Document
include Mongoid::Timestamps::Updated
embedded_in :wiki_page, touch: true
end

class WikiPage
include Mongoid::Document
include Mongoid::Timestamps

field :title, type: String

embeds_many :edits, validate: false
end
if Mongoid::VERSION =~ /\A[345]\./

describe Mongoid::Relations::Embedded::In do

Expand Down Expand Up @@ -48,5 +33,43 @@ class WikiPage
expect(page.updated_at).to be_within(5).of(Time.now)
end
end

context "when the parent of embedded doc has cascade callbacks" do

let!(:book) do
Book.new
end

before do
book.pages.new
book.save
book.unset(:updated_at)
book.pages.first.touch
end

it "touches the parent document" do
expect(book.updated_at).to be_within(5).of(Time.now)
end
end

context "when multiple embedded docs with cascade callbacks" do

let!(:book) do
Book.new
end

before do
2.times { book.pages.new }
book.save
book.unset(:updated_at)
book.pages.first.content = "foo"
book.pages.second.content = "bar"
book.pages.first.touch
end

it "touches the parent document" do
expect(book.updated_at).to be_within(5).of(Time.now)
end
end
end
end

0 comments on commit 6a1fadd

Please sign in to comment.