db-migrate 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,77 @@
1
+ require 'mysql2'
2
+
3
+ module Migrate
4
+ module Storage
5
+ class Mysql < DB
6
+ def initialize(*args)
7
+ super
8
+ @conn = Mysql2::Client.new(
9
+ :database => @config.database,
10
+ :host => @config.host,
11
+ :port => @config.port,
12
+ :username => @config.user,
13
+ :password => @config.password,
14
+ )
15
+ end
16
+
17
+ def create_tables
18
+ Log.info("Creating version table")
19
+ self.exec_sql <<-eos
20
+ CREATE TABLE #{@config.version_info}
21
+ (
22
+ version INT PRIMARY KEY NOT NULL AUTO_INCREMENT,
23
+ description TEXT,
24
+ created_date TIMESTAMP NOT NULL,
25
+ last_up TIMESTAMP,
26
+ last_down TIMESTAMP
27
+ );
28
+ eos
29
+
30
+ self.exec_sql <<-eos
31
+ CREATE TABLE #{@config.version_number} (
32
+ version int(11) not null,
33
+ PRIMARY KEY (version)
34
+ );
35
+ eos
36
+
37
+ self.exec_sql <<-eos
38
+ INSERT INTO #{@config.version_number} VALUES(0);
39
+ eos
40
+ Log.success("Version table created")
41
+ end
42
+
43
+ def exec_sql(sql)
44
+ results = []
45
+ result = @tx.query sql
46
+ return [] if result == nil
47
+
48
+ result.each do |row|
49
+ results << row
50
+ end
51
+ end
52
+
53
+ def has_tx
54
+ @tx != nil
55
+ end
56
+
57
+ def tx
58
+ if has_tx
59
+ yield
60
+ else
61
+ begin
62
+ @conn.query "BEGIN;"
63
+ @tx = @conn
64
+ yield
65
+ @conn.query "COMMIT;"
66
+ rescue Exception => e
67
+ @conn.query "ROLLBACK;"
68
+ raise e
69
+ ensure
70
+ @tx = nil
71
+ end
72
+ end
73
+ end
74
+
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,74 @@
1
+ require "pg"
2
+ require "pry"
3
+
4
+ module Migrate
5
+ module Storage
6
+ class Postgres < DB
7
+ def initialize(*args)
8
+ super
9
+ @conn = PG.connect({
10
+ dbname: @config.database,
11
+ host: @config.host,
12
+ user: @config.user,
13
+ password: @config.password,
14
+ })
15
+ end
16
+
17
+ def create_tables
18
+ Log.info("Creating version table")
19
+ self.exec_sql <<-eos
20
+ CREATE TABLE #{@config.version_info}
21
+ (
22
+ version SERIAL PRIMARY KEY NOT NULL,
23
+ description TEXT,
24
+ created_date TIMESTAMP WITH TIME ZONE NOT NULL,
25
+ last_up TIMESTAMP WITH TIME ZONE,
26
+ last_down TIMESTAMP WITH TIME ZONE
27
+ );
28
+ CREATE UNIQUE INDEX #{@config.version_info}_version_uindex ON #{@config.version_info} (version);
29
+
30
+ CREATE TABLE #{@config.version_number}
31
+ (
32
+ version INT PRIMARY KEY NOT NULL
33
+ );
34
+
35
+ INSERT INTO #{@config.version_number} VALUES(0);
36
+ eos
37
+ Log.success("Version table created")
38
+ end
39
+
40
+
41
+ def extract_version(results)
42
+ if results && results.count > 0
43
+ results[0]["version"]
44
+ else
45
+ raise VersionNotFound
46
+ end
47
+ end
48
+
49
+ def exec_sql(sql)
50
+ @tx.exec sql
51
+ end
52
+
53
+ def has_tx
54
+ @tx != nil
55
+ end
56
+
57
+ def tx
58
+ if has_tx
59
+ yield
60
+ else
61
+ begin
62
+ @conn.transaction do |tx|
63
+ @tx = tx
64
+ yield
65
+ end
66
+ ensure
67
+ @tx = nil
68
+ end
69
+ end
70
+ end
71
+
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,21 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = 'db-migrate'
3
+ s.version = '0.0.1'
4
+ s.licenses = ['MIT']
5
+ s.summary = "Tool for managing and executing your database migrations."
6
+ s.description = "#{s.summary} It supports multiple databases and multiple languages for writing migration scripts."
7
+ s.authors = ["Ivan Pusic"]
8
+ s.email = 'pusic007@gmail.com'
9
+ s.files = `git ls-files -z`.split("\x0")
10
+ s.homepage = 'https://github.com/ivpusic/migrate'
11
+ s.executables << 'migrate'
12
+
13
+ # deps
14
+ s.add_runtime_dependency 'thor', ['0.19.1']
15
+ s.add_runtime_dependency 'highline', ['1.7.8']
16
+ s.add_runtime_dependency 'json', ['1.8.3']
17
+ s.add_runtime_dependency 'mysql2', ['0.4.2']
18
+ s.add_runtime_dependency 'pg', ['0.18.4']
19
+ s.add_runtime_dependency 'parseconfig', ['1.0.6']
20
+ s.add_runtime_dependency 'colorize', ['0.7.7']
21
+ end
@@ -0,0 +1,103 @@
1
+ describe "Config" do
2
+ let(:fixtures) { "spec/lib/fixtures" }
3
+ let(:config) { Config.new(fixtures, "example.config") }
4
+ let(:config_hash) {
5
+ {
6
+ host: "localhost",
7
+ port: ("5432").to_i,
8
+ database: "mydb",
9
+ user: "postgres",
10
+ password: "password",
11
+ version_info: "version_info",
12
+ version_number: "version_number"
13
+ }
14
+ }
15
+
16
+ it "should create new instance" do
17
+ expect(config).not_to eq(nil)
18
+ end
19
+
20
+ it "should save root" do
21
+ expect(config.root).to eq("spec/lib/fixtures")
22
+ end
23
+
24
+ it "should not find file" do
25
+ config = Config.new(".", "custom_file.conf")
26
+ expect(config.exists?).to eq(false)
27
+ end
28
+
29
+ it "should find file" do
30
+ expect(config.exists?).to eq(true)
31
+ end
32
+
33
+ it "should create config file" do
34
+ config_path = "#{fixtures}/test.config"
35
+ begin
36
+ expect(File.exist? config_path).to be false
37
+
38
+ config = Config.new(fixtures, "test.config")
39
+ config.init(config_hash)
40
+ expect(File.exist? config_path). to be true
41
+ ensure
42
+ if File.exist? config_path
43
+ File.delete config_path
44
+ end
45
+ end
46
+ end
47
+
48
+ it "should load configuration" do
49
+ config.init(config_hash)
50
+ config.load!
51
+ expect(config.host).to eq("localhost")
52
+ expect(config.port).to eq("5432")
53
+ expect(config.database).to eq("mydb")
54
+ expect(config.user).to eq("postgres")
55
+ expect(config.password).to eq("password")
56
+ expect(config.version_info).to eq("version_info")
57
+ expect(config.version_number).to eq("version_number")
58
+ end
59
+
60
+ it "should remove configuration" do
61
+ config_path = "#{fixtures}/test.config"
62
+ begin
63
+ expect(File.exist? config_path).to be false
64
+
65
+ config = Config.new(fixtures, "test.config")
66
+ config.init(config_hash)
67
+ expect(File.exist? config_path).to be true
68
+ config.delete
69
+ expect(File.exist? config_path).to be false
70
+ ensure
71
+ if File.exist? config_path
72
+ File.delete config_path
73
+ end
74
+ end
75
+ end
76
+
77
+ [{type: "pg", cls: Storage::Postgres, conf: $pg_config_hash},
78
+ {type: "mysql", cls: Storage::Mysql, conf: $mysql_config_hash}].each do |storage|
79
+ context storage[:type] do
80
+ it "should be able to get database instance" do
81
+ config.init(storage[:conf])
82
+ config.load!
83
+ expect(config.get_db).to be_kind_of(storage[:cls])
84
+ end
85
+ end
86
+ end
87
+
88
+ [{type: "go", cls: Lang::Go}, {type: "sql", cls: Lang::Sql},
89
+ {type: "ruby", cls: Lang::Ruby}, {type: "javascript", cls: Lang::Javascript},
90
+ {type: "python", cls: Lang::Python}].each do |lang|
91
+ context lang[:type] do
92
+ it "should be able to get language instance" do
93
+ config_hash = $pg_config_hash.merge({
94
+ lang: lang[:type]
95
+ })
96
+
97
+ config.init(config_hash)
98
+ config.load!
99
+ expect(config.get_lang).to be_kind_of(lang[:cls])
100
+ end
101
+ end
102
+ end
103
+ end
@@ -0,0 +1,7 @@
1
+ package main
2
+
3
+ import "fmt"
4
+
5
+ func main() {
6
+ fmt.Println("works")
7
+ }
@@ -0,0 +1,7 @@
1
+ package main
2
+
3
+ import "fmt"
4
+
5
+ func main() {
6
+ fmt.Println("works")
7
+ }
@@ -0,0 +1 @@
1
+ console.log("works");
@@ -0,0 +1 @@
1
+ console.log("works");
@@ -0,0 +1 @@
1
+ print "works"
@@ -0,0 +1 @@
1
+ print "works"
@@ -0,0 +1 @@
1
+ puts "works"
@@ -0,0 +1 @@
1
+ puts "works"
@@ -0,0 +1 @@
1
+ -- todo;
@@ -0,0 +1 @@
1
+ -- todo;
@@ -0,0 +1,46 @@
1
+ describe "Lang" do
2
+ langs = [
3
+ Lang::Go.new,
4
+ Lang::Javascript.new,
5
+ Lang::Ruby.new,
6
+ Lang::Sql.new($dbs[0]),
7
+ Lang::Python.new
8
+ ]
9
+
10
+ langs.each do |lang|
11
+ dir = "spec/lib/fixtures/v01"
12
+
13
+ after(:each) do
14
+ if Dir.exist? dir
15
+ Dir.glob("#{dir}/{up.*,down.*}").each do |file|
16
+ File.delete(file)
17
+ end
18
+ Dir.rmdir dir
19
+ end
20
+ end
21
+
22
+ it "#{lang.ext} should be able to create new migration" do
23
+ Dir.mkdir dir
24
+ lang.create_migration(dir)
25
+
26
+ up = "#{dir}/up.#{lang.ext}"
27
+ down = "#{dir}/down.#{lang.ext}"
28
+
29
+ expect(File.exist? up).to be true
30
+ expect(File.exist? down).to be true
31
+ end
32
+
33
+ context "#{lang.ext} when migrating up" do
34
+ [true, false].each do |is_up|
35
+ it "should be able to execute migration script" do
36
+ lang_dir = "spec/lib/fixtures/#{lang.ext}"
37
+
38
+ if lang.ext != "sql"
39
+ out = lang.exec_migration(lang_dir, is_up)
40
+ expect(out.strip).to eq("works")
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,103 @@
1
+ describe "Migrator" do
2
+ $dbs.each do |db|
3
+ config = db.config
4
+ migrator = Migrator.new(config)
5
+
6
+ around(:each) do |test|
7
+ db.tx do
8
+ test.run
9
+ end
10
+ end
11
+
12
+ context db.type do
13
+ it "should be able to initialize" do
14
+ expect{Migrator.new(config)}.not_to raise_error(Exception)
15
+ end
16
+
17
+ it "should make new migration" do
18
+ migration_dir = nil
19
+
20
+ begin
21
+ result = db.exec_sql("SELECT * FROM #{config.version_info} ORDER BY version DESC")
22
+ version = db.extract_version result
23
+
24
+ migration_dir = migrator.new("description")
25
+
26
+ result = db.exec_sql("SELECT * FROM #{config.version_info} ORDER BY version DESC")
27
+ new_version = db.extract_version result
28
+ expect(new_version.to_i).to eq(version.to_i + 1)
29
+ expect(Dir.exist? migration_dir).to be true
30
+ ensure
31
+ if migration_dir != nil
32
+ Dir.glob("#{migration_dir}/{up.*,down.*}").each do |file|
33
+ File.delete file
34
+ end
35
+
36
+ Dir.rmdir migration_dir
37
+ end
38
+ end
39
+ end
40
+
41
+ create_migration_dir = lambda do |version|
42
+ migration = db.get_migration(version)
43
+ migration_dir = migrator.migration_dir(migration)
44
+
45
+ if not Dir.exist? migration_dir
46
+ Dir.mkdir migration_dir
47
+ config.get_lang().create_migration(migration_dir)
48
+ end
49
+ end
50
+
51
+ it "should execute one up migration" do
52
+ current = db.current_version().to_i
53
+ create_migration_dir.call(current + 1)
54
+ migrator.up
55
+
56
+ expect(current.to_i + 1).to eq(db.current_version().to_i)
57
+ end
58
+
59
+ it "should execute multiple up migration" do
60
+ current = db.current_version().to_i
61
+ create_migration_dir.call(current + 1)
62
+ create_migration_dir.call(current + 2)
63
+
64
+ migrator.up(current + 2)
65
+ expect(current.to_i + 2).to eq(db.current_version().to_i)
66
+ end
67
+
68
+ it "should execute one down migration" do
69
+ current = db.current_version().to_i
70
+ create_migration_dir.call(current)
71
+
72
+ migrator.down
73
+ expect(current.to_i - 1).to eq(db.current_version().to_i)
74
+ end
75
+
76
+ it "should execute multiple up migration" do
77
+ current = db.current_version().to_i
78
+ create_migration_dir.call(current)
79
+ create_migration_dir.call(current - 1)
80
+
81
+ migrator.down(current - 2)
82
+ expect(current.to_i - 2).to eq(db.current_version().to_i)
83
+ end
84
+
85
+ it "should get current version" do
86
+ current = db.current_version().to_i
87
+ expect(migrator.current_version().to_i).to eq(current)
88
+ end
89
+
90
+ it "should delete one version" do
91
+ delete = db.current_version().to_i + 1
92
+ migrator.delete(delete)
93
+ expect{db.get_migration(delete)}.to raise_error(VersionNotFound)
94
+ end
95
+
96
+ it "should not delete current version" do
97
+ current = db.current_version().to_i
98
+ migrator.delete(current)
99
+ expect(db.get_migration(current)["version"].to_i).to eq(current)
100
+ end
101
+ end
102
+ end
103
+ end