aboutsummaryrefslogtreecommitdiffstats
path: root/app/models
diff options
context:
space:
mode:
authorAlban Peignier2016-11-22 18:31:14 +0100
committerAlban Peignier2016-11-22 18:31:14 +0100
commita14c8afc2df1d6c7ac186404fa4e1e86cef6a811 (patch)
treef0abb6bbaffef4962cb1fe69c97dd0948ad9553f /app/models
parent85daced332703d1447340c5fc17972a662b4080c (diff)
parent7d58f83b1c38883a79258598b57d76c5f16fb807 (diff)
downloadchouette-core-a14c8afc2df1d6c7ac186404fa4e1e86cef6a811.tar.bz2
Merge branch 'metadata_multiple_periods' into staging
Diffstat (limited to 'app/models')
-rw-r--r--app/models/referential.rb36
-rw-r--r--app/models/referential_metadata.rb146
2 files changed, 131 insertions, 51 deletions
diff --git a/app/models/referential.rb b/app/models/referential.rb
index b75ff3ab9..1a4b543b7 100644
--- a/app/models/referential.rb
+++ b/app/models/referential.rb
@@ -204,34 +204,44 @@ class Referential < ActiveRecord::Base
end
def metadatas_period
- # FIXME
- if metadatas.present?
- metadatas.first.periodes.try :first
+ query = "select min(lower), max(upper) from (select lower(unnest(periodes)) as lower, upper(unnest(periodes)) as upper from public.referential_metadata where public.referential_metadata.referential_id = #{id}) bounds;"
+
+ row = self.class.connection.select_one(query)
+ lower, upper = row["min"], row["max"]
+
+ if lower and upper
+ Range.new(Date.parse(lower), Date.parse(upper)-1)
end
end
alias_method :validity_period, :metadatas_period
def metadatas_lines
- # FIXME
- metadatas.present? ? metadatas.first.lines : []
+ if metadatas.present?
+ scope = workbench ? workbench.lines : associated_lines
+ scope.where(id: metadatas.pluck(:line_ids).flatten)
+ else
+ Chouete::Line.none
+ end
end
def overlapped_referential_ids
return [] unless metadatas.present?
line_ids = metadatas.first.line_ids
- period = metadatas.first.periodes.try :first
+ periodes = metadatas.first.periodes
- return [] unless line_ids.present? && period
+ return [] unless line_ids.present? && periodes.present?
not_myself = "and referential_id != #{id}" if persisted?
- query = "SELECT distinct(referential_id) FROM
- (SELECT unnest(public.referential_metadata.line_ids) as line, unnest(public.referential_metadata.periodes) as period, public.referential_metadata.referential_id
- FROM public.referential_metadata
- INNER JOIN public.referentials ON public.referential_metadata.referential_id = public.referentials.id
- WHERE public.referentials.workbench_id = #{workbench_id} and public.referentials.archived_at is null) as metadatas
- WHERE line in (#{line_ids.join(',')}) and period && '#{ActiveRecord::ConnectionAdapters::PostgreSQLColumn.range_to_string(period)}' #{not_myself};"
+ periods_query = periodes.map do |periode|
+ "period && '#{ActiveRecord::ConnectionAdapters::PostgreSQLColumn.range_to_string(periode)}'"
+ end.join(" OR ")
+
+ query = "select distinct(public.referential_metadata.referential_id) FROM public.referential_metadata, unnest(line_ids) line, LATERAL unnest(periodes) period
+ WHERE public.referential_metadata.referential_id
+ IN (SELECT public.referentials.id FROM public.referentials WHERE referentials.workbench_id = #{workbench_id} and referentials.archived_at is null #{not_myself})
+ AND line in (#{line_ids.join(',')}) and (#{periods_query});"
self.class.connection.select_values(query).map(&:to_i)
end
diff --git a/app/models/referential_metadata.rb b/app/models/referential_metadata.rb
index a1066e43b..0c792a9b9 100644
--- a/app/models/referential_metadata.rb
+++ b/app/models/referential_metadata.rb
@@ -7,68 +7,138 @@ class ReferentialMetadata < ActiveRecord::Base
validates :lines, presence: true
validates :periodes, presence: true
- validates :first_period_begin, :first_period_end, presence: true
-
scope :include_lines, -> (line_ids) { where('line_ids && ARRAY[?]', line_ids) }
scope :include_dateranges, -> (dateranges) { where('periodes && ARRAY[?]', dateranges) }
- def first_period
- periodes.first if periodes
+ class Period
+ include ActiveAttr::Model
+
+ attribute :id, type: Integer
+ attribute :begin, type: Date
+ attribute :end, type: Date
+
+ validates :begin, :end, presence: true
+ validate :check_end_greather_than_begin
+
+ def check_end_greather_than_begin
+ if self.begin and self.end and self.begin > self.end
+ errors.add(:end, :invalid)
+ end
+ end
+
+ def self.from_range(index, range)
+ Period.new id: index, begin: range.begin, end: range.end
+ end
+
+ def range
+ if self.begin and self.end and self.begin <= self.end
+ Range.new self.begin, self.end
+ end
+ end
+
+ def intersect?(*other)
+ return false if range.nil?
+
+ other = other.flatten
+ other = other.delete_if { |o| o.id == id } if id
+
+ other.any? do |period|
+ if other_range = period.range
+ (range & other_range).present?
+ end
+ end
+ end
+
+ # Stuff required for coocon
+ def new_record?
+ !persisted?
+ end
+ def persisted?
+ id.present?
+ end
+
+
+ def mark_for_destruction
+ self._destroy = true
+ end
+
+ attribute :_destroy, type: Boolean
+ alias_method :marked_for_destruction?, :_destroy
end
- def first_period_begin
- @first_period_begin or first_period.try(:begin)
+ # Required by coocon
+ def build_period
+ Period.new
end
- def first_period_begin=(date)
- date = (Date.parse(date) rescue nil) if String === date
- periodes_will_change! unless @first_period_begin == date
- @first_period_begin = date
+
+ def periods
+ @periods ||= init_periods
end
- def first_period_end
- if @first_period_end
- @first_period_end
+
+ def init_periods
+ if periodes
+ periodes.each_with_index.map { |r, index| Period.from_range(index, r) }
else
- if first_period
- date = first_period.end
- date -= 1 if first_period.exclude_end?
- date
- end
+ []
end
end
- def first_period_end=(date)
- date = (Date.parse(date) rescue nil) if String === date
- periodes_will_change! unless @first_period_end == date
- @first_period_end = date
- end
+ private :init_periods
- validate :check_first_period_end
+ validate :validate_periods
- def check_first_period_end
- if @first_period_begin and @first_period_end and @first_period_begin > @first_period_end
- errors.add(:first_period_end, :invalid)
+ def validate_periods
+ Rails.logger.debug "Validate periods"
+ unless periods.all?(&:valid?)
+ errors.add(:periods, :invalid)
end
- end
- before_validation :set_first_period
+ periods.each do |period|
+ Rails.logger.debug "Validate period #{period.inspect} : #{period.intersect?(periods)}"
+ if period.intersect?(periods)
+ period.errors.add(:base, :invalid)
+ Rails.logger.debug "period errors #{period.errors}"
+ end
+ end
+ end
- def set_first_period
- if @first_period_begin and @first_period_end and @first_period_begin <= @first_period_end
- self.periodes ||= []
- self.periodes[0] = Range.new @first_period_begin, @first_period_end
+ def periods_attributes=(attributes = {})
+ @periods = []
+ attributes.each do |index, period_attribute|
+ period = Period.new(period_attribute.merge(id: index))
+ @periods << period unless period.marked_for_destruction?
end
+
+ # if self.periodes != @periods.map(&:range).compact
+ periodes_will_change!
+ # end
end
- def column_for_attribute(name)
- if %i{first_period_begin first_period_end}.include?(name.to_sym)
- ActiveRecord::ConnectionAdapters::Column.new(name, nil, "date")
- else
- super name
+ before_validation :fill_periodes
+
+ def fill_periodes
+ if @periods
+ self.periodes = @periods.map(&:range).compact.sort_by(&:begin)
end
end
+ after_save :clear_periods
+
+ def clear_periods
+ @periods = nil
+ end
+ private :clear_periods
+
def self.new_from from
from.dup.tap do |metadata|
metadata.referential_id = nil
end
end
end
+
+class Range
+ def intersection(other)
+ return nil if (self.max < other.begin or other.max < self.begin)
+ [self.begin, other.begin].max..[self.max, other.max].min
+ end
+ alias_method :&, :intersection
+end