sql_migrations 2.1.0.pre2 → 2.1.0.pre3

Sign up to get free protection for your applications and to get access to all the features.
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