migsql 1.0.4

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 6dce65cec7f13004fde63a68b7b963d0378ef6ce
4
+ data.tar.gz: 314daeaf69aaeafc08238b5253efa6213ee0aba3
5
+ SHA512:
6
+ metadata.gz: 0470c77ea747a8aa646afec4ff314ecdc2c9f859bccc1c89821276a8101c65f73993dfb0ba1ebfc033f98abef24848b057319a0d02713243d9d9bae77b0e91d3
7
+ data.tar.gz: 5e441b168abd9ad87ea51124dfe3bd51fb5a6a573acee0c2a866b127507c264e7405219f35ea5e974e63196b314ef4044f4ce7b11572381208ef1aef436ed0e8
data/bin/migsql ADDED
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+ require_relative '../lib/migsql'
3
+ @app = MigSql.new
4
+ @app.handle_argv(ARGV)
data/lib/migsql/app.rb ADDED
@@ -0,0 +1,84 @@
1
+ require 'colorize'
2
+ class MigSql
3
+
4
+ def initialize
5
+ @migration = Migration.new './db/config.yml'
6
+ @migration.load
7
+ end
8
+
9
+ def handle_argv(argv)
10
+ if argv.length == 0
11
+ puts 'Usage: migsql {init|create-migration|migrate}'.white
12
+ else
13
+ case argv[0]
14
+ when 'init'
15
+ handle_init
16
+ when 'create-migration'
17
+ handle_create_migration argv
18
+ when 'migrate'
19
+ handle_migrate argv
20
+ end
21
+ end
22
+ end
23
+
24
+ def handle_init
25
+ if File.directory?('./db')
26
+ puts 'Error: the ./db directory already exists'.red
27
+ else
28
+ @migration.create_server 'example_database', '127.0.0.1', 'dbname', 'username', 'password'
29
+ @migration.save
30
+ puts 'Default configuration created in ./db/config.yml'.green
31
+ end
32
+ end
33
+
34
+ def handle_create_migration(argv)
35
+ migration_name = argv[1]
36
+ migration_server = get_migration_server(argv[2])
37
+ if !migration_server.nil?
38
+ @migration.create_migration migration_server, migration_name
39
+ end
40
+ end
41
+
42
+ def handle_migrate(argv)
43
+ if argv[1] == 'to'
44
+ migration_server = @migration.get_first_server_name
45
+ migration_target = argv[2]
46
+ else
47
+ migration_server = get_migration_server(argv[1])
48
+ migration_target = argv[3]
49
+ end
50
+ o_target = migration_target
51
+ if !migration_server.nil?
52
+ if migration_target.nil?
53
+ migration_target = @migration.get_latest_migration(migration_server)
54
+ else
55
+ migration_target = @migration.get_migration_by_name(migration_server, migration_target)
56
+ end
57
+ if !migration_target.nil?
58
+ from = @migration.get_migration_status(migration_server)
59
+ plan = @migration.get_migration_plan(migration_server, migration_target, from)
60
+ if !plan.nil?
61
+ @migration.apply_migration_plan(migration_server, plan, migration_target)
62
+ end
63
+ else
64
+ puts "Error: No migration found with name: #{o_target}".red
65
+ end
66
+ end
67
+ end
68
+
69
+ def get_migration_server(server_name)
70
+ if @migration.count_servers == 0
71
+ puts 'Error: Please run migsql init first'.red
72
+ elsif @migration.count_servers > 1 && server_name.nil?
73
+ puts 'Error: Your config has multiple servers, please specify which server to create the migration on'.red
74
+ elsif !server_name.nil? && @migration.get_server(server_name).nil?
75
+ puts "Error: No server named #{server_name} found in your config".red
76
+ nil
77
+ elsif @migration.count_servers == 1
78
+ @migration.get_first_server_name
79
+ else
80
+ server_name
81
+ end
82
+ end
83
+
84
+ end
@@ -0,0 +1,140 @@
1
+ require 'rake'
2
+ require 'fileutils'
3
+ require 'yaml'
4
+ require 'tiny_tds'
5
+ require 'colorize'
6
+ require_relative 'sqlserver'
7
+
8
+ class Migration
9
+ def initialize(path)
10
+ @path = path
11
+ @root = File.dirname(@path)
12
+ @servers = Hash.new
13
+ end
14
+
15
+ def create_server(name, address, database, username, password)
16
+ @servers[name] = SqlServer.new name, address, database, username, password
17
+ end
18
+
19
+ def get_server(name)
20
+ @servers[name]
21
+ end
22
+
23
+ def get_first_server_name
24
+ @servers.keys.first
25
+ end
26
+
27
+ def save
28
+ FileUtils::mkdir_p @root
29
+ File.open(@path, 'w') { |f| f.write @servers.to_yaml }
30
+ end
31
+
32
+ def load
33
+ if File.file?(@path)
34
+ @servers = YAML.load_file(@path)
35
+ end
36
+ end
37
+
38
+ def count_servers
39
+ @servers.length
40
+ end
41
+
42
+ def create_migration(server_name, migration_name)
43
+ if get_migration_by_name(server_name, migration_name).nil?
44
+ migration_name = "#{DateTime.now.strftime('%Q')}_#{migration_name}"
45
+ server_root = "#{@root}/#{server_name}"
46
+ up = "#{server_root}/#{migration_name}_up.sql"
47
+ down = "#{server_root}/#{migration_name}_down.sql"
48
+ FileUtils::mkdir_p server_root
49
+ FileUtils::touch up
50
+ FileUtils::touch down
51
+
52
+ puts "Migration '#{migration_name}' created.".green
53
+ puts "Up: #{up}".white
54
+ puts "Down: #{down}".white
55
+ return true
56
+ else
57
+ puts 'Error: migration name already in use'.red
58
+ return false
59
+ end
60
+ end
61
+
62
+ def get_latest_migration(server_name)
63
+ server_root = "#{@root}/#{server_name}"
64
+ latest_mig = File.basename(Dir["#{server_root}/*_up.sql"].sort.reverse[0])
65
+ /([0-9]+_.*)(_up|_down)\.sql/.match(latest_mig).captures[0]
66
+ end
67
+
68
+ def get_migration_plan(server_name, to, from)
69
+ to = to || get_latest_migration(server_name)
70
+ to_i = /([0-9]+)_?.*/.match(to).captures[0]
71
+
72
+ from_i = /([0-9]+)_?.*/.match(from).captures[0]
73
+
74
+ if to_i > from_i
75
+ plan = get_up_plan server_name, to_i, from_i
76
+ elsif to_i < from_i
77
+ plan = get_down_plan server_name, to_i, from_i
78
+ else
79
+ puts 'No migration needed, database already at current level'.green
80
+ end
81
+ return plan
82
+ end
83
+
84
+ def get_up_plan(server_name, to, from)
85
+ plan = Array.new
86
+ server_root = "#{@root}/#{server_name}"
87
+ Dir["#{server_root}/*_up.sql"].sort.each {|migration|
88
+ current_item = /([0-9]+)_?.*/.match(migration).captures[0]
89
+ if current_item > from && current_item <= to
90
+ plan.push(migration)
91
+ end
92
+ }
93
+ plan
94
+ end
95
+
96
+ def get_down_plan(server_name, to, from)
97
+ plan = Array.new
98
+ server_root = "#{@root}/#{server_name}"
99
+ Dir["#{server_root}/*_down.sql"].sort.reverse.each {|migration|
100
+ current_item = /([0-9]+)_?.*/.match(migration).captures[0]
101
+ if current_item > to && current_item <= from
102
+ plan.push(migration)
103
+ end
104
+ }
105
+ plan
106
+ end
107
+
108
+ def get_migration_by_name(server_name, name)
109
+ server_root = "#{@root}/#{server_name}"
110
+ migration = Dir["#{server_root}/*#{name}_up.sql"][0]
111
+ if !migration.nil?
112
+ migration = /([0-9]+_.*)(_up|_down)\.sql/.match(migration).captures[0]
113
+ end
114
+ return migration
115
+ end
116
+
117
+ def apply_migration_plan(server_name, migration_plan, final_state)
118
+ puts "Applying migration to: #{server_name}".yellow
119
+ migration_plan.each {|migration|
120
+ apply_migration server_name, migration
121
+ }
122
+ server = get_server(server_name)
123
+ server.set_migration_status(final_state)
124
+ puts "Migration Complete, current state: #{final_state}".green
125
+ end
126
+
127
+ def apply_migration(server_name, migration)
128
+ migration_name, updown = /([0-9]+.*)_(.*)\.sql/.match(migration).captures
129
+ puts " - #{migration_name} #{updown}".white
130
+ server = get_server(server_name)
131
+ server.apply_migration(migration)
132
+ end
133
+
134
+ def get_migration_status(server_name)
135
+ get_server(server_name).get_migration_status
136
+ end
137
+
138
+ end
139
+
140
+
@@ -0,0 +1,81 @@
1
+ require 'rake'
2
+ require 'fileutils'
3
+ require 'yaml'
4
+ require 'tiny_tds'
5
+ require 'colorize'
6
+
7
+ class SqlServer
8
+ def initialize(name, address, database, username, password)
9
+ @name = name
10
+ @address = address
11
+ @database = database
12
+ @username = username
13
+ @password = password
14
+ end
15
+
16
+ def name
17
+ return @name
18
+ end
19
+ def address
20
+ return @address
21
+ end
22
+ def database
23
+ return @database
24
+ end
25
+ def username
26
+ return @username
27
+ end
28
+ def password
29
+ return @password
30
+ end
31
+
32
+ def get_sql(name)
33
+ File.read("#{File.dirname(__FILE__)}/../../sql/#{name}.sql")
34
+ end
35
+
36
+ def get_client
37
+ TinyTds::Client.new(
38
+ :username => username,
39
+ :password => password,
40
+ :host => address,
41
+ :database => database
42
+ )
43
+ end
44
+
45
+ def get_migration_status
46
+ client = get_client
47
+ begin
48
+ results = client.execute("SELECT migration FROM _migration")
49
+ result = results.each(:first => true)[0]['migration']
50
+ if result.length == 0
51
+ return '0'
52
+ else
53
+ return result
54
+ end
55
+ rescue Exception => ex
56
+ return '0'
57
+ end
58
+ end
59
+
60
+ def set_migration_status(to)
61
+ client = get_client
62
+ sql = [
63
+ get_sql('create_migration_table'),
64
+ "UPDATE _migration SET migration = '#{to}'"
65
+ ].join(' ')
66
+ client.execute(sql).each
67
+ end
68
+
69
+ def remove_migration
70
+ client = get_client
71
+ client.execute('DROP TABLE _migration')
72
+ end
73
+
74
+ def apply_migration(path)
75
+ client = get_client
76
+ sql = File.read(path)
77
+ client.execute(sql)
78
+ end
79
+
80
+ end
81
+
data/lib/migsql.rb ADDED
@@ -0,0 +1,3 @@
1
+ require_relative 'migsql/sqlserver.rb'
2
+ require_relative 'migsql/migration.rb'
3
+ require_relative 'migsql/app.rb'
@@ -0,0 +1,14 @@
1
+ IF NOT EXISTS(SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[_migration]') AND TYPE IN (N'U'))
2
+ BEGIN
3
+ CREATE TABLE [dbo].[_migration](
4
+ [migration] [varchar](100) NOT NULL,
5
+ [date_applied] [datetime] NOT NULL
6
+ ) ON [PRIMARY];
7
+
8
+ INSERT INTO [dbo].[_migration](
9
+ migration,
10
+ date_applied
11
+ ) VALUES(
12
+ '0', '1990-01-01'
13
+ )
14
+ END
@@ -0,0 +1,5 @@
1
+ CREATE TABLE [dbo].[MigrationTest](
2
+ [col1] [int] NOT NULL,
3
+ [col2] [int] NOT NULL
4
+ ) ON [PRIMARY];
5
+
@@ -0,0 +1,2 @@
1
+ INSERT INTO MigrationTest(col1, col2)
2
+ VALUES('12345', '67890')
metadata ADDED
@@ -0,0 +1,80 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: migsql
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.4
5
+ platform: ruby
6
+ authors:
7
+ - Karl Stoney
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-06-03 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: tiny_tds
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '>='
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '>='
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: colorize
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ description: Simple lightweight up/down MSSQL migrations
42
+ email: karl@jambr.co.uk
43
+ executables:
44
+ - migsql
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - lib/migsql/migration.rb
49
+ - lib/migsql/app.rb
50
+ - lib/migsql/sqlserver.rb
51
+ - lib/migsql.rb
52
+ - bin/migsql
53
+ - sql/create_migration_table.sql
54
+ - sql/populate_test_table.sql
55
+ - sql/create_test_table.sql
56
+ homepage: https://github.com/Stono/migsql
57
+ licenses:
58
+ - MIT
59
+ metadata: {}
60
+ post_install_message:
61
+ rdoc_options: []
62
+ require_paths:
63
+ - lib
64
+ required_ruby_version: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ required_rubygems_version: !ruby/object:Gem::Requirement
70
+ requirements:
71
+ - - '>='
72
+ - !ruby/object:Gem::Version
73
+ version: '0'
74
+ requirements: []
75
+ rubyforge_project:
76
+ rubygems_version: 2.1.11
77
+ signing_key:
78
+ specification_version: 4
79
+ summary: Simple lightweight up/down MSSQL migrations
80
+ test_files: []