migsql 1.0.4

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