aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlban Peignier2017-12-14 11:09:05 +0100
committerAlban Peignier2018-01-05 10:22:59 +0100
commit638a1864a027226c9c0b26b01ca80a85435387f7 (patch)
tree133c131ea10a3635e91a6d7d64b9a00cb97c9e92
parent63c8ca8680c9d77032abde84c7a5d969545d675a (diff)
downloadchouette-core-638a1864a027226c9c0b26b01ca80a85435387f7.tar.bz2
Create Merge operation. Refs #5299
-rw-r--r--app/models/merge.rb155
-rw-r--r--app/models/referential.rb9
-rw-r--r--config/initializers/apartment.rb3
-rw-r--r--db/migrate/20171212152452_create_merges.rb16
-rw-r--r--db/schema.rb13
-rw-r--r--spec/models/merge_spec.rb14
6 files changed, 208 insertions, 2 deletions
diff --git a/app/models/merge.rb b/app/models/merge.rb
new file mode 100644
index 000000000..e87f83402
--- /dev/null
+++ b/app/models/merge.rb
@@ -0,0 +1,155 @@
+class Merge < ActiveRecord::Base
+ extend Enumerize
+
+ belongs_to :workbench
+ enumerize :status, in: %w[new pending successful failed running]
+
+ has_array_of :referentials, class_name: 'Referential'
+
+ delegate :output, to: :workbench
+
+ attr_reader :new
+
+ def merge!
+ update started_at: Time.now, status: :running
+
+ prepare_new
+
+ referentials.each do |referential|
+ merge_referential referential
+ end
+
+ save_current
+ ensure
+ update ended_at: Time.now, status: :successful
+ end
+
+ def prepare_new
+ new =
+ if workbench.output.current
+ Rails.logger.debug "Clone current output"
+ Referential.new_from(workbench.output.current, fixme_functional_scope).tap do |clone|
+ clone.inline_clone = true
+ end
+ else
+ Rails.logger.debug "Create a new output"
+ # 'empty' one
+ attributes = {
+ organisation: workbench.organisation, # TODO could be workbench.organisation by default
+ name: I18n.t("merges.referential_name"),
+ slug: "output_#{workbench.id}_#{Time.now.to_i}"
+ }
+ workbench.referentials.new attributes
+ end
+
+ new.save!
+
+ output.update new: new
+ @new = new
+ end
+
+ def merge_referential(referential)
+ Rails.logger.debug "Merge #{referential.slug}"
+ puts referential.metadatas.inspect
+
+ metadata_merger = MetadatasMerger.new new.metadatas, referential.metadatas
+ metadata_merger.merge
+
+ metadata_merger.conflits.each do |line_id, periods|
+ # clean new on given period
+ end
+ metadata_merger.destroyed_metadatas.each(&:destroy)
+
+ # let's merge data :)
+ end
+
+ def save_current
+ output.update current: new, new: nil
+ output.current.update referential_suite: output
+ end
+
+ def fixme_functional_scope
+ if attribute = workbench.organisation.sso_attributes.try(:[], "functional_scope")
+ JSON.parse(attribute)
+ end
+ end
+
+ def child_change
+
+ end
+
+ class MetadatasMerger
+
+ attr_reader :merge, :metadatas
+ def initialize(merge, metadatas)
+ @merge, @metadatas = merge, metadatas
+ end
+
+ def merge
+ metadatas.each do |metadata|
+ merge_one metadata
+ end
+ end
+
+ def line_metadatas(line_id)
+ merge.select do |m|
+ m.line_ids.include? line_id
+ end
+ end
+
+ def conflits
+ @conflits ||= Hash.new { |h,k| h[k] = [] }
+ end
+
+ def destroyed_metadatas
+ @destroyed_metadatas ||= []
+ end
+
+ def merge_one(metadata)
+ metadata.line_ids.each do |line_id|
+ line_metadatas = line_metadatas(line_id)
+
+ metadata.periodes do |period|
+ before = line_metadatas.find do |m|
+ m.periodes.any? { |p| p.include? period.begin }
+ end
+
+ if before
+ before.end = period.begin - 1
+ end
+
+ between = line_metadatas.select do |m|
+ m.periodes.any? do |p|
+ period.begin < p.begin && p.end < period.end
+ end
+ end
+
+ destroyed_metadatas.concat between
+
+ after = line_metadatas.find do |m|
+ m.periodes.any? { |p| p.include? period.end }
+ end
+
+ if after
+ after.begin = period.end + 1
+ end
+
+ if [before, between, after].any?(&:present?)
+ conflits[line_id] << period
+
+ attributes = {
+ line_ids: line_id,
+ periodes: [period],
+ referential_source_id: metadata.referential_source_id,
+ created_at: metadata.created_at
+ }
+ # line_metadatas should not contain conflicted metadatas
+ metadatas << ReferentialMetadata.new(attributes)
+ end
+ end
+ end
+ end
+
+ end
+
+end
diff --git a/app/models/referential.rb b/app/models/referential.rb
index 1cdda9e6a..c77fd4e3e 100644
--- a/app/models/referential.rb
+++ b/app/models/referential.rb
@@ -305,8 +305,15 @@ class Referential < ActiveRecord::Base
end
end
+ attr_accessor :inline_clone
def clone_schema
- ReferentialCloning.create(source_referential: created_from, target_referential: self)
+ cloning = ReferentialCloning.new source_referential: created_from, target_referential: self
+
+ if inline_clone
+ cloning.clone!
+ else
+ cloning.save!
+ end
end
def create_schema
diff --git a/config/initializers/apartment.rb b/config/initializers/apartment.rb
index 69204a5d7..8becd23c2 100644
--- a/config/initializers/apartment.rb
+++ b/config/initializers/apartment.rb
@@ -77,7 +77,8 @@ Apartment.configure do |config|
'ComplianceCheckSet',
'ComplianceCheckBlock',
'ComplianceCheckResource',
- 'ComplianceCheckMessage'
+ 'ComplianceCheckMessage',
+ 'Merge'
]
# use postgres schemas?
diff --git a/db/migrate/20171212152452_create_merges.rb b/db/migrate/20171212152452_create_merges.rb
new file mode 100644
index 000000000..7915bd91b
--- /dev/null
+++ b/db/migrate/20171212152452_create_merges.rb
@@ -0,0 +1,16 @@
+class CreateMerges < ActiveRecord::Migration
+ def change
+ create_table :merges do |t|
+ t.bigint :workbench_id, index: true, foreign_key: true
+ t.bigint :referential_ids, array: true
+
+ t.string :creator
+ t.string :status
+
+ t.datetime :started_at
+ t.datetime :ended_at
+
+ t.timestamps null: false
+ end
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index e6fdd9d74..667b95c84 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -522,6 +522,19 @@ ActiveRecord::Schema.define(version: 20171227113809) do
add_index "lines", ["registration_number"], name: "lines_registration_number_key", using: :btree
add_index "lines", ["secondary_company_ids"], name: "index_lines_on_secondary_company_ids", using: :gin
+ create_table "merges", id: :bigserial, force: :cascade do |t|
+ t.integer "workbench_id", limit: 8
+ t.integer "referential_ids", limit: 8, array: true
+ t.string "creator"
+ t.string "status"
+ t.datetime "started_at"
+ t.datetime "ended_at"
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
+ end
+
+ add_index "merges", ["workbench_id"], name: "index_merges_on_workbench_id", using: :btree
+
create_table "networks", id: :bigserial, force: :cascade do |t|
t.string "objectid", null: false
t.integer "object_version", limit: 8
diff --git a/spec/models/merge_spec.rb b/spec/models/merge_spec.rb
new file mode 100644
index 000000000..674311f38
--- /dev/null
+++ b/spec/models/merge_spec.rb
@@ -0,0 +1,14 @@
+require "rails_helper"
+
+RSpec.describe Merge do
+
+ it "should work" do
+ workbench = FactoryGirl.create :workbench
+ referential = FactoryGirl.create :referential, workbench: workbench, organisation: workbench.organisation
+
+ merge = Merge.create!(workbench: workbench, referentials: [referential])
+
+ merge.merge!
+ end
+
+end