mysql_framework 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.
- checksums.yaml +7 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/lib/mysql_framework.rb +15 -0
- data/lib/mysql_framework/connector.rb +84 -0
- data/lib/mysql_framework/logger.rb +15 -0
- data/lib/mysql_framework/scripts.rb +5 -0
- data/lib/mysql_framework/scripts/base.rb +58 -0
- data/lib/mysql_framework/scripts/manager.rb +137 -0
- data/lib/mysql_framework/scripts/table.rb +11 -0
- data/lib/mysql_framework/sql_column.rb +54 -0
- data/lib/mysql_framework/sql_condition.rb +20 -0
- data/lib/mysql_framework/sql_query.rb +131 -0
- data/lib/mysql_framework/sql_table.rb +23 -0
- data/lib/mysql_framework/version.rb +3 -0
- data/spec/lib/mysql_framework/connector_spec.rb +192 -0
- data/spec/lib/mysql_framework/logger_spec.rb +20 -0
- data/spec/lib/mysql_framework/scripts/base_spec.rb +91 -0
- data/spec/lib/mysql_framework/scripts/manager_spec.rb +161 -0
- data/spec/lib/mysql_framework/sql_column_spec.rb +73 -0
- data/spec/lib/mysql_framework/sql_condition_spec.rb +13 -0
- data/spec/lib/mysql_framework/sql_query_spec.rb +223 -0
- data/spec/lib/mysql_framework/sql_table_spec.rb +26 -0
- data/spec/spec_helper.rb +52 -0
- data/spec/support/procedure.sql +5 -0
- data/spec/support/scripts/create_demo_table.rb +34 -0
- data/spec/support/scripts/create_test_proc.rb +27 -0
- data/spec/support/scripts/create_test_table.rb +34 -0
- data/spec/support/tables/demo.rb +15 -0
- data/spec/support/tables/test.rb +15 -0
- metadata +157 -0
@@ -0,0 +1,161 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe MysqlFramework::Scripts::Manager do
|
6
|
+
let(:connector) { MysqlFramework::Connector.new }
|
7
|
+
|
8
|
+
before :each do
|
9
|
+
subject.instance_variable_set(:@mysql_connector, connector)
|
10
|
+
end
|
11
|
+
|
12
|
+
describe '#execute' do
|
13
|
+
before :each do
|
14
|
+
subject.initialize_script_history
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'executes all pending scripts' do
|
18
|
+
expect(subject.table_exists?('demo')).to eq(false)
|
19
|
+
expect(subject.table_exists?('test')).to eq(false)
|
20
|
+
|
21
|
+
subject.execute
|
22
|
+
|
23
|
+
expect(subject.table_exists?('demo')).to eq(true)
|
24
|
+
expect(subject.table_exists?('test')).to eq(true)
|
25
|
+
end
|
26
|
+
|
27
|
+
after :each do
|
28
|
+
subject.drop_all_tables
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe '#apply_by_tag' do
|
33
|
+
before :each do
|
34
|
+
subject.initialize_script_history
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'executes all pending scripts that match the tag' do
|
38
|
+
expect(subject.table_exists?('demo')).to eq(false)
|
39
|
+
expect(subject.table_exists?('test')).to eq(false)
|
40
|
+
|
41
|
+
subject.apply_by_tag([MysqlFramework::Support::Tables::TestTable::NAME])
|
42
|
+
|
43
|
+
expect(subject.table_exists?('demo')).to eq(false)
|
44
|
+
expect(subject.table_exists?('test')).to eq(true)
|
45
|
+
end
|
46
|
+
|
47
|
+
after :each do
|
48
|
+
subject.drop_all_tables
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
describe '#drop_all_tables' do
|
53
|
+
it 'drops the script history table and any registered tables' do
|
54
|
+
expect(subject).to receive(:drop_script_history)
|
55
|
+
expect(subject).to receive(:drop_table).with('test')
|
56
|
+
expect(subject).to receive(:drop_table).with('demo')
|
57
|
+
|
58
|
+
subject.drop_all_tables
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
describe '#retrieve_last_executed_script' do
|
63
|
+
before :each do
|
64
|
+
subject.initialize_script_history
|
65
|
+
end
|
66
|
+
|
67
|
+
context 'when no scripts have been executed' do
|
68
|
+
it 'returns 0' do
|
69
|
+
expect(subject.retrieve_last_executed_script).to eq(0)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
context 'when scripts have been executed previously' do
|
74
|
+
before :each do
|
75
|
+
subject.apply_by_tag([MysqlFramework::Support::Tables::TestTable::NAME])
|
76
|
+
end
|
77
|
+
|
78
|
+
it 'returns the last executed script' do
|
79
|
+
expect(subject.retrieve_last_executed_script).to eq(201807031200)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
after :each do
|
84
|
+
subject.drop_script_history
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
describe '#initialize_script_history' do
|
89
|
+
it 'creates a migration history table' do
|
90
|
+
expect(subject.table_exists?('migration_script_history')).to eq(false)
|
91
|
+
subject.initialize_script_history
|
92
|
+
expect(subject.table_exists?('migration_script_history')).to eq(true)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
describe '#calculate_pending_scripts' do
|
97
|
+
it 'returns any scripts that are newer than the given date in ascending order' do
|
98
|
+
timestamp = 201701010000 # 00:00 01/01/2017
|
99
|
+
results = subject.calculate_pending_scripts(timestamp)
|
100
|
+
|
101
|
+
expect(results.length).to eq(3)
|
102
|
+
expect(results[0]).to be_a(MysqlFramework::Support::Scripts::CreateTestTable)
|
103
|
+
expect(results[1]).to be_a(MysqlFramework::Support::Scripts::CreateDemoTable)
|
104
|
+
end
|
105
|
+
|
106
|
+
context 'when there are scripts older than the given date' do
|
107
|
+
it 'returns only scripts that are newer than the given date in ascending order' do
|
108
|
+
timestamp = 201802021010 # 10:10 02/02/2018
|
109
|
+
results = subject.calculate_pending_scripts(timestamp)
|
110
|
+
|
111
|
+
expect(results.length).to eq(2)
|
112
|
+
expect(results[0]).to be_a(MysqlFramework::Support::Scripts::CreateDemoTable)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
describe '#table_exists?' do
|
118
|
+
context 'when the table exists' do
|
119
|
+
it 'returns true' do
|
120
|
+
expect(subject.table_exists?('gems')).to eq(true)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
context 'when the table does not exist' do
|
125
|
+
it 'returns false' do
|
126
|
+
expect(subject.table_exists?('foo')).to eq(false)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
describe '#drop_script_history' do
|
132
|
+
it 'drops the migration script history table' do
|
133
|
+
query = <<~SQL
|
134
|
+
DROP TABLE IF EXISTS `#{ENV.fetch('MYSQL_DATABASE')}`.`migration_script_history`
|
135
|
+
SQL
|
136
|
+
expect(connector).to receive(:query).with(query)
|
137
|
+
subject.drop_script_history
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
describe '#drop_table' do
|
142
|
+
it 'drops the given table' do
|
143
|
+
expect(connector).to receive(:query).with(<<~SQL)
|
144
|
+
DROP TABLE IF EXISTS `some_database`.`some_table`
|
145
|
+
SQL
|
146
|
+
subject.drop_table('`some_database`.`some_table`')
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
describe '#all_tables' do
|
151
|
+
it 'returns all registered tables' do
|
152
|
+
expect(subject.all_tables).to eq(['test', 'demo'])
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
describe '.all_tables' do
|
157
|
+
it 'stores a class level array of tables' do
|
158
|
+
expect(described_class.all_tables).to eq(['test', 'demo'])
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe MysqlFramework::SqlColumn do
|
6
|
+
subject { described_class.new(table: 'gems', column: 'version') }
|
7
|
+
|
8
|
+
describe '#to_s' do
|
9
|
+
it 'returns the prepared sql name with backticks' do
|
10
|
+
expect(subject.to_s).to eq('`gems`.`version`')
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
describe '#to_sym' do
|
15
|
+
it 'returns the column name as a symbol' do
|
16
|
+
expect(subject.to_sym).to eq(:version)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe '#eq' do
|
21
|
+
it 'returns a SqlCondition for the comparison' do
|
22
|
+
condition = subject.eq('2.0.0')
|
23
|
+
expect(condition).to be_a(MysqlFramework::SqlCondition)
|
24
|
+
expect(condition.to_s).to eq('`gems`.`version` = ?')
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe '#not_eq' do
|
29
|
+
it 'returns a SqlCondition for the comparison' do
|
30
|
+
condition = subject.not_eq('2.0.0')
|
31
|
+
expect(condition).to be_a(MysqlFramework::SqlCondition)
|
32
|
+
expect(condition.to_s).to eq('`gems`.`version` <> ?')
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
describe '#gt' do
|
37
|
+
it 'returns a SqlCondition for the comparison' do
|
38
|
+
condition = subject.gt('2.0.0')
|
39
|
+
expect(condition).to be_a(MysqlFramework::SqlCondition)
|
40
|
+
expect(condition.to_s).to eq('`gems`.`version` > ?')
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
describe '#gte' do
|
45
|
+
it 'returns a SqlCondition for the comparison' do
|
46
|
+
condition = subject.gte('2.0.0')
|
47
|
+
expect(condition).to be_a(MysqlFramework::SqlCondition)
|
48
|
+
expect(condition.to_s).to eq('`gems`.`version` >= ?')
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
describe '#lt' do
|
53
|
+
it 'returns a SqlCondition for the comparison' do
|
54
|
+
condition = subject.lt('2.0.0')
|
55
|
+
expect(condition).to be_a(MysqlFramework::SqlCondition)
|
56
|
+
expect(condition.to_s).to eq('`gems`.`version` < ?')
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
describe '#lte' do
|
61
|
+
it 'returns a SqlCondition for the comparison' do
|
62
|
+
condition = subject.lte('2.0.0')
|
63
|
+
expect(condition).to be_a(MysqlFramework::SqlCondition)
|
64
|
+
expect(condition.to_s).to eq('`gems`.`version` <= ?')
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
describe '#as' do
|
69
|
+
it 'returns the column specified as another name' do
|
70
|
+
expect(subject.as('v')).to eq('`gems`.`version` as `v`')
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe MysqlFramework::SqlCondition do
|
6
|
+
subject { described_class.new(column: 'version', comparison: '=', value: '1.0.0') }
|
7
|
+
|
8
|
+
describe '#to_s' do
|
9
|
+
it 'returns the condition as a string for a prepared statement' do
|
10
|
+
expect(subject.to_s).to eq('version = ?')
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,223 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe MysqlFramework::SqlQuery do
|
6
|
+
let(:gems) { MysqlFramework::SqlTable.new('gems') }
|
7
|
+
let(:versions) { MysqlFramework::SqlTable.new('versions') }
|
8
|
+
|
9
|
+
describe 'building a query' do
|
10
|
+
it 'builds the insert query as expected' do
|
11
|
+
subject.insert(gems, 15)
|
12
|
+
.into(
|
13
|
+
gems[:name],
|
14
|
+
gems[:author],
|
15
|
+
gems[:created_at],
|
16
|
+
gems[:updated_at]
|
17
|
+
)
|
18
|
+
.values(
|
19
|
+
'mysql_framework',
|
20
|
+
'sage',
|
21
|
+
'2018-06-28 10:00:00',
|
22
|
+
'2018-06-28 10:00:00'
|
23
|
+
)
|
24
|
+
|
25
|
+
expect(subject.sql).to eq('insert into `gems` partition(p15) (`gems`.`name`,`gems`.`author`,`gems`.`created_at`,`gems`.`updated_at`) values (?,?,?,?)')
|
26
|
+
expect(subject.params).to eq(['mysql_framework', 'sage', '2018-06-28 10:00:00', '2018-06-28 10:00:00'])
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'builds the update query as expected' do
|
30
|
+
subject.update(gems, 20)
|
31
|
+
.set(
|
32
|
+
name: 'mysql_framework',
|
33
|
+
updated_at: '2018-06-28 13:00:00'
|
34
|
+
)
|
35
|
+
.where(
|
36
|
+
gems[:id].eq('12345')
|
37
|
+
)
|
38
|
+
|
39
|
+
expect(subject.sql).to eq('update `gems` partition(p20) set `name` = ?, `updated_at` = ? where (`gems`.`id` = ?)')
|
40
|
+
expect(subject.params).to eq(['mysql_framework', '2018-06-28 13:00:00', '12345'])
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'builds the delete query as expected' do
|
44
|
+
subject.delete.from(gems, 30)
|
45
|
+
.where(
|
46
|
+
gems[:id].eq('45678')
|
47
|
+
)
|
48
|
+
|
49
|
+
expect(subject.sql).to eq('delete from `gems` partition(p30) where (`gems`.`id` = ?)')
|
50
|
+
expect(subject.params).to eq(['45678'])
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'builds a basic select query as expected' do
|
54
|
+
subject.select('*')
|
55
|
+
.from(gems, 40)
|
56
|
+
.where(
|
57
|
+
gems[:id].eq('9876')
|
58
|
+
)
|
59
|
+
|
60
|
+
expect(subject.sql).to eq('select * from `gems` partition(p40) where (`gems`.`id` = ?)')
|
61
|
+
expect(subject.params).to eq(['9876'])
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'builds a joined select query as expected' do
|
65
|
+
subject.select('*')
|
66
|
+
.from(gems, 40)
|
67
|
+
.join(versions).on(versions[:gem_id], gems[:id])
|
68
|
+
.where(
|
69
|
+
gems[:id].eq('9876')
|
70
|
+
)
|
71
|
+
|
72
|
+
expect(subject.sql).to eq('select * from `gems` partition(p40) join `versions` on `versions`.`gem_id` = `gems`.`id` where (`gems`.`id` = ?)')
|
73
|
+
expect(subject.params).to eq(['9876'])
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
describe '#select' do
|
78
|
+
it 'sets the sql for a select statement' do
|
79
|
+
subject.select(gems[:id], gems[:name])
|
80
|
+
expect(subject.sql).to eq('select `gems`.`id`,`gems`.`name`')
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
describe '#delete' do
|
85
|
+
it 'sets the sql for a delete statement' do
|
86
|
+
subject.delete
|
87
|
+
expect(subject.sql).to eq('delete')
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
describe '#update' do
|
92
|
+
it 'sets the sql for an update statement' do
|
93
|
+
subject.update(gems)
|
94
|
+
expect(subject.sql).to eq('update `gems`')
|
95
|
+
end
|
96
|
+
|
97
|
+
context 'when a partition is specified' do
|
98
|
+
it 'sets the sql for an update statement' do
|
99
|
+
subject.update(gems, 25)
|
100
|
+
expect(subject.sql).to eq('update `gems` partition(p25)')
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
describe '#insert' do
|
106
|
+
it 'sets the sql for an insert statement' do
|
107
|
+
subject.insert(gems)
|
108
|
+
expect(subject.sql).to eq('insert into `gems`')
|
109
|
+
end
|
110
|
+
|
111
|
+
context 'when a partition is specified' do
|
112
|
+
it 'sets the sql for an insert statement' do
|
113
|
+
subject.insert(gems, 35)
|
114
|
+
expect(subject.sql).to eq('insert into `gems` partition(p35)')
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
describe '#into' do
|
120
|
+
it 'sets the sql for an into statement' do
|
121
|
+
subject.into(gems[:name], gems[:author], gems[:created_at])
|
122
|
+
expect(subject.sql).to eq('(`gems`.`name`,`gems`.`author`,`gems`.`created_at`)')
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
describe '#values' do
|
127
|
+
it 'sets the sql for the values statement' do
|
128
|
+
subject.values('mysql_framework', 'sage', '2016-06-28 10:00:00')
|
129
|
+
expect(subject.sql).to eq('values (?,?,?)')
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
describe '#set' do
|
134
|
+
it 'sets the sql for the set statement' do
|
135
|
+
subject.set(name: 'mysql_framework', author: 'sage', created_at: '2016-06-28 10:00:00')
|
136
|
+
expect(subject.sql).to eq('set `name` = ?, `author` = ?, `created_at` = ?')
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
describe '#from' do
|
141
|
+
it 'sets the sql for a from statement' do
|
142
|
+
subject.from(gems)
|
143
|
+
expect(subject.sql).to eq('from `gems`')
|
144
|
+
end
|
145
|
+
|
146
|
+
context 'when a partition is specified' do
|
147
|
+
it 'sets the sql for a from statement' do
|
148
|
+
subject.from(gems, 45)
|
149
|
+
expect(subject.sql).to eq('from `gems` partition(p45)')
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
describe '#where' do
|
155
|
+
before :each do
|
156
|
+
subject.where(gems['author'].eq('sage'), gems['created_at'].gt('2018-01-01 00:00:00'))
|
157
|
+
end
|
158
|
+
|
159
|
+
it 'appends where to the sql' do
|
160
|
+
expect(subject.sql).to include('where')
|
161
|
+
end
|
162
|
+
|
163
|
+
it 'sets the sql for the where statement' do
|
164
|
+
expect(subject.sql).to eq('where (`gems`.`author` = ? and `gems`.`created_at` > ?)')
|
165
|
+
end
|
166
|
+
|
167
|
+
context 'when the sql already contains a where' do
|
168
|
+
it 'does not append an extra where' do
|
169
|
+
subject.and.where(gems['name'].eq('mysql_framework'))
|
170
|
+
expect(subject.sql).to eq('where (`gems`.`author` = ? and `gems`.`created_at` > ?) and (`gems`.`name` = ?)')
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
describe '#and' do
|
176
|
+
it 'appends the sql for an and statement' do
|
177
|
+
subject.and
|
178
|
+
expect(subject.sql).to eq('and')
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
describe '#or' do
|
183
|
+
it 'appends the sql for an or statement' do
|
184
|
+
subject.or
|
185
|
+
expect(subject.sql).to eq('or')
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
describe '#order' do
|
190
|
+
it 'appends the sql for an order statement' do
|
191
|
+
subject.order(gems[:created_at], gems[:updated_at])
|
192
|
+
expect(subject.sql).to eq('order by `gems`.`created_at`,`gems`.`updated_at`')
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
describe '#order_desc' do
|
197
|
+
it 'appends the sql for an order descending statement' do
|
198
|
+
subject.order_desc(gems[:created_at], gems[:updated_at])
|
199
|
+
expect(subject.sql).to eq('order by `gems`.`created_at`,`gems`.`updated_at` desc')
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
describe '#limit' do
|
204
|
+
it 'appends the sql for a limit statement' do
|
205
|
+
subject.limit(10)
|
206
|
+
expect(subject.sql).to eq('limit 10')
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
describe '#join' do
|
211
|
+
it 'appends the sql for a join statement' do
|
212
|
+
subject.join(versions)
|
213
|
+
expect(subject.sql).to eq('join `versions`')
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
describe '#on' do
|
218
|
+
it 'appends the sql for the on statement' do
|
219
|
+
subject.on(gems[:id], versions[:gem_id])
|
220
|
+
expect(subject.sql).to eq('on `gems`.`id` = `versions`.`gem_id`')
|
221
|
+
end
|
222
|
+
end
|
223
|
+
end
|