1 /*
2 * Copyright (c) 2015, 2016 Oracle and/or its affiliates. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License, version 2.0,
6 * as published by the Free Software Foundation.
7 *
8 * This program is also distributed with certain software (including
9 * but not limited to OpenSSL) that is licensed under separate terms,
10 * as designated in a particular file or component or in included license
11 * documentation. The authors of MySQL hereby grant you an additional
12 * permission to link the program and your derivative works with the
13 * separately licensed software that they have included with MySQL.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License, version 2.0, for more details.
19 *
20 * You should have received a copy of the GNU General Public License along
21 * with this program; if not, write to the Free Software Foundation, Inc.,
22 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
23 */
24
25 #include "update_statement_builder.h"
26 #include "mysqld_error.h"
27 #include "ngs_common/protocol_protobuf.h"
28
29 #include <gtest/gtest.h>
30
31 namespace xpl
32 {
33 namespace test
34 {
35
36 class Update_statement_builder_impl: public Update_statement_builder
37 {
38 public:
Update_statement_builder_impl(Expression_generator & gen)39 Update_statement_builder_impl(Expression_generator &gen) : Update_statement_builder(gen) {}
40 using Update_statement_builder::add_operation;
41 using Update_statement_builder::add_table_operation;
42 using Update_statement_builder::add_document_operation;
43 using Update_statement_builder::add_document_operation_item;
44 using Update_statement_builder::Operation_list;
45 using Update_statement_builder::Operation_item;
46 using Update_statement_builder::Generator;
47 };
48
49
50 class Update_statement_builder_test : public ::testing::Test
51 {
52 public:
Update_statement_builder_test()53 Update_statement_builder_test()
54 : args(*msg.mutable_args()),
55 expr_gen(query, args, schema, true),
56 builder(expr_gen),
57 oper(-1)
58 {}
59 Update_statement_builder::Update msg;
60 Expression_generator::Args &args;
61 Query_string_builder query;
62 std::string schema;
63 Expression_generator expr_gen;
64 Update_statement_builder_impl builder;
65 int oper;
66
67 enum {DM_DOCUMENT = 0, DM_TABLE = 1};
68
69 typedef ::Mysqlx::Crud::UpdateOperation UpdateOperation;
70 };
71
72
73
74 namespace
75 {
76
operator <<(::google::protobuf::Message & msg,const std::string & txt)77 void operator<< (::google::protobuf::Message &msg, const std::string& txt)
78 {
79 ASSERT_TRUE(::google::protobuf::TextFormat::ParseFromString(txt, &msg));
80 }
81
82 const std::string value_ = "value: {type: LITERAL literal {type: ";
83 const std::string value_1 = value_ + "V_DOUBLE v_double: 1.0}}";
84 const std::string value_2 = value_ + "V_STRING v_string: {value: 'two'}}}";
85 const std::string value_3 = value_ + "V_SINT v_signed_int: -3}}";
86 const std::string placeholder_0 = "value: {type: PLACEHOLDER position: 0}";
87 } // namespace
88
89
TEST_F(Update_statement_builder_test,add_operation_empty_list)90 TEST_F(Update_statement_builder_test, add_operation_empty_list)
91 {
92 Update_statement_builder_impl::Operation_list operation;
93 EXPECT_THROW(builder.add_operation(operation, DM_TABLE), ngs::Error_code);
94 }
95
96
TEST_F(Update_statement_builder_test,add_table_operation_one_item)97 TEST_F(Update_statement_builder_test, add_table_operation_one_item)
98 {
99 Update_statement_builder_impl::Operation_list operation;
100 *operation.Add() << "source {name: 'xfield'}"
101 "operation: SET " + value_1;
102 EXPECT_NO_THROW(builder.add_table_operation(operation));
103 EXPECT_EQ("`xfield`=1", query.get());
104 }
105
106
TEST_F(Update_statement_builder_test,add_table_operation_two_items)107 TEST_F(Update_statement_builder_test, add_table_operation_two_items)
108 {
109 Update_statement_builder_impl::Operation_list operation;
110 *operation.Add() << "source {name: 'xfield'}"
111 "operation: SET " + value_1;;
112 *operation.Add() << "source {name: 'yfield'}"
113 "operation: SET " + value_2;
114 EXPECT_NO_THROW(builder.add_table_operation(operation));
115 EXPECT_EQ("`xfield`=1,`yfield`='two'", query.get());
116 }
117
118
TEST_F(Update_statement_builder_test,add_table_operation_two_items_same_source)119 TEST_F(Update_statement_builder_test, add_table_operation_two_items_same_source)
120 {
121 Update_statement_builder_impl::Operation_list operation;
122 *operation.Add() << "source {name: 'xfield'}"
123 "operation: SET " + value_1;;
124 *operation.Add() << "source {name: 'xfield'}"
125 "operation: SET " + value_2;
126 EXPECT_NO_THROW(builder.add_table_operation(operation));
127 EXPECT_EQ("`xfield`=1,`xfield`='two'", query.get());
128 }
129
130
TEST_F(Update_statement_builder_test,add_table_operation_two_items_placeholder)131 TEST_F(Update_statement_builder_test, add_table_operation_two_items_placeholder)
132 {
133 *args.Add() << "type: V_DOUBLE v_double: 2.2";
134
135 Update_statement_builder_impl::Operation_list operation;
136 *operation.Add() << "source {name: 'xfield'}"
137 "operation: SET " + value_1;;
138 *operation.Add() << "source {name: 'yfield'}"
139 "operation: SET " + placeholder_0;
140 EXPECT_NO_THROW(builder.add_table_operation(operation));
141 EXPECT_EQ("`xfield`=1,`yfield`=2.2", query.get());
142 }
143
144
TEST_F(Update_statement_builder_test,add_table_operation_empty_name)145 TEST_F(Update_statement_builder_test, add_table_operation_empty_name)
146 {
147 Update_statement_builder_impl::Operation_list operation;
148 *operation.Add() << "source {} operation: SET " + value_1;;
149 EXPECT_THROW(builder.add_table_operation(operation), ngs::Error_code);
150 }
151
152
TEST_F(Update_statement_builder_test,add_table_operation_item_name_with_table)153 TEST_F(Update_statement_builder_test, add_table_operation_item_name_with_table)
154 {
155 Update_statement_builder_impl::Operation_list operation;
156 *operation.Add() << "source {name: 'xfield' table_name: 'xtable'}"
157 "operation: SET " + value_1;
158 EXPECT_THROW(builder.add_table_operation(operation), ngs::Error_code);
159 }
160
161
TEST_F(Update_statement_builder_test,add_table_operation_item_name_with_table_and_schema)162 TEST_F(Update_statement_builder_test, add_table_operation_item_name_with_table_and_schema)
163 {
164 Update_statement_builder_impl::Operation_list operation;
165 *operation.Add() << "source {name: 'xfield' table_name: 'xtable' schema_name: 'xschema'}"
166 "operation: SET " + value_1;
167 EXPECT_THROW(builder.add_table_operation(operation), ngs::Error_code);
168 }
169
170
TEST_F(Update_statement_builder_test,add_operation_one_item_for_table)171 TEST_F(Update_statement_builder_test, add_operation_one_item_for_table)
172 {
173 Update_statement_builder_impl::Operation_list operation;
174 *operation.Add() << "source {name: 'xfield'}"
175 "operation: SET " + value_1;
176 EXPECT_NO_THROW(builder.add_operation(operation, DM_TABLE));
177 EXPECT_EQ(" SET `xfield`=1", query.get());
178 }
179
180 namespace
181 {
182 const std::string table_full_message(
183 "collection {name: 'xtable' schema: 'xschema'}"
184 "data_model: TABLE "
185 "operation {source {name: 'yfield'}"
186 " operation: SET"
187 " value {type: LITERAL literal {type: V_OCTETS"
188 " v_octets {value: 'booom'}}}}"
189 "criteria {type: OPERATOR "
190 " operator {name: '>' "
191 " param {type: IDENT identifier {name: 'xfield'}}"
192 " param {type: LITERAL literal {type: V_DOUBLE"
193 " v_double: 1.0}}}}"
194 "order {expr {type: IDENT identifier {name: 'xfield'}}"
195 " direction: DESC}");
196 } // namespace
197
198
TEST_F(Update_statement_builder_test,build_update_for_table)199 TEST_F(Update_statement_builder_test, build_update_for_table)
200 {
201 msg << table_full_message + "limit {row_count: 2}";
202 EXPECT_NO_THROW(builder.build(msg));
203 EXPECT_EQ("UPDATE `xschema`.`xtable`"
204 " SET `yfield`='booom'"
205 " WHERE (`xfield` > 1)"
206 " ORDER BY `xfield` DESC"
207 " LIMIT 2", query.get());
208 }
209
TEST_F(Update_statement_builder_test,build_update_for_table_forrbiden_offset_in_limit)210 TEST_F(Update_statement_builder_test, build_update_for_table_forrbiden_offset_in_limit)
211 {
212 msg << table_full_message + "limit {row_count: 2 offset: 5}";
213 EXPECT_THROW(builder.build(msg), ngs::Error_code);
214 }
215
216
217 namespace
218 {
219 const std::string source_ = "source {document_path {type: MEMBER value: ";
220 const std::string source_index_ = "source {document_path {type: ARRAY_INDEX index: ";
221 const std::string source_first = source_ + "'first'}}";
222 const std::string source_second = source_ + "'second'}}";
223 const std::string source_third = source_ + "'third'}}";
224 const std::string source_index_first_0 = source_ + "'first'} document_path {type:ARRAY_INDEX index: 0}}";
225 const std::string source_index_0 = source_index_ + " 0}}";
226 const std::string source_index_1 = source_index_ + " 1}}";
227
228 const std::string document_full_message(
229 "collection {name: 'xtable' schema: 'xschema'}"
230 "data_model: DOCUMENT "
231 "operation {source {document_path {type: MEMBER value: 'first'}}"
232 " operation: ITEM_SET"
233 " value: {type: LITERAL literal {type: V_DOUBLE v_double: 1.0}}}"
234 "criteria {type: OPERATOR "
235 " operator {name: '>' "
236 " param {type: IDENT identifier {document_path {type: MEMBER value: 'second'}}}"
237 " param {type: LITERAL literal {type: V_DOUBLE"
238 " v_double: 1.0}}}}"
239 "order {expr {type: IDENT identifier {document_path {type: MEMBER value: 'third'}}}"
240 " direction: DESC}");
241 } // namespace
242
243
TEST_F(Update_statement_builder_test,add_document_operation_not_allowed_set)244 TEST_F(Update_statement_builder_test, add_document_operation_not_allowed_set)
245 {
246 Update_statement_builder_impl::Operation_list operation;
247 *operation.Add() << source_first + "operation: SET " + value_1;
248 EXPECT_THROW(builder.add_document_operation(operation), ngs::Error_code);
249 }
250
251
TEST_F(Update_statement_builder_test,add_document_operation_remove)252 TEST_F(Update_statement_builder_test, add_document_operation_remove)
253 {
254 Update_statement_builder_impl::Operation_list operation;
255 *operation.Add() << source_first + "operation: ITEM_REMOVE ";
256 EXPECT_NO_THROW(builder.add_document_operation(operation));
257 EXPECT_EQ("doc=JSON_REMOVE(doc,'$.first')", query.get());
258 }
259
260
TEST_F(Update_statement_builder_test,add_document_operation_set)261 TEST_F(Update_statement_builder_test, add_document_operation_set)
262 {
263 Update_statement_builder_impl::Operation_list operation;
264 *operation.Add() << source_first + "operation: ITEM_SET " + value_1;
265 EXPECT_NO_THROW(builder.add_document_operation(operation));
266 EXPECT_EQ("doc=JSON_SET(doc,'$.first',1)",
267 query.get());
268 }
269
270
TEST_F(Update_statement_builder_test,add_document_operation_replace)271 TEST_F(Update_statement_builder_test, add_document_operation_replace)
272 {
273 Update_statement_builder_impl::Operation_list operation;
274 *operation.Add() << source_first + "operation: ITEM_REPLACE " + value_1;
275 EXPECT_NO_THROW(builder.add_document_operation(operation));
276 EXPECT_EQ("doc=JSON_REPLACE(doc,'$.first',1)",
277 query.get());
278 }
279
280
TEST_F(Update_statement_builder_test,add_document_operation_merge)281 TEST_F(Update_statement_builder_test, add_document_operation_merge)
282 {
283 Update_statement_builder_impl::Operation_list operation;
284 *operation.Add() << source_first +
285 "operation: ITEM_MERGE "
286 "value {type: LITERAL literal {type: V_OCTETS v_octets {value: '{\\\"two\\\": 2.0}'}}}";
287 ASSERT_NO_THROW(builder.add_document_operation(operation));
288 EXPECT_EQ(
289 "doc=JSON_MERGE(doc,IF(JSON_TYPE('{\\\"two\\\": 2.0}')='OBJECT',"
290 "JSON_REMOVE('{\\\"two\\\": 2.0}','$._id'),'_ERROR_'))",
291 query.get());
292 }
293
294
TEST_F(Update_statement_builder_test,add_document_operation_array_insert)295 TEST_F(Update_statement_builder_test, add_document_operation_array_insert)
296 {
297 Update_statement_builder_impl::Operation_list operation;
298 *operation.Add() << source_index_first_0 + "operation: ARRAY_INSERT " + value_1;
299 EXPECT_NO_THROW(builder.add_document_operation(operation));
300 EXPECT_EQ("doc=JSON_ARRAY_INSERT(doc,'$.first[0]',1)",
301 query.get());
302 }
303
304
TEST_F(Update_statement_builder_test,add_document_operation_array_append)305 TEST_F(Update_statement_builder_test, add_document_operation_array_append)
306 {
307 Update_statement_builder_impl::Operation_list operation;
308 *operation.Add() << source_first + "operation: ARRAY_APPEND " + value_1;
309 EXPECT_NO_THROW(builder.add_document_operation(operation));
310 EXPECT_EQ("doc=JSON_ARRAY_APPEND(doc,'$.first',1)",
311 query.get());
312 }
313
314
TEST_F(Update_statement_builder_test,add_document_operation_array_append_twice)315 TEST_F(Update_statement_builder_test, add_document_operation_array_append_twice)
316 {
317 Update_statement_builder_impl::Operation_list operation;
318 *operation.Add() << source_first + "operation: ARRAY_APPEND " + value_1;
319 *operation.Add() << source_first + "operation: ARRAY_APPEND " + value_2;
320 EXPECT_NO_THROW(builder.add_document_operation(operation));
321 EXPECT_EQ("doc=JSON_ARRAY_APPEND(doc,'$.first',1,'$.first','two')",
322 query.get());
323 }
324
325
TEST_F(Update_statement_builder_test,add_document_operation_remove_twice)326 TEST_F(Update_statement_builder_test, add_document_operation_remove_twice)
327 {
328 Update_statement_builder_impl::Operation_list operation;
329 *operation.Add() << source_first + "operation: ITEM_REMOVE ";
330 *operation.Add() << source_second + "operation: ITEM_REMOVE ";
331 EXPECT_NO_THROW(builder.add_document_operation(operation));
332 EXPECT_EQ("doc=JSON_REMOVE(doc,'$.first','$.second')",
333 query.get());
334 }
335
336
TEST_F(Update_statement_builder_test,add_document_operation_set_twice)337 TEST_F(Update_statement_builder_test, add_document_operation_set_twice)
338 {
339 Update_statement_builder_impl::Operation_list operation;
340 *operation.Add() << source_first + "operation: ITEM_SET " + value_1;
341 *operation.Add() << source_second + "operation: ITEM_SET " + value_2;
342 EXPECT_NO_THROW(builder.add_document_operation(operation));
343 EXPECT_EQ("doc=JSON_SET(doc,'$.first',1,'$.second','two')",
344 query.get());
345 }
346
347
TEST_F(Update_statement_builder_test,add_document_operation_set_twice_placeholder)348 TEST_F(Update_statement_builder_test, add_document_operation_set_twice_placeholder)
349 {
350 *args.Add() << "type: V_DOUBLE v_double: 2.2";
351 *args.Add() << "type: V_OCTETS v_octets {value: '$.second'}";
352 Update_statement_builder_impl::Operation_list operation;
353 *operation.Add() << source_first + "operation: ITEM_SET " + value_1;
354 *operation.Add() << source_second + "operation: ITEM_SET " + placeholder_0;
355 EXPECT_NO_THROW(builder.add_document_operation(operation));
356 EXPECT_EQ("doc=JSON_SET(doc,'$.first',1,'$.second',2.2)",
357 query.get());
358 }
359
360
TEST_F(Update_statement_builder_test,add_document_operation_merge_twice)361 TEST_F(Update_statement_builder_test, add_document_operation_merge_twice)
362 {
363 Update_statement_builder_impl::Operation_list operation;
364 *operation.Add() << "source {} operation: ITEM_MERGE "
365 "value {type: LITERAL literal {type: V_OCTETS v_octets {value: '{\\\"two\\\": 2.0}'}}}";
366 *operation.Add() << "source {} operation: ITEM_MERGE "
367 "value {type: LITERAL literal {type: V_OCTETS v_octets {value: '{\\\"three\\\": 3.0}'}}}";
368 ASSERT_NO_THROW(builder.add_document_operation(operation));
369 EXPECT_EQ(
370 "doc=JSON_MERGE(doc,IF(JSON_TYPE('{\\\"two\\\": 2.0}')='OBJECT',"
371 "JSON_REMOVE('{\\\"two\\\": 2.0}','$._id'),'_ERROR_'),"
372 "IF(JSON_TYPE('{\\\"three\\\": 3.0}')='OBJECT',"
373 "JSON_REMOVE('{\\\"three\\\": 3.0}','$._id'),'_ERROR_'))",
374 query.get());
375 }
376
377
TEST_F(Update_statement_builder_test,add_document_operation_remove_set)378 TEST_F(Update_statement_builder_test, add_document_operation_remove_set)
379 {
380 Update_statement_builder_impl::Operation_list operation;
381 *operation.Add() << source_first + "operation: ITEM_REMOVE ";
382 *operation.Add() << source_second + "operation: ITEM_SET " + value_2;
383 EXPECT_NO_THROW(builder.add_document_operation(operation));
384 EXPECT_EQ("doc=JSON_SET(JSON_REMOVE(doc,'$.first'),'$.second','two')",
385 query.get());
386 }
387
388
TEST_F(Update_statement_builder_test,add_document_operation_remove_twice_set)389 TEST_F(Update_statement_builder_test, add_document_operation_remove_twice_set)
390 {
391 Update_statement_builder_impl::Operation_list operation;
392 *operation.Add() << source_first + "operation: ITEM_REMOVE ";
393 *operation.Add() << source_second + "operation: ITEM_REMOVE ";
394 *operation.Add() << source_third + "operation: ITEM_SET " + value_3;
395 EXPECT_NO_THROW(builder.add_document_operation(operation));
396 EXPECT_EQ("doc=JSON_SET(JSON_REMOVE(doc,'$.first','$.second'),'$.third',-3)",
397 query.get());
398 }
399
400
TEST_F(Update_statement_builder_test,add_document_operation_set_remove_set)401 TEST_F(Update_statement_builder_test, add_document_operation_set_remove_set)
402 {
403 Update_statement_builder_impl::Operation_list operation;
404 *operation.Add() << source_first + "operation: ITEM_SET " + value_1;
405 *operation.Add() << source_second + "operation: ITEM_REMOVE ";
406 *operation.Add() << source_third + "operation: ITEM_SET " + value_3;
407 EXPECT_NO_THROW(builder.add_document_operation(operation));
408 EXPECT_EQ("doc=JSON_SET(JSON_REMOVE("
409 "JSON_SET(doc,'$.first',1),'$.second'),'$.third',-3)",
410 query.get());
411 }
412
413
TEST_F(Update_statement_builder_test,add_document_operation_set_merge)414 TEST_F(Update_statement_builder_test, add_document_operation_set_merge)
415 {
416 Update_statement_builder_impl::Operation_list operation;
417 *operation.Add() << source_first + "operation: ITEM_SET " + value_1;
418 *operation.Add() << "source {} operation: ITEM_MERGE "
419 "value {type: LITERAL literal {type: V_OCTETS v_octets {value: '{\\\"three\\\": 3.0}'}}}";
420 ASSERT_NO_THROW(builder.add_document_operation(operation));
421 EXPECT_EQ(
422 "doc=JSON_MERGE(JSON_SET(doc,'$.first',1),"
423 "IF(JSON_TYPE('{\\\"three\\\": 3.0}')='OBJECT',"
424 "JSON_REMOVE('{\\\"three\\\": 3.0}','$._id'),'_ERROR_'))",
425 query.get());
426 }
427
428
TEST_F(Update_statement_builder_test,add_document_operation_item_forbiden_column)429 TEST_F(Update_statement_builder_test, add_document_operation_item_forbiden_column)
430 {
431 Update_statement_builder_impl::Operation_item operation;
432 operation << "source {name: 'xcolumn'} operation: ITEM_SET " + value_3;
433 ASSERT_THROW(builder.add_document_operation_item(operation, oper),
434 ngs::Error_code);
435 ASSERT_EQ(UpdateOperation::ITEM_SET, oper);
436 }
437
438
TEST_F(Update_statement_builder_test,add_document_operation_item_forbiden_schema)439 TEST_F(Update_statement_builder_test, add_document_operation_item_forbiden_schema)
440 {
441 Update_statement_builder_impl::Operation_item operation;
442 operation << "source {schema_name: 'xschema'} operation: ITEM_SET "
443 + value_3;
444 ASSERT_THROW(builder.add_document_operation_item(operation, oper),
445 ngs::Error_code);
446 ASSERT_EQ(UpdateOperation::ITEM_SET, oper);
447 }
448
449
TEST_F(Update_statement_builder_test,add_document_operation_item_forbiden_table)450 TEST_F(Update_statement_builder_test, add_document_operation_item_forbiden_table)
451 {
452 Update_statement_builder_impl::Operation_item operation;
453 operation << "source {table_name: 'xtable'} operation: ITEM_SET "
454 + value_3;
455 ASSERT_THROW(builder.add_document_operation_item(operation, oper),
456 ngs::Error_code);
457 ASSERT_EQ(UpdateOperation::ITEM_SET, oper);
458 }
459
460
TEST_F(Update_statement_builder_test,add_document_operation_item_forbiden_id_change)461 TEST_F(Update_statement_builder_test, add_document_operation_item_forbiden_id_change)
462 {
463 Update_statement_builder_impl::Operation_item operation;
464 operation << "source {document_path {type: MEMBER value: '_id'}} operation: ITEM_SET "
465 + value_3;
466 ASSERT_THROW(builder.add_document_operation_item(operation, oper),
467 ngs::Error_code);
468 ASSERT_EQ(UpdateOperation::ITEM_SET, oper);
469 }
470
471
TEST_F(Update_statement_builder_test,add_document_operation_item_empty_document_path)472 TEST_F(Update_statement_builder_test, add_document_operation_item_empty_document_path)
473 {
474 Update_statement_builder_impl::Operation_item operation;
475 operation << "source {} operation: ITEM_SET " + value_3;
476 ASSERT_THROW(builder.add_document_operation_item(operation, oper),
477 ngs::Error_code);
478 ASSERT_EQ(UpdateOperation::ITEM_SET, oper);
479 }
480
481
TEST_F(Update_statement_builder_test,add_document_operation_item_root_path)482 TEST_F(Update_statement_builder_test, add_document_operation_item_root_path)
483 {
484 Update_statement_builder_impl::Operation_item operation;
485 operation << "source {document_path {type: MEMBER value: ''}} operation: ITEM_SET " + value_3;
486 ASSERT_NO_THROW(builder.add_document_operation_item(operation, oper));
487 ASSERT_EQ(UpdateOperation::ITEM_SET, oper);
488 }
489
490
TEST_F(Update_statement_builder_test,add_document_operation_item_empty_member)491 TEST_F(Update_statement_builder_test, add_document_operation_item_empty_member)
492 {
493 Update_statement_builder_impl::Operation_item operation;
494 operation << "source {document_path {type: MEMBER value: 'first'} "
495 "document_path {type: MEMBER value: ''}} "
496 "operation: ITEM_SET " + value_3;
497 ASSERT_THROW(builder.add_document_operation_item(operation, oper),
498 xpl::Expression_generator::Error);
499 ASSERT_EQ(UpdateOperation::ITEM_SET, oper);
500 }
501
502
TEST_F(Update_statement_builder_test,add_document_operation_item_empty_member_reverse)503 TEST_F(Update_statement_builder_test, add_document_operation_item_empty_member_reverse)
504 {
505 Update_statement_builder_impl::Operation_item operation;
506 operation << "source {document_path {type: MEMBER value: ''} "
507 "document_path {type: MEMBER value: 'first'}} "
508 "operation: ITEM_SET " + value_3;
509 ASSERT_THROW(builder.add_document_operation_item(operation, oper),
510 xpl::Expression_generator::Error);
511 ASSERT_EQ(UpdateOperation::ITEM_SET, oper);
512 }
513
514
TEST_F(Update_statement_builder_test,add_document_operation_item_root_as_array)515 TEST_F(Update_statement_builder_test, add_document_operation_item_root_as_array)
516 {
517 Update_statement_builder_impl::Operation_item operation;
518 operation << source_index_0 + "operation: ITEM_SET " + value_3;
519 ASSERT_THROW(builder.add_document_operation_item(operation, oper),
520 ngs::Error_code);
521 ASSERT_EQ(UpdateOperation::ITEM_SET, oper);
522 }
523
524
TEST_F(Update_statement_builder_test,add_document_operation_item_root_as_array_asterisk)525 TEST_F(Update_statement_builder_test, add_document_operation_item_root_as_array_asterisk)
526 {
527 Update_statement_builder_impl::Operation_item operation;
528 operation << "source {document_path {type: ARRAY_INDEX_ASTERISK}} "
529 "operation: ITEM_SET " + value_3;
530 ASSERT_THROW(builder.add_document_operation_item(operation, oper),
531 ngs::Error_code);
532 ASSERT_EQ(UpdateOperation::ITEM_SET, oper);
533 }
534
535
TEST_F(Update_statement_builder_test,add_document_operation_item_root_double_asterisk)536 TEST_F(Update_statement_builder_test, add_document_operation_item_root_double_asterisk)
537 {
538 Update_statement_builder_impl::Operation_item operation;
539 operation << "source {document_path {type: DOUBLE_ASTERISK}} "
540 "operation: ITEM_SET " + value_3;
541 ASSERT_THROW(builder.add_document_operation_item(operation, oper),
542 ngs::Error_code);
543 ASSERT_EQ(UpdateOperation::ITEM_SET, oper);
544 }
545
546
TEST_F(Update_statement_builder_test,add_operation_one_item_for_document)547 TEST_F(Update_statement_builder_test, add_operation_one_item_for_document)
548 {
549 Update_statement_builder_impl::Operation_list operation;
550 *operation.Add() << source_first + "operation: ITEM_SET " + value_1;
551 EXPECT_NO_THROW(builder.add_operation(operation, DM_DOCUMENT));
552 EXPECT_EQ(" SET doc=JSON_SET(doc,'$.first',1)",
553 query.get());
554 }
555
556
TEST_F(Update_statement_builder_test,build_update_for_document)557 TEST_F(Update_statement_builder_test, build_update_for_document)
558 {
559 msg << document_full_message + "limit {row_count: 2}";
560 EXPECT_NO_THROW(builder.build(msg));
561 EXPECT_EQ("UPDATE `xschema`.`xtable` "
562 "SET doc=JSON_SET(doc,'$.first',1) "
563 "WHERE (JSON_EXTRACT(doc,'$.second') > 1) "
564 "ORDER BY JSON_EXTRACT(doc,'$.third') "
565 "DESC LIMIT 2",
566 query.get());
567 }
568
569
570 namespace
571 {
get_operation(const std::string & name,const std::string & member,const std::string & oper,const std::string & value)572 std::string get_operation(const std::string &name, const std::string &member,
573 const std::string &oper, const std::string &value)
574 {
575 std::string str("source {");
576 if (!name.empty())
577 str += "name: '" + name + "' ";
578 if (!member.empty())
579 {
580 str += "document_path {type: ";
581 if (isdigit(member[0]))
582 {
583 str += "ARRAY_INDEX index: " + member;
584 }
585 else
586 {
587 str += "MEMBER ";
588 if (member != "$")
589 str += "value: '" + member + "' ";
590 }
591 str += "}";
592 }
593 str += "} operation: " + oper;
594 if (!value.empty())
595 str += " " + value;
596 return str;
597 }
598
599 } // namespace
600
601
TEST_F(Update_statement_builder_test,add_document_operation_set_whole_doc)602 TEST_F(Update_statement_builder_test, add_document_operation_set_whole_doc)
603 {
604 Update_statement_builder_impl::Operation_list operation;
605 *operation.Add() << get_operation("", "$", "ITEM_SET", value_2);
606 EXPECT_NO_THROW(builder.add_document_operation(operation));
607 EXPECT_EQ("doc=JSON_SET(doc,'$','two')",
608 query.get());
609 }
610
611
TEST_F(Update_statement_builder_test,add_table_operation_set_needless_doc_path)612 TEST_F(Update_statement_builder_test, add_table_operation_set_needless_doc_path)
613 {
614 Update_statement_builder_impl::Operation_list operation;
615 *operation.Add() << get_operation("xfield", "first", "SET", value_1);
616 EXPECT_THROW(builder.add_table_operation(operation), ngs::Error_code);
617 }
618
619
TEST_F(Update_statement_builder_test,add_table_operation_item_set_missing_doc_path)620 TEST_F(Update_statement_builder_test, add_table_operation_item_set_missing_doc_path)
621 {
622 Update_statement_builder_impl::Operation_list operation;
623 *operation.Add() << get_operation("xfield", "", "ITEM_SET", value_1);
624 EXPECT_THROW(builder.add_table_operation(operation), ngs::Error_code);
625 }
626
627
TEST_F(Update_statement_builder_test,add_table_operation_item_set)628 TEST_F(Update_statement_builder_test, add_table_operation_item_set)
629 {
630 Update_statement_builder_impl::Operation_list operation;
631 *operation.Add() << get_operation("xfield", "first", "ITEM_SET", value_1);
632 ASSERT_NO_THROW(builder.add_table_operation(operation));
633 EXPECT_EQ("`xfield`=JSON_SET(`xfield`,'$.first',1)",
634 query.get());
635 }
636
637
TEST_F(Update_statement_builder_test,add_table_operation_item_set_twice)638 TEST_F(Update_statement_builder_test, add_table_operation_item_set_twice)
639 {
640 Update_statement_builder_impl::Operation_list operation;
641 *operation.Add() << get_operation("xfield", "first", "ITEM_SET", value_1);
642 *operation.Add() << get_operation("xfield", "second", "ITEM_SET", value_2);
643 ASSERT_NO_THROW(builder.add_table_operation(operation));
644 EXPECT_EQ(
645 "`xfield`=JSON_SET(`xfield`,'$.first',1,'$.second','two')",
646 query.get());
647 }
648
649
TEST_F(Update_statement_builder_test,add_table_operation_item_set_twice_but_different)650 TEST_F(Update_statement_builder_test, add_table_operation_item_set_twice_but_different)
651 {
652 Update_statement_builder_impl::Operation_list operation;
653 *operation.Add() << get_operation("xfield", "first", "ITEM_SET", value_1);
654 *operation.Add() << get_operation("yfield", "second", "ITEM_SET", value_2);
655 ASSERT_NO_THROW(builder.add_table_operation(operation));
656 EXPECT_EQ(
657 "`xfield`=JSON_SET(`xfield`,'$.first',1),"
658 "`yfield`=JSON_SET(`yfield`,'$.second','two')",
659 query.get());
660 }
661
662
TEST_F(Update_statement_builder_test,add_table_operation_item_set_triple)663 TEST_F(Update_statement_builder_test, add_table_operation_item_set_triple)
664 {
665 Update_statement_builder_impl::Operation_list operation;
666 *operation.Add() << get_operation("xfield", "first", "ITEM_SET", value_1);
667 *operation.Add() << get_operation("xfield", "second", "ITEM_SET", value_2);
668 *operation.Add() << get_operation("xfield", "third", "ITEM_SET", value_3);
669 ASSERT_NO_THROW(builder.add_table_operation(operation));
670 EXPECT_EQ(
671 "`xfield`=JSON_SET(`xfield`,'$.first',1,'$.second','two','$.third',-3)",
672 query.get());
673 }
674
675
TEST_F(Update_statement_builder_test,add_table_operation_item_set_mix_first)676 TEST_F(Update_statement_builder_test, add_table_operation_item_set_mix_first)
677 {
678 Update_statement_builder_impl::Operation_list operation;
679 *operation.Add() << get_operation("xfield", "", "SET", value_1);
680 *operation.Add() << get_operation("xfield", "second", "ITEM_SET", value_2);
681 *operation.Add() << get_operation("xfield", "third", "ITEM_SET", value_3);
682 ASSERT_NO_THROW(builder.add_table_operation(operation));
683 EXPECT_EQ(
684 "`xfield`=1,"
685 "`xfield`=JSON_SET(`xfield`,'$.second','two','$.third',-3)",
686 query.get());
687 }
688
689
TEST_F(Update_statement_builder_test,add_table_operation_item_set_mix_last)690 TEST_F(Update_statement_builder_test, add_table_operation_item_set_mix_last)
691 {
692 Update_statement_builder_impl::Operation_list operation;
693 *operation.Add() << get_operation("xfield", "second", "ITEM_SET", value_2);
694 *operation.Add() << get_operation("xfield", "third", "ITEM_SET", value_3);
695 *operation.Add() << get_operation("xfield", "", "SET", value_1);
696 ASSERT_NO_THROW(builder.add_table_operation(operation));
697 EXPECT_EQ(
698 "`xfield`=JSON_SET(`xfield`,'$.second','two','$.third',-3),"
699 "`xfield`=1",
700 query.get());
701 }
702
703
TEST_F(Update_statement_builder_test,add_table_operation_item_set_mix_middle)704 TEST_F(Update_statement_builder_test, add_table_operation_item_set_mix_middle)
705 {
706 Update_statement_builder_impl::Operation_list operation;
707 *operation.Add() << get_operation("xfield", "second", "ITEM_SET", value_2);
708 *operation.Add() << get_operation("xfield", "", "SET", value_1);
709 *operation.Add() << get_operation("xfield", "third", "ITEM_SET", value_3);
710 ASSERT_NO_THROW(builder.add_table_operation(operation));
711 EXPECT_EQ(
712 "`xfield`=JSON_SET(`xfield`,'$.second','two'),"
713 "`xfield`=1,"
714 "`xfield`=JSON_SET(`xfield`,'$.third',-3)",
715 query.get());
716 }
717
718
TEST_F(Update_statement_builder_test,add_table_operation_item_set_fourth)719 TEST_F(Update_statement_builder_test, add_table_operation_item_set_fourth)
720 {
721 Update_statement_builder_impl::Operation_list operation;
722 *operation.Add() << get_operation("xfield", "first", "ITEM_SET", value_1);
723 *operation.Add() << get_operation("xfield", "second", "ITEM_SET", value_2);
724 *operation.Add() << get_operation("yfield", "first", "ITEM_SET", value_1);
725 *operation.Add() << get_operation("yfield", "second", "ITEM_SET", value_2);
726 ASSERT_NO_THROW(builder.add_table_operation(operation));
727 EXPECT_EQ(
728 "`xfield`=JSON_SET(`xfield`,'$.first',1,'$.second','two'),"
729 "`yfield`=JSON_SET(`yfield`,'$.first',1,'$.second','two')",
730 query.get());
731 }
732
733
TEST_F(Update_statement_builder_test,add_table_operation_item_remove_one)734 TEST_F(Update_statement_builder_test, add_table_operation_item_remove_one)
735 {
736 Update_statement_builder_impl::Operation_list operation;
737 *operation.Add() << get_operation("xfield", "first", "ITEM_REMOVE", "");
738 ASSERT_NO_THROW(builder.add_table_operation(operation));
739 EXPECT_EQ(
740 "`xfield`=JSON_REMOVE(`xfield`,'$.first')",
741 query.get());
742 }
743
744
TEST_F(Update_statement_builder_test,add_table_operation_item_remove_twice)745 TEST_F(Update_statement_builder_test, add_table_operation_item_remove_twice)
746 {
747 Update_statement_builder_impl::Operation_list operation;
748 *operation.Add() << get_operation("xfield", "first", "ITEM_REMOVE", "");
749 *operation.Add() << get_operation("xfield", "second", "ITEM_REMOVE", "");
750 ASSERT_NO_THROW(builder.add_table_operation(operation));
751 EXPECT_EQ(
752 "`xfield`=JSON_REMOVE(`xfield`,'$.first','$.second')",
753 query.get());
754 }
755
756
TEST_F(Update_statement_builder_test,add_table_operation_item_replace_one)757 TEST_F(Update_statement_builder_test, add_table_operation_item_replace_one)
758 {
759 Update_statement_builder_impl::Operation_list operation;
760 *operation.Add() << get_operation("xfield", "first", "ITEM_REPLACE", value_1);
761 ASSERT_NO_THROW(builder.add_table_operation(operation));
762 EXPECT_EQ(
763 "`xfield`=JSON_REPLACE(`xfield`,'$.first',1)",
764 query.get());
765 }
766
767
TEST_F(Update_statement_builder_test,add_table_operation_item_replace_twice)768 TEST_F(Update_statement_builder_test, add_table_operation_item_replace_twice)
769 {
770 Update_statement_builder_impl::Operation_list operation;
771 *operation.Add() << get_operation("xfield", "first", "ITEM_REPLACE", value_1);
772 *operation.Add() << get_operation("xfield", "second", "ITEM_REPLACE", value_2);
773 ASSERT_NO_THROW(builder.add_table_operation(operation));
774 EXPECT_EQ(
775 "`xfield`=JSON_REPLACE(`xfield`,'$.first',1,'$.second','two')",
776 query.get());
777 }
778
779
TEST_F(Update_statement_builder_test,add_table_operation_item_merge_one)780 TEST_F(Update_statement_builder_test, add_table_operation_item_merge_one)
781 {
782 Update_statement_builder_impl::Operation_list operation;
783 *operation.Add() << get_operation("xfield", "first", "ITEM_MERGE", value_1);
784 ASSERT_NO_THROW(builder.add_table_operation(operation));
785 EXPECT_EQ(
786 "`xfield`=JSON_MERGE(`xfield`,1)",
787 query.get());
788 }
789
790
TEST_F(Update_statement_builder_test,add_table_operation_item_merge_twice)791 TEST_F(Update_statement_builder_test, add_table_operation_item_merge_twice)
792 {
793 Update_statement_builder_impl::Operation_list operation;
794 *operation.Add() << get_operation("xfield", "first", "ITEM_MERGE", value_1);
795 *operation.Add() << get_operation("xfield", "second", "ITEM_MERGE", value_2);
796 ASSERT_NO_THROW(builder.add_table_operation(operation));
797 EXPECT_EQ(
798 "`xfield`=JSON_MERGE(`xfield`,1,'two')",
799 query.get());
800 }
801
802
TEST_F(Update_statement_builder_test,add_table_operation_array_insert_one)803 TEST_F(Update_statement_builder_test, add_table_operation_array_insert_one)
804 {
805 Update_statement_builder_impl::Operation_list operation;
806 *operation.Add() << get_operation("xfield", "0", "ARRAY_INSERT", value_1);
807 ASSERT_NO_THROW(builder.add_table_operation(operation));
808 EXPECT_EQ(
809 "`xfield`=JSON_ARRAY_INSERT(`xfield`,'$[0]',1)",
810 query.get());
811 }
812
813
TEST_F(Update_statement_builder_test,add_table_operation_array_insert_twice)814 TEST_F(Update_statement_builder_test, add_table_operation_array_insert_twice)
815 {
816 Update_statement_builder_impl::Operation_list operation;
817 *operation.Add() << get_operation("xfield", "0", "ARRAY_INSERT", value_1);
818 *operation.Add() << get_operation("xfield", "1", "ARRAY_INSERT", value_2);
819 ASSERT_NO_THROW(builder.add_table_operation(operation));
820 EXPECT_EQ(
821 "`xfield`=JSON_ARRAY_INSERT(`xfield`,'$[0]',1,'$[1]','two')",
822 query.get());
823 }
824
825
TEST_F(Update_statement_builder_test,add_table_operation_array_append_one)826 TEST_F(Update_statement_builder_test, add_table_operation_array_append_one)
827 {
828 Update_statement_builder_impl::Operation_list operation;
829 *operation.Add() << get_operation("xfield", "first", "ARRAY_APPEND", value_1);
830 ASSERT_NO_THROW(builder.add_table_operation(operation));
831 EXPECT_EQ(
832 "`xfield`=JSON_ARRAY_APPEND(`xfield`,'$.first',1)",
833 query.get());
834 }
835
836
TEST_F(Update_statement_builder_test,add_table_operation_array_append_twice)837 TEST_F(Update_statement_builder_test, add_table_operation_array_append_twice)
838 {
839 Update_statement_builder_impl::Operation_list operation;
840 *operation.Add() << get_operation("xfield", "first", "ARRAY_APPEND", value_1);
841 *operation.Add() << get_operation("xfield", "second", "ARRAY_APPEND", value_2);
842 ASSERT_NO_THROW(builder.add_table_operation(operation));
843 EXPECT_EQ(
844 "`xfield`=JSON_ARRAY_APPEND(`xfield`,'$.first',1,'$.second','two')",
845 query.get());
846 }
847
848
TEST_F(Update_statement_builder_test,add_table_operation_array_append_twice_placeholder)849 TEST_F(Update_statement_builder_test, add_table_operation_array_append_twice_placeholder)
850 {
851 *args.Add() << "type: V_DOUBLE v_double: 2.2";
852 Update_statement_builder_impl::Operation_list operation;
853 *operation.Add() << get_operation("xfield", "first", "ARRAY_APPEND", value_1);
854 *operation.Add() << get_operation("xfield", "second", "ARRAY_APPEND", placeholder_0);
855 ASSERT_NO_THROW(builder.add_table_operation(operation));
856 EXPECT_EQ(
857 "`xfield`=JSON_ARRAY_APPEND(`xfield`,'$.first',1,'$.second',2.2)",
858 query.get());
859 }
860
861 } // namespace test
862 } // namespace xpl
863
864
865