aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--app/models/referential.rb12
-rw-r--r--app/models/referential_cloning.rb20
-rw-r--r--app/workers/referential_cloning_worker.rb19
-rw-r--r--spec/models/referential_spec.rb11
-rw-r--r--spec/workers/referential_cloning_worker_spec.rb4
5 files changed, 58 insertions, 8 deletions
diff --git a/app/models/referential.rb b/app/models/referential.rb
index da5791914..5a2e1d15d 100644
--- a/app/models/referential.rb
+++ b/app/models/referential.rb
@@ -171,14 +171,22 @@ class Referential < ActiveRecord::Base
projection_type || ""
end
- after_create :autocreate_referential_metadata
+ after_create :autocreate_referential_metadata, :clone_schema
def autocreate_referential_metadata
self.create_referential_metadata if workbench
end
+ def clone_schema
+ if self.created_from
+ ReferentialCloning.create(source_referential: self.created_from, target_referential: self)
+ end
+ end
+
before_create :create_schema
def create_schema
- Apartment::Tenant.create slug
+ if self.created_from.nil?
+ Apartment::Tenant.create slug
+ end
end
before_validation :assign_line_and_stop_area_referential, :on => :create
diff --git a/app/models/referential_cloning.rb b/app/models/referential_cloning.rb
index 8d765f985..9bf824ac5 100644
--- a/app/models/referential_cloning.rb
+++ b/app/models/referential_cloning.rb
@@ -2,6 +2,12 @@ class ReferentialCloning < ActiveRecord::Base
include AASM
belongs_to :source_referential, class_name: 'Referential'
belongs_to :target_referential, class_name: 'Referential'
+ after_commit :perform_clone, :on => :create
+
+ private
+ def perform_clone
+ ReferentialCloningWorker.perform_async(self.id)
+ end
aasm column: :status do
state :new, :initial => true
@@ -9,16 +15,24 @@ class ReferentialCloning < ActiveRecord::Base
state :successful
state :failed
- event :run do
+ event :run, after: :update_started_at do
transitions :from => [:new, :failed], :to => :pending
end
- event :successful do
+ event :successful, after: :update_ended_at do
transitions :from => [:pending, :failed], :to => :successful
end
- event :failed do
+ event :failed, after: :update_ended_at do
transitions :from => :pending, :to => :failed
end
end
+
+ def update_started_at
+ update_attribute(:started_at, Time.now)
+ end
+
+ def update_ended_at
+ update_attribute(:ended_at, Time.now)
+ end
end
diff --git a/app/workers/referential_cloning_worker.rb b/app/workers/referential_cloning_worker.rb
new file mode 100644
index 000000000..c0cdc8cb8
--- /dev/null
+++ b/app/workers/referential_cloning_worker.rb
@@ -0,0 +1,19 @@
+class ReferentialCloningWorker
+ include Sidekiq::Worker
+
+ def perform(referential_cloning_id)
+ ref_cloning = ReferentialCloning.find referential_cloning_id
+ sql_func = "CREATE OR REPLACE FUNCTION clone_schema( source_schema text, dest_schema text, include_recs boolean) RETURNS void AS $BODY$ DECLARE src_oid oid; tbl_oid oid; func_oid oid; object text; buffer text; srctbl text; default_ text; column_ text; qry text; dest_qry text; v_def text; seqval bigint; sq_last_value bigint; sq_max_value bigint; sq_start_value bigint; sq_increment_by bigint; sq_min_value bigint; sq_cache_value bigint; sq_log_cnt bigint; sq_is_called boolean; sq_is_cycled boolean; sq_cycled char(10); BEGIN SELECT oid INTO src_oid FROM pg_namespace WHERE nspname = quote_ident(source_schema); IF NOT FOUND THEN RAISE NOTICE 'source schema % does not exist!', source_schema; RETURN ; END IF; PERFORM nspname FROM pg_namespace WHERE nspname = quote_ident(dest_schema); IF FOUND THEN RAISE NOTICE 'dest schema % already exists!', dest_schema; RETURN ; END IF; EXECUTE 'CREATE SCHEMA ' || quote_ident(dest_schema) ; FOR object IN SELECT sequence_name::text FROM information_schema.sequences WHERE sequence_schema = quote_ident(source_schema) LOOP EXECUTE 'CREATE SEQUENCE ' || quote_ident(dest_schema) || '.' || quote_ident(object); srctbl := quote_ident(source_schema) || '.' || quote_ident(object); EXECUTE 'SELECT last_value, max_value, start_value, increment_by, min_value, cache_value, log_cnt, is_cycled, is_called FROM ' || quote_ident(source_schema) || '.' || quote_ident(object) || ';' INTO sq_last_value, sq_max_value, sq_start_value, sq_increment_by, sq_min_value, sq_cache_value, sq_log_cnt, sq_is_cycled, sq_is_called ; IF sq_is_cycled THEN sq_cycled := 'CYCLE'; ELSE sq_cycled := 'NO CYCLE'; END IF; EXECUTE 'ALTER SEQUENCE ' || quote_ident(dest_schema) || '.' || quote_ident(object) || ' INCREMENT BY ' || sq_increment_by || ' MINVALUE ' || sq_min_value || ' MAXVALUE ' || sq_max_value || ' START WITH ' || sq_start_value || ' RESTART ' || sq_min_value || ' CACHE ' || sq_cache_value || sq_cycled || ' ;' ; buffer := quote_ident(dest_schema) || '.' || quote_ident(object); IF include_recs THEN EXECUTE 'SELECT setval( ''' || buffer || ''', ' || sq_last_value || ', ' || sq_is_called || ');' ; ELSE EXECUTE 'SELECT setval( ''' || buffer || ''', ' || sq_start_value || ', ' || sq_is_called || ');' ; END IF; END LOOP; FOR object IN SELECT TABLE_NAME::text FROM information_schema.tables WHERE table_schema = quote_ident(source_schema) AND table_type = 'BASE TABLE' LOOP buffer := dest_schema || '.' || quote_ident(object); EXECUTE 'CREATE TABLE ' || buffer || '(LIKE ' || quote_ident(source_schema) || '.' || quote_ident(object) || ' INCLUDING ALL)'; IF include_recs THEN EXECUTE 'INSERT INTO ' || buffer || ' SELECT * FROM ' || quote_ident(source_schema) || '.' || quote_ident(object) || ';'; END IF; FOR column_, default_ IN SELECT column_name::text, REPLACE(column_default::text, source_schema, dest_schema) FROM information_schema.COLUMNS WHERE table_schema = dest_schema AND TABLE_NAME = object AND column_default LIKE 'nextval(%' || quote_ident(source_schema) || '%::regclass)' LOOP EXECUTE 'ALTER TABLE ' || buffer || ' ALTER COLUMN ' || column_ || ' SET DEFAULT ' || default_; END LOOP; END LOOP; FOR qry IN SELECT 'ALTER TABLE ' || quote_ident(dest_schema) || '.' || quote_ident(rn.relname) || ' ADD CONSTRAINT ' || quote_ident(ct.conname) || ' ' || pg_get_constraintdef(ct.oid) || ';' FROM pg_constraint ct JOIN pg_class rn ON rn.oid = ct.conrelid WHERE connamespace = src_oid AND rn.relkind = 'r' AND ct.contype = 'f' LOOP EXECUTE qry; END LOOP; FOR object IN SELECT table_name::text, view_definition FROM information_schema.views WHERE table_schema = quote_ident(source_schema) LOOP buffer := dest_schema || '.' || quote_ident(object); SELECT view_definition INTO v_def FROM information_schema.views WHERE table_schema = quote_ident(source_schema) AND table_name = quote_ident(object); EXECUTE 'CREATE OR REPLACE VIEW ' || buffer || ' AS ' || v_def || ';' ; END LOOP; FOR func_oid IN SELECT oid FROM pg_proc WHERE pronamespace = src_oid LOOP SELECT pg_get_functiondef(func_oid) INTO qry; SELECT replace(qry, source_schema, dest_schema) INTO dest_qry; EXECUTE dest_qry; END LOOP; RETURN; END; $BODY$ LANGUAGE plpgsql VOLATILE COST 100;"
+ sql_clone = "SELECT clone_schema('#{ref_cloning.source_referential.slug}', '#{ref_cloning.target_referential.slug}', TRUE);"
+ ref_cloning.run!
+
+ begin
+ ActiveRecord::Base.connection.execute sql_func
+ ActiveRecord::Base.connection.execute sql_clone
+ ref_cloning.successful!
+ rescue Exception => e
+ Rails.logger.error "ReferentialCloningWorker : #{e}"
+ ref_cloning.failed!
+ end
+ end
+end
diff --git a/spec/models/referential_spec.rb b/spec/models/referential_spec.rb
index f8e6ffacc..9f87d0629 100644
--- a/spec/models/referential_spec.rb
+++ b/spec/models/referential_spec.rb
@@ -1,12 +1,17 @@
require 'spec_helper'
describe Referential, :type => :model do
+ let(:ref) { create :referential }
- it "create a rule_parameter_set" do
- referential = create(:referential)
+ # it "create a rule_parameter_set" do
+ # referential = create(:referential)
#expect(referential.rule_parameter_sets.size).to eq(1)
- end
+ # end
it { should have_one(:referential_metadata) }
it { should belong_to(:workbench) }
+
+ it 'should create a ReferentialCloning when a referential is cloned' do
+ expect { create(:referential, created_from: ref) }.to change{ReferentialCloning.count}.by(1)
+ end
end
diff --git a/spec/workers/referential_cloning_worker_spec.rb b/spec/workers/referential_cloning_worker_spec.rb
new file mode 100644
index 000000000..dd7b33f23
--- /dev/null
+++ b/spec/workers/referential_cloning_worker_spec.rb
@@ -0,0 +1,4 @@
+require 'rails_helper'
+RSpec.describe ReferentialCloningWorker, type: :worker do
+ pending "add some examples to (or delete) #{__FILE__}"
+end