bootstrap-db 0.0.3 → 0.1.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +15 -0
- data/README.md +38 -9
- data/lib/bootstrap/db.rb +8 -0
- data/lib/bootstrap/db/adapter.rb +50 -0
- data/lib/bootstrap/db/adapter/mysql.rb +68 -0
- data/lib/bootstrap/db/adapter/postgres.rb +149 -0
- data/lib/bootstrap/db/{rake_helper.rb → command.rb} +1 -5
- data/lib/bootstrap/db/config.rb +12 -16
- data/lib/bootstrap/db/log.rb +11 -0
- data/lib/bootstrap/db/sql/rebase_time.sql +108 -0
- data/lib/bootstrap/db/tasks/bootstrap-db.rake +49 -61
- data/lib/bootstrap/db/version.rb +1 -1
- metadata +11 -14
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
NjVjNjYxOTZmYzUzMzM2MzNiOWM2M2ZmYjgwNzNiYWE3Nzk2MmY3OA==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
Y2FjNWM5MzgxNTg4N2M4MDk4ZmNjNmM5MmYzMTIxODIzNWQ3MDIxNw==
|
7
|
+
!binary "U0hBNTEy":
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
OWZlNDgxOTAyMjU5ZDAwZjY1MmExOGRmZGMxMGM2MGMzMWE0NzE5NTBmMGIz
|
10
|
+
N2Q2ZDRhNTUzOTcwNjNlZDllNjBmNmUyYWFjNDA0Zjg3NzE4MzVjOWZmOGFk
|
11
|
+
ZmIxNzk5NWY1ZTc1NWI0YjJiOTY4YThlNWJhZGNhYzVkZjliMGE=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
YzkyODRkMjEyZjViOWIyZjY4Yzc0NDNmYzJjN2QyMThkNmU3NWIzOTA5ZTJm
|
14
|
+
ZGIxYWM0NGIzYTEwZTgwY2YwYWE1MDJjNDRkN2EzZTA5NmNkNWVjMWI2YzYx
|
15
|
+
OTMxOGFmY2EwY2QzZGUyYWNlYTk5MDgxOGM5OWZhYTZiZjljN2U=
|
data/README.md
CHANGED
@@ -2,8 +2,14 @@
|
|
2
2
|
|
3
3
|
## Purpose
|
4
4
|
|
5
|
-
|
6
|
-
|
5
|
+
To be able to load and dump a database as quickly as possible.
|
6
|
+
Primary use is to load a large dataset quickly, with practical applications for running
|
7
|
+
test suites (with extensive seed data).
|
8
|
+
|
9
|
+
Some projects require extensive seed data, with many complex values, which can take excessive time to generate. The idea of this project is to create a 'snapshot' in time of this generated seed data, and be able to load almost instantly. With the time rebase task, this can also have the time and dates rebased to the current time, allowing relative time tests to work.
|
10
|
+
|
11
|
+
For example:
|
12
|
+
* Running a project with multiple customer types and scenarios, with complex underlying data. This takes around ~55 seconds to generate. You don't want to run this for *every single test* you run. So on change of the data, recreate the dump, and set the test suite to load. Now it will take ~1 second.
|
7
13
|
|
8
14
|
## Add this line to your application's Gemfile:
|
9
15
|
|
@@ -17,8 +23,8 @@ Currently accepting MySQL & Postgres databases and specifically gear to Rails ap
|
|
17
23
|
|
18
24
|
```
|
19
25
|
rake bootstrap:db:dump #Dump default to db/bootstrap/bootstrap_data.sql
|
20
|
-
rake bootstrap:db:dump
|
21
|
-
rake bootstrap:db:dump
|
26
|
+
rake bootstrap:db:dump RAILS_ENV=production #Dump specific Rails environment using database.yml
|
27
|
+
rake bootstrap:db:dump BOOTSTRAP_DIR=db/my_bootstraps/ #Dump to specific directory
|
22
28
|
rake bootstrap:db:dump FILE_NAME=live_database.dump #Dump specific file to default bootstrap location
|
23
29
|
```
|
24
30
|
|
@@ -29,14 +35,22 @@ Currently accepting MySQL & Postgres databases and specifically gear to Rails ap
|
|
29
35
|
rake bootstrap:db:dump IGNORE_TABLES='messages,incidents'
|
30
36
|
```
|
31
37
|
|
38
|
+
### Database Rebuild and Dump
|
39
|
+
|
40
|
+
Recreate the database from scratch, seed and then dump.
|
41
|
+
|
42
|
+
```
|
43
|
+
rake bootstrap:db:recreate #Dump default to db/bootstrap/bootstrap_data.sql
|
44
|
+
```
|
45
|
+
|
32
46
|
### Database Load
|
33
47
|
|
34
48
|
Load, and overwrite, current database environment with a passed file name.
|
35
49
|
|
36
50
|
```
|
37
51
|
rake bootstrap:db:load #Load default from db/bootstrap/bootstrap_data.sql
|
38
|
-
rake bootstrap:db:load
|
39
|
-
rake bootstrap:db:load
|
52
|
+
rake bootstrap:db:load RAILS_ENV=production #Load specific Rails environment using database.yml
|
53
|
+
rake bootstrap:db:load BOOTSTRAP_DIR=db/custom_dir/ #Load from specific dump directory
|
40
54
|
rake bootstrap:db:load FILE_NAME=live_database_dump.sql #Load specific file from default bootstrap location
|
41
55
|
```
|
42
56
|
|
@@ -56,6 +70,20 @@ Pass 'VERBOSE=true' if you'd like to see more information. For example:
|
|
56
70
|
rake bootstrap:db:dump VERBOSE=true
|
57
71
|
```
|
58
72
|
|
73
|
+
### Database Time Rebaser
|
74
|
+
|
75
|
+
Load, and overwrite, current database environment with a passed snapshot. Then 'rebase' all date and time values from the generated snapshot point in time to 'now'.
|
76
|
+
|
77
|
+
Working example:
|
78
|
+
* A customer may have an activity feed with a variety of tests to check date ranges of results. With the `time rebaser` task, this will actively loop over every date or time value in a db and `rebase` the time to a new point (comparing it to the generated time).
|
79
|
+
* For this to work, you can only use *relative* time tests (1.week.ago, 4.months.ago, 5.years.from.now), as the rebaser doesn't know what should be fixed and not. You cannot generate data (and snapshot the dump) with data like `Time.zone.today.beginning_of_year` and expect the test to find the data. *All* date and time fields will be shifted based on the difference between when the data was generated and the load time.
|
80
|
+
|
81
|
+
|
82
|
+
*all the same options as `bootstrap:db:load` apply here too*
|
83
|
+
```
|
84
|
+
rake bootstrap:db:load_and_rebase #Load default from db/bootstrap/bootstrap_data.sql and rebase all time and date values
|
85
|
+
```
|
86
|
+
|
59
87
|
## Requirements
|
60
88
|
|
61
89
|
* Rails
|
@@ -64,11 +92,12 @@ Pass 'VERBOSE=true' if you'd like to see more information. For example:
|
|
64
92
|
* mysql/postgresql
|
65
93
|
|
66
94
|
|
67
|
-
## TODO
|
95
|
+
## TODO
|
96
|
+
* Write extensive readme examples
|
68
97
|
* This has been quickly rebuilt from a ridiculously old project of mine (http://github.com/tommeier/bootstrap). This should be refactored into proper objects and expose classes as well as rake tasks. Fully tested.
|
69
|
-
* Proper mapping of parameter for dumping (eg. --username) to database config
|
70
98
|
* List required attributes for each database (like `host` and raise on missing)
|
71
|
-
*
|
99
|
+
* Clearly list options available to Rake tasks
|
100
|
+
* Convert rake tasks to script tasks (if 'load_config' can be loaded)
|
72
101
|
|
73
102
|
## Contributing
|
74
103
|
|
data/lib/bootstrap/db.rb
CHANGED
@@ -2,10 +2,18 @@ require 'bootstrap/db/version'
|
|
2
2
|
|
3
3
|
module Bootstrap
|
4
4
|
module Db
|
5
|
+
|
6
|
+
# Error when unable to find '.bootstrap' file when required
|
7
|
+
class MissingSettingsFileError < StandardError; end
|
5
8
|
end
|
6
9
|
end
|
7
10
|
|
8
11
|
require 'bootstrap/db/config'
|
9
12
|
require 'bootstrap/db/railtie'
|
13
|
+
require 'bootstrap/db/log'
|
14
|
+
require 'bootstrap/db/command'
|
15
|
+
require 'bootstrap/db/adapter'
|
16
|
+
require 'bootstrap/db/adapter/mysql'
|
17
|
+
require 'bootstrap/db/adapter/postgres'
|
10
18
|
|
11
19
|
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module Bootstrap
|
2
|
+
module Db
|
3
|
+
class Adapter
|
4
|
+
include Bootstrap::Db::Command
|
5
|
+
|
6
|
+
attr_reader :config, :file_name, :file_path
|
7
|
+
|
8
|
+
def initialize(config)
|
9
|
+
@config = config
|
10
|
+
|
11
|
+
@file_name = ENV['FILE_NAME'] || default_file_name
|
12
|
+
@file_path = File.expand_path(File.join(config.bootstrap_dir, file_name))
|
13
|
+
end
|
14
|
+
|
15
|
+
# implemented by adapters
|
16
|
+
def command_string
|
17
|
+
raise NotImplementedError
|
18
|
+
end
|
19
|
+
|
20
|
+
# implemented by adapters
|
21
|
+
def default_file_name
|
22
|
+
raise NotImplementedError
|
23
|
+
end
|
24
|
+
|
25
|
+
def ignore_tables
|
26
|
+
@ignore_tables ||= begin
|
27
|
+
ENV['IGNORE_TABLES'].split(',') if ENV['IGNORE_TABLES']
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def additional_parameters
|
32
|
+
@optional_parameters ||= begin
|
33
|
+
ENV['ADDITIONAL_PARAMS'].split(',') if ENV['ADDITIONAL_PARAMS']
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def current_db_time
|
38
|
+
if Time.respond_to?(:zone)
|
39
|
+
#Handle custom timezones
|
40
|
+
if time_zone = (ENV['TZ'] || ENV['ZONEBIE_TZ'])
|
41
|
+
Time.zone ||= time_zone
|
42
|
+
end
|
43
|
+
Time.zone.now
|
44
|
+
else
|
45
|
+
Time.now
|
46
|
+
end.to_formatted_s(:db)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
module Bootstrap
|
2
|
+
module Db
|
3
|
+
class Mysql < Adapter
|
4
|
+
# Config -> command line parameter
|
5
|
+
CONNECTION_MAP = {
|
6
|
+
:username => :u,
|
7
|
+
:password => :p,
|
8
|
+
:host => :h
|
9
|
+
}
|
10
|
+
|
11
|
+
# Compile connection string
|
12
|
+
def connection_string
|
13
|
+
@connection_string ||= begin
|
14
|
+
CONNECTION_MAP.inject([]) do |result, (config_name, command_name)|
|
15
|
+
config_value = config.settings[config_name.to_s]
|
16
|
+
result << "-#{command_name} '#{config_value}'" if config_value
|
17
|
+
result
|
18
|
+
end.join(' ')
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def dump!
|
23
|
+
#mysqldump --help
|
24
|
+
dump_command = [
|
25
|
+
"mysqldump",
|
26
|
+
"-q --add-drop-table --add-locks",
|
27
|
+
"--extended-insert --lock-tables",
|
28
|
+
"--single-transaction",
|
29
|
+
connection_string
|
30
|
+
]
|
31
|
+
|
32
|
+
if ignore_tables.present?
|
33
|
+
ignore_tables.each do |table_name|
|
34
|
+
dump_command << "--ignore-table='#{config.settings["database"]}.#{table_name.strip}'"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
if additional_parameters.present?
|
39
|
+
additional_parameters.each do |param|
|
40
|
+
dump_command << param
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
dump_command << "#{config.settings['database']} > #{file_path}"
|
45
|
+
|
46
|
+
display_and_execute(dump_command.join(' '))
|
47
|
+
end
|
48
|
+
|
49
|
+
def load!
|
50
|
+
#mysql --help
|
51
|
+
load_command = [
|
52
|
+
"mysql",
|
53
|
+
"-f",
|
54
|
+
connection_string,
|
55
|
+
"#{config.settings["database"]} < #{file_path}"
|
56
|
+
]
|
57
|
+
|
58
|
+
display_and_execute(load_command.join(' '))
|
59
|
+
end
|
60
|
+
|
61
|
+
private
|
62
|
+
|
63
|
+
def default_file_name
|
64
|
+
'bootstrap_data.sql'
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,149 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
module Bootstrap
|
4
|
+
module Db
|
5
|
+
class Postgres < Adapter
|
6
|
+
LOAD_COMMAND = "pg_restore"
|
7
|
+
|
8
|
+
CONNECTION_PARAMS = [ :username, :password, :host, :port ]
|
9
|
+
CONFIG_DEFAULTS = {
|
10
|
+
:port => 5423
|
11
|
+
}
|
12
|
+
|
13
|
+
# Compile connection string
|
14
|
+
def connection_string
|
15
|
+
@connection_string ||= begin
|
16
|
+
CONNECTION_PARAMS.inject([]) do |result, element|
|
17
|
+
config_value = config.settings[element.to_s] || CONFIG_DEFAULTS[element]
|
18
|
+
result << "--#{element}='#{config_value}'" if config_value
|
19
|
+
result
|
20
|
+
end.join(' ')
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def dump!
|
25
|
+
#pg_dump --help
|
26
|
+
dump_command = [
|
27
|
+
"pg_dump",
|
28
|
+
"--create --format=c",
|
29
|
+
"--file=#{file_path}",
|
30
|
+
connection_string
|
31
|
+
]
|
32
|
+
|
33
|
+
if ignore_tables.present?
|
34
|
+
ignore_tables.each do |table_name|
|
35
|
+
dump_command << "--exclude-table='#{config.settings["database"]}.#{table_name.strip}'"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
if additional_parameters.present?
|
40
|
+
additional_parameters.each do |param|
|
41
|
+
dump_command << param
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
dump_command << config.settings['database']
|
46
|
+
|
47
|
+
result = display_and_execute(dump_command.join(' '))
|
48
|
+
|
49
|
+
save_generated_time!
|
50
|
+
|
51
|
+
result
|
52
|
+
end
|
53
|
+
|
54
|
+
def load!
|
55
|
+
#pg_restore --help
|
56
|
+
load_command = [
|
57
|
+
"pg_restore",
|
58
|
+
"--single-transaction --format=c",
|
59
|
+
"--dbname='#{config.settings["database"]}'",
|
60
|
+
connection_string,
|
61
|
+
file_path
|
62
|
+
]
|
63
|
+
|
64
|
+
display_and_execute(load_command.join(' '))
|
65
|
+
end
|
66
|
+
|
67
|
+
def rebase!
|
68
|
+
generated_time = load_generated_time!
|
69
|
+
|
70
|
+
load_rebase_functions!
|
71
|
+
|
72
|
+
start_point = generated_time
|
73
|
+
rebase_to = current_db_time
|
74
|
+
|
75
|
+
rebase_cmd = "SELECT rebase_db_time('#{start_point}'::timestamp, '#{rebase_to}'::timestamp);"
|
76
|
+
result = display_and_execute("#{psql_execute} --command=#{rebase_cmd.shellescape}")
|
77
|
+
log(result.inspect)
|
78
|
+
end
|
79
|
+
|
80
|
+
private
|
81
|
+
|
82
|
+
def psql_execute
|
83
|
+
@psql_execute ||= begin
|
84
|
+
[
|
85
|
+
'psql',
|
86
|
+
connection_string,
|
87
|
+
"--dbname='#{config.settings['database']}'"
|
88
|
+
].join(' ')
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def load_rebase_functions!
|
93
|
+
function_sql_path = File.expand_path('../../sql/rebase_time.sql', __FILE__)
|
94
|
+
display_and_execute("#{psql_execute} --file='#{function_sql_path}'")
|
95
|
+
end
|
96
|
+
|
97
|
+
def default_file_name
|
98
|
+
'bootstrap_data.dump' #Custom format 'c'
|
99
|
+
end
|
100
|
+
|
101
|
+
def load_generated_time!
|
102
|
+
settings = current_settings
|
103
|
+
|
104
|
+
generated_times = settings[:generated_on]
|
105
|
+
generated_time = generated_times && generated_times[file_path]
|
106
|
+
|
107
|
+
unless generated_time
|
108
|
+
error_message =<<-ERR
|
109
|
+
Error - Cannot find generated time. Please recreate dump.
|
110
|
+
A generated time is required to know how to rebase time correctly.
|
111
|
+
Looking in: #{settings_path}
|
112
|
+
ERR
|
113
|
+
raise MissingSettingsFileError.new(error_message)
|
114
|
+
end
|
115
|
+
|
116
|
+
generated_time
|
117
|
+
end
|
118
|
+
|
119
|
+
# Save and track generated time of bootstrap
|
120
|
+
def save_generated_time!
|
121
|
+
settings = current_settings
|
122
|
+
settings[:generated_on] ||= {}
|
123
|
+
|
124
|
+
#Clear any bootstraps that may have been removed
|
125
|
+
settings[:generated_on].each do |file, generated_time|
|
126
|
+
settings[:generated_on].delete(file) unless File.exists?(file)
|
127
|
+
end
|
128
|
+
|
129
|
+
#Set current bootstrap generated time
|
130
|
+
settings[:generated_on][file_path] = current_db_time
|
131
|
+
puts settings.inspect
|
132
|
+
|
133
|
+
#Save settings file
|
134
|
+
File.open(settings_path, "w") do |file|
|
135
|
+
file.write settings.to_yaml
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
def current_settings
|
140
|
+
return {} unless File.exists?(settings_path)
|
141
|
+
YAML::load_file(settings_path) || {}
|
142
|
+
end
|
143
|
+
|
144
|
+
def settings_path
|
145
|
+
@settings_path ||= File.expand_path(File.join(config.bootstrap_dir, '.bootstrap'))
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
data/lib/bootstrap/db/config.rb
CHANGED
@@ -3,15 +3,15 @@ module Bootstrap
|
|
3
3
|
class Config
|
4
4
|
DB_CONFIG_PATH = 'config/database.yml'
|
5
5
|
|
6
|
-
attr_accessor :settings, :adapter, :
|
6
|
+
attr_accessor :settings, :adapter, :bootstrap_dir
|
7
7
|
|
8
|
-
def initialize(
|
9
|
-
self.settings =
|
10
|
-
self.adapter = settings[
|
8
|
+
def initialize(loaded_settings)
|
9
|
+
self.settings = loaded_settings[Rails.env]
|
10
|
+
self.adapter = self.settings["adapter"].to_sym
|
11
11
|
|
12
|
-
self.
|
13
|
-
|
14
|
-
|
12
|
+
self.bootstrap_dir = ENV['BOOTSTRAP_DIR'] || default_directory
|
13
|
+
|
14
|
+
ensure_bootstrap_dir_exists!
|
15
15
|
end
|
16
16
|
|
17
17
|
def self.load!(configuration_path = File.join(Rails.root, DB_CONFIG_PATH))
|
@@ -30,17 +30,13 @@ module Bootstrap
|
|
30
30
|
|
31
31
|
private
|
32
32
|
|
33
|
-
def
|
34
|
-
@
|
33
|
+
def default_directory
|
34
|
+
@default_directory ||= File.join(Rails.root, 'db', 'bootstrap')
|
35
35
|
end
|
36
36
|
|
37
|
-
def
|
38
|
-
|
39
|
-
|
40
|
-
'bootstrap_data.dump' #Custom format 'c'
|
41
|
-
else
|
42
|
-
'bootstrap_data.sql' #MySQL
|
43
|
-
end
|
37
|
+
def ensure_bootstrap_dir_exists!
|
38
|
+
#Create directories if they don't exist
|
39
|
+
Dir.mkdir bootstrap_dir unless File.exists?(bootstrap_dir)
|
44
40
|
end
|
45
41
|
end
|
46
42
|
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
-- Setup functions for being able to rebase time + date values
|
2
|
+
-- from a point the db data was generated to a new point.
|
3
|
+
|
4
|
+
-- Rebase time values to a fixed point
|
5
|
+
CREATE OR REPLACE FUNCTION rebase_time(
|
6
|
+
fixed_point timestamp,
|
7
|
+
new_point timestamp,
|
8
|
+
original_time timestamp)
|
9
|
+
RETURNS timestamp AS
|
10
|
+
$$
|
11
|
+
DECLARE
|
12
|
+
result timestamp := new_point;
|
13
|
+
BEGIN
|
14
|
+
IF (original_time = fixed_point) THEN
|
15
|
+
result := new_point;
|
16
|
+
ELSIF (original_time < fixed_point) THEN
|
17
|
+
-- Original time was set in the past
|
18
|
+
result := (new_point - (fixed_point - original_time));
|
19
|
+
ELSIF (original_time > fixed_point) THEN
|
20
|
+
-- Original time was set in the future
|
21
|
+
result := (new_point + (original_time - fixed_point));
|
22
|
+
END IF;
|
23
|
+
--RAISE NOTICE 'Original: %, New: %', original_time, result;
|
24
|
+
RETURN result;
|
25
|
+
END;
|
26
|
+
$$
|
27
|
+
LANGUAGE 'plpgsql' STABLE;
|
28
|
+
|
29
|
+
--Rebase date values to a fixed point
|
30
|
+
CREATE OR REPLACE FUNCTION rebase_date(
|
31
|
+
fixed_point date,
|
32
|
+
new_point date,
|
33
|
+
original date)
|
34
|
+
RETURNS date AS
|
35
|
+
$$
|
36
|
+
DECLARE
|
37
|
+
result date := new_point;
|
38
|
+
BEGIN
|
39
|
+
IF (original = fixed_point) THEN
|
40
|
+
result := new_point;
|
41
|
+
ELSIF (original < fixed_point) THEN
|
42
|
+
-- Original was set in the past
|
43
|
+
result := (new_point - (fixed_point - original));
|
44
|
+
ELSE
|
45
|
+
-- Original was set in the future
|
46
|
+
result := (new_point + (original - fixed_point));
|
47
|
+
END IF;
|
48
|
+
RETURN result;
|
49
|
+
END;
|
50
|
+
$$
|
51
|
+
LANGUAGE 'plpgsql' STABLE;
|
52
|
+
|
53
|
+
--Rebase all date/timestamp values in db to a fixed point
|
54
|
+
--Returns the number of rows affected
|
55
|
+
CREATE OR REPLACE FUNCTION rebase_db_time(
|
56
|
+
fixed_point timestamp,
|
57
|
+
new_point timestamp
|
58
|
+
)
|
59
|
+
RETURNS integer AS
|
60
|
+
$$
|
61
|
+
DECLARE
|
62
|
+
column_data record;
|
63
|
+
update_command varchar := '';
|
64
|
+
function_name varchar := '';
|
65
|
+
fixed_point_type varchar := '';
|
66
|
+
update_result integer := 0;
|
67
|
+
result integer := 0;
|
68
|
+
BEGIN
|
69
|
+
FOR column_data IN (
|
70
|
+
SELECT table_name, column_name, data_type
|
71
|
+
FROM information_schema.columns
|
72
|
+
WHERE
|
73
|
+
table_schema = 'public'
|
74
|
+
AND data_type IN
|
75
|
+
('timestamp without time zone',
|
76
|
+
'timestamp with time zone',
|
77
|
+
'date')
|
78
|
+
ORDER BY table_name DESC ) LOOP
|
79
|
+
--'date'
|
80
|
+
IF column_data.data_type = 'date' THEN
|
81
|
+
function_name := 'rebase_date';
|
82
|
+
ELSE
|
83
|
+
function_name := 'rebase_time';
|
84
|
+
END IF;
|
85
|
+
|
86
|
+
update_command := format('UPDATE %s SET %I = %s(%L::%s, %L::%s, %s.%s::%s);',
|
87
|
+
column_data.table_name,
|
88
|
+
column_data.column_name,
|
89
|
+
function_name,
|
90
|
+
fixed_point,
|
91
|
+
column_data.data_type,
|
92
|
+
new_point,
|
93
|
+
column_data.data_type,
|
94
|
+
column_data.table_name,
|
95
|
+
column_data.column_name,
|
96
|
+
column_data.data_type);
|
97
|
+
|
98
|
+
--RAISE EXCEPTION '%', update_command;
|
99
|
+
EXECUTE update_command;
|
100
|
+
|
101
|
+
GET DIAGNOSTICS update_result := ROW_COUNT;
|
102
|
+
result := result + update_result;
|
103
|
+
END LOOP;
|
104
|
+
--RAISE EXCEPTION '%', result;
|
105
|
+
RETURN result;
|
106
|
+
END;
|
107
|
+
$$
|
108
|
+
LANGUAGE 'plpgsql' VOLATILE;
|
@@ -1,88 +1,76 @@
|
|
1
|
-
require File.join(File.dirname(__FILE__), '../rake_helper')
|
2
|
-
|
3
1
|
namespace :bootstrap do
|
4
2
|
namespace :db do
|
5
|
-
include Bootstrap::Db::
|
3
|
+
include Bootstrap::Db::Log
|
4
|
+
|
5
|
+
desc "Recreate bootstrap (drop, create + seed)"
|
6
|
+
task :recreate => ['db:drop', 'db:setup', :dump]
|
6
7
|
|
7
8
|
desc "Dump the current database to a SQL file"
|
8
|
-
task :dump => :
|
9
|
+
task :dump => ['db:load_config'] do
|
9
10
|
config = Bootstrap::Db::Config.load!
|
10
11
|
|
11
|
-
|
12
|
-
|
13
|
-
|
12
|
+
bootstrap = case config.adapter
|
13
|
+
when :mysql
|
14
|
+
Bootstrap::Db::Mysql.new(config)
|
15
|
+
when :postgresql
|
16
|
+
Bootstrap::Db::Postgres.new(config)
|
17
|
+
else
|
18
|
+
raise "Error : Task not supported by '#{config.adapter}'"
|
19
|
+
end
|
14
20
|
|
15
|
-
|
16
|
-
Dir.mkdir config.dump_dir unless File.exists?(config.dump_dir)
|
21
|
+
log "Generating dump of database: '#{bootstrap.file_name}'"
|
17
22
|
|
18
|
-
|
23
|
+
bootstrap.dump!
|
19
24
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
default_sql_attrs += " --ignore-table=#{settings["database"]}.#{table_name.strip}"
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
if passed_params
|
31
|
-
passed_params.each do |param|
|
32
|
-
default_sql_attrs += " #{param}"
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
password_attrs = " -p#{settings["password"]}" if settings["password"]
|
37
|
-
#--all-tablespaces
|
38
|
-
display_and_execute("mysqldump #{default_sql_attrs} -h #{settings["host"]} -u #{settings["username"]}#{password_attrs} #{settings["database"]} > #{config.dump_path}")
|
25
|
+
log "Dump completed --> '#{bootstrap.file_path}'"
|
26
|
+
end
|
27
|
+
|
28
|
+
desc "Load a SQL dump into the current environment"
|
29
|
+
task :load => ['db:load_config'] do
|
30
|
+
config = Bootstrap::Db::Config.load!
|
39
31
|
|
32
|
+
bootstrap = case config.adapter
|
33
|
+
when :mysql
|
34
|
+
Bootstrap::Db::Mysql.new(config)
|
40
35
|
when :postgresql
|
41
|
-
|
42
|
-
|
36
|
+
Bootstrap::Db::Postgres.new(config)
|
37
|
+
else
|
38
|
+
raise "Task not supported by '#{config.adapter}'"
|
39
|
+
end
|
43
40
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
end
|
48
|
-
end
|
41
|
+
unless File.exists?(bootstrap.file_path)
|
42
|
+
raise "Unable to find dump at location - '#{bootstrap.file_path}'"
|
43
|
+
end
|
49
44
|
|
50
|
-
|
51
|
-
passed_params.each do |param|
|
52
|
-
default_sql_attrs += " #{param}"
|
53
|
-
end
|
54
|
-
end
|
45
|
+
log "Loading dump: '#{bootstrap.file_name}'"
|
55
46
|
|
56
|
-
|
47
|
+
bootstrap.load!
|
57
48
|
|
58
|
-
|
59
|
-
else
|
60
|
-
raise "Error : Task not supported by '#{settings['adapter']}'"
|
61
|
-
end
|
62
|
-
log "Dump completed --> '#{config.dump_path}'"
|
49
|
+
log "Database load completed..."
|
63
50
|
end
|
64
51
|
|
65
|
-
desc "Load a SQL dump
|
66
|
-
task :
|
52
|
+
desc "Load a SQL dump and rebase the time to this point in time"
|
53
|
+
task :load_and_rebase => ['db:load_config', :load] do
|
67
54
|
config = Bootstrap::Db::Config.load!
|
68
|
-
settings = config.settings[Rails.env]
|
69
|
-
raise "Unable to find dump at location - '#{config.dump_path}'" unless File.exists?(config.dump_path)
|
70
55
|
|
71
|
-
|
72
|
-
|
73
|
-
case config.adapter
|
56
|
+
bootstrap = case config.adapter
|
74
57
|
when :mysql
|
75
|
-
|
76
|
-
display_and_execute("mysql -f -h #{settings["host"]} -u #{settings["username"]}#{password_attrs.to_s} #{settings["database"]} < #{config.dump_path}")
|
58
|
+
raise "Not supported yet. Sorry"
|
77
59
|
when :postgresql
|
78
|
-
|
79
|
-
user_attribute = " --username=#{settings["username"]}" if settings['username']
|
80
|
-
display_and_execute("pg_restore #{default_sql_attrs} --host=#{settings["host"]} --port=#{settings["port"] || 5432} --dbname=#{settings["database"]}#{user_attribute} #{config.dump_path}")
|
60
|
+
Bootstrap::Db::Postgres.new(config)
|
81
61
|
else
|
82
|
-
raise "Task not supported by '#{
|
62
|
+
raise "Task not supported by '#{config.adapter}'"
|
83
63
|
end
|
84
64
|
|
85
|
-
|
65
|
+
unless File.exists?(bootstrap.file_path)
|
66
|
+
raise "Unable to find dump at location - '#{bootstrap.file_path}'"
|
67
|
+
end
|
68
|
+
|
69
|
+
log "Rebasing database time relative to now..."
|
70
|
+
|
71
|
+
bootstrap.rebase!
|
72
|
+
|
73
|
+
log "Database rebase completed..."
|
86
74
|
end
|
87
75
|
end
|
88
76
|
end
|
data/lib/bootstrap/db/version.rb
CHANGED
metadata
CHANGED
@@ -1,20 +1,18 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bootstrap-db
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
5
|
-
prerelease:
|
4
|
+
version: 0.1.3
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Tom Meier
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date: 2013-
|
11
|
+
date: 2013-08-23 00:00:00.000000000 Z
|
13
12
|
dependencies:
|
14
13
|
- !ruby/object:Gem::Dependency
|
15
14
|
name: railties
|
16
15
|
requirement: !ruby/object:Gem::Requirement
|
17
|
-
none: false
|
18
16
|
requirements:
|
19
17
|
- - ! '>='
|
20
18
|
- !ruby/object:Gem::Version
|
@@ -22,7 +20,6 @@ dependencies:
|
|
22
20
|
type: :runtime
|
23
21
|
prerelease: false
|
24
22
|
version_requirements: !ruby/object:Gem::Requirement
|
25
|
-
none: false
|
26
23
|
requirements:
|
27
24
|
- - ! '>='
|
28
25
|
- !ruby/object:Gem::Version
|
@@ -30,7 +27,6 @@ dependencies:
|
|
30
27
|
- !ruby/object:Gem::Dependency
|
31
28
|
name: bundler
|
32
29
|
requirement: !ruby/object:Gem::Requirement
|
33
|
-
none: false
|
34
30
|
requirements:
|
35
31
|
- - ~>
|
36
32
|
- !ruby/object:Gem::Version
|
@@ -38,7 +34,6 @@ dependencies:
|
|
38
34
|
type: :development
|
39
35
|
prerelease: false
|
40
36
|
version_requirements: !ruby/object:Gem::Requirement
|
41
|
-
none: false
|
42
37
|
requirements:
|
43
38
|
- - ~>
|
44
39
|
- !ruby/object:Gem::Version
|
@@ -46,7 +41,6 @@ dependencies:
|
|
46
41
|
- !ruby/object:Gem::Dependency
|
47
42
|
name: rake
|
48
43
|
requirement: !ruby/object:Gem::Requirement
|
49
|
-
none: false
|
50
44
|
requirements:
|
51
45
|
- - ! '>='
|
52
46
|
- !ruby/object:Gem::Version
|
@@ -54,7 +48,6 @@ dependencies:
|
|
54
48
|
type: :development
|
55
49
|
prerelease: false
|
56
50
|
version_requirements: !ruby/object:Gem::Requirement
|
57
|
-
none: false
|
58
51
|
requirements:
|
59
52
|
- - ! '>='
|
60
53
|
- !ruby/object:Gem::Version
|
@@ -73,34 +66,38 @@ files:
|
|
73
66
|
- Rakefile
|
74
67
|
- bootstrap-db.gemspec
|
75
68
|
- lib/bootstrap/db.rb
|
69
|
+
- lib/bootstrap/db/adapter.rb
|
70
|
+
- lib/bootstrap/db/adapter/mysql.rb
|
71
|
+
- lib/bootstrap/db/adapter/postgres.rb
|
72
|
+
- lib/bootstrap/db/command.rb
|
76
73
|
- lib/bootstrap/db/config.rb
|
74
|
+
- lib/bootstrap/db/log.rb
|
77
75
|
- lib/bootstrap/db/railtie.rb
|
78
|
-
- lib/bootstrap/db/
|
76
|
+
- lib/bootstrap/db/sql/rebase_time.sql
|
79
77
|
- lib/bootstrap/db/tasks/bootstrap-db.rake
|
80
78
|
- lib/bootstrap/db/version.rb
|
81
79
|
homepage: http://github.com/tommeier/bootstrap-db
|
82
80
|
licenses:
|
83
81
|
- MIT
|
82
|
+
metadata: {}
|
84
83
|
post_install_message:
|
85
84
|
rdoc_options: []
|
86
85
|
require_paths:
|
87
86
|
- lib
|
88
87
|
required_ruby_version: !ruby/object:Gem::Requirement
|
89
|
-
none: false
|
90
88
|
requirements:
|
91
89
|
- - ! '>='
|
92
90
|
- !ruby/object:Gem::Version
|
93
91
|
version: '0'
|
94
92
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
95
|
-
none: false
|
96
93
|
requirements:
|
97
94
|
- - ! '>='
|
98
95
|
- !ruby/object:Gem::Version
|
99
96
|
version: '0'
|
100
97
|
requirements: []
|
101
98
|
rubyforge_project:
|
102
|
-
rubygems_version:
|
99
|
+
rubygems_version: 2.0.7
|
103
100
|
signing_key:
|
104
|
-
specification_version:
|
101
|
+
specification_version: 4
|
105
102
|
summary: Database dump and loader
|
106
103
|
test_files: []
|