module Carto module Db class UserSchemaMover # Approach: move object by object (tables, views, materialized and functions) STEPS_STRATEGY = :move_schema_content_step_by_step STRATEGIES = [STEPS_STRATEGY].freeze def initialize(user) @user = user end def default_strategy STEPS_STRATEGY end def move_objects(new_schema, strategy = default_strategy) raise "Not valid: #{strategy}" unless STRATEGIES.include?(strategy) old_schema = @user.database_schema @user.database_schema = new_schema @user.this.update database_schema: new_schema send(strategy, old_schema, new_schema) end private # Moves the schema by moving tables, views... def move_schema_content_step_by_step(old_schema, new_schema) @user.in_database(as: :superuser) do |conn| database = Database.new(@user.database_name, conn) database.create_schema(new_schema) @user.db_service.rebuild_quota_trigger_with_database(conn) conn.transaction do @user.real_tables(old_schema). each { |t| move_table_to_schema(t, conn, old_schema, new_schema) } views(conn, old_schema). each { |v| move_view_to_schema(v, conn, old_schema, new_schema) } materialized_views(conn, old_schema). each { |v| move_materialized_view_to_schema(v, conn, old_schema, new_schema) } functions(conn, old_schema). each { |f| move_function_to_schema(f, conn, old_schema, new_schema) } end end end def move_table_to_schema(table, database, old_schema, new_schema) old_name = "#{old_schema}.#{table[:relname]}" was_cartodbfied = cdb_drop_triggers(table, database, old_schema) database.run(%{ ALTER TABLE #{old_name} SET SCHEMA "#{new_schema}" }) cdb_cartodbfy(table, database, new_schema) if was_cartodbfied end def cdb_drop_triggers(table, database, schema) name = "#{schema}.#{table[:relname]}" cartodbfied = Carto::UserTable.find_by_user_id_and_name(@user.id, table[:relname]).present? database.run(%{ SELECT cartodb._CDB_drop_triggers('#{name}'::REGCLASS) }) if cartodbfied cartodbfied end def cdb_cartodbfy(table, database, schema) name = "#{schema}.#{table[:relname]}" database.run(%{ SELECT cartodb.CDB_CartodbfyTable('#{schema}'::TEXT, '#{name}'::REGCLASS) }) end def move_view_to_schema(view, database, old_schema, new_schema) old_name = "#{old_schema}.#{view.name}" database.run(%{ ALTER VIEW #{old_name} SET SCHEMA "#{new_schema}" }) end def move_materialized_view_to_schema(view, database, old_schema, new_schema) old_name = "#{old_schema}.#{view.name}" database.run(%{ ALTER MATERIALIZED VIEW #{old_name} SET SCHEMA "#{new_schema}" }) end def move_function_to_schema(function, database, old_schema, new_schema) old_name = "#{old_schema}.#{function.name}" database.run(%{ ALTER FUNCTION #{old_name}(#{function.argument_data_types}) SET SCHEMA "#{new_schema}" }) end def views(db, schema = @user.database_schema, owner_role = @user.database_username) Carto::Db::Database.new(@user.database_name, db).views(schema, owner_role, 'v') end def materialized_views(db, schema = @user.database_schema, owner_role = @user.database_username) Carto::Db::Database.new(@user.database_name, db).views(schema, owner_role, 'm') end def functions(db, schema = @user.database_schema, owner_role = @user.database_username) Carto::Db::Database.new(@user.database_name, db).functions(schema, owner_role) end end end end