# frozen_string_literal: true # Establece una relación de muchos a muchos artículos. Cada campo es un # Array de UUID que se mantienen sincronizados. # # Por ejemplo: # # Un libro puede tener muches autores y une autore muchos libros. La # relación has_many tiene que traer todes les autores relacionades con # el libro actual. La relación belongs_to tiene que traer todes les # autores que tienen este libro. La relación es bidireccional, no hay # diferencia entre has_many y belongs_to. class MetadataHasAndBelongsToMany < MetadataBelongsTo def default_value [] end # Posts a los que pertenece. Memoizamos por value para obtener # siempre la última relación. # # Buscamos todos los Post contenidos en el valor actual. No # garantizamos el orden. # # @return [PostRelation] Posts def belongs_to @belongs_to ||= {} @belongs_to[value.hash.to_s] ||= posts.where(uuid: value) end # Devuelve la lista de Posts relacionados con este buscándolos en la # relación inversa. #save debería mantenerlos sincronizados. # # @return [PostRelation] def has_many @has_many ||= {} @has_many[value.hash.to_s] ||= posts.where(inverse.to_sym => post.uuid.value) end alias had_many has_many # Posts a los que pertenecía # # @return [PostRelation] Posts def belonged_to @belonged_to ||= posts.where(uuid: document.data.fetch(name.to_s, [])) end # Mantiene la relación inversa si existe. # # La relación belongs_to se mantiene actualizada en la modificación # actual. Lo que buscamos es mantener sincronizada esa relación. # # Buscamos en belongs_to la relación local, si se eliminó hay que # quitarla de la relación remota, sino hay que agregarla. def save return true unless changed? self[:value] = sanitize value return true unless inverse? && !included? (belonged_to - belongs_to).each do |p| p[inverse].value.delete post.uuid.value end (belongs_to - belonged_to).each do |p| p[inverse].value << post.uuid.value end true end def sanitize(sanitizable) sanitizable.map do |v| super v end end def post_exists? return true if empty? && can_be_empty? !belongs_to.empty? end # Todos los artículos relacionados incluyen a este? def included? belongs_to.map do |p| p[inverse].value.include? post.uuid.value end.all? end end