Skip to content

Instantly share code, notes, and snippets.

@leifcr
Last active May 24, 2020 14:39
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save leifcr/1ddc118e47a13c9a7ee3073504192332 to your computer and use it in GitHub Desktop.
Save leifcr/1ddc118e47a13c9a7ee3073504192332 to your computer and use it in GitHub Desktop.
module MyProject
module Mongoid
module Document
extend ActiveSupport::Concern
included do
include ::Mongoid::Document
include ::Mongoid::Timestamps
include ::Mongoid::DotNotation
include ::Mongoid::SearchForObject
end
end
end
end
module MyProject
module Mongoid
module EmbeddedDocument
extend ActiveSupport::Concern
included do
include ::Mongoid::Document
include ::Mongoid::RootFromEmbedded
include ::Mongoid::DotNotation
include ::Mongoid::SearchForObject
include ::Mongoid::EmbeddedDocumentPath
end
end
end
end
module Mongoid
module EmbeddedDocumentPath
extend ActiveSupport::Concern
def embedded_document_path
edp_get_parent_document(self)
end
private
def edp_get_parent_document(element)
retval = Array.new
new_els = Array.new
p = nil
element.reflect_on_all_associations(:embedded_in).each do |r|
p = element.send(r.name.to_s)
unless p.nil?
retval.unshift({klass: p.class.name, id: p.id})
new_els = edp_get_parent_document(p)
if new_els.length > 0
new_els.reverse_each do |ne|
retval.unshift(ne)
end
end
end
end
retval
end
end
end
module Mongoid
#
# Module DotNotation provides Embedded notation for Mongoid Documents
#
# Add to your mongoid document:
# include Mongoid::EmbeddedNotation
#
# @author Leif Ringstad <leif@bitelm.com>
#
module DotNotation
extend ActiveSupport::Concern
#
# Get dot notification for the current mongoid document. (embedded or not)
#
# Example
# farm_document
# has_many fields
# field_document
# has_many cows
#
# Calling on a cow will return "fields.cows"
# Calling on a field will return "fields"
# Calling on a farm will return ""
#
# @return [String] The dot notation for a given embedded document
#
def dot_notation
dn = dot_notation_for_element_nested(self)
if dn.nil?
return ""
else
dn[0] = ''
end
dn
end
private
#
# Get dot notification for nested elements (nesting updwards)
#
# @param [Mongoid::Document] el A valid Mongoid:Document
#
# @return [String] The dot notation for a given element
#
def dot_notation_for_element_nested(el)
# Get non-nil_embedded_relation
p = get_embedded_relation(el)
# puts p.inspect
if p.nil?
return nil
else
"#{dot_notation_for_element_nested(p[0])}.#{p[1].inverse_of}"
end
end
#
# Get the embedded relation of an object/element
#
# @param [Mongoid::Document] el A valid Mongoid:Document
#
# @returns Array [p, r] where p is the parent element for the embedded element, and
# r is the inverse reflection name
def get_embedded_relation(el)
el.reflect_on_all_associations(:embedded_in).each do |r|
# puts r.inspect
p = el.send(r.name.to_s)
return [p, r] unless p.nil?
end
nil
end
end
end
module Mongoid
# Add to your mongoid document:
# include Mongoid::RootFromEmbedded
# @author Leif Ringstad <leif@bitelm.com>
module RootFromEmbedded
extend ActiveSupport::Concern
def root_from_embedded
recurse_up_to_highest_element(self)
end
#
# Recurse up to the highest element (root document)
#
#
def recurse_up_to_highest_element(el)
p = nil
retval = nil
el.reflect_on_all_associations(:embedded_in).each do |r|
p = el.send(r.name.to_s)
unless p.nil?
retval = recurse_up_to_highest_element(p)
return p if retval.nil?
end
end
retval
end
end
end
module Mongoid
# Add to your mongoid document:
# include Mongoid::SearchForObject
# @author Leif Ringstad <leif@bitelm.com>
module SearchForObject
extend ActiveSupport::Concern
#
# Search for a object given the dot notation, value and field
#
# @param [String] dn The dot notation to search for
# @param [Array, BigDecimal, Boolean, Date, DateTime, Float, Hash, Integer, Moped::BSON::ObjectId, Moped::BSON::Binary, Range, Regexp, String, Symbol, Time, TimeWithZone] _value The value on the field to search for in any valid Mongoid type.
# @param [Symbol] _field The field to search for the value. Default :id
#
# @return [Array] An array of embedded Mongoid documents
#
def search_for_object( dn, _value, _field = :id )
return search_value_on_self(_value, _field) if dn.empty?
dns = dn.split(".")
work_dn = dns.shift
remaining_dn = dns.join(".")
retval = Array.new
if remaining_dn.length == 0
r = search_for_elements_in_array(work_dn, _value, _field)
retval.concat(r) unless r.nil?
else
self.send(work_dn).each do |a|
r = a.search_for_object(remaining_dn, _value, _field)
retval.concat(r) unless r.nil?
end
end
retval
end
private
#
# Find all elements within the array that matches value on a field
#
# @param [String] dn A dot notation with only one part. Should be a string that the object responds to has_one or has_many
# @param [Array, BigDecimal, Boolean, Date, DateTime, Float, Hash, Integer, Moped::BSON::ObjectId, Moped::BSON::Binary, Range, Regexp, String, Symbol, Time, TimeWithZone] _value The value on the field to search for in any valid Mongoid type.
# @param [Symbol] _field The field to search for the value. Default :id
#
# @return [<type>] <description>
#
def search_for_elements_in_array(dn, _value, _field = :id)
return nil unless self.respond_to?(dn)
self.send(dn).find_all {|e| e.send(_field) == _value}
end
#
# Search for value on self
#
# @param [Array, BigDecimal, Boolean, Date, DateTime, Float, Hash, Integer, Moped::BSON::ObjectId, Moped::BSON::Binary, Range, Regexp, String, Symbol, Time, TimeWithZone] _value The value on the field to search for in any valid Mongoid type.
# @param [Symbol] _field The field to search for the value. Default :id
#
# @return [self] <description>
#
def search_value_on_self(_value, _field)
return [self] if (self.send(_field) == _value)
nil
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment