14819: Merge branch 'master' into 14819-arvados-jobs-on-stretch
[arvados.git] / services / api / db / migrate / 20140811184643_collection_use_regular_uuids.rb
index d82dcf9009cfdcb3ab6f2cc9d9d1127d2d6dafd8..003f74b1363653c4627668010afdd31546dfabf3 100644 (file)
+# Copyright (C) The Arvados Authors. All rights reserved.
+#
+# SPDX-License-Identifier: AGPL-3.0
+
 class CollectionUseRegularUuids < ActiveRecord::Migration
   def up
     add_column :collections, :name, :string
     add_column :collections, :description, :string
-    add_column :collections, :properties, :string
+    add_column :collections, :properties, :text
+    add_column :collections, :expires_at, :date
+    remove_column :collections, :locator
+
+    say_with_time "Step 1. Move manifest hashes into portable_data_hash field" do
+      ActiveRecord::Base.connection.execute("update collections set portable_data_hash=uuid, uuid=null")
+    end
+
+    say_with_time "Step 2. Create new collection objects from the name links in the table." do
+      from_clause = %{
+from links inner join collections on head_uuid=collections.portable_data_hash
+where link_class='name' and collections.uuid is null
+}
+      links = ActiveRecord::Base.connection.select_all %{
+select links.uuid, head_uuid, tail_uuid, links.name,
+manifest_text, links.created_at, links.modified_at, links.modified_by_client_uuid, links.modified_by_user_uuid
+#{from_clause}
+}
+      links.each do |d|
+        ActiveRecord::Base.connection.execute %{
+insert into collections (uuid, portable_data_hash, owner_uuid, name, manifest_text, created_at, modified_at, modified_by_client_uuid, modified_by_user_uuid, updated_at)
+values (#{ActiveRecord::Base.connection.quote Collection.generate_uuid},
+#{ActiveRecord::Base.connection.quote d['head_uuid']},
+#{ActiveRecord::Base.connection.quote d['tail_uuid']},
+#{ActiveRecord::Base.connection.quote d['name']},
+#{ActiveRecord::Base.connection.quote d['manifest_text']},
+#{ActiveRecord::Base.connection.quote d['created_at']},
+#{ActiveRecord::Base.connection.quote d['modified_at']},
+#{ActiveRecord::Base.connection.quote d['modified_by_client_uuid']},
+#{ActiveRecord::Base.connection.quote d['modified_by_user_uuid']},
+#{ActiveRecord::Base.connection.quote d['modified_at']})
+}
+      end
+      ActiveRecord::Base.connection.execute "delete from links where links.uuid in (select links.uuid #{from_clause})"
+    end
+
+    say_with_time "Step 3. Create new collection objects from the can_read links in the table." do
+      from_clause = %{
+from links inner join collections on head_uuid=collections.portable_data_hash
+where link_class='permission' and links.name='can_read' and collections.uuid is null
+}
+      links = ActiveRecord::Base.connection.select_all %{
+select links.uuid, head_uuid, tail_uuid, manifest_text, links.created_at, links.modified_at
+#{from_clause}
+}
+      links.each do |d|
+        ActiveRecord::Base.connection.execute %{
+insert into collections (uuid, portable_data_hash, owner_uuid, manifest_text, created_at, modified_at, modified_by_client_uuid, modified_by_user_uuid, updated_at)
+values (#{ActiveRecord::Base.connection.quote Collection.generate_uuid},
+#{ActiveRecord::Base.connection.quote d['head_uuid']},
+#{ActiveRecord::Base.connection.quote d['tail_uuid']},
+#{ActiveRecord::Base.connection.quote d['manifest_text']},
+#{ActiveRecord::Base.connection.quote d['created_at']},
+#{ActiveRecord::Base.connection.quote d['modified_at']},
+#{ActiveRecord::Base.connection.quote d['modified_by_client_uuid']},
+#{ActiveRecord::Base.connection.quote d['modified_by_user_uuid']},
+#{ActiveRecord::Base.connection.quote d['modified_at']})
+}
+      end
+      ActiveRecord::Base.connection.execute "delete from links where links.uuid in (select links.uuid #{from_clause})"
+    end
+
+    say_with_time "Step 4. Migrate remaining orphan collection objects" do
+      links = ActiveRecord::Base.connection.select_all %{
+select portable_data_hash, owner_uuid, manifest_text, created_at, modified_at
+from collections
+where uuid is null and portable_data_hash not in (select portable_data_hash from collections where uuid is not null)
+}
+      links.each do |d|
+        ActiveRecord::Base.connection.execute %{
+insert into collections (uuid, portable_data_hash, owner_uuid, manifest_text, created_at, modified_at, modified_by_client_uuid, modified_by_user_uuid, updated_at)
+values (#{ActiveRecord::Base.connection.quote Collection.generate_uuid},
+#{ActiveRecord::Base.connection.quote d['portable_data_hash']},
+#{ActiveRecord::Base.connection.quote d['owner_uuid']},
+#{ActiveRecord::Base.connection.quote d['manifest_text']},
+#{ActiveRecord::Base.connection.quote d['created_at']},
+#{ActiveRecord::Base.connection.quote d['modified_at']},
+#{ActiveRecord::Base.connection.quote d['modified_by_client_uuid']},
+#{ActiveRecord::Base.connection.quote d['modified_by_user_uuid']},
+#{ActiveRecord::Base.connection.quote d['modified_at']})
+}
+      end
+    end
+
+    say_with_time "Step 5. Delete old collection objects." do
+      ActiveRecord::Base.connection.execute("delete from collections where uuid is null")
+    end
+
+    say_with_time "Step 6. Delete permission links where tail_uuid is a collection (invalid records)" do
+      ActiveRecord::Base.connection.execute %{
+delete from links where links.uuid in (select links.uuid
+from links
+where tail_uuid like '________________________________+%' and link_class='permission' )
+}
+    end
 
-    ActiveRecord::Base.connection.execute("update collections set portable_data_hash=uuid, uuid=null;")
+    say_with_time "Step 7. Migrate collection -> collection provenance links to jobs" do
+      from_clause = %{
+from links
+where head_uuid like '________________________________+%' and tail_uuid like '________________________________+%' and links.link_class = 'provenance'
+}
+      links = ActiveRecord::Base.connection.select_all %{
+select links.uuid, head_uuid, tail_uuid, links.created_at, links.modified_at, links.modified_by_client_uuid, links.modified_by_user_uuid, links.owner_uuid
+#{from_clause}
+}
+      links.each do |d|
+        newuuid = Job.generate_uuid
+        ActiveRecord::Base.connection.execute %{
+insert into jobs (uuid, script_parameters, output, running, success, created_at, modified_at, modified_by_client_uuid, modified_by_user_uuid, owner_uuid, updated_at)
+values (#{ActiveRecord::Base.connection.quote newuuid},
+#{ActiveRecord::Base.connection.quote "---\ninput: "+d['tail_uuid']},
+#{ActiveRecord::Base.connection.quote d['head_uuid']},
+#{ActiveRecord::Base.connection.quote false},
+#{ActiveRecord::Base.connection.quote true},
+#{ActiveRecord::Base.connection.quote d['created_at']},
+#{ActiveRecord::Base.connection.quote d['modified_at']},
+#{ActiveRecord::Base.connection.quote d['modified_by_client_uuid']},
+#{ActiveRecord::Base.connection.quote d['modified_by_user_uuid']},
+#{ActiveRecord::Base.connection.quote d['owner_uuid']},
+#{ActiveRecord::Base.connection.quote d['modified_at']})
+}
+      end
+      ActiveRecord::Base.connection.execute "delete from links where links.uuid in (select links.uuid #{from_clause})"
+    end
 
-    data = ActiveRecord::Base.connection.select_all("select head_uuid, tail_uuid, links.name, manifest_text from links inner join collections on head_uuid=collections.portable_data_hash where link_class='name'")
-    created_at = Time.now
-    data.each do |d|
-      c = Collection.generate_uuid
-      s = "insert into collections (uuid, portable_data_hash, owner_uuid, name, manifest_text, created_at, updated_at) values (#{ActiveRecord::Base.connection.quote c}, #{ActiveRecord::Base.connection.quote d['head_uuid']}, #{ActiveRecord::Base.connection.quote d['tail_uuid']}, #{ActiveRecord::Base.connection.quote d['name']}, #{ActiveRecord::Base.connection.quote d['manifest_text']}, #{ActiveRecord::Base.connection.quote created_at}, #{ActiveRecord::Base.connection.quote created_at})"
-      ActiveRecord::Base.connection.execute(s)
+    say_with_time "Step 8. Migrate remaining links with head_uuid pointing to collections" do
+      from_clause = %{
+from links inner join collections on links.head_uuid=portable_data_hash
+where collections.uuid is not null
+}
+      links = ActiveRecord::Base.connection.select_all %{
+select links.uuid, collections.uuid as collectionuuid, tail_uuid, link_class, links.properties,
+links.name, links.created_at, links.modified_at, links.modified_by_client_uuid, links.modified_by_user_uuid, links.owner_uuid
+#{from_clause}
+}
+      links.each do |d|
+        ActiveRecord::Base.connection.execute %{
+insert into links (uuid, head_uuid, tail_uuid, link_class, name, properties, created_at, modified_at, modified_by_client_uuid, modified_by_user_uuid, owner_uuid, updated_at)
+values (#{ActiveRecord::Base.connection.quote Link.generate_uuid},
+#{ActiveRecord::Base.connection.quote d['collectionuuid']},
+#{ActiveRecord::Base.connection.quote d['tail_uuid']},
+#{ActiveRecord::Base.connection.quote d['link_class']},
+#{ActiveRecord::Base.connection.quote d['name']},
+#{ActiveRecord::Base.connection.quote d['properties']},
+#{ActiveRecord::Base.connection.quote d['created_at']},
+#{ActiveRecord::Base.connection.quote d['modified_at']},
+#{ActiveRecord::Base.connection.quote d['modified_by_client_uuid']},
+#{ActiveRecord::Base.connection.quote d['modified_by_user_uuid']},
+#{ActiveRecord::Base.connection.quote d['owner_uuid']},
+#{ActiveRecord::Base.connection.quote d['modified_at']})
+}
+      end
+      ActiveRecord::Base.connection.execute "delete from links where links.uuid in (select links.uuid #{from_clause})"
     end
 
-    data = ActiveRecord::Base.connection.select_all("select head_uuid, tail_uuid, manifest_text from links inner join collections on head_uuid=collections.portable_data_hash where link_class='permission' and links.name='can_read'")
-    created_at = Time.now
-    data.each do |d|
-      c = Collection.generate_uuid
-      s = "insert into collections (uuid, portable_data_hash, owner_uuid, name, manifest_text, created_at, updated_at) values (#{ActiveRecord::Base.connection.quote c}, #{ActiveRecord::Base.connection.quote d['head_uuid']}, #{ActiveRecord::Base.connection.quote d['tail_uuid']}, #{ActiveRecord::Base.connection.quote 'something something'}, #{ActiveRecord::Base.connection.quote d['manifest_text']}, #{ActiveRecord::Base.connection.quote created_at}, #{ActiveRecord::Base.connection.quote created_at})"
-      ActiveRecord::Base.connection.execute(s)
+    say_with_time "Step 9. Delete any remaining name links" do
+      ActiveRecord::Base.connection.execute("delete from links where link_class='name'")
     end
 
+    say_with_time "Step 10. Validate links table" do
+      links = ActiveRecord::Base.connection.select_all %{
+select links.uuid, head_uuid, tail_uuid, link_class, name
+from links
+where head_uuid like '________________________________+%' or tail_uuid like '________________________________+%'
+}
+      links.each do |d|
+        raise "Bad row #{d}"
+      end
+    end
 
   end
 
   def down
-    #remove_column :collections, :name
-    #remove_column :collections, :description
-    #remove_column :collections, :properties
-
+    raise ActiveRecord::IrreversibleMigration, "Can't downmigrate changes to collections and links without potentially losing data."
   end
 end