flydata 0.2.7 → 0.2.8

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.
@@ -9,7 +9,7 @@ module Flydata
9
9
  def encrypt(text, key)
10
10
  validate_presence(text: text, key: key)
11
11
  cipher = build_cipher(:encrypt, key)
12
- Base64.encode64(cipher.update(text) + cipher.final)
12
+ Base64.strict_encode64(cipher.update(text) + cipher.final)
13
13
  end
14
14
 
15
15
  def decrypt(text, key, param_name = nil)
@@ -105,6 +105,10 @@ EOT
105
105
  # QUERY: alter table modify column
106
106
  TEST_EVENT_QUERY_ALTER_TABLE_MODIFY_COLUMN = <<EOT
107
107
  {"marker"=>0, "timestamp"=>#{TEST_TIMESTAMP}, "type_code"=>2, "server_id"=>1, "event_length"=>112, "next_position"=>1352, "flags"=>0, "event_type"=>"Query", "thread_id"=>48, "exec_time"=>0, "error_code"=>0, "variables"=>[0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 6, 3, 115, 116, 100, 4, 33, 0, 33, 0, 8, 0], "db_name"=>"test_db", "query"=>"alter table test_table modify column sum float"}
108
+ EOT
109
+ # QUERY: alter table add index
110
+ TEST_EVENT_QUERY_ALTER_TABLE_ADD_INDEX = <<EOT
111
+ {"marker"=>0, "timestamp"=>#{TEST_TIMESTAMP}, "type_code"=>2, "server_id"=>1, "event_length"=>217, "next_position"=>337, "flags"=>0, "event_type"=>"Query", "thread_id"=>10097, "exec_time"=>0, "error_code"=>0, "variables"=>[0, 0, 0, 0, 0, 1, 0, 0, 0, 64, 0, 0, 0, 0, 6, 3, 115, 116, 100, 4, 33, 0, 33, 0, 8, 0, 12, 1, 109, 97, 107, 95, 100, 101, 118, 101, 108, 111, 112, 109, 101, 110, 116, 0], "db_name"=>"test_db", "query"=>"ALTER TABLE `test_db`.`test_table` \nADD INDEX `my_index` USING HASH (`extra` ASC) COMMENT 'How does this look in binlog?'"}
108
112
  EOT
109
113
  # - 03 STOP_EVENT
110
114
  TEST_EVENT_STOP = <<EOT
@@ -179,6 +183,7 @@ EOT
179
183
  let(:update_three_byte_event) { create_event(TEST_EVENT_THREE_BYTE_UPDATE) }
180
184
  let(:alter_table_add_column_event) { create_event(TEST_EVENT_QUERY_ALTER_TABLE_ADD_COLUMN) }
181
185
  let(:alter_table_drop_column_event) { create_event(TEST_EVENT_QUERY_ALTER_TABLE_DROP_COLUMN) }
186
+ let(:alter_table_add_index_event) { create_event(TEST_EVENT_QUERY_ALTER_TABLE_ADD_INDEX) }
182
187
 
183
188
  let(:query_event) { create_event(TEST_EVENT_QUERY_CREATE_DATABSE) }
184
189
  let(:table_map_event) { create_event(TEST_EVENT_TABLE_MAP) }
@@ -309,7 +314,7 @@ EOT
309
314
  table_rev: 2, # increment revision
310
315
  seq: 2,
311
316
  actions: [{
312
- action: :add_column, column: "sum", :type=>'int4'}],
317
+ action: :add_column, column: "sum", :type=>'int4', :query=>'add column sum integer'}],
313
318
  })
314
319
  end
315
320
  end
@@ -324,7 +329,26 @@ EOT
324
329
  table_rev: 2, # increment revision
325
330
  seq: 2,
326
331
  actions: [{
327
- action: :drop_column, column: "sum"}],
332
+ action: :drop_column, column: "sum", :query=>'drop column sum'}],
333
+ })
334
+ end
335
+ end
336
+
337
+ context 'when received alter table add index event' do
338
+ it 'emits a nonbreaking event without table_rev increment' do
339
+ expect_emitted_records(alter_table_add_index_event, {
340
+ type: :alter_table,
341
+ table_name: "test_table",
342
+ schema_name: "test_db",
343
+ respect_order: true,
344
+ src_pos: "mysql-bin.000048\t#{337 - 217}",
345
+ table_rev: 1,
346
+ seq: 2,
347
+ actions: [{
348
+ action: :add_index,
349
+ support_level: :nonbreaking,
350
+ query: "ADD INDEX `my_index` USING HASH (`extra` ASC) COMMENT 'How does this look in binlog?'",
351
+ }],
328
352
  })
329
353
  end
330
354
  end
@@ -69,7 +69,7 @@ module Mysql
69
69
  expect(parser).to receive(:parse).and_return(nil)
70
70
  end
71
71
  it "returns nil with a warn log" do
72
- expect($log).to receive(:warn).with(/Received unsupported alter table query\. query:'#{query}'/)
72
+ expect($log).to receive(:error).with(/Received unsupported alter table query\. query:'#{query}'/)
73
73
 
74
74
  expect(subject.process(record, normalized_query)).to eq(nil)
75
75
  end
@@ -25,7 +25,8 @@ describe 'MysqlAlterTableParser' do
25
25
  actions: [{
26
26
  action: :add_column,
27
27
  column: "value",
28
- type: "varchar(78)"
28
+ type: "varchar(78)",
29
+ query: "add column value varchar(26)"
29
30
  }]
30
31
  })
31
32
  end
@@ -41,7 +42,8 @@ describe 'MysqlAlterTableParser' do
41
42
  actions: [{
42
43
  action: :add_column,
43
44
  column: "value",
44
- type: "varbinary(4294967295)"
45
+ type: "varbinary(4294967295)",
46
+ query: "add column value longblob"
45
47
  }]
46
48
  })
47
49
  end
@@ -57,28 +59,42 @@ describe 'MysqlAlterTableParser' do
57
59
  actions: [{
58
60
  action: :add_column,
59
61
  column: "value",
60
- type: "varchar(78)"
62
+ type: "varchar(78)",
63
+ query: "add value varchar(26)"
61
64
  }]
62
65
  })
63
66
  end
64
67
  end
65
68
 
66
69
  context 'with multiple columns' do
67
- let(:query) { "alter table test_table add column (value1 varchar(26), value2 varchar(26))" }
68
- it do
69
- expect(subject).to eq({
70
- type: :alter_table,
71
- table_name: "test_table",
72
- actions: [{
73
- action: :add_column,
74
- column: "value1",
75
- type: "varchar(78)"
76
- },{
77
- action: :add_column,
78
- column: "value2",
79
- type: "varchar(78)"
80
- }]
81
- })
70
+ shared_examples 'test result hash' do
71
+ it do
72
+ expect(subject).to eq({
73
+ type: :alter_table,
74
+ table_name: "test_table",
75
+ actions: [{
76
+ action: :add_column,
77
+ column: "value1",
78
+ type: "varchar(78)",
79
+ query: "#{expected_query}"
80
+ },{
81
+ action: :add_column,
82
+ column: "value2",
83
+ type: "varchar(78)",
84
+ query: "#{expected_query}"
85
+ }]
86
+ })
87
+ end
88
+ end
89
+ context 'with spaces before opening bracket' do
90
+ let(:query) { "alter table test_table add column (value1 varchar(26), value2 varchar(26))" }
91
+ let(:expected_query) {"add column (value1 varchar(26), value2 varchar(26))"}
92
+ include_examples 'test result hash'
93
+ end
94
+ context 'without spaces before opening bracket' do
95
+ let(:query) { "alter table test_table add column(value1 varchar(26), value2 varchar(26))" }
96
+ let(:expected_query) {"add column(value1 varchar(26), value2 varchar(26))"}
97
+ include_examples 'test result hash'
82
98
  end
83
99
  end
84
100
 
@@ -91,11 +107,13 @@ describe 'MysqlAlterTableParser' do
91
107
  actions: [{
92
108
  action: :add_column,
93
109
  column: "value1",
94
- type: "varchar(78)"
110
+ type: "varchar(78)",
111
+ query: "add ( value1 varchar(26), value2 varchar(26) )"
95
112
  },{
96
113
  action: :add_column,
97
114
  column: "value2",
98
- type: "varchar(78)"
115
+ type: "varchar(78)",
116
+ query: "add ( value1 varchar(26), value2 varchar(26) )"
99
117
  }]
100
118
  })
101
119
  end
@@ -113,11 +131,13 @@ describe 'MysqlAlterTableParser' do
113
131
  type: "varchar(78)",
114
132
  not_null: true,
115
133
  default: "flydata",
134
+ query: "add (value1 varchar(26) not null default 'flydata', value2 int auto_increment)"
116
135
  },{
117
136
  action: :add_column,
118
137
  column: "value2",
119
138
  type: "int4",
120
139
  auto_increment: true,
140
+ query: "add (value1 varchar(26) not null default 'flydata', value2 int auto_increment)"
121
141
  }]
122
142
  })
123
143
  end
@@ -135,11 +155,13 @@ describe 'MysqlAlterTableParser' do
135
155
  type: "varchar(78)",
136
156
  not_null: true,
137
157
  default: "flydata",
158
+ query: "add (`value1` varchar(26) not null default 'flydata', `value2` int auto_increment)"
138
159
  },{
139
160
  action: :add_column,
140
161
  column: "value2",
141
162
  type: "int4",
142
163
  auto_increment: true,
164
+ query: "add (`value1` varchar(26) not null default 'flydata', `value2` int auto_increment)"
143
165
  }]
144
166
  })
145
167
  end
@@ -156,13 +178,15 @@ describe 'MysqlAlterTableParser' do
156
178
  column: "value",
157
179
  type: "varchar(78)",
158
180
  after: 'id',
181
+ query: "add column value varchar(26) after id"
159
182
  }]
160
183
  })
161
184
  end
162
185
  end
163
-
164
- context 'with after option, backticks only on table name and a comment' do
165
- let(:query) { %Q|alter table `test_table` add column value varchar(26) comment 'Ignorable comment' after id| }
186
+ shared_examples "generating a flydata record for the given query" do
187
+ let(:after_column_name) { 'id' }
188
+ let(:actions) { %Q|add column value varchar(26) comment 'Ignorable comment' after #{after_column}| }
189
+ let(:query) { %Q|alter table `test_table` #{actions}| }
166
190
  it do
167
191
  expect(subject).to eq({
168
192
  type: :alter_table,
@@ -171,11 +195,23 @@ describe 'MysqlAlterTableParser' do
171
195
  action: :add_column,
172
196
  column: "value",
173
197
  type: "varchar(78)",
174
- after: 'id',
198
+ after: after_column_name,
199
+ query: actions
175
200
  }]
176
201
  })
177
202
  end
178
203
  end
204
+ context 'with after option, quoted after column name' do
205
+ let(:after_column) { "`#{after_column_name}`" }
206
+
207
+ it_behaves_like "generating a flydata record for the given query"
208
+ end
209
+
210
+ context 'with after option, backticks only on table name and a comment' do
211
+ let(:after_column) { after_column_name }
212
+
213
+ it_behaves_like "generating a flydata record for the given query"
214
+ end
179
215
 
180
216
  context 'with first option' do
181
217
  let(:query) { "alter table test_table add column value varchar(26) first" }
@@ -188,6 +224,7 @@ describe 'MysqlAlterTableParser' do
188
224
  column: "value",
189
225
  type: "varchar(78)",
190
226
  position: :first,
227
+ query: "add column value varchar(26) first"
191
228
  }]
192
229
  })
193
230
  end
@@ -205,6 +242,7 @@ describe 'MysqlAlterTableParser' do
205
242
  type: "varchar(78)",
206
243
  unique: true,
207
244
  position: :first,
245
+ query: "add column value varchar(26) UNIQUE first"
208
246
  }]
209
247
  })
210
248
  end
@@ -214,7 +252,7 @@ describe 'MysqlAlterTableParser' do
214
252
  shared_examples "a query parser parsing a query adding a column with a default value" do
215
253
  let(:query) { "alter table test_table add column col #{data_type} default #{value}" }
216
254
  it do
217
- expect(subject).to eq({
255
+ is_expected.to eq({
218
256
  type: :alter_table,
219
257
  table_name: "test_table",
220
258
  actions: [{
@@ -222,108 +260,109 @@ describe 'MysqlAlterTableParser' do
222
260
  column: "col",
223
261
  type: expected_data_type,
224
262
  default: expected_value,
263
+ query: "add column col #{data_type} default #{value}"
225
264
  }]
226
265
  })
227
266
  end
228
267
  end
229
-
268
+
230
269
  context 'for timestamp column' do
231
270
  let(:data_type) { "timestamp" }
232
271
  let(:expected_data_type) { "datetime" }
233
272
  context 'taking current_timestamp' do
234
273
  let(:value) { "current_timestamp" }
235
274
  let(:expected_value) { "current_timestamp" }
236
-
275
+
237
276
  it_behaves_like "a query parser parsing a query adding a column with a default value"
238
277
  end
239
278
  context 'taking localtime' do
240
279
  let(:value) { "localtime" }
241
280
  let(:expected_value) { "current_timestamp" }
242
-
281
+
243
282
  it_behaves_like "a query parser parsing a query adding a column with a default value"
244
283
  end
245
284
  context 'taking localtimestamp' do
246
285
  let(:value) { "localtimestamp" }
247
286
  let(:expected_value) { "current_timestamp" }
248
-
287
+
249
288
  it_behaves_like "a query parser parsing a query adding a column with a default value"
250
289
  end
251
290
  context 'taking now()' do
252
291
  let(:value) { "now()" }
253
292
  let(:expected_value) { "current_timestamp" }
254
-
293
+
255
294
  it_behaves_like "a query parser parsing a query adding a column with a default value"
256
295
  end
257
296
  end
258
-
297
+
259
298
  context 'for integer column' do
260
299
  let(:data_type) { "int(11)" }
261
300
  let(:expected_data_type) { "int4(11)" }
262
-
301
+
263
302
  context 'taking a positive number without sign' do
264
303
  let(:value) { "1" }
265
304
  let(:expected_value) { "1" }
266
-
305
+
267
306
  it_behaves_like "a query parser parsing a query adding a column with a default value"
268
307
  end
269
308
  context 'taking a positive number' do
270
309
  let(:value) { "+1" }
271
310
  let(:expected_value) { "1" }
272
-
311
+
273
312
  it_behaves_like "a query parser parsing a query adding a column with a default value"
274
313
  end
275
314
  context 'taking a negative number' do
276
315
  let(:value) { "-1" }
277
316
  let(:expected_value) { "-1" }
278
-
317
+
279
318
  it_behaves_like "a query parser parsing a query adding a column with a default value"
280
319
  end
281
320
  context 'taking a negative number string' do
282
321
  let(:value) { %Q|'-1'| }
283
322
  let(:expected_value) { "-1" }
284
-
323
+
285
324
  it_behaves_like "a query parser parsing a query adding a column with a default value"
286
325
  end
287
326
  context 'taking null' do
288
327
  let(:value) { %Q|NULL| }
289
328
  let(:expected_value) { nil }
290
-
329
+
291
330
  it_behaves_like "a query parser parsing a query adding a column with a default value"
292
331
  end
293
332
  end
294
-
333
+
295
334
  context 'for decimal column' do
296
335
  let(:data_type) { "decimal(10,2)" }
297
336
  let(:expected_data_type) { "numeric(10,2)" }
298
-
337
+
299
338
  context 'taking a positive number without sign' do
300
339
  let(:value) { "2.4" }
301
340
  let(:expected_value) { "2.4" }
302
-
341
+
303
342
  it_behaves_like "a query parser parsing a query adding a column with a default value"
304
343
  end
305
344
  context 'taking a positive number with sign' do
306
345
  let(:value) { "+0.4" }
307
346
  let(:expected_value) { "0.4" }
308
-
347
+
309
348
  it_behaves_like "a query parser parsing a query adding a column with a default value"
310
349
  end
311
350
  context 'taking a positive number no integer part' do
312
351
  let(:value) { ".05" }
313
352
  let(:expected_value) { "0.05" }
314
-
353
+
315
354
  it_behaves_like "a query parser parsing a query adding a column with a default value"
316
355
  end
317
356
  context 'taking a negative number' do
318
357
  let(:value) { "-20.43" }
319
358
  let(:expected_value) { "-20.43" }
320
-
359
+
321
360
  it_behaves_like "a query parser parsing a query adding a column with a default value"
322
361
  end
323
362
  context 'taking a negative number no integer part' do
324
363
  let(:value) { "-.43" }
325
364
  let(:expected_value) { "-0.43" }
326
-
365
+
327
366
  it_behaves_like "a query parser parsing a query adding a column with a default value"
328
367
  end
329
368
  end
@@ -331,35 +370,35 @@ describe 'MysqlAlterTableParser' do
331
370
  context 'for varchar column' do
332
371
  let(:data_type) { "varchar(10)" }
333
372
  let(:expected_data_type) { "varchar(30)" }
334
-
373
+
335
374
  context 'taking null' do
336
375
  let(:value) { "NULL" }
337
376
  let(:expected_value) { nil }
338
-
377
+
339
378
  it_behaves_like "a query parser parsing a query adding a column with a default value"
340
379
  end
341
380
  context 'taking empty string' do
342
381
  let(:value) { %Q|''| }
343
382
  let(:expected_value) { "" }
344
-
383
+
345
384
  it_behaves_like "a query parser parsing a query adding a column with a default value"
346
385
  end
347
386
  context 'taking a string with spaces' do
348
387
  let(:value) { %Q|'0 0 0 0 0 0 0'| }
349
388
  let(:expected_value) { "0 0 0 0 0 0 0" }
350
-
389
+
351
390
  it_behaves_like "a query parser parsing a query adding a column with a default value"
352
391
  end
353
392
  context 'taking a backslash' do
354
393
  let(:value) { %q|'\\\\'| }
355
394
  let(:expected_value) { %q|\\\\| }
356
-
395
+
357
396
  it_behaves_like "a query parser parsing a query adding a column with a default value"
358
397
  end
359
398
  context 'taking a string with special characters' do
360
399
  let(:value) { %q|'https://flydata.com $ \\\\\'\"\n\t'| }
361
400
  let(:expected_value) { %q|https://flydata.com $ \\\\\'\"\n\t| }
362
-
401
+
363
402
  it_behaves_like "a query parser parsing a query adding a column with a default value"
364
403
  end
365
404
  end
@@ -376,6 +415,7 @@ describe 'MysqlAlterTableParser' do
376
415
  action: :add_column,
377
416
  column: "extra",
378
417
  type: "varchar(#{length * 3})",
418
+ query: "add column extra varchar(#{length}) null"
379
419
  }]
380
420
  })
381
421
  end
@@ -390,7 +430,8 @@ describe 'MysqlAlterTableParser' do
390
430
  table_name: "test_table",
391
431
  actions: [{
392
432
  action: :drop_column,
393
- column: "value"
433
+ column: "value",
434
+ query: "drop column value"
394
435
  }])
395
436
  end
396
437
  end
@@ -403,7 +444,8 @@ describe 'MysqlAlterTableParser' do
403
444
  table_name: "test_table",
404
445
  actions: [{
405
446
  action: :drop_column,
406
- column: "value"
447
+ column: "value",
448
+ query: "drop value"
407
449
  }])
408
450
  end
409
451
  end
@@ -416,7 +458,8 @@ describe 'MysqlAlterTableParser' do
416
458
  table_name: "test_table",
417
459
  actions: [{
418
460
  action: :drop_column,
419
- column: "value"
461
+ column: "value",
462
+ query: "drop `value`"
420
463
  }])
421
464
  end
422
465
  end
@@ -429,7 +472,8 @@ describe 'MysqlAlterTableParser' do
429
472
  table_name: "test_table",
430
473
  actions: [{
431
474
  action: :drop_column,
432
- column: "value"
475
+ column: "value",
476
+ query: "drop value"
433
477
  }])
434
478
  end
435
479
  end
@@ -442,7 +486,8 @@ describe 'MysqlAlterTableParser' do
442
486
  table_name: "test_table",
443
487
  actions: [{
444
488
  action: :drop_column,
445
- column: "value"
489
+ column: "value",
490
+ query: "DROP value"
446
491
  }])
447
492
  end
448
493
  end
@@ -456,7 +501,8 @@ describe 'MysqlAlterTableParser' do
456
501
  table_name: "test_table",
457
502
  actions: [{
458
503
  action: :drop_column,
459
- column: "value"
504
+ column: "value",
505
+ query: "drop value"
460
506
  }])
461
507
  end
462
508
  end
@@ -470,35 +516,12 @@ describe 'MysqlAlterTableParser' do
470
516
  table_name: "test_table",
471
517
  actions: [{
472
518
  action: :drop_column,
473
- column: "value"
519
+ column: "value",
520
+ query: "drop `value`"
474
521
  }])
475
522
  end
476
523
  end
477
524
 
478
- context 'when query has unsupported drop dextension' do
479
- subject { parser.parse(query) }
480
-
481
- context 'with primary key drop' do
482
- let(:query) { "alter table test_table drop PRIMARY KEY" }
483
- it { expect(subject).to be_nil }
484
- end
485
-
486
- context 'with index drop' do
487
- let(:query) { "alter table test_table drop Index index_name" }
488
- it { expect(subject).to be_nil }
489
- end
490
-
491
- context 'with key drop' do
492
- let(:query) { "alter table test_table drop key index_name" }
493
- it { expect(subject).to be_nil }
494
- end
495
-
496
- context 'with foreign key drop' do
497
- let(:query) { "alter table test_table drop foreign key foreign_key_name" }
498
- it { expect(subject).to be_nil }
499
- end
500
- end
501
-
502
525
  context 'with multiple alter specs' do
503
526
  context 'with add column and drop column' do
504
527
  let(:query) { "alter table test_table add column value varchar(26) after id, drop old_value" }
@@ -511,13 +534,408 @@ describe 'MysqlAlterTableParser' do
511
534
  column: "value",
512
535
  type: "varchar(78)",
513
536
  after: 'id',
537
+ query: "add column value varchar(26) after id"
514
538
  },{
515
539
  action: :drop_column,
516
540
  column: "old_value",
541
+ query: "drop old_value"
517
542
  }]
518
543
  })
519
544
  end
520
545
  end
521
546
  end
547
+
548
+ let(:query) { "ALTER TABLE `test_schema`.`test_table` #{alter_table_action}" }
549
+ shared_examples "a parser parsing a single action alter table query" do
550
+ it do
551
+ is_expected.to eq({
552
+ type: :alter_table,
553
+ schema_name: "test_schema",
554
+ table_name: "test_table",
555
+ actions: [action_hash]
556
+ })
557
+ end
558
+ end
559
+ shared_examples "a parser parsing a nonbreaking query" do
560
+ let(:action_hash) {
561
+ {
562
+ action: action,
563
+ support_level: :nonbreaking,
564
+ query: alter_table_action,
565
+ }
566
+ }
567
+ it_behaves_like "a parser parsing a single action alter table query"
568
+ end
569
+ shared_examples "a parser parsing a breaking query" do
570
+ let(:action_hash) {
571
+ {
572
+ action: action,
573
+ query: alter_table_action,
574
+ }
575
+ }
576
+ it_behaves_like "a parser parsing a single action alter table query"
577
+ end
578
+ shared_examples "a debug parser" do
579
+ it do
580
+ puts query
581
+ result = parser.parse(query)
582
+ p result
583
+ puts "FAILURE: #{parser.failure_reason}"
584
+ end
585
+ end
586
+ shared_examples "test normal key options" do |*examples|
587
+ context "with normal key options" do
588
+ context "key_block_size" do
589
+ let(:normal_key_options) { " KEY_BLOCK_SIZE = 102400" }
590
+ it_behaves_like *examples
591
+ end
592
+ context "key_block_size with no space" do
593
+ let(:normal_key_options) { " KEY_BLOCK_SIZE=102400" }
594
+ it_behaves_like *examples
595
+ end
596
+ context "key_block_size no equal sign" do
597
+ let(:normal_key_options) { " KEY_BLOCK_SIZE 102400" }
598
+ it_behaves_like *examples
599
+ end
600
+ context "using" do
601
+ let(:normal_key_options) { " using btree" }
602
+ it_behaves_like *examples
603
+ end
604
+ context "comment" do
605
+ let(:normal_key_options) { " comment 'Hello World!'" }
606
+ it_behaves_like *examples
607
+ end
608
+ context "key_block_size and comment" do
609
+ let(:normal_key_options) { " KEY_BLOCK_SIZE 102400 comment 'Hello World!'" }
610
+ it_behaves_like *examples
611
+ end
612
+ context "none" do
613
+ it_behaves_like *examples do
614
+ let(:normal_key_options) { "" }
615
+ end
616
+ end
617
+ end
618
+ end
619
+ shared_examples "test key list" do |*examples|
620
+ context "with a single key" do
621
+ it_behaves_like *examples do
622
+ let(:key_list) { " testKey" }
623
+ let(:expected_key_list) { [ "testKey" ] }
624
+ end
625
+ end
626
+ context "with a quoted single key" do
627
+ it_behaves_like *examples do
628
+ let(:key_list) { " `testKey`" }
629
+ let(:expected_key_list) { [ "testKey" ] }
630
+ end
631
+ end
632
+ context "with multiple keys with order" do
633
+ it_behaves_like *examples do
634
+ let(:key_list) { " testKey1 ASC, testKey2 desc" }
635
+ let(:expected_key_list) { [ "testKey1 asc", "testKey2 desc" ] }
636
+ end
637
+ end
638
+ end
639
+
640
+ shared_examples "test constraint keyword" do |*examples|
641
+ context "with constraint keyword" do
642
+ context "with constraint name" do
643
+ it_behaves_like *examples do
644
+ let(:constraint_keyword) { " CONSTRAINT `chkName`" }
645
+ end
646
+ end
647
+ context "without constraint name" do
648
+ it_behaves_like *examples do
649
+ let(:constraint_keyword) { " CONSTRAINT" }
650
+ end
651
+ end
652
+ end
653
+ context "without constraint keyword" do
654
+ it_behaves_like *examples do
655
+ let(:constraint_keyword) { "" }
656
+ end
657
+ end
658
+ end
659
+ shared_examples "test key name" do |*examples|
660
+ context "with key name" do
661
+ it_behaves_like *examples do
662
+ let(:key_name) { " testKey" }
663
+ end
664
+ end
665
+ context "without key name" do
666
+ it_behaves_like *examples do
667
+ let(:key_name) { "" }
668
+ end
669
+ end
670
+ context "with quoted key name" do
671
+ it_behaves_like *examples do
672
+ let(:key_name) { " `testKey`" }
673
+ end
674
+ end
675
+ end
676
+ shared_examples "test key or index" do |*examples|
677
+ context "with key" do
678
+ it_behaves_like *examples do
679
+ let(:key_or_index) { " KEY" }
680
+ end
681
+ end
682
+ context "with index" do
683
+ it_behaves_like *examples do
684
+ let(:key_or_index) { " index" }
685
+ end
686
+ end
687
+ end
688
+ shared_examples "test optional key or index" do |*examples|
689
+ include_examples "test key or index", *examples
690
+ context "with none" do
691
+ it_behaves_like *examples do
692
+ let(:key_or_index) { "" }
693
+ end
694
+ end
695
+ end
696
+ shared_examples "test using option" do |*examples|
697
+ context "with BTREE" do
698
+ it_behaves_like *examples do
699
+ let(:using_option) { " USING BTREE" }
700
+ end
701
+ end
702
+ context "with hash" do
703
+ it_behaves_like *examples do
704
+ let(:using_option) { " using hash" }
705
+ end
706
+ end
707
+ context "with none" do
708
+ it_behaves_like *examples do
709
+ let(:using_option) { "" }
710
+ end
711
+ end
712
+ end
713
+ shared_examples "test field identifier" do |*examples|
714
+ context "without ." do
715
+ it_behaves_like "test identifier", *examples do
716
+ let(:field_ident) { " #{ident}" }
717
+ end
718
+ end
719
+ context "with single ." do
720
+ it_behaves_like "test identifier", *examples do
721
+ let(:field_ident) { " #{ident}.#{ident}"}
722
+ end
723
+ end
724
+ context "with two ." do
725
+ it_behaves_like "test identifier", *examples do
726
+ let(:field_ident) { " #{ident}.#{ident}.#{ident}" }
727
+ end
728
+ end
729
+ end
730
+ shared_examples "test identifier" do |*examples|
731
+ context "unquoted identifier" do
732
+ it_behaves_like *examples do
733
+ let(:ident) {"test_ident1"}
734
+ end
735
+ end
736
+ context "quoted identifier" do
737
+ it_behaves_like *examples do
738
+ let(:ident) {"`test_ident1`"}
739
+ end
740
+ end
741
+ end
742
+
743
+ context 'add index' do
744
+ let(:action) { :add_index }
745
+ context "with a simple add index" do
746
+ let(:alter_table_action) { "ADD INDEX `test` (`t_now`)" }
747
+ it_behaves_like "a parser parsing a nonbreaking query"
748
+ end
749
+ context "with a simple add index and without space before the opening bracket" do
750
+ let(:alter_table_action) { "ADD INDEX `test`(`t_now`)" }
751
+ it_behaves_like "a parser parsing a nonbreaking query"
752
+ end
753
+ context "with a simple add index with order" do
754
+ let(:alter_table_action) { "ADD INDEX `test` (`t_now` ASC)" }
755
+ it_behaves_like "a parser parsing a nonbreaking query"
756
+ end
757
+ context "with an add index with multiple fields" do
758
+ let(:key_list) { "`t_now` ASC, `t_timestamp` DESC" }
759
+ let(:alter_table_action) { "ADD INDEX `test` (#{key_list})" }
760
+ it_behaves_like "a parser parsing a nonbreaking query"
761
+
762
+ context "with spaces around key list" do
763
+ let(:key_list) { " `t_now` ASC, `t_timestamp` DESC " }
764
+ it_behaves_like "a parser parsing a nonbreaking query"
765
+ end
766
+
767
+ context "with a field without order" do
768
+ let(:key_list) { " `t_now` ASC, `t_timestamp`" }
769
+ it_behaves_like "a parser parsing a nonbreaking query"
770
+ end
771
+ end
772
+ context "with an add index with no index name" do
773
+ let(:alter_table_action) { "ADD INDEX (`t_now` ASC)" }
774
+ it_behaves_like "a parser parsing a nonbreaking query"
775
+ end
776
+ context "with an add index with USING" do
777
+ let(:using_option) { "USING BTREE" }
778
+ let(:alter_table_action) { "ADD INDEX `test` #{using_option} (`t_now` ASC)" }
779
+ it_behaves_like "a parser parsing a nonbreaking query"
780
+
781
+ context "without index name" do
782
+ let(:alter_table_action) { "ADD INDEX #{using_option} (`t_now` ASC)" }
783
+ it_behaves_like "a parser parsing a nonbreaking query"
784
+ end
785
+
786
+ context "without index name and without space before the opening bracket" do
787
+ let(:alter_table_action) { "ADD INDEX #{using_option}(`t_now` ASC)" }
788
+ it_behaves_like "a parser parsing a nonbreaking query"
789
+ end
790
+
791
+ context "with hash" do
792
+ let(:using_option) { "USING hash" }
793
+ it_behaves_like "a parser parsing a nonbreaking query"
794
+ end
795
+ end
796
+ context "with normal key options" do
797
+ let(:alter_table_action) { "ADD INDEX (`t_now` ASC)#{normal_key_options}" }
798
+ it_behaves_like "test normal key options", "a parser parsing a nonbreaking query"
799
+ end
800
+ end
801
+ context "fulltext or spatial" do
802
+ let(:action) { :add_index }
803
+ shared_examples "test all permutations" do |examples|
804
+ context "key_or_index" do
805
+ shared_examples "a parser parsing a nonbreaking query with key options" do
806
+ let(:alter_table_action) { "ADD #{fulltext_or_spatial} #{key_or_index} #{key_name} (test_column)#{key_options}" }
807
+ context "no key option" do
808
+ it_behaves_like "a parser parsing a nonbreaking query" do
809
+ let(:key_options) { "" }
810
+ end
811
+ end
812
+ context "key_block_size" do
813
+ it_behaves_like "a parser parsing a nonbreaking query" do
814
+ let(:key_options) { " KEY_BLOCK_SIZE 2048" }
815
+ end
816
+ end
817
+ context "comment" do
818
+ it_behaves_like "a parser parsing a nonbreaking query" do
819
+ let(:key_options) { " COMMENT 'Hello World!'" }
820
+ end
821
+ end
822
+ context "comment and key_block_size" do
823
+ it_behaves_like "a parser parsing a nonbreaking query" do
824
+ let(:key_options) { " KEY_BLOCK_SIZE = 1024 COMMENT 'Hello World!'" }
825
+ end
826
+ end
827
+ end
828
+ shared_examples "a parser parsing a nonbreaking query with key options fulltext" do
829
+ it_behaves_like "a parser parsing a nonbreaking query with key options"
830
+ let(:alter_table_action) { "ADD #{fulltext_or_spatial} #{key_or_index} #{key_name} (test_column)#{key_options}" }
831
+ context "with parser" do
832
+ it_behaves_like "a parser parsing a nonbreaking query" do
833
+ let(:key_options) { " WITH PARSER test_parser" }
834
+ end
835
+ end
836
+ end
837
+ shared_examples "a parser parsing a query with either key or index" do |*examples|
838
+ let(:alter_table_action) { "ADD #{fulltext_or_spatial} #{key_or_index} #{key_name} (test_column)" }
839
+ context "no key name" do
840
+ it_behaves_like *examples do
841
+ let(:key_name) { "" }
842
+ end
843
+ end
844
+ context "simple key name" do
845
+ it_behaves_like *examples do
846
+ let(:key_name) { "test_key" }
847
+ end
848
+ end
849
+ context "quoted key name" do
850
+ it_behaves_like *examples do
851
+ let(:key_name) { "`test_key`" }
852
+ end
853
+ end
854
+ end
855
+ it_behaves_like "test optional key or index", "a parser parsing a query with either key or index", examples
856
+ end
857
+ end
858
+ context "with fulltext" do
859
+ it_behaves_like "test all permutations", "a parser parsing a nonbreaking query with key options fulltext" do
860
+ let(:fulltext_or_spatial) { "FULLTEXT" }
861
+ end
862
+ end
863
+ context "with spatial" do
864
+ it_behaves_like "test all permutations", "a parser parsing a nonbreaking query with key options" do
865
+ let(:fulltext_or_spatial) { "SPATIAL" }
866
+ end
867
+ end
868
+ end
869
+ context "check constraint" do
870
+ let(:action) { :add_check_constraint }
871
+ let(:alter_table_action) { "ADD#{constraint_keyword} CHECK (#{constraint_expr})" }
872
+ shared_examples "test constraint expr" do
873
+ context "with constraint expr" do
874
+ it_behaves_like "test constraint keyword", "a parser parsing a nonbreaking query" do
875
+ let(:constraint_expr) { "P_Id>0 AND City='Sandnes'" }
876
+ end
877
+ end
878
+ end
879
+
880
+ context "test all" do
881
+ it_behaves_like "test constraint expr"
882
+ end
883
+ end
884
+ context "unique constraint" do
885
+ let(:action) { :add_unique_constraint }
886
+ let(:alter_table_action) { "ADD#{constraint_keyword} UNIQUE#{key_or_index}#{key_name}#{using_option} (#{key_list})#{normal_key_options}" }
887
+
888
+ it_behaves_like "test constraint keyword", "test optional key or index",
889
+ "test key name", "test using option", "test key list",
890
+ "test normal key options",
891
+ # "a debug parser"
892
+ "a parser parsing a nonbreaking query"
893
+ end
894
+ context "primary key constraint" do
895
+ let(:alter_table_action) { "ADD#{constraint_keyword} PRIMARY KEY#{key_name}#{using_option} (#{key_list})#{normal_key_options}" }
896
+ let(:action) { :add_primary_key_constraint }
897
+ let(:action_hash) {
898
+ {
899
+ action: action,
900
+ keys: expected_key_list,
901
+ query: alter_table_action,
902
+ }
903
+ }
904
+
905
+ it_behaves_like "test constraint keyword",
906
+ "test key name", "test using option", "test key list",
907
+ "test normal key options",
908
+ # "a debug parser"
909
+ "a parser parsing a single action alter table query"
910
+ end
911
+ context "enable keys" do
912
+ let(:alter_table_action) { "ENABLE KEYS" }
913
+ let(:action) { :enable_keys }
914
+ let(:action_hash) {
915
+ {
916
+ action: action,
917
+ support_level: :nonbreaking,
918
+ query: alter_table_action,
919
+ }
920
+ }
921
+ end
922
+ context "drop primary key" do
923
+ let(:alter_table_action) { "DROP PRIMARY KEY" }
924
+ let(:action) { :drop_primary_key }
925
+
926
+ it_behaves_like "a parser parsing a breaking query"
927
+ end
928
+ context "drop foreign key" do
929
+ let(:alter_table_action) { "DROP FOREIGN KEY#{field_ident}" }
930
+ let(:action) { :drop_foreign_key }
931
+
932
+ it_behaves_like "test field identifier", "a parser parsing a nonbreaking query"
933
+ end
934
+ context "drop key or index" do
935
+ let(:alter_table_action) { "DROP#{key_or_index}#{field_ident}" }
936
+ let(:action) { "drop_#{key_or_index.strip.downcase}".to_sym }
937
+
938
+ it_behaves_like "test key or index", "test field identifier", "a parser parsing a nonbreaking query"
939
+ end
522
940
  end
523
941
  end