db-migrate 0.0.1

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.
@@ -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