44from datetime import datetime , timedelta
55
66from .bootstrap import (
7+ _generate_sql_copy_commands ,
78 _get_time_offsets ,
9+ _suffix ,
10+ _trigger_column_copies ,
11+ _override_config_to_map_data ,
812 calculate_sql_alters_from_state_info ,
913 write_state_info ,
1014)
1418
1519class MockDatabase (DatabaseCommand ):
1620 def __init__ (self ):
17- self .response = []
21+ self ._response = list ()
22+ self ._select_response = [[{"id" : 150 }]]
1823 self .num_queries = 0
1924
2025 def run (self , cmd ):
@@ -36,9 +41,9 @@ def run(self, cmd):
3641 ]
3742
3843 if "SELECT" in cmd :
39- return [{ "id" : 150 }]
44+ return self . _select_response . pop ()
4045
41- return self .response
46+ return self ._response . pop ()
4247
4348 def db_name (self ):
4449 return SqlInput ("the-database" )
@@ -82,6 +87,7 @@ def test_get_time_offsets(self):
8287 )
8388
8489 def test_read_state_info (self ):
90+ self .maxDiff = None
8591 conf_past = Config ()
8692 conf_past .curtime = datetime (2021 , 3 , 1 )
8793 conf_past .dbcmd = MockDatabase ()
@@ -97,6 +103,12 @@ def test_read_state_info(self):
97103 conf_now = Config ()
98104 conf_now .curtime = datetime (2021 , 3 , 3 )
99105 conf_now .dbcmd = MockDatabase ()
106+ conf_now .dbcmd ._response = [
107+ [
108+ {"Field" : "id" , "Type" : "bigint UNSIGNED" },
109+ {"Field" : "serial" , "Type" : "varchar" },
110+ ]
111+ ]
100112 conf_now .tables = [Table ("test" ).set_partition_period (timedelta (days = 30 ))]
101113
102114 state_fs .seek (0 )
@@ -105,10 +117,137 @@ def test_read_state_info(self):
105117 x ,
106118 {
107119 "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`;" ,
112140 ]
113141 },
114142 )
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