4
4
from datetime import datetime , timedelta
5
5
6
6
from .bootstrap import (
7
+ _generate_sql_copy_commands ,
7
8
_get_time_offsets ,
9
+ _suffix ,
10
+ _trigger_column_copies ,
11
+ _override_config_to_map_data ,
8
12
calculate_sql_alters_from_state_info ,
9
13
write_state_info ,
10
14
)
14
18
15
19
class MockDatabase (DatabaseCommand ):
16
20
def __init__ (self ):
17
- self .response = []
21
+ self ._response = list ()
22
+ self ._select_response = [[{"id" : 150 }]]
18
23
self .num_queries = 0
19
24
20
25
def run (self , cmd ):
@@ -36,9 +41,9 @@ def run(self, cmd):
36
41
]
37
42
38
43
if "SELECT" in cmd :
39
- return [{ "id" : 150 }]
44
+ return self . _select_response . pop ()
40
45
41
- return self .response
46
+ return self ._response . pop ()
42
47
43
48
def db_name (self ):
44
49
return SqlInput ("the-database" )
@@ -82,6 +87,7 @@ def test_get_time_offsets(self):
82
87
)
83
88
84
89
def test_read_state_info (self ):
90
+ self .maxDiff = None
85
91
conf_past = Config ()
86
92
conf_past .curtime = datetime (2021 , 3 , 1 )
87
93
conf_past .dbcmd = MockDatabase ()
@@ -97,6 +103,12 @@ def test_read_state_info(self):
97
103
conf_now = Config ()
98
104
conf_now .curtime = datetime (2021 , 3 , 3 )
99
105
conf_now .dbcmd = MockDatabase ()
106
+ conf_now .dbcmd ._response = [
107
+ [
108
+ {"Field" : "id" , "Type" : "bigint UNSIGNED" },
109
+ {"Field" : "serial" , "Type" : "varchar" },
110
+ ]
111
+ ]
100
112
conf_now .tables = [Table ("test" ).set_partition_period (timedelta (days = 30 ))]
101
113
102
114
state_fs .seek (0 )
@@ -105,10 +117,137 @@ def test_read_state_info(self):
105
117
x ,
106
118
{
107
119
"test" : [
108
- "ALTER TABLE `test` REORGANIZE PARTITION `p_start` INTO "
109
- "(PARTITION `p_20210303` VALUES LESS THAN (156), "
110
- "PARTITION `p_20210402` VALUES LESS THAN (2406), "
111
- "PARTITION `p_20210502` VALUES LESS THAN MAXVALUE);"
120
+ "DROP TABLE IF EXISTS test_new_20210303;" ,
121
+ "CREATE TABLE test_new_20210303 LIKE test;" ,
122
+ "ALTER TABLE test_new_20210303 REMOVE PARTITIONING;" ,
123
+ "ALTER TABLE test_new_20210303 PARTITION BY RANGE(id) (" ,
124
+ "\t PARTITION p_start VALUES LESS THAN MAXVALUE" ,
125
+ ");" ,
126
+ "ALTER TABLE `test_new_20210303` REORGANIZE PARTITION `p_start` "
127
+ + "INTO (PARTITION `p_20210303` VALUES LESS THAN (156), "
128
+ + "PARTITION `p_20210402` VALUES LESS THAN (2406), PARTITION "
129
+ + "`p_20210502` VALUES LESS THAN MAXVALUE);" ,
130
+ "CREATE OR REPLACE TRIGGER copy_inserts_from_test_to_test_new_20210303" ,
131
+ "\t AFTER INSERT ON test FOR EACH ROW" ,
132
+ "\t \t INSERT INTO test_new_20210303 SET" ,
133
+ "\t \t \t `id` = NEW.`id`," ,
134
+ "\t \t \t `serial` = NEW.`serial`;" ,
135
+ "CREATE OR REPLACE TRIGGER copy_updates_from_test_to_test_new_20210303" ,
136
+ "\t AFTER UPDATE ON test FOR EACH ROW" ,
137
+ "\t \t UPDATE test_new_20210303 SET" ,
138
+ "\t \t \t `serial` = NEW.`serial`" ,
139
+ "\t \t WHERE `id` = NEW.`id`;" ,
112
140
]
113
141
},
114
142
)
143
+
144
+ def test_read_state_info_map_table (self ):
145
+ self .maxDiff = None
146
+ conf = Config ()
147
+ conf .assume_partitioned_on = ["order" , "auth" ]
148
+ conf .curtime = datetime (2021 , 3 , 3 )
149
+ conf .dbcmd = MockDatabase ()
150
+ conf .dbcmd ._select_response = [[{"auth" : 22 }], [{"order" : 11 }]]
151
+ conf .dbcmd ._response = [
152
+ [
153
+ {"Field" : "order" , "Type" : "bigint UNSIGNED" },
154
+ {"Field" : "auth" , "Type" : "bigint UNSIGNED" },
155
+ ]
156
+ ]
157
+ conf .tables = [Table ("map_table" ).set_partition_period (timedelta (days = 30 ))]
158
+
159
+ state_fs = io .StringIO ()
160
+ yaml .dump (
161
+ {
162
+ "tables" : {"map_table" : {"order" : 11 , "auth" : 22 }},
163
+ "time" : (conf .curtime - timedelta (days = 1 )),
164
+ },
165
+ state_fs ,
166
+ )
167
+ state_fs .seek (0 )
168
+
169
+ x = calculate_sql_alters_from_state_info (conf , state_fs )
170
+ print (x )
171
+ self .assertEqual (
172
+ x ,
173
+ {
174
+ "map_table" : [
175
+ "DROP TABLE IF EXISTS map_table_new_20210303;" ,
176
+ "CREATE TABLE map_table_new_20210303 LIKE map_table;" ,
177
+ "ALTER TABLE map_table_new_20210303 REMOVE PARTITIONING;" ,
178
+ "ALTER TABLE map_table_new_20210303 PARTITION BY RANGE(order, auth) (" ,
179
+ "\t PARTITION p_assumed VALUES LESS THAN MAXVALUE" ,
180
+ ");" ,
181
+ "ALTER TABLE `map_table_new_20210303` REORGANIZE PARTITION "
182
+ + "`p_assumed` INTO (PARTITION `p_20210303` VALUES LESS THAN "
183
+ + "(11, 22), PARTITION `p_20210402` VALUES LESS THAN "
184
+ + "(11, 22), PARTITION `p_20210502` VALUES LESS THAN "
185
+ + "MAXVALUE, MAXVALUE);" ,
186
+ "CREATE OR REPLACE TRIGGER copy_inserts_from_map_table_"
187
+ + "to_map_table_new_20210303" ,
188
+ "\t AFTER INSERT ON map_table FOR EACH ROW" ,
189
+ "\t \t INSERT INTO map_table_new_20210303 SET" ,
190
+ "\t \t \t `auth` = NEW.`auth`," ,
191
+ "\t \t \t `order` = NEW.`order`;" ,
192
+ ]
193
+ },
194
+ )
195
+
196
+ def test_trigger_column_copies (self ):
197
+ self .assertEqual (list (_trigger_column_copies ([])), [])
198
+ self .assertEqual (list (_trigger_column_copies (["a" ])), ["`a` = NEW.`a`" ])
199
+ self .assertEqual (
200
+ list (_trigger_column_copies (["b" , "a" , "c" ])),
201
+ ["`b` = NEW.`b`" , "`a` = NEW.`a`" , "`c` = NEW.`c`" ],
202
+ )
203
+
204
+ def test_suffix (self ):
205
+ self .assertEqual (list (_suffix (["a" ])), ["a" ])
206
+ self .assertEqual (list (_suffix (["a" , "b" ])), ["a" , "b" ])
207
+ self .assertEqual (list (_suffix (["a" , "b" ], indent = " " )), [" a" , " b" ])
208
+ self .assertEqual (list (_suffix (["a" , "b" ], mid_suffix = "," )), ["a," , "b" ])
209
+ self .assertEqual (list (_suffix (["a" , "b" ], final_suffix = ";" )), ["a" , "b;" ])
210
+ self .assertEqual (
211
+ list (_suffix (["a" , "b" ], mid_suffix = "," , final_suffix = ";" )), ["a," , "b;" ]
212
+ )
213
+
214
+ def test_generate_sql_copy_commands (self ):
215
+ conf = Config ()
216
+ conf .assume_partitioned_on = ["id" ]
217
+ conf .curtime = datetime (2021 , 3 , 3 )
218
+ conf .dbcmd = MockDatabase ()
219
+ map_data = _override_config_to_map_data (conf )
220
+ cmds = list (
221
+ _generate_sql_copy_commands (
222
+ Table ("old" ),
223
+ map_data ,
224
+ ["id" , "field" ],
225
+ Table ("new" ),
226
+ ["STRAIGHT_UP_INSERTED" , "STUFF GOES HERE" ],
227
+ )
228
+ )
229
+
230
+ print (cmds )
231
+ self .assertEqual (
232
+ cmds ,
233
+ [
234
+ "DROP TABLE IF EXISTS new;" ,
235
+ "CREATE TABLE new LIKE old;" ,
236
+ "ALTER TABLE new REMOVE PARTITIONING;" ,
237
+ "ALTER TABLE new PARTITION BY RANGE(id) (" ,
238
+ "\t PARTITION p_assumed VALUES LESS THAN MAXVALUE" ,
239
+ ");" ,
240
+ "STRAIGHT_UP_INSERTED" ,
241
+ "STUFF GOES HERE" ,
242
+ "CREATE OR REPLACE TRIGGER copy_inserts_from_old_to_new" ,
243
+ "\t AFTER INSERT ON old FOR EACH ROW" ,
244
+ "\t \t INSERT INTO new SET" ,
245
+ "\t \t \t `field` = NEW.`field`," ,
246
+ "\t \t \t `id` = NEW.`id`;" ,
247
+ "CREATE OR REPLACE TRIGGER copy_updates_from_old_to_new" ,
248
+ "\t AFTER UPDATE ON old FOR EACH ROW" ,
249
+ "\t \t UPDATE new SET" ,
250
+ "\t \t \t `field` = NEW.`field`" ,
251
+ "\t \t WHERE `id` = NEW.`id`;" ,
252
+ ],
253
+ )
0 commit comments