storey 0.4.0 → 0.4.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +1 -1
- data/lib/storey/dumper.rb +20 -18
- data/lib/storey/duplicator.rb +105 -73
- data/lib/storey/hstore.rb +29 -5
- data/lib/storey/migrator.rb +36 -32
- data/lib/storey/native_schema_matcher.rb +19 -0
- data/lib/storey/ruby_dumper.rb +15 -13
- data/lib/storey/sql_dumper.rb +19 -17
- data/lib/storey/suffixifier.rb +37 -0
- data/lib/storey/unsuffixifier.rb +33 -0
- data/lib/storey/version.rb +1 -1
- data/lib/storey.rb +21 -32
- data/spec/spec_helper.rb +3 -1
- data/spec/storey/duplicator_spec.rb +19 -0
- data/spec/storey/native_schema_matcher_spec.rb +35 -0
- data/spec/storey/schema_search_path_for_spec.rb +0 -2
- data/spec/storey/suffixifier_spec.rb +39 -0
- data/spec/storey/unsuffixifier_spec.rb +33 -0
- metadata +12 -68
- data/spec/storey/suffixify_spec.rb +0 -11
data/README.md
CHANGED
@@ -6,7 +6,7 @@ Heavily inspired by the Apartment gem, Storey simplifies the implementation of m
|
|
6
6
|
|
7
7
|
# Configuration
|
8
8
|
|
9
|
-
Typically set in an initializer: config/initializer/storey.rb
|
9
|
+
Typically set in an initializer: `config/initializer/storey.rb`
|
10
10
|
|
11
11
|
# Defines the tables that should stay available to all (ie in the public schema)
|
12
12
|
# Note that there's currently no way to exclude tables that aren't linked to models
|
data/lib/storey/dumper.rb
CHANGED
@@ -1,25 +1,27 @@
|
|
1
|
-
|
1
|
+
module Storey
|
2
|
+
class Dumper
|
2
3
|
|
3
|
-
|
4
|
+
delegate :dump, to: :dumper
|
4
5
|
|
5
|
-
|
6
|
-
|
7
|
-
|
6
|
+
def self.dump(*args)
|
7
|
+
self.new(*args).dump
|
8
|
+
end
|
8
9
|
|
9
|
-
|
10
|
-
|
11
|
-
|
10
|
+
def initialize(options={})
|
11
|
+
@options = options
|
12
|
+
end
|
12
13
|
|
13
|
-
|
14
|
-
|
15
|
-
|
14
|
+
def dumper
|
15
|
+
dumper_class.new(@options)
|
16
|
+
end
|
16
17
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
18
|
+
def dumper_class
|
19
|
+
schema_format = Rails.configuration.active_record.schema_format || :ruby
|
20
|
+
klass = case schema_format
|
21
|
+
when :sql; SqlDumper
|
22
|
+
when :ruby; RubyDumper
|
23
|
+
end
|
24
|
+
end
|
24
25
|
|
26
|
+
end
|
25
27
|
end
|
data/lib/storey/duplicator.rb
CHANGED
@@ -1,99 +1,131 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
def perform!
|
20
|
-
dump_schema
|
21
|
-
replace_occurances
|
22
|
-
load_schema
|
23
|
-
end
|
1
|
+
module Storey
|
2
|
+
class Duplicator
|
3
|
+
|
4
|
+
attr_accessor(:source_schema,
|
5
|
+
:target_schema,
|
6
|
+
:source_file,
|
7
|
+
:target_file,
|
8
|
+
:structure_only,
|
9
|
+
:file_prefix,
|
10
|
+
:dump_path,
|
11
|
+
:source_dump_path,
|
12
|
+
:target_dump_path)
|
13
|
+
|
14
|
+
def initialize(from_schema, to_schema, options={})
|
15
|
+
unless from_schema
|
16
|
+
fail SchemaNotFound, "cannot duplicate from nil schema"
|
17
|
+
end
|
24
18
|
|
25
|
-
|
19
|
+
self.dump_path = File.join Rails.root, 'tmp', 'schema_dumps'
|
20
|
+
self.source_dump_path = File.join self.dump_path, 'source'
|
21
|
+
self.target_dump_path = File.join self.dump_path, 'target'
|
22
|
+
self.structure_only = options[:structure_only] || false
|
23
|
+
|
24
|
+
self.source_schema = suffixify(from_schema)
|
25
|
+
self.target_schema = suffixify(to_schema)
|
26
|
+
self.file_prefix = "#{Time.now.to_i}_#{rand(100000)}"
|
27
|
+
self.source_file = File.join(
|
28
|
+
self.source_dump_path,
|
29
|
+
"#{self.file_prefix}_#{self.source_schema}.sql"
|
30
|
+
)
|
31
|
+
self.target_file = File.join(
|
32
|
+
self.target_dump_path,
|
33
|
+
"#{self.file_prefix}_#{self.target_schema}.sql"
|
34
|
+
)
|
35
|
+
end
|
26
36
|
|
27
|
-
|
28
|
-
|
29
|
-
|
37
|
+
def perform!
|
38
|
+
dump_schema
|
39
|
+
replace_occurances
|
40
|
+
load_schema
|
41
|
+
end
|
30
42
|
|
31
|
-
|
32
|
-
options[:username] ||= Storey.database_config[:username]
|
33
|
-
options[:file] ||= self.source_file
|
34
|
-
options[:schema] ||= self.source_schema
|
43
|
+
private
|
35
44
|
|
36
|
-
|
37
|
-
|
38
|
-
|
45
|
+
def dump_schema(options={})
|
46
|
+
ENV['PGPASSWORD'] = Storey.database_config[:password]
|
47
|
+
prepare_schema_dump_directories
|
39
48
|
|
40
|
-
|
41
|
-
|
49
|
+
unless Storey.database_config[:host].blank?
|
50
|
+
options[:host] ||= Storey.database_config[:host]
|
51
|
+
end
|
52
|
+
options[:username] ||= Storey.database_config[:username]
|
53
|
+
options[:file] ||= self.source_file
|
54
|
+
options[:schema] ||= self.source_schema
|
42
55
|
|
43
|
-
|
44
|
-
|
45
|
-
|
56
|
+
switches = options.map { |k, v| "--#{k}=#{v}" }
|
57
|
+
switches << '--schema-only' if self.structure_only
|
58
|
+
switches = switches.join(" ")
|
46
59
|
|
47
|
-
|
48
|
-
|
49
|
-
|
60
|
+
success = system("pg_dump #{switches} #{Storey.database_config[:database]}")
|
61
|
+
unless success
|
62
|
+
raise StoreyError, "There seems to have been a problem dumping `#{self.source_schema}` to make a copy of it into `#{self.target_schema}`"
|
63
|
+
end
|
64
|
+
end
|
50
65
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
::Storey.create_plain_schema self.target_schema
|
66
|
+
def prepare_schema_dump_directories
|
67
|
+
[self.source_dump_path, self.target_dump_path].each do |d|
|
68
|
+
FileUtils.mkdir_p(d)
|
69
|
+
end
|
56
70
|
end
|
57
71
|
|
58
|
-
|
72
|
+
def load_schema(options={})
|
73
|
+
options[:file] ||= self.target_file
|
74
|
+
switches = Storey.command_line_switches(options)
|
59
75
|
|
60
|
-
|
76
|
+
if duplicating_from_default?
|
77
|
+
# Since we are copying the source schema and we're after structure only,
|
78
|
+
# the dump_schema ended up creating a SQL file without the "CREATE SCHEMA" command
|
79
|
+
# thus we have to create it manually
|
80
|
+
::Storey.create_plain_schema self.target_schema
|
81
|
+
end
|
61
82
|
|
62
|
-
|
63
|
-
end
|
83
|
+
`psql #{switches}`
|
64
84
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
85
|
+
copy_source_schema_migrations
|
86
|
+
|
87
|
+
ENV['PGPASSWORD'] = nil
|
88
|
+
end
|
89
|
+
|
90
|
+
def copy_source_schema_migrations
|
91
|
+
::Storey.switch self.target_schema do
|
92
|
+
source_schema_migrations.each do |version|
|
93
|
+
unless target_schema_migrations.include?(version)
|
94
|
+
command = "INSERT INTO schema_migrations (version) VALUES ('#{version}');"
|
95
|
+
ActiveRecord::Base.connection.execute command
|
96
|
+
end
|
70
97
|
end
|
71
98
|
end
|
72
99
|
end
|
73
|
-
end
|
74
100
|
|
75
|
-
|
76
|
-
|
77
|
-
|
101
|
+
def source_schema_migrations
|
102
|
+
::Storey.switch(self.source_schema) do
|
103
|
+
ActiveRecord::Migrator.get_all_versions
|
104
|
+
end
|
78
105
|
end
|
79
|
-
end
|
80
106
|
|
81
|
-
|
82
|
-
|
83
|
-
|
107
|
+
def target_schema_migrations
|
108
|
+
::Storey.switch(self.target_schema) do
|
109
|
+
ActiveRecord::Migrator.get_all_versions
|
110
|
+
end
|
84
111
|
end
|
85
|
-
end
|
86
112
|
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
113
|
+
def replace_occurances
|
114
|
+
File.open(self.source_file, 'r') do |file|
|
115
|
+
file.each_line do |line|
|
116
|
+
new_line = line.gsub(/#{self.source_schema}/, self.target_schema)
|
117
|
+
File.open(self.target_file, 'a') {|tf| tf.puts new_line}
|
118
|
+
end
|
92
119
|
end
|
93
120
|
end
|
94
|
-
end
|
95
121
|
|
96
|
-
|
97
|
-
|
122
|
+
def duplicating_from_default?
|
123
|
+
::Storey.matches_default_search_path?(self.source_schema) && self.structure_only
|
124
|
+
end
|
125
|
+
|
126
|
+
def suffixify(schema_name)
|
127
|
+
Suffixifier.suffixify schema_name
|
128
|
+
end
|
129
|
+
|
98
130
|
end
|
99
131
|
end
|
data/lib/storey/hstore.rb
CHANGED
@@ -1,8 +1,32 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
1
|
+
module Storey
|
2
|
+
class Hstore
|
3
|
+
|
4
|
+
def self.install
|
5
|
+
self.new.install
|
6
|
+
end
|
7
|
+
|
8
|
+
def install
|
9
|
+
ensure_hstore_is_persistent
|
10
|
+
Storey.create 'hstore', force: true
|
11
|
+
ActiveRecord::Base.connection.execute "CREATE EXTENSION IF NOT EXISTS hstore SCHEMA #{suffixify('hstore')}"
|
12
|
+
rescue ActiveRecord::StatementInvalid => e
|
13
|
+
if e.message =~ /could not open extension control file/
|
14
|
+
fail StoreyError, "Oops! Looks like the Hstore extension is not installed. Please install it for your OS first."
|
15
|
+
end
|
16
|
+
fail e
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def ensure_hstore_is_persistent
|
22
|
+
unless Storey.persistent_schemas.include?('hstore')
|
23
|
+
fail StoreyError, 'You are attempting to install hstore data type, but the hstore schema (where the data type will be installed) is not one of the persistent schemas. Please add hstore to the list of persistent schemas.'
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def suffixify(schema_name)
|
28
|
+
Suffixifier.suffixify(schema_name)
|
29
|
+
end
|
4
30
|
|
5
|
-
Storey.create 'hstore', force: true
|
6
|
-
ActiveRecord::Base.connection.execute "CREATE EXTENSION IF NOT EXISTS hstore SCHEMA #{Storey.suffixify('hstore')}"
|
7
31
|
end
|
8
32
|
end
|
data/lib/storey/migrator.rb
CHANGED
@@ -1,44 +1,48 @@
|
|
1
|
-
module Storey
|
2
|
-
|
1
|
+
module Storey
|
2
|
+
module Migrator
|
3
3
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
4
|
+
extend self
|
5
|
+
|
6
|
+
def migrate_all
|
7
|
+
self.migrate 'public'
|
8
|
+
Dumper.dump
|
9
|
+
Storey.schemas(public: false).each do |schema|
|
10
|
+
self.migrate schema
|
11
|
+
end
|
9
12
|
end
|
10
|
-
end
|
11
13
|
|
12
|
-
|
13
|
-
|
14
|
-
|
14
|
+
def migrate(schema)
|
15
|
+
Storey.switch schema do
|
16
|
+
ActiveRecord::Migrator.migrate ActiveRecord::Migrator.migrations_path
|
17
|
+
end
|
15
18
|
end
|
16
|
-
end
|
17
19
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
20
|
+
def run(direction, schema, version)
|
21
|
+
Storey.switch schema do
|
22
|
+
ActiveRecord::Migrator.run(
|
23
|
+
direction,
|
24
|
+
ActiveRecord::Migrator.migrations_path,
|
25
|
+
version
|
26
|
+
)
|
27
|
+
end
|
25
28
|
end
|
26
|
-
end
|
27
29
|
|
28
|
-
|
29
|
-
|
30
|
-
|
30
|
+
def rollback_all(step=1)
|
31
|
+
Storey.schemas.each do |schema_name|
|
32
|
+
self.rollback(schema_name, step)
|
33
|
+
end
|
34
|
+
Dumper.dump
|
31
35
|
end
|
32
|
-
Storey::Dumper.dump
|
33
|
-
end
|
34
36
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
37
|
+
def rollback(schema, step=1)
|
38
|
+
Storey.switch schema do
|
39
|
+
puts "= Rolling back `#{schema}` #{step} steps"
|
40
|
+
ActiveRecord::Migrator.rollback(
|
41
|
+
ActiveRecord::Migrator.migrations_path,
|
42
|
+
step
|
43
|
+
)
|
44
|
+
end
|
42
45
|
end
|
46
|
+
|
43
47
|
end
|
44
48
|
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Storey
|
2
|
+
class NativeSchemaMatcher
|
3
|
+
NATIVE_SCHEMAS = ['"$user"', 'public']
|
4
|
+
|
5
|
+
def self.matches?(*args)
|
6
|
+
self.new(*args).matches?
|
7
|
+
end
|
8
|
+
|
9
|
+
def initialize(schema_name)
|
10
|
+
@schema_name = schema_name
|
11
|
+
end
|
12
|
+
|
13
|
+
def matches?
|
14
|
+
NATIVE_SCHEMAS.include?(@schema_name) ||
|
15
|
+
(NATIVE_SCHEMAS - @schema_name.split(',')).empty?
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
data/lib/storey/ruby_dumper.rb
CHANGED
@@ -1,21 +1,23 @@
|
|
1
1
|
require 'active_record/schema_dumper'
|
2
2
|
|
3
|
-
|
3
|
+
module Storey
|
4
|
+
class RubyDumper
|
4
5
|
|
5
|
-
|
6
|
-
|
7
|
-
|
6
|
+
def self.dump(*args)
|
7
|
+
self.new(*args).dump
|
8
|
+
end
|
8
9
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
10
|
+
def initialize(options={})
|
11
|
+
default_file_path = File.join(Rails.root, 'db', 'schema.rb')
|
12
|
+
@file = options[:file] || default_file_path
|
13
|
+
end
|
13
14
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
15
|
+
def dump
|
16
|
+
File.open(@file, "w:utf-8") do |file|
|
17
|
+
ActiveRecord::Base.establish_connection(Rails.env)
|
18
|
+
ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, file)
|
19
|
+
end
|
18
20
|
end
|
19
|
-
end
|
20
21
|
|
22
|
+
end
|
21
23
|
end
|
data/lib/storey/sql_dumper.rb
CHANGED
@@ -1,23 +1,25 @@
|
|
1
|
-
|
1
|
+
module Storey
|
2
|
+
class SqlDumper
|
2
3
|
|
3
|
-
|
4
|
-
|
5
|
-
|
4
|
+
def self.dump(*args)
|
5
|
+
self.new(*args).dump
|
6
|
+
end
|
6
7
|
|
7
|
-
|
8
|
-
|
9
|
-
|
8
|
+
def initialize(options={})
|
9
|
+
@file = options[:file] || File.join(Rails.root, "db", "structure.sql")
|
10
|
+
end
|
10
11
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
12
|
+
def dump
|
13
|
+
abcs = ActiveRecord::Base.configurations
|
14
|
+
set_psql_env(abcs[Rails.env])
|
15
|
+
search_path = abcs[Rails.env]['schema_search_path']
|
16
|
+
unless search_path.blank?
|
17
|
+
search_path = search_path.split(",").map{|search_path_part| "--schema=#{Shellwords.escape(search_path_part.strip)}" }.join(" ")
|
18
|
+
end
|
19
|
+
`pg_dump -i -s -x -O -f #{Shellwords.escape(@file)} #{search_path} #{Shellwords.escape(abcs[Rails.env]['database'])}`
|
20
|
+
raise 'Error dumping database' if $?.exitstatus == 1
|
21
|
+
File.open(@file, "a") { |f| f << "SET search_path TO #{ActiveRecord::Base.connection.schema_search_path};\n\n" }
|
17
22
|
end
|
18
|
-
`pg_dump -i -s -x -O -f #{Shellwords.escape(@file)} #{search_path} #{Shellwords.escape(abcs[Rails.env]['database'])}`
|
19
|
-
raise 'Error dumping database' if $?.exitstatus == 1
|
20
|
-
File.open(@file, "a") { |f| f << "SET search_path TO #{ActiveRecord::Base.connection.schema_search_path};\n\n" }
|
21
|
-
end
|
22
23
|
|
24
|
+
end
|
23
25
|
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Storey
|
2
|
+
class Suffixifier
|
3
|
+
|
4
|
+
def self.suffixify(*args)
|
5
|
+
self.new(*args).suffixify
|
6
|
+
end
|
7
|
+
|
8
|
+
def initialize(schema_name)
|
9
|
+
@schema_name = schema_name
|
10
|
+
end
|
11
|
+
|
12
|
+
def suffixify
|
13
|
+
schema_names.map do |schema_name|
|
14
|
+
if schema_name =~ /\w+#{suffix}/ || native_schema?(schema_name)
|
15
|
+
schema_name
|
16
|
+
else
|
17
|
+
"#{schema_name}#{suffix}"
|
18
|
+
end
|
19
|
+
end.join(',')
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def schema_names
|
25
|
+
@schema_names ||= @schema_name.split(',')
|
26
|
+
end
|
27
|
+
|
28
|
+
def suffix
|
29
|
+
Storey.suffix
|
30
|
+
end
|
31
|
+
|
32
|
+
def native_schema?(schema_name)
|
33
|
+
NativeSchemaMatcher.matches?(schema_name)
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Storey
|
2
|
+
class Unsuffixifier
|
3
|
+
|
4
|
+
def self.unsuffixify(*args)
|
5
|
+
self.new(*args).unsuffixify
|
6
|
+
end
|
7
|
+
|
8
|
+
def initialize(schema_name)
|
9
|
+
@schema_name = schema_name
|
10
|
+
end
|
11
|
+
|
12
|
+
def unsuffixify
|
13
|
+
schema_names.map do |schema_name|
|
14
|
+
if schema_name =~ /(["\$\w]+)#{suffix}/
|
15
|
+
$1
|
16
|
+
else
|
17
|
+
schema_name
|
18
|
+
end
|
19
|
+
end.join(',')
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def suffix
|
25
|
+
Storey.suffix
|
26
|
+
end
|
27
|
+
|
28
|
+
def schema_names
|
29
|
+
@schema_name.split(',')
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
data/lib/storey/version.rb
CHANGED
data/lib/storey.rb
CHANGED
@@ -9,6 +9,9 @@ require 'storey/hstore'
|
|
9
9
|
require 'storey/dumper'
|
10
10
|
require 'storey/ruby_dumper'
|
11
11
|
require 'storey/sql_dumper'
|
12
|
+
require 'storey/native_schema_matcher'
|
13
|
+
require 'storey/suffixifier'
|
14
|
+
require 'storey/unsuffixifier'
|
12
15
|
|
13
16
|
module Storey
|
14
17
|
RESERVED_SCHEMAS = %w(hstore)
|
@@ -87,7 +90,7 @@ module Storey
|
|
87
90
|
end
|
88
91
|
|
89
92
|
def create_plain_schema(schema_name)
|
90
|
-
name =
|
93
|
+
name = suffixify schema_name
|
91
94
|
command = %{"CREATE SCHEMA #{name}"}
|
92
95
|
switches = self.command_line_switches(command: command)
|
93
96
|
`psql #{switches}`
|
@@ -143,8 +146,7 @@ module Storey
|
|
143
146
|
path = self.schema_search_path_for(name)
|
144
147
|
|
145
148
|
unless self.schema_exists?(name)
|
146
|
-
fail(Storey::SchemaNotFound,
|
147
|
-
%{The schema "#{path}" cannot be found.})
|
149
|
+
fail(Storey::SchemaNotFound, %{The schema "#{path}" cannot be found.})
|
148
150
|
end
|
149
151
|
|
150
152
|
ActiveRecord::Base.connection.schema_search_path = path
|
@@ -159,7 +161,7 @@ module Storey
|
|
159
161
|
end
|
160
162
|
|
161
163
|
def schema_exists?(name)
|
162
|
-
schema_name =
|
164
|
+
schema_name = suffixify(name)
|
163
165
|
|
164
166
|
schemas_in_db = self.schemas(suffix: self.suffix.present?)
|
165
167
|
schemas_in_db << %("$user")
|
@@ -196,34 +198,6 @@ module Storey
|
|
196
198
|
duplicator.perform!
|
197
199
|
end
|
198
200
|
|
199
|
-
def suffixify(schema_name)
|
200
|
-
if Storey.suffix &&
|
201
|
-
!schema_name.include?(Storey.suffix) &&
|
202
|
-
!matches_default_search_path?(schema_name)
|
203
|
-
|
204
|
-
"#{schema_name}#{Storey.suffix}"
|
205
|
-
else
|
206
|
-
schema_name
|
207
|
-
end
|
208
|
-
end
|
209
|
-
|
210
|
-
def unsuffixify(name)
|
211
|
-
search_path = name
|
212
|
-
if Storey.suffix
|
213
|
-
paths = []
|
214
|
-
name.split(',').each do |schema|
|
215
|
-
result = if schema =~ /(\w+)#{Storey.suffix}/
|
216
|
-
$1
|
217
|
-
else
|
218
|
-
schema
|
219
|
-
end
|
220
|
-
paths << result
|
221
|
-
end
|
222
|
-
search_path = paths.join(',')
|
223
|
-
end
|
224
|
-
search_path
|
225
|
-
end
|
226
|
-
|
227
201
|
def matches_default_search_path?(schema_name)
|
228
202
|
paths = self.default_search_path.split(',')
|
229
203
|
paths.each do |path|
|
@@ -251,4 +225,19 @@ module Storey
|
|
251
225
|
end
|
252
226
|
end
|
253
227
|
end
|
228
|
+
|
229
|
+
private
|
230
|
+
|
231
|
+
def matches_native_schemas?(schema_name)
|
232
|
+
NativeSchemaMatcher.matches?(schema_name)
|
233
|
+
end
|
234
|
+
|
235
|
+
def suffixify(schema_name)
|
236
|
+
Suffixifier.suffixify(schema_name)
|
237
|
+
end
|
238
|
+
|
239
|
+
def unsuffixify(schema_name)
|
240
|
+
Unsuffixifier.unsuffixify schema_name
|
241
|
+
end
|
242
|
+
|
254
243
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -13,12 +13,14 @@ require 'pry'
|
|
13
13
|
|
14
14
|
RSpec.configure do |config|
|
15
15
|
config.before(:suite) do
|
16
|
+
Storey.reload_config!
|
17
|
+
|
16
18
|
# Clean the public schema
|
17
19
|
Storey.switch do
|
18
20
|
tables = ActiveRecord::Base.connection.tables
|
19
21
|
# Don't invoke DatabaseCleaner if there are no tables,
|
20
22
|
# since that library chokes and tries to drop tables without names
|
21
|
-
if tables.size != 1
|
23
|
+
if tables.size != 1 || tables[0] != 'schema_migrations'
|
22
24
|
DatabaseCleaner.clean_with :truncation
|
23
25
|
end
|
24
26
|
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Storey::Duplicator do
|
4
|
+
|
5
|
+
describe '#perform!' do
|
6
|
+
context "when the dump is a failure" do
|
7
|
+
it 'should raise an error' do
|
8
|
+
duplicator = described_class.new('non-existent-will-fail-dump', 'new')
|
9
|
+
expect {
|
10
|
+
duplicator.perform!
|
11
|
+
}.to raise_error(
|
12
|
+
Storey::StoreyError,
|
13
|
+
"There seems to have been a problem dumping `non-existent-will-fail-dump` to make a copy of it into `new`"
|
14
|
+
)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Storey::NativeSchemaMatcher do
|
4
|
+
|
5
|
+
describe '#matches?' do
|
6
|
+
context 'when the schema is "$user"' do
|
7
|
+
it 'should be true' do
|
8
|
+
m = described_class.new('"$user"')
|
9
|
+
m.matches?.should be_true
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
context 'when the schema is public' do
|
14
|
+
it 'should be true' do
|
15
|
+
m = described_class.new('public')
|
16
|
+
m.matches?.should be_true
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
context 'when given comma separated string of schemas all matching' do
|
21
|
+
it 'should be true' do
|
22
|
+
m = described_class.new('"$user",public')
|
23
|
+
m.matches?.should be_true
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
context 'when the schema is neither "$user" or public' do
|
28
|
+
it 'should be false' do
|
29
|
+
m = described_class.new('something')
|
30
|
+
m.matches?.should be_false
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
@@ -3,8 +3,6 @@ require 'spec_helper'
|
|
3
3
|
describe Storey, '#schema_search_path_for' do
|
4
4
|
|
5
5
|
context 'given a search path that is one of the persistent schemas' do
|
6
|
-
# Storey.create 'bola'
|
7
|
-
# Storey.create 'halla'
|
8
6
|
Storey.persistent_schemas = %w(halla)
|
9
7
|
Storey.schema_search_path_for('bola,halla').should == 'bola,halla'
|
10
8
|
Storey.schema_search_path_for('halla').should == 'halla'
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Storey::Suffixifier do
|
4
|
+
|
5
|
+
describe '#suffixify' do
|
6
|
+
subject do
|
7
|
+
described_class.new(schema_name).suffixify
|
8
|
+
end
|
9
|
+
|
10
|
+
context 'suffixes have been turned on' do
|
11
|
+
before { Storey.suffix = '_suff' }
|
12
|
+
|
13
|
+
context 'when the schema given has not already been suffixified' do
|
14
|
+
let(:schema_name) { 'boom' }
|
15
|
+
it { should == 'boom_suff' }
|
16
|
+
end
|
17
|
+
|
18
|
+
context 'when the schema given has already been suffixified' do
|
19
|
+
let(:schema_name) { 'boom_suff' }
|
20
|
+
it { should == 'boom_suff' }
|
21
|
+
end
|
22
|
+
|
23
|
+
context 'when given comma separated schemas' do
|
24
|
+
let(:schema_name) { '"$user",public,foo,bar,baz' }
|
25
|
+
|
26
|
+
it 'should return a comma separted schema string with the non-native schemas suffixified' do
|
27
|
+
subject.should == '"$user",public,foo_suff,bar_suff,baz_suff'
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
context 'suffixes are not on' do
|
33
|
+
before { Storey.suffix = nil }
|
34
|
+
let(:schema_name) { 'boom' }
|
35
|
+
it { should == 'boom' }
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Storey::Unsuffixifier do
|
4
|
+
|
5
|
+
describe '#unsuffixify' do
|
6
|
+
subject { described_class.new(schema_name).unsuffixify }
|
7
|
+
|
8
|
+
context 'when the suffix is set' do
|
9
|
+
before { Storey.suffix = '_buff' }
|
10
|
+
|
11
|
+
context 'when the schema name does not have a suffix' do
|
12
|
+
let(:schema_name) { 'big' }
|
13
|
+
it { should == 'big' }
|
14
|
+
end
|
15
|
+
|
16
|
+
context 'when the schema name has a suffix' do
|
17
|
+
let(:schema_name) { 'big_buff' }
|
18
|
+
it { should == 'big' }
|
19
|
+
end
|
20
|
+
|
21
|
+
context 'when the schema name is comma separated schemas' do
|
22
|
+
let(:schema_name) { '"$user",public,froo_buff,la_buff' }
|
23
|
+
it {should == '"$user",public,froo,la'}
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
context 'when the suffix is not set' do
|
28
|
+
let(:schema_name) { '"$user",public,froo_buff' }
|
29
|
+
it { should == '"$user",public,froo_buff' }
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: storey
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.
|
4
|
+
version: 0.4.1
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-
|
12
|
+
date: 2013-03-16 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rspec-rails
|
@@ -110,9 +110,12 @@ files:
|
|
110
110
|
- lib/storey/exceptions.rb
|
111
111
|
- lib/storey/hstore.rb
|
112
112
|
- lib/storey/migrator.rb
|
113
|
+
- lib/storey/native_schema_matcher.rb
|
113
114
|
- lib/storey/railtie.rb
|
114
115
|
- lib/storey/ruby_dumper.rb
|
115
116
|
- lib/storey/sql_dumper.rb
|
117
|
+
- lib/storey/suffixifier.rb
|
118
|
+
- lib/storey/unsuffixifier.rb
|
116
119
|
- lib/storey/version.rb
|
117
120
|
- lib/tasks/storey.rake
|
118
121
|
- rvmrc.sample
|
@@ -166,8 +169,10 @@ files:
|
|
166
169
|
- spec/storey/drop_spec.rb
|
167
170
|
- spec/storey/dumper_spec.rb
|
168
171
|
- spec/storey/duplicate_spec.rb
|
172
|
+
- spec/storey/duplicator_spec.rb
|
169
173
|
- spec/storey/excluded_models_spec.rb
|
170
174
|
- spec/storey/hstore_spec.rb
|
175
|
+
- spec/storey/native_schema_matcher_spec.rb
|
171
176
|
- spec/storey/persistent_schemas_spec.rb
|
172
177
|
- spec/storey/ruby_dumper_spec.rb
|
173
178
|
- spec/storey/schema_exists_spec.rb
|
@@ -175,8 +180,9 @@ files:
|
|
175
180
|
- spec/storey/schema_spec.rb
|
176
181
|
- spec/storey/schemas_spec.rb
|
177
182
|
- spec/storey/sql_dumper_spec.rb
|
178
|
-
- spec/storey/
|
183
|
+
- spec/storey/suffixifier_spec.rb
|
179
184
|
- spec/storey/switch_spec.rb
|
185
|
+
- spec/storey/unsuffixifier_spec.rb
|
180
186
|
- spec/tasks/storey_rake_spec.rb
|
181
187
|
- storey.gemspec
|
182
188
|
homepage: https://github.com/ramontayag/storey
|
@@ -193,7 +199,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
193
199
|
version: '0'
|
194
200
|
segments:
|
195
201
|
- 0
|
196
|
-
hash:
|
202
|
+
hash: 1554154607789373813
|
197
203
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
198
204
|
none: false
|
199
205
|
requirements:
|
@@ -202,73 +208,11 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
202
208
|
version: '0'
|
203
209
|
segments:
|
204
210
|
- 0
|
205
|
-
hash:
|
211
|
+
hash: 1554154607789373813
|
206
212
|
requirements: []
|
207
213
|
rubyforge_project: storey
|
208
214
|
rubygems_version: 1.8.24
|
209
215
|
signing_key:
|
210
216
|
specification_version: 3
|
211
217
|
summary: Manage multiple PostgreSQL schemas in your multi-tenant app.
|
212
|
-
test_files:
|
213
|
-
- spec/config/database.yml.sample
|
214
|
-
- spec/dummy/Rakefile
|
215
|
-
- spec/dummy/app/assets/javascripts/application.js
|
216
|
-
- spec/dummy/app/assets/stylesheets/application.css
|
217
|
-
- spec/dummy/app/controllers/application_controller.rb
|
218
|
-
- spec/dummy/app/helpers/application_helper.rb
|
219
|
-
- spec/dummy/app/mailers/.gitkeep
|
220
|
-
- spec/dummy/app/models/.gitkeep
|
221
|
-
- spec/dummy/app/models/company.rb
|
222
|
-
- spec/dummy/app/models/fake.rb
|
223
|
-
- spec/dummy/app/models/post.rb
|
224
|
-
- spec/dummy/app/views/layouts/application.html.erb
|
225
|
-
- spec/dummy/config.ru
|
226
|
-
- spec/dummy/config/application.rb
|
227
|
-
- spec/dummy/config/boot.rb
|
228
|
-
- spec/dummy/config/database.yml.sample
|
229
|
-
- spec/dummy/config/environment.rb
|
230
|
-
- spec/dummy/config/environments/development.rb
|
231
|
-
- spec/dummy/config/environments/production.rb
|
232
|
-
- spec/dummy/config/environments/test.rb
|
233
|
-
- spec/dummy/config/initializers/backtrace_silencers.rb
|
234
|
-
- spec/dummy/config/initializers/inflections.rb
|
235
|
-
- spec/dummy/config/initializers/mime_types.rb
|
236
|
-
- spec/dummy/config/initializers/secret_token.rb
|
237
|
-
- spec/dummy/config/initializers/session_store.rb
|
238
|
-
- spec/dummy/config/initializers/wrap_parameters.rb
|
239
|
-
- spec/dummy/config/locales/en.yml
|
240
|
-
- spec/dummy/config/routes.rb
|
241
|
-
- spec/dummy/db/migrate/20120115060713_create_companies.rb
|
242
|
-
- spec/dummy/db/migrate/20120115060728_create_posts.rb
|
243
|
-
- spec/dummy/db/schema.rb
|
244
|
-
- spec/dummy/lib/assets/.gitkeep
|
245
|
-
- spec/dummy/log/.gitkeep
|
246
|
-
- spec/dummy/public/404.html
|
247
|
-
- spec/dummy/public/422.html
|
248
|
-
- spec/dummy/public/500.html
|
249
|
-
- spec/dummy/public/favicon.ico
|
250
|
-
- spec/dummy/script/rails
|
251
|
-
- spec/fixtures/.gitkeep
|
252
|
-
- spec/migrator_spec.rb
|
253
|
-
- spec/spec_helper.rb
|
254
|
-
- spec/storey/command_line_switches_spec.rb
|
255
|
-
- spec/storey/configuration_spec.rb
|
256
|
-
- spec/storey/create_plain_schema_spec.rb
|
257
|
-
- spec/storey/create_spec.rb
|
258
|
-
- spec/storey/default_schema.rb
|
259
|
-
- spec/storey/default_search_path_spec.rb
|
260
|
-
- spec/storey/drop_spec.rb
|
261
|
-
- spec/storey/dumper_spec.rb
|
262
|
-
- spec/storey/duplicate_spec.rb
|
263
|
-
- spec/storey/excluded_models_spec.rb
|
264
|
-
- spec/storey/hstore_spec.rb
|
265
|
-
- spec/storey/persistent_schemas_spec.rb
|
266
|
-
- spec/storey/ruby_dumper_spec.rb
|
267
|
-
- spec/storey/schema_exists_spec.rb
|
268
|
-
- spec/storey/schema_search_path_for_spec.rb
|
269
|
-
- spec/storey/schema_spec.rb
|
270
|
-
- spec/storey/schemas_spec.rb
|
271
|
-
- spec/storey/sql_dumper_spec.rb
|
272
|
-
- spec/storey/suffixify_spec.rb
|
273
|
-
- spec/storey/switch_spec.rb
|
274
|
-
- spec/tasks/storey_rake_spec.rb
|
218
|
+
test_files: []
|
@@ -1,11 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe Storey, '.suffixify' do
|
4
|
-
context 'given a schema that is not the default schema' do
|
5
|
-
it 'should not add a suffix' do
|
6
|
-
Storey.suffix = '_doo'
|
7
|
-
Storey.suffixify('public').should == 'public'
|
8
|
-
Storey.suffixify(%{"$user",public}).should == %{"$user",public}
|
9
|
-
end
|
10
|
-
end
|
11
|
-
end
|