sql_migrations 2.1.0.pre2 → 2.1.0.pre3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a937f095c9b3ddd985e5d2a1794711b46096ac7a
4
- data.tar.gz: 3c4fa8831f5dd444265ad9ca0d2d2a804b484e98
3
+ metadata.gz: 9522fb2b47a3d5a48d724c2b452013756df04608
4
+ data.tar.gz: f2c3fa4aca5e5c87d173a5d80c9294c5e5957ca1
5
5
  SHA512:
6
- metadata.gz: 7a8232c7f4cfe99c3c3ebf2a5afbfa0e25b092f4102c81aca32e47a7a71112f8ef2b4a2e3ef0aa97b31b8b31828f24984813135ec0683a156b14c48d1f820810
7
- data.tar.gz: 2e591e9d7c2ab71b9e745ee8596947a3e0af17b5d971914273bf5cc27ebfabe305081d08db3b9c6fcd99cfe09b0ec8cef7a952d6e9edd15a38f94f4dc6ff3119
6
+ metadata.gz: 3f7c4b21c50dd78dcdfe0505c97cc9fe7a9e6f09bc42c0fd5750f121cd68df1da105a0ba59ef028e105804c25aa14a4b2f3f44e48c285d95e77637ae19b73c8e
7
+ data.tar.gz: 5fa155c9c61d31c69d73d148b4f731001535e806453a82d833aa514878e228fe67424c5d8b502b1e2eeaa157c31181211f053c9eaba1de529d1c51b687fe31d8
data/.rubocop.yml ADDED
@@ -0,0 +1,6 @@
1
+ Metrics/LineLength:
2
+ Max: 95
3
+ Metrics/MethodLength:
4
+ Max: 18
5
+ Style/SignalException:
6
+ Enabled: false
data/README.md CHANGED
@@ -1,11 +1,11 @@
1
- # sql-migrations
1
+ # sql_migrations
2
2
 
3
3
  [![Gem Version](https://badge.fury.io/rb/sql_migrations.svg)](http://badge.fury.io/rb/sql_migrations)
4
- [![Build Status](https://travis-ci.org/grzesiek/sql-migrations.svg?branch=master)](https://travis-ci.org/grzesiek/sql-migrations)
4
+ [![Build Status](https://travis-ci.org/grzesiek/sql_migrations.svg?branch=master)](https://travis-ci.org/grzesiek/sql_migrations)
5
5
 
6
6
  Simple standalone migrations you can use with plain SQL.
7
7
 
8
- This gives you possibility to execute migrations, seed datebase (on production and in test environment with fixtures) in non-Ruby pojects.
8
+ This gives you possibility to execute migrations, seed datebase (on production and in test environment with fixtures) in non-Ruby projects.
9
9
  `sql-migrations` can work with multiple different databases, and support many db adapters.
10
10
 
11
11
  ## Why ?
@@ -47,50 +47,64 @@ For example, if you work on old Zend 1 project, and you want to take benefit fro
47
47
  4. Create database config file in `db/config/databases.yml`
48
48
 
49
49
  ```yaml
50
- default:
51
- development:
52
- adapter: mysql2
53
- encoding: utf8
54
- database: test_db_dev
55
- username: test_user
56
- password: test_pass
57
- host: 192.168.1.1
58
- test:
59
- adapter: mysql2
60
- encoding: utf8
61
- database: <%= ENV['DB_NAME'] %>
62
- username: <%= ENV['DB_USER'] %>
63
- password: <%= ENV['DB_PASS'] %>
64
- host: <%= ENV['DB_HOST'] %>
65
- production:
66
- adapter: mysql2
67
- encoding: utf8
68
- database: test_db_prod
69
- username: test_user
70
- password: test_pass
71
- host: 192.168.1.100
72
-
73
- second_db:
74
- development:
75
- adapter: mysql2
76
- encoding: utf8
77
- database: second_db_dev
78
- username: test_user
79
- password: test_pass
80
- host: 127.0.0.1
81
- test:
82
- adapter: mysql2
83
- encoding: utf8
84
- database: second_db_test
85
- username: test_user
86
- password: test_pass
87
- host: 127.0.0.1
50
+ production:
51
+ databases:
52
+ default:
53
+ adapter: mysql2
54
+ encoding: utf8
55
+ database: default_db_prod
56
+ username: prod_user
57
+ password: prod_pass
58
+ host: 192.168.1.1
59
+ options:
60
+ separator: ;
61
+
62
+ development:
63
+ databases:
64
+ default:
65
+ adapter: mysql2
66
+ encoding: utf8
67
+ database: default_db_dev
68
+ username: dev_user
69
+ password: dev_pass
70
+ host: 127.0.0.1
71
+ second_db:
72
+ adapter: mysql2
73
+ encoding: utf8
74
+ database: second_db_dev
75
+ username: test_user
76
+ password: test_pass
77
+ host: 127.0.0.1
78
+ options:
79
+ separator: ;
80
+
81
+ test:
82
+ databases:
83
+ default:
84
+ adapter: mysql2
85
+ encoding: utf8
86
+ database: <%= ENV['DB_DEFAULT_NAME'] %>
87
+ username: <%= ENV['DB_DEFAULT_USER'] %>
88
+ password: <%= ENV['DB_DEFAULT_PASS'] %>
89
+ host: <%= ENV['DB_DEFAULT_HOST'] %>
90
+ second_db:
91
+ adapter: mysql2
92
+ encoding: utf8
93
+ database: <%= ENV['DB_SECOND_NAME'] %>
94
+ username: <%= ENV['DB_SECOND_USER'] %>
95
+ password: <%= ENV['DB_SECOND_PASS'] %>
96
+ host: <%= ENV['DB_SECOND_HOST'] %>
97
+ options:
98
+ separator: ;
88
99
  ```
89
100
 
90
- Note that you need to define `default` database configuration.
91
-
92
101
  As shown above, it is possible to use ERB-like syntax to use environment variables in config.
93
102
 
103
+ `default` database configuration is optional, nonetheless if supplied it will not be necessary to create additional subdirectory to store migrations (look below).
104
+
105
+ If you have multi-statement migrations you should provide `separator` configuration variable in `options` block. `options` key is optional in YAML.
106
+
107
+
94
108
  4. Migrations/seed/fixtures can be executed using rake tasks. So you will need to create `Rakefile`:
95
109
 
96
110
  ```ruby
@@ -101,12 +115,39 @@ For example, if you work on old Zend 1 project, and you want to take benefit fro
101
115
  SqlMigrations.load_tasks
102
116
  ```
103
117
 
118
+ You can also create Rake tasks by yourself:
119
+
120
+ ```ruby
121
+ require 'sql_migrations'
122
+ SqlMigrations::Config.load!('databases.yml')
123
+
124
+ namespace :db do
125
+ desc 'Migrate database'
126
+ task :migrate do
127
+ puts '[i] Running migrations ...'
128
+ SqlMigrations.migrate
129
+ end
130
+
131
+ desc 'Seed database'
132
+ task :seed do
133
+ puts '[i] Seeding databases ...'
134
+ SqlMigrations.seed
135
+ end
136
+
137
+ desc 'Prepare databases -- migrate and seed'
138
+ task :prepare do
139
+ Rake::Task['db:migrate'].invoke
140
+ Rake::Task['db:seed'].invoke
141
+ end
142
+ end
143
+ ```
144
+
104
145
  5. It's ready !
105
146
 
106
147
 
107
148
  ## Usage
108
149
 
109
- 1. Valid migration/seed/fixture file names match agains regexp `/(\d{8})_(\d{6})_(.*)?\.sql/`. So valid filenames would be:
150
+ 1. Valid migration/seed/fixture file names match against regexp `/(\d{8})_(\d{6})_(.*)?\.sql/`. So valid filenames would be:
110
151
 
111
152
 
112
153
  20150303_180100_test_migration.sql
@@ -115,7 +156,7 @@ For example, if you work on old Zend 1 project, and you want to take benefit fro
115
156
 
116
157
  You can put plain SQL into that files.
117
158
 
118
- 2. It is possible to create migration files, seed files and fixtures inside followig directory structure:
159
+ 2. It is possible to create migration files, seed files and fixtures inside following directory structure:
119
160
 
120
161
  db/
121
162
  migrations/
@@ -142,7 +183,7 @@ For example, if you work on old Zend 1 project, and you want to take benefit fro
142
183
 
143
184
  db/
144
185
  migrations/
145
- 20150303_180100_test_migration.sql
186
+ 20150303_180100_test_migration_for_default_database.sql
146
187
  second_db/
147
188
  20150303_180101_test_migration_for_second_db.sql
148
189
 
@@ -172,7 +213,7 @@ For example, if you work on old Zend 1 project, and you want to take benefit fro
172
213
  # this will list all migrations/seed files/fixtures that where found
173
214
  rake sqlmigration:files:list
174
215
 
175
- 6. Enviroment variables
216
+ 6. Environment variables
176
217
 
177
218
  If you want to run migration on different database (for example test) specify ENV:
178
219
 
@@ -192,4 +233,4 @@ For example, if you work on old Zend 1 project, and you want to take benefit fro
192
233
 
193
234
  ## License
194
235
 
195
- This is free sofware licensed under MIT license, see LICENSE file
236
+ This is free software licensed under MIT license, see LICENSE file
data/Rakefile CHANGED
@@ -1,6 +1,13 @@
1
- require "bundler/gem_tasks"
1
+ require 'bundler/gem_tasks'
2
2
  require 'rspec/core/rake_task'
3
+ require 'rubocop/rake_task'
3
4
 
4
5
  RSpec::Core::RakeTask.new('spec')
5
- task :default => :spec
6
+ RuboCop::RakeTask.new
6
7
 
8
+ task :test do
9
+ Rake::Task['spec'].invoke
10
+ Rake::Task['rubocop'].invoke
11
+ end
12
+
13
+ task default: :test
@@ -1,36 +1,55 @@
1
1
  module SqlMigrations
2
+ # Configuration class
3
+ #
2
4
  class Config
3
5
  class << self
4
- attr_reader :options
6
+ attr_reader :env
5
7
 
6
- def load!(config_file)
7
- @options = YAML.load(ERB.new(File.new(config_file).read).result)
8
+ def load!(config_file, env = nil)
9
+ @env = (env || ENV['ENV'] || ENV['RAKE_ENV'] || :development).to_sym
10
+ config = get_config_for_env_from_file(config_file)
11
+ @databases = config[:databases]
12
+ @options = config[:options]
13
+ { databases: @databases, options: @options }
8
14
  end
9
- end
10
15
 
11
- def initialize
12
- @env = (ENV['ENV'] ||= "development").to_sym
13
- @options = self.class.options
14
- @databases = get_databases_from_config
15
- end
16
+ def databases
17
+ get_config_required(:@databases)
18
+ end
19
+
20
+ def options
21
+ get_config_optional(:@options)
22
+ end
23
+
24
+ private
16
25
 
17
- def databases
18
- @databases.map do |db|
19
- db_options = @options[db.to_s][@env.to_s]
20
- unless db_options
21
- raise "Configuration for #{db} in environment #{@env} not found !"
26
+ def get_config_required(config_variable)
27
+ config_value = instance_variable_get(config_variable)
28
+ if config_value.nil? || config_value.empty?
29
+ raise "No configuration for `#{config_variable.to_s[1..-1]}` !"
22
30
  end
23
- db_options.merge!(name: db)
31
+ config_value
32
+ end
33
+
34
+ def get_config_optional(config_variable)
35
+ config_value = instance_variable_get(config_variable)
36
+ (config_value.nil? || config_value.empty?) ? {} : config_value
24
37
  end
25
- end
26
38
 
27
- private
28
- def get_databases_from_config
29
- databases = @options.map { |k, v| k.to_sym }
30
- unless databases.include?(:default)
31
- raise "Default database configuration not found !"
39
+ def get_config_for_env_from_file(file)
40
+ yaml_hash = YAML.load(ERB.new(File.new(file).read).result)
41
+ config = symbolize_keys(yaml_hash)[@env]
42
+ raise LoadError, "No configuration for `#{@env}` environment found !" unless config
43
+ config
44
+ end
45
+
46
+ def symbolize_keys(hash)
47
+ hash.each_with_object({}) do |(key, value), new_hash|
48
+ new_key = key.is_a?(String) ? key.to_sym : key
49
+ new_value = value.is_a?(Hash) ? symbolize_keys(value) : value
50
+ new_hash[new_key] = new_value
51
+ end
32
52
  end
33
- databases
34
53
  end
35
54
  end
36
55
  end
@@ -1,66 +1,84 @@
1
1
  module SqlMigrations
2
+ # Class that represents database gem will connect to
3
+ #
2
4
  class Database
3
-
4
5
  SCHEMA_TABLE = :sqlmigrations_schema
5
- attr_reader :db, :name
6
+ attr_reader :name, :driver
6
7
 
7
- def initialize(options)
8
- @name = options[:name] || :default
8
+ def initialize(name, options)
9
+ @name = name
10
+ @adapter = options[:adapter]
9
11
  begin
10
- @db = self.class.connect(options)
12
+ @driver = self.class.connect(options)
11
13
  rescue
12
- puts "[-] Could not connect to database using #{options['adapter']} adapter"
14
+ puts "[-] Could not connect to `#{@name}` database using #{@adapter} adapter"
13
15
  raise
14
16
  else
15
- puts "[+] Connected to database using #{options['adapter']} adapter"
17
+ puts "[+] Connected to `#{@name}` database using #{@adapter} adapter"
16
18
  end
17
19
  install_table
18
20
  end
19
21
 
20
22
  def execute_migrations
21
- puts "[i] Executing migrations"
22
- Migration.find(@name).each { |migration| migration.execute(self) }
23
+ migrations = Migration.find(@name)
24
+ if !migrations.empty?
25
+ puts "[i] Executing migrations for `#{@name}` database"
26
+ migrations.each { |migration| migration.execute(self) }
27
+ else
28
+ puts "[i] No new migrations for `#{@name}` database"
29
+ end
23
30
  end
24
31
 
25
32
  def seed_database
26
- puts "[i] Seeding database"
27
- Seed.find(@name).each { |seed| seed.execute(self) }
33
+ seeds = Seed.find(@name)
34
+ if !seeds.empty?
35
+ puts "[i] Seeding `#{@name}` database"
36
+ seeds.each { |seed| seed.execute(self) }
37
+ else
38
+ puts "[i] No new seeds for `#{@name}` database"
39
+ end
28
40
  end
29
41
 
30
42
  def seed_with_fixtures
31
- puts "[i] Seeding test database with fixtures"
32
- Fixture.find(@name).each { |fixture| fixture.execute(self) }
43
+ fixtures = Fixture.find(@name)
44
+ if !fixtures.empty?
45
+ puts "[i] Seeding `#{@name}` database with fixtures"
46
+ fixtures.each { |fixture| fixture.execute(self) }
47
+ else
48
+ puts "[i] No new fixturess for `#{@name}` database"
49
+ end
33
50
  end
34
51
 
35
52
  def schema_dataset
36
- @db[SCHEMA_TABLE]
53
+ @driver[SCHEMA_TABLE]
37
54
  end
38
55
 
39
56
  private
40
57
 
41
58
  def self.connect(options)
42
- Sequel.connect(adapter: options['adapter'],
43
- host: options['host'],
44
- database: options['database'],
45
- user: options['username'],
46
- password: options['password'],
59
+ Sequel.connect(adapter: options[:adapter],
60
+ encoding: options[:encoding],
61
+ host: options[:host],
62
+ database: options[:database],
63
+ user: options[:username],
64
+ password: options[:password],
47
65
  test: true)
48
66
  end
49
67
 
50
68
  def install_table
51
69
  # Check if we have migrations_schema table present
52
- unless @db.table_exists?(SCHEMA_TABLE)
53
- puts "[!] Installing `#{SCHEMA_TABLE}`"
54
- @db.create_table(SCHEMA_TABLE) do
55
- primary_key :id
56
- Bignum :time
57
- DateTime :executed
58
- String :name
59
- String :type
60
- index [ :time, :type ]
61
- end
70
+ return if @driver.table_exists?(SCHEMA_TABLE)
71
+ puts "[!] Installing `#{SCHEMA_TABLE}`"
72
+ @driver.create_table(SCHEMA_TABLE) do
73
+ # rubocop:disable Style/SingleSpaceBeforeFirstArg
74
+ primary_key :id
75
+ Bignum :time
76
+ DateTime :executed
77
+ String :name
78
+ String :type
79
+ index [:time, :type]
80
+ # rubocop:enable Style/SingleSpaceBeforeFirstArg
62
81
  end
63
82
  end
64
-
65
83
  end
66
84
  end
@@ -0,0 +1,64 @@
1
+ module SqlMigrations
2
+ # Class for finding sql scripts
3
+ #
4
+ class FindScripts
5
+ class << self
6
+ def find(db_name, type)
7
+ files = []
8
+ Find.find(Dir.pwd) do |path|
9
+ file_parameters = match_file(db_name, type, path)
10
+ next unless file_parameters
11
+ file_parameters.merge!(path: path)
12
+ files << file_parameters
13
+ end
14
+ files
15
+ end
16
+
17
+ def match_file(db_dir, type, path)
18
+ # parent_dir/base_dir/filename_that_matches_regexp.sql
19
+ _filename, base_dir, parent_dir = path.split(File::SEPARATOR).last(3).reverse
20
+
21
+ # Only files that match agains regexp will do
22
+ file_parameters = file_match_regexp(File.basename(path))
23
+ return nil unless file_parameters
24
+
25
+ # Only files that lay in specific directory structure will do
26
+ file_database = file_match_directories(parent_dir, base_dir, db_dir, type)
27
+ return nil unless file_database
28
+
29
+ { date: file_parameters[1], time: file_parameters[2],
30
+ name: file_parameters[3], db_name: file_database }
31
+ end
32
+
33
+ def file_match_regexp(file_name)
34
+ file_name.match(/(\d{8})_(\d{6})_(.*)?\.sql/)
35
+ end
36
+
37
+ def file_match_directories(parent_dir, base_dir, db_dir, type)
38
+ # example: migrations/migration_file.sql
39
+ file_in_type_base_dir = (base_dir == type.to_s)
40
+ # example: migrations/some_database/migration_file.sql
41
+ file_in_type_parent_dir = (parent_dir == type.to_s)
42
+ # example migrations/some_database/migration_file.sql
43
+ file_in_db_dir = (base_dir == db_dir.to_s)
44
+
45
+ file_in_valid_db_dir = (file_in_type_parent_dir && file_in_db_dir)
46
+
47
+ # If we are matching script assigned to :default database
48
+ # scripts can be placed in base_dir or in parent dir indicating type
49
+ # and in :default base_dir
50
+ if db_dir == :default
51
+ matches = file_in_type_base_dir || file_in_valid_db_dir
52
+ file_database = :default
53
+ else
54
+ # Otherwise only files for specific type dir (migration/fixture/seed)
55
+ # and specific database dir apply
56
+ matches = file_in_valid_db_dir
57
+ file_database = base_dir.to_sym
58
+ end
59
+
60
+ matches ? file_database : nil
61
+ end
62
+ end
63
+ end
64
+ end
@@ -1,13 +1,13 @@
1
1
  module SqlMigrations
2
+ # Fixture class
3
+ #
2
4
  class Fixture < SqlScript
3
-
4
5
  def self.find(db_name)
5
6
  super(db_name, :fixture)
6
7
  end
7
8
 
8
9
  def to_s
9
- "Fixture #{@name}, datetime: #{@date + @time}"
10
+ "Fixture #{@name} for `#{@db_name}` database, datetime: #{@date + @time}"
10
11
  end
11
-
12
12
  end
13
13
  end
@@ -1,13 +1,13 @@
1
1
  module SqlMigrations
2
+ # Migration class
3
+ #
2
4
  class Migration < SqlScript
3
-
4
5
  def self.find(db_name)
5
6
  super(db_name, :migrations)
6
7
  end
7
8
 
8
9
  def to_s
9
- "Migration #{@name} for db: #{@db_name}, datetime: #{@date + @time}"
10
+ "Migration #{@name} for `#{@db_name}` database, datetime: #{@date + @time}"
10
11
  end
11
-
12
12
  end
13
13
  end
@@ -1,13 +1,13 @@
1
1
  module SqlMigrations
2
+ # Seed class
3
+ #
2
4
  class Seed < SqlScript
3
-
4
5
  def self.find(db_name)
5
6
  super(db_name, :seed)
6
7
  end
7
8
 
8
9
  def to_s
9
- "Seed data #{@name}, datetime: #{@date + @time}"
10
+ "Seed data #{@name} for `#{@db_name}` database, datetime: #{@date + @time}"
10
11
  end
11
-
12
12
  end
13
13
  end
@@ -1,26 +1,27 @@
1
1
  module SqlMigrations
2
+ # SqlScript class
3
+ #
2
4
  class SqlScript
3
-
4
5
  attr_reader :date, :time, :name
5
6
 
6
- def initialize(path, opts)
7
- @date = opts[:date]
8
- @time = opts[:time]
9
- @name = opts[:name]
10
- @path = opts[:path]
11
- @db_name = opts[:db_name]
12
- @content = File.read(path)
13
- @type = self.class.name.downcase.split('::').last
14
- @datetime = (@date + @time).to_i
7
+ def initialize(content, opts)
8
+ @content = content
9
+ @date = opts[:date]
10
+ @time = opts[:time]
11
+ @name = opts[:name]
12
+ @db_name = opts[:db_name]
13
+ @type = self.class.name.downcase.split('::').last
14
+ @datetime = (@date + @time).to_i
15
15
  end
16
16
 
17
17
  def execute(db)
18
18
  @database = db
19
- return false unless is_new?
19
+ return false unless new?
20
+ driver = @database.driver
20
21
  begin
21
- @database.db.transaction do
22
+ driver.transaction do
22
23
  @benchmark = Benchmark.measure do
23
- @database.db.run @content
24
+ statements.each { |query| driver.run(query) }
24
25
  end
25
26
  end
26
27
  rescue
@@ -31,45 +32,31 @@ module SqlMigrations
31
32
  end
32
33
  end
33
34
 
34
- def self.find(db_name, type)
35
- scripts = []
36
- Find.find(Dir.pwd) do |path|
37
- if !db_name.is_a? Array then db_name = [ db_name ] end
38
- file_date, file_time, file_name, file_db = self.file_options(db_name, type, path)
39
- next unless file_name
40
- scripts << self.new(path, date: file_date, time: file_time, name: file_name, db_name: file_db)
35
+ def statements
36
+ separator = Config.options[:separator]
37
+ if separator
38
+ statements = @content.split(separator)
39
+ statements.collect!(&:strip)
40
+ statements.reject(&:empty?)
41
+ else
42
+ [@content]
41
43
  end
42
- scripts.sort_by { |file| (file.date + file.time).to_i }
43
44
  end
44
45
 
45
- private
46
- def self.file_options(db_names, type, path)
47
-
48
- up_dir, dir, filename = path.split(File::SEPARATOR)[-3, 3]
49
-
50
- # Only files that match agains this regexp
51
- file_opts = File.basename(path).match(/(\d{8})_(\d{6})_(.*)?\.sql/)
52
- return nil unless file_opts
53
-
54
- file_in_type_dir = (dir == type.to_s)
55
- file_in_type_updir = (up_dir == type.to_s)
56
- file_in_db_dir = db_names.include?(dir.to_sym)
57
-
58
- # There is exception when we are looking for files for more than one database
59
- # or we are checking default database only
60
- if db_names == [ :default ] || db_names.count > 1
61
- return nil unless (file_in_type_dir || (file_in_db_dir && file_in_type_updir))
62
- else
63
- # Only files for specific type (migration/fixture/seed)
64
- # Only files for specific database
65
- return nil unless (file_in_db_dir && file_in_type_updir)
46
+ def self.find(db_name, type)
47
+ files = FindScripts.find(db_name, type)
48
+ scripts = files.map do |parameters|
49
+ path = parameters.delete(:path)
50
+ content = File.read(path)
51
+ new(content, parameters)
66
52
  end
67
53
 
68
- file_database = db_names.include?(dir.to_sym) ? dir : :default
69
- return file_opts[1], file_opts[2], file_opts[3], file_database
54
+ scripts.sort_by { |file| (file.date + file.time).to_i }
70
55
  end
71
56
 
72
- def is_new?
57
+ private
58
+
59
+ def new?
73
60
  schema = @database.schema_dataset
74
61
  last = schema.order(Sequel.asc(:time)).where(type: @type).last
75
62
  is_new = schema.where(time: @datetime, type: @type).count == 0
@@ -83,10 +70,10 @@ module SqlMigrations
83
70
 
84
71
  def on_success
85
72
  puts "[+] Successfully executed #{@type}, name: #{@name}"
73
+ puts " #{@type.capitalize} file: #{@date}_#{@time}_#{@name}.sql"
86
74
  puts " Benchmark: #{@benchmark}"
87
75
  schema = @database.schema_dataset
88
76
  schema.insert(time: @datetime, name: @name, type: @type, executed: DateTime.now)
89
77
  end
90
-
91
78
  end
92
79
  end
@@ -1,6 +1,6 @@
1
1
  namespace :sqlmigrations do
2
2
  namespace :files do
3
- desc "List found migration and seed files"
3
+ desc 'List found migration and seed files'
4
4
  task :list do
5
5
  SqlMigrations.list_files
6
6
  end
@@ -1,6 +1,6 @@
1
1
  namespace :sqlmigrations do
2
2
  namespace :db do
3
- desc "Run migrations"
3
+ desc 'Run migrations'
4
4
  task :migrate do
5
5
  SqlMigrations.migrate
6
6
  end
@@ -1,6 +1,6 @@
1
1
  namespace :sqlmigrations do
2
2
  namespace :db do
3
- desc "Seed database"
3
+ desc 'Seed database'
4
4
  task :seed do
5
5
  SqlMigrations.seed
6
6
  end
@@ -1,7 +1,7 @@
1
1
  namespace :sqlmigrations do
2
2
  namespace :db do
3
3
  namespace :test do
4
- desc "Seed test database with fixtures"
4
+ desc 'Seed test database with fixtures'
5
5
  task :seed do
6
6
  SqlMigrations.seed_test
7
7
  end
@@ -1,3 +1,5 @@
1
+ # SqlMigrations
2
+ #
1
3
  module SqlMigrations
2
- VERSION = "2.1.0.pre2"
4
+ VERSION = '2.1.0.pre3'
3
5
  end
@@ -8,36 +8,37 @@ require 'erb'
8
8
  require 'sql_migrations/version'
9
9
  require 'sql_migrations/database'
10
10
  require 'sql_migrations/config'
11
+ require 'sql_migrations/find_scripts'
11
12
  require 'sql_migrations/sql_script'
12
13
  require 'sql_migrations/migration'
13
14
  require 'sql_migrations/seed'
14
15
  require 'sql_migrations/fixture'
15
16
 
17
+ # SqlMigrations
18
+ #
16
19
  module SqlMigrations
17
20
  class << self
18
-
19
21
  def load_tasks
20
- load "sql_migrations/tasks/migrate.rake"
21
- load "sql_migrations/tasks/seed.rake"
22
- load "sql_migrations/tasks/seed_test.rake"
23
- load "sql_migrations/tasks/list.rake"
22
+ load 'sql_migrations/tasks/migrate.rake'
23
+ load 'sql_migrations/tasks/seed.rake'
24
+ load 'sql_migrations/tasks/seed_test.rake'
25
+ load 'sql_migrations/tasks/list.rake'
24
26
  end
25
27
 
26
28
  def migrate
27
- databases { |db| db.execute_migrations }
29
+ databases(&:execute_migrations)
28
30
  end
29
31
 
30
32
  def seed
31
- databases { |db| db.seed_database }
33
+ databases(&:seed_database)
32
34
  end
33
35
 
34
36
  def seed_test
35
- databases { |db| db.seed_with_fixtures }
37
+ databases(&:seed_with_fixtures)
36
38
  end
37
39
 
38
40
  def list_files
39
- Config.new.databases.each do |db_config|
40
- name = db_config[:name]
41
+ Config.databases.each do |name, _config|
41
42
  Migration.find(name).each { |migration| puts migration }
42
43
  Seed.find(name).each { |seed| puts seed }
43
44
  Fixture.find(name).each { |fixture| puts fixture }
@@ -45,9 +46,10 @@ module SqlMigrations
45
46
  end
46
47
 
47
48
  private
49
+
48
50
  def databases
49
- Config.new.databases.each do |db_config|
50
- db = Database.new(db_config)
51
+ Config.databases.each do |name, config|
52
+ db = Database.new(name, config)
51
53
  yield db
52
54
  end
53
55
  end
@@ -1,16 +1,40 @@
1
+ describe 'no loadable configuration file' do
2
+ it 'should raise error when config is not loaded' do
3
+ expect { SqlMigrations.list_files }.to raise_error RuntimeError
4
+ end
5
+ end
6
+
1
7
  describe 'loadable configuration file' do
2
8
  before do
3
9
  File.open('databases.yml', 'w') do |f|
4
- f.puts 'default:'
5
- f.puts ' test:'
6
- f.puts ' adapter: sqlite3'
7
- f.puts ' database: <%= ENV["DB_NAME"] %>'
10
+ f.puts 'development:'
11
+ f.puts ' databases:'
12
+ f.puts ' default:'
13
+ f.puts ' adapter: sqlite3'
14
+ f.puts ' database: <%= ENV["DB_NAME"] %>'
15
+ f.puts ' options:'
16
+ f.puts ' separator: ;'
8
17
  end
18
+ ENV['DB_NAME'] = 'test_database'
19
+ SqlMigrations::Config.load! 'databases.yml'
9
20
  end
10
21
 
11
22
  it 'should use environment variables in config' do
12
- ENV['DB_NAME'] = 'test_database'
13
- SqlMigrations::Config.load! 'databases.yml'
14
- expect(SqlMigrations::Config.options['default']['test']['database']).to eq 'test_database'
23
+ databases = SqlMigrations::Config.databases
24
+ expect(databases[:default][:database]).to eq 'test_database'
25
+ end
26
+
27
+ it 'should parse database correctly' do
28
+ databases = SqlMigrations::Config.databases[:default]
29
+ expect(databases).to eq(adapter: 'sqlite3', database: 'test_database')
30
+ end
31
+
32
+ it 'should parse options correctly' do
33
+ options = SqlMigrations::Config.options
34
+ expect(options[:separator]).to eq ';'
35
+ end
36
+
37
+ after do
38
+ ENV.delete('DB_NAME')
15
39
  end
16
40
  end
@@ -0,0 +1,28 @@
1
+ describe 'multistatement migration' do
2
+ before do
3
+ Dir.mkdir('/migrations')
4
+ File.open('/migrations/20150514_154010_test_multistatement_migration.sql', 'w') do |f|
5
+ f.puts 'CREATE TABLE multi_test_table1(col_int1 INTEGER, col_str1 STRING);'
6
+ f.puts 'CREATE TABLE multi_test_table2(col_int2 INTEGER, col_str2 STRING);'
7
+ end
8
+ allow(SqlMigrations::Config).to receive(:databases) { { default: { development: {} } } }
9
+ allow(SqlMigrations::Config).to receive(:options) { { separator: ';' } }
10
+ @migration = SqlMigrations::Migration.find(:default).first
11
+ end
12
+
13
+ it 'should have multiple statements' do
14
+ expect(@migration.statements.count).to eq 2
15
+ end
16
+
17
+ it 'should be properly executed' do
18
+ $stdout = StringIO.new
19
+ database = SqlMigrations::Database.new(:default, adapter: :sqlite)
20
+ @migration.execute(database)
21
+ expect(@sqlite_db.table_exists?(:multi_test_table1)).to be true
22
+ expect(@sqlite_db[:multi_test_table1].columns).to include(:col_int1)
23
+ expect(@sqlite_db[:multi_test_table1].columns).to include(:col_str1)
24
+ expect(@sqlite_db.table_exists?(:multi_test_table2)).to be true
25
+ expect(@sqlite_db[:multi_test_table2].columns).to include(:col_int2)
26
+ expect(@sqlite_db[:multi_test_table2].columns).to include(:col_str2)
27
+ end
28
+ end
@@ -1,26 +1,25 @@
1
1
  describe 'migrations valid order support engine' do
2
2
  before do
3
- allow(SqlMigrations::Config).to receive(:options) { { "default" => { "development" => {}}} }
3
+ allow(SqlMigrations::Config).to receive(:databases) { { default: { development: {} } } }
4
4
  $stdout = StringIO.new
5
5
  Dir.mkdir('/migrations')
6
6
  File.open('/migrations/20150305_154010_test_migration.sql', 'w') do |f|
7
- f.puts "CREATE TABLE test_table(col_int INTEGER, col_str STRING)"
7
+ f.puts 'CREATE TABLE test_table(col_int INTEGER, col_str STRING)'
8
8
  end
9
9
 
10
- @database = SqlMigrations::Database.new(name: :default, 'adapter' => :sqlite)
11
- migration = SqlMigrations::Migration.find([ :default ]).first
10
+ @database = SqlMigrations::Database.new(:default, adapter: :sqlite)
11
+ migration = SqlMigrations::Migration.find(:default).first
12
12
  migration.execute(@database)
13
13
 
14
14
  File.open('/migrations/20150305_154011_test2_migration.sql', 'w') do |f|
15
- f.puts "CREATE TABLE test_table2(col_int2 INTEGER, col_str2 STRING)"
15
+ f.puts 'CREATE TABLE test_table2(col_int2 INTEGER, col_str2 STRING)'
16
16
  end
17
17
  File.open('/migrations/20150305_154012_test3_migration.sql', 'w') do |f|
18
- f.puts "CREATE TABLE test_table3(col_int3 INTEGER, col_str3 STRING)"
18
+ f.puts 'CREATE TABLE test_table3(col_int3 INTEGER, col_str3 STRING)'
19
19
  end
20
- @migrations = SqlMigrations::Migration.find([ :default ])
20
+ @migrations = SqlMigrations::Migration.find(:default)
21
21
  end
22
22
 
23
-
24
23
  it 'should find all migrations' do
25
24
  expect(@migrations.count).to be 3
26
25
  end
@@ -35,7 +34,6 @@ describe 'migrations valid order support engine' do
35
34
  end
36
35
 
37
36
  it 'should create all tables' do
38
- database = SqlMigrations::Database.new(name: :default, 'adapter' => :sqlite)
39
37
  @migrations.each { |migration| migration.execute(@database) }
40
38
  expect(@sqlite_db.table_exists?(:test_table)).to be true
41
39
  expect(@sqlite_db[:test_table].columns).to include(:col_int)
@@ -2,10 +2,10 @@ describe 'migration' do
2
2
  before do
3
3
  Dir.mkdir('/migrations')
4
4
  File.open('/migrations/20150305_154010_test_migration.sql', 'w') do |f|
5
- f.puts "CREATE TABLE test_table(col_int INTEGER, col_str STRING)"
5
+ f.puts 'CREATE TABLE test_table(col_int INTEGER, col_str STRING)'
6
6
  end
7
- allow(SqlMigrations::Config).to receive(:options) { { "default" => { "development" => {}}} }
8
- @migration = SqlMigrations::Migration.find([ :default ]).first
7
+ allow(SqlMigrations::Config).to receive(:databases) { { default: { development: {} } } }
8
+ @migration = SqlMigrations::Migration.find(:default).first
9
9
  end
10
10
 
11
11
  it 'should be found and initialized' do
@@ -26,7 +26,7 @@ describe 'migration' do
26
26
 
27
27
  it 'should be properly executed' do
28
28
  $stdout = StringIO.new
29
- database = SqlMigrations::Database.new(name: :default, 'adapter' => :sqlite)
29
+ database = SqlMigrations::Database.new(:default, adapter: :sqlite)
30
30
  @migration.execute(database)
31
31
  expect(@sqlite_db.table_exists?(:test_table)).to be true
32
32
  expect(@sqlite_db[:test_table].columns).to include(:col_int)
@@ -1,28 +1,30 @@
1
1
  describe 'schema table in database' do
2
2
  before do
3
- allow(SqlMigrations::Config).to receive(:options) { { "default" => { "development" => {}}} }
3
+ allow(SqlMigrations::Config).to receive(:databases) { { default: {} } }
4
4
  end
5
5
 
6
6
  it 'should be created if it does not exist' do
7
7
  expect do
8
- @database = SqlMigrations::Database.new(name: :default, 'adapter' => :sqlite)
9
- end.to output("[+] Connected to database using sqlite adapter\n" +
8
+ @database = SqlMigrations::Database.new(:default, adapter: :sqlite)
9
+ end.to output("[+] Connected to `default` database using sqlite adapter\n" \
10
10
  "[!] Installing `sqlmigrations_schema`\n").to_stdout
11
- expect(@database.db.table_exists?(:sqlmigrations_schema)).to be true
11
+ expect(@database.driver.table_exists?(:sqlmigrations_schema)).to be true
12
12
  end
13
13
 
14
14
  it 'should not be create if it exists' do
15
15
  @sqlite_db.create_table(:sqlmigrations_schema) do
16
+ # rubocop:disable Style/SingleSpaceBeforeFirstArg
16
17
  primary_key :id
17
- Bignum :time
18
- DateTime :executed
19
- String :name
20
- String :type
21
- index [ :time, :type ]
18
+ Bignum :time
19
+ DateTime :executed
20
+ String :name
21
+ String :type
22
+ index [:time, :type]
23
+ # rubocop:enable Style/SingleSpaceBeforeFirstArg
22
24
  end
23
25
  expect do
24
- @database = SqlMigrations::Database.new(name: :default, 'adapter' => :sqlite)
25
- end.to output("[+] Connected to database using sqlite adapter\n").to_stdout
26
- expect(@database.db.table_exists?(:sqlmigrations_schema)).to be true
26
+ @database = SqlMigrations::Database.new(:default, adapter: :sqlite)
27
+ end.to output("[+] Connected to `default` database using sqlite adapter\n").to_stdout
28
+ expect(@database.driver.table_exists?(:sqlmigrations_schema)).to be true
27
29
  end
28
30
  end
@@ -1,3 +1,4 @@
1
+ # rubocop:disable Metrics/LineLength
1
2
  describe 'sql scripts' do
2
3
  before do
3
4
  Dir.mkdir('/migrations')
@@ -5,27 +6,41 @@ describe 'sql scripts' do
5
6
  Dir.mkdir('/fixtures')
6
7
 
7
8
  File.open('/migrations/20150305_154010_first_test_migration.sql', 'w') do |f|
8
- f.puts "CREATE TABLE first_test_table(col_int1 INTEGER, col_str1 STRING)"
9
+ f.puts 'CREATE TABLE first_test_table(col_int1 INTEGER, col_str1 STRING)'
9
10
  end
10
11
  File.open('/migrations/20150305_154011_second_test_migration.sql', 'w') do |f|
11
- f.puts "CREATE TABLE second_test_table(col_int2 INTEGER, col_str2 STRING)"
12
+ f.puts 'CREATE TABLE second_test_table(col_int2 INTEGER, col_str2 STRING)'
12
13
  end
13
14
  File.open('/seed/20150305_154010_test_seed.sql', 'w') do |f|
14
- f.puts "INSERT INTO first_test_table(col_int1, col_str1) VALUES(123, 'test_string1')"
15
- f.puts "INSERT INTO second_test_table(col_int2, col_str2) VALUES(456, 'test_string2')"
15
+ f.puts 'INSERT INTO first_test_table(col_int1, col_str1) VALUES(123, "test_string1")'
16
+ f.puts 'INSERT INTO second_test_table(col_int2, col_str2) VALUES(456, "test_string2")'
16
17
  end
17
18
  File.open('/fixtures/20150305_154010_test_test_seed', 'w') do |f|
18
- f.puts "INSERT INTO first_test2_table(col_int1, col_str1) VALUES(2123, '2test_string1')"
19
- f.puts "INSERT INTO second_test2_table(col_int2, col_str2) VALUES(2456, '2test_string2')"
19
+ f.puts 'INSERT INTO first_test2_table(col_int1, col_str1) VALUES(2123, "2test_string1")'
20
+ f.puts 'INSERT INTO second_test2_table(col_int2, col_str2) VALUES(2456, "2test_string2")'
20
21
  end
21
- allow(SqlMigrations::Config).to receive(:options) { { "default" => { "development" => {}}} }
22
+
23
+ Dir.mkdir('/migrations/test2_db')
24
+ File.open('/migrations/test2_db/20150511_144000_second_db_test_migration.sql', 'w') do |f|
25
+ f.puts 'CREATE TABLE second_db_test_table(col_int1 INTEGER, col_str1 STRING)'
26
+ end
27
+
28
+ Dir.mkdir('/migrations/default')
29
+ File.open('/migrations/default//20150511_144100_default_db_test2_migration.sql', 'w') do |f|
30
+ f.puts 'CREATE TABLE default_db_test2_table(col_int1 INTEGER, col_str1 STRING)'
31
+ end
32
+
33
+ allow(SqlMigrations::Config).to receive(:databases) { { default: {}, test2_db: {} } }
22
34
  end
23
35
 
24
36
  it 'should be found' do
25
37
  expect { SqlMigrations.list_files }.to \
26
- output("Migration first_test_migration for db: default, datetime: 20150305154010\n" +
27
- "Migration second_test_migration for db: default, datetime: 20150305154011\n" +
28
- "Seed data test_seed, datetime: 20150305154010\n").to_stdout
38
+ output("Migration first_test_migration for `default` database, datetime: 20150305154010\n" \
39
+ "Migration second_test_migration for `default` database, datetime: 20150305154011\n" \
40
+ "Migration default_db_test2_migration for `default` database, datetime: 20150511144100\n" \
41
+ "Seed data test_seed for `default` database, datetime: 20150305154010\n" \
42
+ "Migration second_db_test_migration for `test2_db` database, datetime: 20150511144000\n"
43
+ ).to_stdout
29
44
  end
30
-
31
45
  end
46
+ # rubocop:enable Metrics/LineLength
data/spec/spec_helper.rb CHANGED
@@ -3,10 +3,16 @@ require 'memfs'
3
3
  Bundler.require
4
4
 
5
5
  RSpec.configure do |config|
6
+ config.profile_examples = 2
7
+ config.order = :random
8
+ Kernel.srand config.seed
9
+
6
10
  config.before do
7
11
  @sqlite_db = Sequel.sqlite
8
12
  allow(SqlMigrations::Database).to receive(:connect) { @sqlite_db }
9
13
  MemFs.activate!
14
+ # Reset configuration for every test suite
15
+ SqlMigrations::Config.instance_eval('@databases = nil; @options = nil')
10
16
  end
11
17
 
12
18
  config.after do
@@ -4,23 +4,26 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
4
  require 'sql_migrations/version'
5
5
 
6
6
  Gem::Specification.new do |spec|
7
- spec.name = "sql_migrations"
7
+ spec.name = 'sql_migrations'
8
8
  spec.version = SqlMigrations::VERSION
9
- spec.authors = ["Grzegorz Bizon"]
10
- spec.email = ["grzegorz.bizon@ntsn.pl"]
11
- spec.summary = %q{Simple standalone migrations you can use with plain SQL}
12
- spec.homepage = "http://github.com/grzesiek/sql-migrations"
13
- spec.license = "MIT"
9
+ spec.authors = ['Grzegorz Bizon']
10
+ spec.email = ['grzegorz.bizon@ntsn.pl']
11
+ spec.summary = 'Simple standalone migrations you can use with plain SQL'
12
+ spec.homepage = 'http://github.com/grzesiek/sql_migrations'
13
+ spec.license = 'MIT'
14
14
 
15
15
  spec.files = `git ls-files -z`.split("\x0")
16
16
  spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
17
17
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
18
- spec.require_paths = ["lib"]
18
+ spec.require_paths = ['lib']
19
19
 
20
+ # rubocop:disable Style/SingleSpaceBeforeFirstArg
20
21
  spec.add_development_dependency 'rspec', '~> 3.2.0'
21
22
  spec.add_development_dependency 'sqlite3', '~> 1.3.10'
22
23
  spec.add_development_dependency 'memfs', '~> 0.4.3'
24
+ spec.add_development_dependency 'rubocop', '~> 0.31.0'
23
25
  spec.add_dependency 'bundler', '~> 1.7'
24
26
  spec.add_dependency 'rake', '~> 10.0'
25
27
  spec.add_dependency 'sequel', '~> 4.19.0'
28
+ # rubocop:enable Style/SingleSpaceBeforeFirstArg
26
29
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sql_migrations
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.0.pre2
4
+ version: 2.1.0.pre3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Grzegorz Bizon
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-05-11 00:00:00.000000000 Z
11
+ date: 2015-05-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec
@@ -52,6 +52,20 @@ dependencies:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
54
  version: 0.4.3
55
+ - !ruby/object:Gem::Dependency
56
+ name: rubocop
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: 0.31.0
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: 0.31.0
55
69
  - !ruby/object:Gem::Dependency
56
70
  name: bundler
57
71
  requirement: !ruby/object:Gem::Requirement
@@ -103,6 +117,7 @@ extra_rdoc_files: []
103
117
  files:
104
118
  - ".gitignore"
105
119
  - ".rspec"
120
+ - ".rubocop.yml"
106
121
  - ".travis.yml"
107
122
  - Gemfile
108
123
  - LICENSE
@@ -111,6 +126,7 @@ files:
111
126
  - lib/sql_migrations.rb
112
127
  - lib/sql_migrations/config.rb
113
128
  - lib/sql_migrations/database.rb
129
+ - lib/sql_migrations/find_scripts.rb
114
130
  - lib/sql_migrations/fixture.rb
115
131
  - lib/sql_migrations/migration.rb
116
132
  - lib/sql_migrations/seed.rb
@@ -121,13 +137,14 @@ files:
121
137
  - lib/sql_migrations/tasks/seed_test.rake
122
138
  - lib/sql_migrations/version.rb
123
139
  - spec/features/config_spec.rb
140
+ - spec/features/migration_multistatement_spec.rb
124
141
  - spec/features/migration_order_spec.rb
125
142
  - spec/features/migration_spec.rb
126
143
  - spec/features/schema_table_spec.rb
127
144
  - spec/features/sql_scripts_spec.rb
128
145
  - spec/spec_helper.rb
129
146
  - sql_migrations.gemspec
130
- homepage: http://github.com/grzesiek/sql-migrations
147
+ homepage: http://github.com/grzesiek/sql_migrations
131
148
  licenses:
132
149
  - MIT
133
150
  metadata: {}
@@ -153,6 +170,7 @@ specification_version: 4
153
170
  summary: Simple standalone migrations you can use with plain SQL
154
171
  test_files:
155
172
  - spec/features/config_spec.rb
173
+ - spec/features/migration_multistatement_spec.rb
156
174
  - spec/features/migration_order_spec.rb
157
175
  - spec/features/migration_spec.rb
158
176
  - spec/features/schema_table_spec.rb