module Genealogy::QueryMethods
Module QueryMethods
provides methods to run genealogy queries to retrive relatives by role. It’s included by the genealogy enabled AR model
Public Instance Methods
get list of known ancestrors iterateing over parents @param [Hash] options @option options [Symbol] generations lets you limit how many generations will be included in the output. @return [ActiveRecord::Relation] list of ancestors (limited by a number of generations if so indicated)
# File lib/genealogy/query_methods.rb, line 131 def ancestors(options = {}) ids = [] if options[:generations] raise ArgumentError, ":generations option must be an Integer" unless options[:generations].is_a? Integer generation_count = 0 generation_ids = parents.compact.map(&:id) while (generation_count < options[:generations]) && (generation_ids.length > 0) next_gen_ids = [] ids += generation_ids until generation_ids.empty? ids.unshift(generation_ids.shift) next_gen_ids += gclass.find(ids.first).parents.compact.map(&:id) end generation_ids = next_gen_ids generation_count += 1 end else remaining_ids = parents.compact.map(&:id) until remaining_ids.empty? ids << remaining_ids.shift remaining_ids += gclass.find(ids.last).parents.compact.map(&:id) end end gclass.where(id: ids) end
@see uncles_and_aunts
# File lib/genealogy/query_methods.rb, line 222 def aunts(options = {}) uncles_and_aunts(options).females end
@param [Hash] options @option options [Object] spouse to filter children by spouse @return [ActiveRecord::Relation] children
# File lib/genealogy/query_methods.rb, line 50 def children(options = {}) raise SexError, "Sex value not valid for #{self}. It's needed to look for children" unless gclass.sex_values.include? sex_before_type_cast result = gclass.where("#{gclass::SEX2PARENT[ssex]}_id" => self) if options.keys.include? :spouse check_indiv(spouse = options[:spouse],opposite_ssex) result = result.where("#{gclass::SEX2PARENT[opposite_ssex]}_id" => spouse ) if spouse end result end
@param [Hash] options @option options [Symbol] lineage to filter uncles by lineage: :paternal or :maternal @option options [Symbol] half to filter uncles (see siblings
) @return [ActiveRecord::Relation] list of uncles and aunts’ children
# File lib/genealogy/query_methods.rb, line 250 def cousins(options = {}) ids = uncles_and_aunts(options).inject([]){|memo,uncle| memo |= uncle.children.pluck(:id)} gclass.where(id: ids) end
get list of known descendants iterateing over children … @param [Hash] options @option options [Symbol] generations lets you limit how many generations will be included in the output. @return [ActiveRecord::Relation] list of descendants (limited by a number of generations if so indicated)
# File lib/genealogy/query_methods.rb, line 162 def descendants(options = {}) ids = [] if options[:generations] generation_count = 0 generation_ids = children.map(&:id) while (generation_count < options[:generations]) && (generation_ids.length > 0) next_gen_ids = [] ids += generation_ids until generation_ids.empty? ids.unshift(generation_ids.shift) next_gen_ids += gclass.find(ids.first).children.map(&:id) end generation_ids = next_gen_ids generation_count += 1 end else remaining_ids = children.map(&:id) until remaining_ids.empty? ids << remaining_ids.shift remaining_ids += gclass.find(ids.last).children.pluck(:id) # break if (remaining_ids - ids).empty? can be necessary in case of loop. Idem for ancestors method end end gclass.where(id: ids) end
family with option extended: :true @see family
# File lib/genealogy/query_methods.rb, line 355 def extended_family(options = {}) family(options.merge(extended: true)) end
family_hash
with option extended: :true @see family_hash
# File lib/genealogy/query_methods.rb, line 336 def extended_family_hash(options = {}) family_hash(options.merge(extended: true)) end
family individuals @return [Array] @see family_hash
# File lib/genealogy/query_methods.rb, line 343 def family(options = {}) family_hash(options).inject([]) do |memo, r| [r.last].compact.flatten.each do |relative| relative.role_as_relative = r.first.to_s.singularize.to_sym memo << relative end memo end end
family hash with roles as keys? :spouse and individuals as values. Defaults roles are :father, :mother, :children, :siblings and current_spouse if enabled @option options [Symbol] half to filter siblings (see siblings
) @option options [Boolean] extended to include roles for grandparents, grandchildren, uncles, aunts, nieces, nephews and cousins @option options [Boolean] singular_role to use singularized role as keys @return [Hash] family hash with roles as keys? :spouse and individuals as values.
# File lib/genealogy/query_methods.rb, line 278 def family_hash(options = {}) roles = [:father, :mother, :children, :siblings] roles += [:current_spouse] if self.class.current_spouse_enabled roles += case options[:half] when nil [] when :include [:half_siblings] when :include_separately [:paternal_half_siblings, :maternal_half_siblings] when :father [:paternal_half_siblings] when :mother [:maternal_half_siblings] else raise ArgumentError, "Admitted values for :half options are: :father, :mother, :include, :include_separately, nil" end roles += [:paternal_grandfather, :paternal_grandmother, :maternal_grandfather, :maternal_grandmother, :grandchildren, :uncles_and_aunts, :nieces_and_nephews, :cousins] if options[:extended] == true res = roles.inject({}){|res,role| res.merge!({role => self.send(role)})} if options[:singular_role] == true res2 = { father: res[:father], mother: res[:mother], daughter: res[:children].females, son: res[:children].males, sister: res[:siblings].females, brother: res[:siblings].males } res2[:current_spouse] = res[:current_spouse] if res.has_key? :current_spouse res2.merge!({ paternal_grandfather: res[:paternal_grandfather], paternal_grandmother: res[:paternal_grandmother], maternal_grandfather: res[:maternal_grandfather], maternal_grandmother: res[:maternal_grandmother], grandchild: res[:grandchildren], uncle: res[:uncles_and_aunts].males, aunts: res[:uncles_and_aunts].females, nephew: res[:nieces_and_nephews].males, niece: res[:nieces_and_nephews].females, cousin: res[:cousins] }) if options[:extended] == true res2.merge!({ paternal_half_brother: res[:paternal_half_siblings].males, paternal_half_sister: res[:paternal_half_siblings].females, maternal_half_brother: res[:maternal_half_siblings].males, maternal_half_sister: res[:maternal_half_siblings].females, }) if options[:half] == :include_separately res = res2 end res end
@return [ActiveRecord::Relation] list of grandchildren
# File lib/genealogy/query_methods.rb, line 189 def grandchildren result = children.inject([]){|memo,child| memo |= child.children} end
@return [4-elements Array] paternal_grandfather
, paternal_grandmother
, maternal_grandfather
, maternal_grandmother
# File lib/genealogy/query_methods.rb, line 38 def grandparents [paternal_grandfather, paternal_grandmother, maternal_grandfather, maternal_grandmother] end
@return [ActiveRecord::Relation] list of grat-grandchildren
# File lib/genealogy/query_methods.rb, line 194 def great_grandchildren result = grandchildren.compact.inject([]){|memo,grandchild| memo |= grandchild.children} end
@return [8-elements Array] paternal_grandfather
‘s father, paternal_grandmother
’s father, maternal_grandfather
‘s father, maternal_grandmother
’s father, paternal_grandfather
‘s mother, paternal_grandmother
’s mother, maternal_grandfather
‘s mother, maternal_grandmother
’s mother
# File lib/genealogy/query_methods.rb, line 43 def great_grandparents grandparents.inject([]){|memo, gp| memo += (gp.try(:parents) || [nil,nil]) }.flatten end
siblings with option half: :only @see siblings
# File lib/genealogy/query_methods.rb, line 111 def half_siblings(options = {}) siblings(options.merge(half: :only)) end
@see uncles_and_aunts
# File lib/genealogy/query_methods.rb, line 242 def maternal_aunts(options = {}) aunts(options.merge(lineage: :maternal)) end
@return [ActiveRecord, NilClass]
# File lib/genealogy/query_methods.rb, line 19 def maternal_grandfather mother && mother.father end
@return [ActiveRecord, NilClass]
# File lib/genealogy/query_methods.rb, line 23 def maternal_grandmother mother && mother.mother end
@return [2-elements Array] maternal_grandfather
and maternal_grandmother
# File lib/genealogy/query_methods.rb, line 33 def maternal_grandparents (mother && mother.parents) || [nil,nil] end
siblings with option half: :mother @see siblings
# File lib/genealogy/query_methods.rb, line 123 def maternal_half_siblings(options = {}) siblings(options.merge(half: :mother)) end
@see uncles_and_aunts
# File lib/genealogy/query_methods.rb, line 232 def maternal_uncles(options = {}) uncles(options.merge(lineage: :maternal)) end
@see nieces_and_nephews
# File lib/genealogy/query_methods.rb, line 264 def nephews(options = {}) nieces_and_nephews.males end
@see nieces_and_nephews
# File lib/genealogy/query_methods.rb, line 269 def nieces(options = {}) nieces_and_nephews.females end
@param [Hash] options @option options [Symbol] half to filter siblings (see siblings
) @return [ActiveRecord::Relation] list of nieces and nephews
# File lib/genealogy/query_methods.rb, line 258 def nieces_and_nephews(options = {}) ids = siblings(options).inject([]){|memo,sib| memo |= sib.children.pluck(:id)} gclass.where(id: ids) end
@return [2-elements Array] father and mother
# File lib/genealogy/query_methods.rb, line 7 def parents [father,mother] end
@see uncles_and_aunts
# File lib/genealogy/query_methods.rb, line 237 def paternal_aunts(options = {}) aunts(options.merge(lineage: :paternal)) end
@return [ActiveRecord, NilClass]
# File lib/genealogy/query_methods.rb, line 11 def paternal_grandfather father && father.father end
@return [ActiveRecord, NilClass]
# File lib/genealogy/query_methods.rb, line 15 def paternal_grandmother father && father.mother end
@return [2-elements Array] paternal_grandfather
and paternal_grandmother
# File lib/genealogy/query_methods.rb, line 28 def paternal_grandparents (father && father.parents) || [nil,nil] end
siblings with option half: :father @see siblings
# File lib/genealogy/query_methods.rb, line 117 def paternal_half_siblings(options = {}) siblings(options.merge(half: :father)) end
@see uncles_and_aunts
# File lib/genealogy/query_methods.rb, line 227 def paternal_uncles(options = {}) uncles(options.merge(lineage: :paternal)) end
@param [Hash] options @option options [Symbol] half let you filter siblings. Possible values are:
:father for paternal halfsiblings :mother for maternal halfsiblings :only for all halfsiblings :include for fullsiblings and halfsiblings
@return [ActiveRecord::Relation] list of fullsiblings and/or halfsiblings
# File lib/genealogy/query_methods.rb, line 72 def siblings(options = {}) spouse = options[:spouse] result = gclass.where.not(id: id) case options[:half] when nil # only full siblings result.all_with(:parents).where(father_id: father, mother_id: mother) when :father # common father result = result.all_with(:father).where(father_id: father) if spouse check_indiv(spouse, :female) result.where(mother_id: spouse) elsif mother result.where("mother_id != ? or mother_id is ?", mother_id, nil) else result end when :mother # common mother result = result.all_with(:mother).where(mother_id: mother) if spouse check_indiv(spouse, :male) result.where(father_id: spouse) elsif father result.where("father_id != ? or father_id is ?", father_id, nil) else result end when :only # only half siblings ids = siblings(half: :father).pluck(:id) | siblings(half: :mother).pluck(:id) result.where(id: ids) when :include # including half siblings result.where("father_id = ? or mother_id = ?", father_id, mother_id) else raise ArgumentError, "Admitted values for :half options are: :father, :mother, false, true or nil" end end
@return [ActiveRecord::Relation] list of individuals with whom has had children
# File lib/genealogy/query_methods.rb, line 61 def spouses gclass.where(id: children.pluck("#{gclass::SEX2PARENT[opposite_ssex]}_id".to_sym).compact.uniq) | (self.class.current_spouse_enabled ? [] : [current_spouse]) end
@see uncles_and_aunts
# File lib/genealogy/query_methods.rb, line 217 def uncles(options = {}) uncles_and_aunts(options).males end
list of uncles and aunts iterating through parents’ siblings @param [Hash] options @option options [Symbol] lineage to filter by lineage: :paternal or :maternal @option options [Symbol] half to filter by half siblings (see siblings
) @return [ActiveRecord::Relation] list of uncles and aunts
# File lib/genealogy/query_methods.rb, line 203 def uncles_and_aunts(options={}) relation = case options[:lineage] when :paternal [father] when :maternal [mother] else parents end ids = relation.compact.inject([]){|memo,parent| memo |= parent.siblings(half: options[:half]).pluck(:id)} gclass.where(id: ids) end