|
1 | 1 | # frozen_string_literal: true |
2 | 2 |
|
3 | | -require 'active_record' |
| 3 | +require "activerecord-cockroachdb-adapter" |
4 | 4 | require_relative 'paths_cockroachdb' |
| 5 | +require 'support/config' # ARTest.config |
| 6 | +require 'support/connection' # ARTest.connect |
5 | 7 |
|
6 | 8 | module TemplateCreator |
7 | | - # extend self |
8 | | - |
9 | | - DEFAULT_CONNECTION_HASH = { |
10 | | - adapter: 'cockroachdb', |
11 | | - database: 'defaultdb', |
12 | | - port: 26257, |
13 | | - user: 'root', |
14 | | - host: 'localhost' |
15 | | - }.freeze |
| 9 | + class DefaultDB < ActiveRecord::Base |
| 10 | + establish_connection( |
| 11 | + adapter: 'cockroachdb', |
| 12 | + database: 'defaultdb', |
| 13 | + port: 26257, |
| 14 | + user: 'root', |
| 15 | + host: 'localhost' |
| 16 | + ) |
| 17 | + end |
16 | 18 |
|
17 | | - BACKUP_DIR = "nodelocal://self/activerecord-crdb-adapter" |
| 19 | + # Database created once the backup is finished to make sure we have a |
| 20 | + # clean backup to work with. See #template_exists? |
| 21 | + EXISTS = "exists" |
| 22 | + BACKUP_DIR = "userfile://defaultdb.public/activerecord-crdb-adapter" |
18 | 23 |
|
19 | 24 | module_function |
20 | 25 |
|
21 | | - def ar_version |
22 | | - ActiveRecord.version.version.gsub('.','') |
| 26 | + def template_version |
| 27 | + ar_version = ActiveRecord.version.version.gsub('.','_') |
| 28 | + main_schema_digest = Digest::MD5.file(SCHEMA_ROOT + "/schema.rb").hexdigest |
| 29 | + crdb_schema_digest = Digest::MD5.file("#{__dir__}/../schema/cockroachdb_specific_schema.rb").hexdigest |
| 30 | + "#{ar_version}_#{main_schema_digest}_#{crdb_schema_digest}" |
23 | 31 | end |
24 | 32 |
|
25 | 33 | def version_backup_path |
26 | | - BACKUP_DIR + "/#{ar_version}" |
| 34 | + BACKUP_DIR + "/#{template_version}" |
27 | 35 | end |
28 | 36 |
|
29 | | - def template_db_name |
30 | | - "activerecord_unittest_template#{ar_version}" |
| 37 | + def template_db_name(db_name) |
| 38 | + "#{db_name}__template__#{template_version}" |
31 | 39 | end |
32 | 40 |
|
33 | | - def connect(connection_hash=nil) |
34 | | - connection_hash = DEFAULT_CONNECTION_HASH if connection_hash.nil? |
35 | | - ActiveRecord::Base.establish_connection(connection_hash) |
| 41 | + def template_exists? |
| 42 | + template_db_exists?(EXISTS) |
36 | 43 | end |
37 | 44 |
|
38 | | - def template_db_exists? |
39 | | - ActiveRecord::Base.lease_connection.select_value("SELECT 1 FROM pg_database WHERE datname='#{template_db_name}'") == 1 |
| 45 | + def databases |
| 46 | + @databases ||=ARTest.config.dig("connections", "cockroachdb").map { |_, value| value["database"] }.uniq |
40 | 47 | end |
41 | 48 |
|
42 | | - def drop_template_db |
43 | | - ActiveRecord::Base.lease_connection.execute("DROP DATABASE #{template_db_name}") |
| 49 | + def with_template_db_names |
| 50 | + old_crdb = ARTest.config["connections"]["cockroachdb"] |
| 51 | + new_crdb = old_crdb.transform_values { _1.merge("database" => template_db_name(_1["database"])) } |
| 52 | + ARTest.config["connections"]["cockroachdb"] = new_crdb |
| 53 | + yield |
| 54 | + ensure |
| 55 | + ARTest.config["connections"]["cockroachdb"] = old_crdb |
44 | 56 | end |
45 | 57 |
|
46 | | - def create_template_db |
47 | | - ActiveRecord::Base.lease_connection.execute("CREATE DATABASE #{template_db_name}") |
| 58 | + def template_db_exists?(db_name) |
| 59 | + DefaultDB.lease_connection.select_value("SELECT 1 FROM pg_database WHERE datname='#{template_db_name(db_name)}'") == 1 |
48 | 60 | end |
49 | 61 |
|
50 | | - def load_schema |
51 | | - p 'loading schema' |
52 | | - load ARTest::CockroachDB.root_activerecord_test + '/schema/schema.rb' |
53 | | - load 'test/schema/cockroachdb_specific_schema.rb' |
| 62 | + def drop_template_db(db_name) |
| 63 | + DefaultDB.lease_connection.execute("DROP DATABASE #{template_db_name(db_name)} CASCADE") |
54 | 64 | end |
55 | 65 |
|
56 | | - def create_test_template |
57 | | - connect |
58 | | - raise "#{template_db_name} already exists. If you do not have a backup created, please drop the database and run again." if template_db_exists? |
59 | | - |
60 | | - create_template_db |
| 66 | + def create_template_db(db_name) |
| 67 | + DefaultDB.lease_connection.execute("CREATE DATABASE #{template_db_name(db_name)}") |
| 68 | + end |
61 | 69 |
|
62 | | - # switch connection to template db |
63 | | - conn = DEFAULT_CONNECTION_HASH.dup |
64 | | - conn['database'] = template_db_name |
65 | | - connect(conn) |
| 70 | + def create_test_template(&block) |
| 71 | + databases.each do |db_name| |
| 72 | + drop_template_db(db_name) if template_db_exists?(db_name) |
| 73 | + create_template_db(db_name) |
| 74 | + end |
66 | 75 |
|
67 | | - load_schema |
| 76 | + with_template_db_names do |
| 77 | + shh { ARTest.connect } |
| 78 | + block.call |
| 79 | + end |
68 | 80 |
|
69 | | - # create BACKUP to restore from |
70 | | - ActiveRecord::Base.lease_connection.execute("BACKUP DATABASE #{template_db_name} TO '#{version_backup_path}'") |
| 81 | + DefaultDB.lease_connection.execute(<<~SQL) |
| 82 | + BACKUP DATABASE #{databases.map { |db| template_db_name(db) }.join(', ')} |
| 83 | + INTO '#{version_backup_path}' |
| 84 | + SQL |
| 85 | + create_template_db(EXISTS) |
71 | 86 | end |
72 | 87 |
|
73 | | - def restore_from_template |
74 | | - connect |
75 | | - raise "The TemplateDB does not exist. Run 'rake db:create_test_template' first." unless template_db_exists? |
76 | | - |
77 | | - begin |
78 | | - ActiveRecord::Base.lease_connection.execute("DROP DATABASE activerecord_unittest") |
79 | | - rescue ActiveRecord::StatementInvalid => e |
80 | | - unless e.cause.class == PG::InvalidCatalogName |
81 | | - raise e |
| 88 | + def load_from_template(&block) |
| 89 | + create_test_template(&block) unless template_exists? |
| 90 | + databases.each do |db_name| |
| 91 | + begin |
| 92 | + DefaultDB.lease_connection.execute("DROP DATABASE #{db_name}") |
| 93 | + rescue ActiveRecord::StatementInvalid => e |
| 94 | + unless e.cause.class == PG::InvalidCatalogName |
| 95 | + raise e |
| 96 | + end |
82 | 97 | end |
| 98 | + DefaultDB.lease_connection.execute("CREATE DATABASE #{db_name}") |
| 99 | + DefaultDB.lease_connection.execute(<<~SQL) |
| 100 | + RESTORE #{template_db_name(db_name)}.* |
| 101 | + FROM LATEST IN '#{version_backup_path}' |
| 102 | + WITH into_db = '#{db_name}' |
| 103 | + SQL |
83 | 104 | end |
84 | | - ActiveRecord::Base.lease_connection.execute("CREATE DATABASE activerecord_unittest") |
| 105 | + end |
85 | 106 |
|
86 | | - ActiveRecord::Base.lease_connection.execute("RESTORE #{template_db_name}.* FROM '#{version_backup_path}' WITH into_db = 'activerecord_unittest'") |
| 107 | + private def shh |
| 108 | + original_stdout = $stdout |
| 109 | + $stdout = StringIO.new |
| 110 | + yield |
| 111 | + ensure |
| 112 | + $stdout = original_stdout |
87 | 113 | end |
88 | 114 | end |
0 commit comments