forked from mongodb/mongoid
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Setting keys on many-to-many relations now sets the inverse:
- In some cases this may cause up to 2 extra atomic queries to keep both
sides of the relation in sync.
- Fixes #622
- Loading branch information
Showing
11 changed files
with
481 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
# encoding: utf-8 | ||
module Mongoid # :nodoc: | ||
module Relations #:nodoc: | ||
|
||
# This module handles the behaviour for synchronizing foreign keys between | ||
# both sides of a many to many relations. | ||
module Synchronization | ||
extend ActiveSupport::Concern | ||
|
||
# Is the document able to be synced on the inverse side? This is only if | ||
# the key has changed and the relation bindings have not been run. | ||
# | ||
# @example Are the foreign keys syncable? | ||
# document.syncable?(metadata) | ||
# | ||
# @param [ Metadata ] metadata The relation metadata. | ||
# | ||
# @return [ true, false ] If we can sync. | ||
# | ||
# @since 2.1.0 | ||
def syncable?(metadata) | ||
!synced?(metadata.foreign_key) && send(metadata.foreign_key_check) | ||
end | ||
|
||
# Get the synced foreign keys. | ||
# | ||
# @example Get the synced foreign keys. | ||
# document.synced | ||
# | ||
# @return [ Hash ] The synced foreign keys. | ||
# | ||
# @since 2.1.0 | ||
def synced | ||
@synced ||= {} | ||
end | ||
|
||
# Has the document been synced for the foreign key? | ||
# | ||
# @todo Change the sync to be key based. | ||
# | ||
# @example Has the document been synced? | ||
# document.synced? | ||
# | ||
# @param [ String ] foreign_key The foreign key. | ||
# | ||
# @return [ true, false ] If we can sync. | ||
# | ||
# @since 2.1.0 | ||
def synced?(foreign_key) | ||
!!synced[foreign_key] | ||
end | ||
|
||
# Update the inverse keys for the relation. | ||
# | ||
# @example Update the inverse keys | ||
# document.update_inverse_keys(metadata) | ||
# | ||
# @param [ Metadata ] meta The document metadata. | ||
# | ||
# @return [ Object ] The updated values. | ||
# | ||
# @since 2.1.0 | ||
def update_inverse_keys(meta) | ||
old, new = changes[meta.foreign_key] | ||
meta.criteria(new - old).add_to_set(meta.inverse_foreign_key, id) | ||
meta.criteria(old - new).pull(meta.inverse_foreign_key, id) | ||
end | ||
|
||
module ClassMethods #:nodoc: | ||
|
||
# Set up the syncing of many to many foreign keys. | ||
# | ||
# @example Set up the syncing. | ||
# Person.synced(metadata) | ||
# | ||
# @param [ Metadata ] metadata The relation metadata. | ||
# | ||
# @since 2.1.0 | ||
def synced(metadata) | ||
synced_save(metadata) | ||
end | ||
|
||
private | ||
|
||
# Set up the sync of inverse keys that needs to happen on a save. | ||
# | ||
# If the foreign key field has changed and the document is not | ||
# synced, $addToSet the new ids, $pull the ones no longer in the | ||
# array from the inverse side. | ||
# | ||
# @example Set up the save syncing. | ||
# Person.synced_save(metadata) | ||
# | ||
# @param [ Metadata ] metadata The relation metadata. | ||
# | ||
# @return [ Class ] The class getting set up. | ||
# | ||
# @since 2.1.0 | ||
def synced_save(metadata) | ||
tap do | ||
set_callback( | ||
:save, | ||
:after, | ||
:if => lambda { |doc| doc.syncable?(metadata) } | ||
) do |doc| | ||
doc.update_inverse_keys(metadata) | ||
end | ||
end | ||
end | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.