summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTess Avitabile <tess.avitabile@mongodb.com>2017-04-14 16:06:18 -0400
committerTess Avitabile <tess.avitabile@mongodb.com>2017-04-20 13:22:12 -0400
commit0293c14cbdc5646d9f09f4fe5b2a27e6d540dce0 (patch)
tree427f823c34f54fcd8d7fa28969ce7f40c740a354
parentc08590a6ac9dc54c9d910822d47ea17140b56f89 (diff)
downloadmongo-0293c14cbdc5646d9f09f4fe5b2a27e6d540dce0.tar.gz
SERVER-28621 Parse BSON update expression into an UpdateNode tree
-rw-r--r--src/mongo/db/SConscript3
-rw-r--r--src/mongo/db/auth/SConscript4
-rw-r--r--src/mongo/db/auth/authz_manager_external_state_mock.cpp2
-rw-r--r--src/mongo/db/auth/role_graph_update.cpp2
-rw-r--r--src/mongo/db/catalog/collection.cpp2
-rw-r--r--src/mongo/db/catalog/collection_impl.cpp2
-rw-r--r--src/mongo/db/exec/SConscript2
-rw-r--r--src/mongo/db/exec/projection_exec.cpp2
-rw-r--r--src/mongo/db/exec/update.h2
-rw-r--r--src/mongo/db/ops/SConscript107
-rw-r--r--src/mongo/db/ops/modifier_add_to_set.cpp6
-rw-r--r--src/mongo/db/ops/modifier_add_to_set_test.cpp2
-rw-r--r--src/mongo/db/ops/modifier_bit.cpp6
-rw-r--r--src/mongo/db/ops/modifier_bit_test.cpp2
-rw-r--r--src/mongo/db/ops/modifier_compare.cpp6
-rw-r--r--src/mongo/db/ops/modifier_compare_test.cpp2
-rw-r--r--src/mongo/db/ops/modifier_current_date.cpp6
-rw-r--r--src/mongo/db/ops/modifier_current_date_test.cpp2
-rw-r--r--src/mongo/db/ops/modifier_inc.cpp6
-rw-r--r--src/mongo/db/ops/modifier_inc_test.cpp2
-rw-r--r--src/mongo/db/ops/modifier_object_replace.cpp2
-rw-r--r--src/mongo/db/ops/modifier_object_replace_test.cpp2
-rw-r--r--src/mongo/db/ops/modifier_pop.cpp6
-rw-r--r--src/mongo/db/ops/modifier_pop_test.cpp2
-rw-r--r--src/mongo/db/ops/modifier_pull.cpp6
-rw-r--r--src/mongo/db/ops/modifier_pull_all.cpp6
-rw-r--r--src/mongo/db/ops/modifier_pull_all_test.cpp2
-rw-r--r--src/mongo/db/ops/modifier_pull_test.cpp2
-rw-r--r--src/mongo/db/ops/modifier_push.cpp6
-rw-r--r--src/mongo/db/ops/modifier_push_test.cpp2
-rw-r--r--src/mongo/db/ops/modifier_rename.cpp6
-rw-r--r--src/mongo/db/ops/modifier_rename_test.cpp2
-rw-r--r--src/mongo/db/ops/modifier_set.cpp6
-rw-r--r--src/mongo/db/ops/modifier_set_test.cpp2
-rw-r--r--src/mongo/db/ops/modifier_unset.cpp6
-rw-r--r--src/mongo/db/ops/modifier_unset_test.cpp2
-rw-r--r--src/mongo/db/ops/parsed_update.h4
-rw-r--r--src/mongo/db/ops/update.cpp2
-rw-r--r--src/mongo/db/query/get_executor.h2
-rw-r--r--src/mongo/db/update/SConscript135
-rw-r--r--src/mongo/db/update/array_filter.cpp (renamed from src/mongo/db/ops/array_filter.cpp)2
-rw-r--r--src/mongo/db/update/array_filter.h (renamed from src/mongo/db/ops/array_filter.h)0
-rw-r--r--src/mongo/db/update/array_filter_test.cpp (renamed from src/mongo/db/ops/array_filter_test.cpp)2
-rw-r--r--src/mongo/db/update/field_checker.cpp (renamed from src/mongo/db/ops/field_checker.cpp)2
-rw-r--r--src/mongo/db/update/field_checker.h (renamed from src/mongo/db/ops/field_checker.h)0
-rw-r--r--src/mongo/db/update/field_checker_test.cpp (renamed from src/mongo/db/ops/field_checker_test.cpp)2
-rw-r--r--src/mongo/db/update/log_builder.cpp (renamed from src/mongo/db/ops/log_builder.cpp)2
-rw-r--r--src/mongo/db/update/log_builder.h (renamed from src/mongo/db/ops/log_builder.h)0
-rw-r--r--src/mongo/db/update/log_builder_test.cpp (renamed from src/mongo/db/ops/log_builder_test.cpp)2
-rw-r--r--src/mongo/db/update/modifier_table.cpp (renamed from src/mongo/db/ops/modifier_table.cpp)13
-rw-r--r--src/mongo/db/update/modifier_table.h (renamed from src/mongo/db/ops/modifier_table.h)6
-rw-r--r--src/mongo/db/update/modifier_table_test.cpp (renamed from src/mongo/db/ops/modifier_table_test.cpp)2
-rw-r--r--src/mongo/db/update/path_support.cpp (renamed from src/mongo/db/ops/path_support.cpp)2
-rw-r--r--src/mongo/db/update/path_support.h (renamed from src/mongo/db/ops/path_support.h)0
-rw-r--r--src/mongo/db/update/path_support_test.cpp (renamed from src/mongo/db/ops/path_support_test.cpp)2
-rw-r--r--src/mongo/db/update/set_node.cpp43
-rw-r--r--src/mongo/db/update/set_node.h48
-rw-r--r--src/mongo/db/update/set_node_test.cpp55
-rw-r--r--src/mongo/db/update/update_driver.cpp (renamed from src/mongo/db/ops/update_driver.cpp)8
-rw-r--r--src/mongo/db/update/update_driver.h (renamed from src/mongo/db/ops/update_driver.h)2
-rw-r--r--src/mongo/db/update/update_driver_test.cpp (renamed from src/mongo/db/ops/update_driver_test.cpp)2
-rw-r--r--src/mongo/db/update/update_leaf_node.h58
-rw-r--r--src/mongo/db/update/update_node.h68
-rw-r--r--src/mongo/db/update/update_object_node.cpp153
-rw-r--r--src/mongo/db/update/update_object_node.h80
-rw-r--r--src/mongo/db/update/update_object_node_test.cpp333
-rw-r--r--src/mongo/dbtests/query_stage_update.cpp2
-rw-r--r--src/mongo/s/SConscript2
-rw-r--r--src/mongo/s/shard_key_pattern.cpp2
69 files changed, 1077 insertions, 187 deletions
diff --git a/src/mongo/db/SConscript b/src/mongo/db/SConscript
index 698fc103a51..be946688dd3 100644
--- a/src/mongo/db/SConscript
+++ b/src/mongo/db/SConscript
@@ -33,6 +33,7 @@ env.SConscript(
'sorter',
'stats',
'storage',
+ 'update',
'views',
],
exports=[
@@ -873,7 +874,6 @@ env.Library(
"matcher/expressions_mongod_only",
"op_observer_d",
"ops/write_ops",
- "ops/update_driver",
"ops/write_ops_parsers",
"pipeline/aggregation",
"pipeline/serveronly",
@@ -913,6 +913,7 @@ env.Library(
"storage/storage_options",
"storage/wiredtiger/storage_wiredtiger" if wiredtiger else [],
"ttl_d",
+ "update/update_driver",
"update_index_data",
"views/views_mongod",
],
diff --git a/src/mongo/db/auth/SConscript b/src/mongo/db/auth/SConscript
index e8fb1d4b0b0..836d7278f83 100644
--- a/src/mongo/db/auth/SConscript
+++ b/src/mongo/db/auth/SConscript
@@ -46,9 +46,9 @@ env.Library('authcore', ['action_set.cpp',
'$BUILD_DIR/mongo/crypto/scramauth',
'$BUILD_DIR/mongo/db/catalog/document_validation',
'$BUILD_DIR/mongo/db/common',
- '$BUILD_DIR/mongo/db/ops/update_driver',
'$BUILD_DIR/mongo/db/namespace_string',
'$BUILD_DIR/mongo/db/service_context',
+ '$BUILD_DIR/mongo/db/update/update_driver',
'$BUILD_DIR/mongo/util/md5',
'$BUILD_DIR/mongo/util/net/network'])
@@ -173,8 +173,8 @@ env.Library(
],
LIBDEPS=[
'$BUILD_DIR/mongo/db/matcher/expressions',
- '$BUILD_DIR/mongo/db/ops/update_driver',
'$BUILD_DIR/mongo/db/service_context',
+ '$BUILD_DIR/mongo/db/update/update_driver',
'authcore'
]
)
diff --git a/src/mongo/db/auth/authz_manager_external_state_mock.cpp b/src/mongo/db/auth/authz_manager_external_state_mock.cpp
index 7b8d72ad1f7..f4fef4fde08 100644
--- a/src/mongo/db/auth/authz_manager_external_state_mock.cpp
+++ b/src/mongo/db/auth/authz_manager_external_state_mock.cpp
@@ -41,7 +41,7 @@
#include "mongo/db/matcher/extensions_callback_disallow_extensions.h"
#include "mongo/db/namespace_string.h"
#include "mongo/db/operation_context_noop.h"
-#include "mongo/db/ops/update_driver.h"
+#include "mongo/db/update/update_driver.h"
#include "mongo/platform/unordered_set.h"
#include "mongo/stdx/memory.h"
#include "mongo/util/map_util.h"
diff --git a/src/mongo/db/auth/role_graph_update.cpp b/src/mongo/db/auth/role_graph_update.cpp
index 3432890406c..d1b45e3b98d 100644
--- a/src/mongo/db/auth/role_graph_update.cpp
+++ b/src/mongo/db/auth/role_graph_update.cpp
@@ -35,7 +35,7 @@
#include "mongo/db/auth/authorization_manager.h"
#include "mongo/db/auth/role_graph.h"
#include "mongo/db/auth/user_management_commands_parser.h"
-#include "mongo/db/ops/update_driver.h"
+#include "mongo/db/update/update_driver.h"
#include "mongo/util/mongoutils/str.h"
namespace mongo {
diff --git a/src/mongo/db/catalog/collection.cpp b/src/mongo/db/catalog/collection.cpp
index baacbe3e0c3..c9b6ad39f19 100644
--- a/src/mongo/db/catalog/collection.cpp
+++ b/src/mongo/db/catalog/collection.cpp
@@ -52,7 +52,6 @@
#include "mongo/db/matcher/extensions_callback_disallow_extensions.h"
#include "mongo/db/op_observer.h"
#include "mongo/db/operation_context.h"
-#include "mongo/db/ops/update_driver.h"
#include "mongo/db/ops/update_request.h"
#include "mongo/db/query/collation/collator_factory_interface.h"
#include "mongo/db/repl/replication_coordinator_global.h"
@@ -63,6 +62,7 @@
#include "mongo/db/storage/record_fetcher.h"
#include "mongo/db/storage/record_store.h"
#include "mongo/db/storage/wiredtiger/wiredtiger_record_store.h"
+#include "mongo/db/update/update_driver.h"
#include "mongo/db/auth/user_document_parser.h" // XXX-ANDY
#include "mongo/rpc/object_check.h"
diff --git a/src/mongo/db/catalog/collection_impl.cpp b/src/mongo/db/catalog/collection_impl.cpp
index 841667fc2e0..646f5ce934d 100644
--- a/src/mongo/db/catalog/collection_impl.cpp
+++ b/src/mongo/db/catalog/collection_impl.cpp
@@ -55,7 +55,6 @@
#include "mongo/db/matcher/extensions_callback_disallow_extensions.h"
#include "mongo/db/op_observer.h"
#include "mongo/db/operation_context.h"
-#include "mongo/db/ops/update_driver.h"
#include "mongo/db/ops/update_request.h"
#include "mongo/db/query/collation/collator_factory_interface.h"
#include "mongo/db/repl/replication_coordinator_global.h"
@@ -66,6 +65,7 @@
#include "mongo/db/storage/record_fetcher.h"
#include "mongo/db/storage/record_store.h"
#include "mongo/db/storage/wiredtiger/wiredtiger_record_store.h"
+#include "mongo/db/update/update_driver.h"
#include "mongo/db/auth/user_document_parser.h" // XXX-ANDY
#include "mongo/rpc/object_check.h"
diff --git a/src/mongo/db/exec/SConscript b/src/mongo/db/exec/SConscript
index ba660d93d0f..af06b19c3bf 100644
--- a/src/mongo/db/exec/SConscript
+++ b/src/mongo/db/exec/SConscript
@@ -93,9 +93,9 @@ env.Library(
"$BUILD_DIR/mongo/db/fts/base",
"$BUILD_DIR/mongo/db/index/index_descriptor",
"$BUILD_DIR/mongo/db/index/key_generator",
- "$BUILD_DIR/mongo/db/ops/update_driver",
"$BUILD_DIR/mongo/db/pipeline/pipeline",
"$BUILD_DIR/mongo/db/repl/repl_coordinator_global",
+ "$BUILD_DIR/mongo/db/update/update_driver",
"$BUILD_DIR/mongo/scripting/scripting",
"$BUILD_DIR/mongo/db/storage/storage_options",
"$BUILD_DIR/mongo/s/common",
diff --git a/src/mongo/db/exec/projection_exec.cpp b/src/mongo/db/exec/projection_exec.cpp
index 2846acbc245..edf0386d042 100644
--- a/src/mongo/db/exec/projection_exec.cpp
+++ b/src/mongo/db/exec/projection_exec.cpp
@@ -32,9 +32,9 @@
#include "mongo/db/exec/working_set_computed_data.h"
#include "mongo/db/matcher/expression.h"
#include "mongo/db/matcher/expression_parser.h"
-#include "mongo/db/ops/path_support.h"
#include "mongo/db/query/collation/collator_interface.h"
#include "mongo/db/query/query_request.h"
+#include "mongo/db/update/path_support.h"
#include "mongo/util/mongoutils/str.h"
namespace mongo {
diff --git a/src/mongo/db/exec/update.h b/src/mongo/db/exec/update.h
index e88a26e445b..fa866f87606 100644
--- a/src/mongo/db/exec/update.h
+++ b/src/mongo/db/exec/update.h
@@ -32,9 +32,9 @@
#include "mongo/db/catalog/collection.h"
#include "mongo/db/exec/plan_stage.h"
#include "mongo/db/jsobj.h"
-#include "mongo/db/ops/update_driver.h"
#include "mongo/db/ops/update_request.h"
#include "mongo/db/ops/update_result.h"
+#include "mongo/db/update/update_driver.h"
namespace mongo {
diff --git a/src/mongo/db/ops/SConscript b/src/mongo/db/ops/SConscript
index 43a97cc2c47..de8e3b27176 100644
--- a/src/mongo/db/ops/SConscript
+++ b/src/mongo/db/ops/SConscript
@@ -5,54 +5,6 @@ Import("env")
env = env.Clone()
env.Library(
- target='update_common',
- source=[
- 'field_checker.cpp',
- 'log_builder.cpp',
- 'path_support.cpp',
- ],
- LIBDEPS=[
- '$BUILD_DIR/mongo/base',
- '$BUILD_DIR/mongo/bson/mutable/mutable_bson',
- '$BUILD_DIR/mongo/db/common',
- '$BUILD_DIR/mongo/db/matcher/expressions',
- ],
-)
-
-env.CppUnitTest(
- target='field_checker_test',
- source=[
- 'field_checker_test.cpp',
- ],
- LIBDEPS=[
- 'update_common',
- ],
-)
-
-env.CppUnitTest(
- target='log_builder_test',
- source=[
- 'log_builder_test.cpp',
- ],
- LIBDEPS=[
- '$BUILD_DIR/mongo/bson/mutable/mutable_bson_test_utils',
- 'update_common',
- ],
-)
-
-env.CppUnitTest(
- target='path_support_test',
- source=[
- 'path_support_test.cpp',
- ],
- LIBDEPS=[
- '$BUILD_DIR/mongo/bson/mutable/mutable_bson_test_utils',
- '$BUILD_DIR/mongo/db/matcher/expressions',
- 'update_common',
- ],
-)
-
-env.Library(
target='update',
source=[
'modifier_add_to_set.cpp',
@@ -76,7 +28,7 @@ env.Library(
'$BUILD_DIR/mongo/db/logical_time',
'$BUILD_DIR/mongo/db/bson/dotted_path_support',
'$BUILD_DIR/mongo/db/matcher/expressions',
- 'update_common',
+ '$BUILD_DIR/mongo/db/update/update_common',
],
)
@@ -212,40 +164,6 @@ env.CppUnitTest(
)
env.Library(
- target='update_driver',
- source=[
- 'modifier_table.cpp',
- 'update_driver.cpp',
- ],
- LIBDEPS=[
- '$BUILD_DIR/mongo/base',
- '$BUILD_DIR/mongo/db/common',
- '$BUILD_DIR/mongo/db/query/query_planner',
- '$BUILD_DIR/mongo/db/update_index_data',
- 'update',
- ],
-)
-
-env.CppUnitTest(
- target='modifier_table_test',
- source='modifier_table_test.cpp',
- LIBDEPS=[
- 'update_driver',
- ],
-)
-
-env.CppUnitTest(
- target='update_driver_test',
- source='update_driver_test.cpp',
- LIBDEPS=[
- '$BUILD_DIR/mongo/bson/mutable/mutable_bson_test_utils',
- '$BUILD_DIR/mongo/db/query/query_planner',
- '$BUILD_DIR/mongo/db/query/query_test_service_context',
- 'update_driver',
- ],
-)
-
-env.Library(
target='write_ops_parsers',
source=[
'write_ops_parsers.cpp',
@@ -266,25 +184,6 @@ env.CppUnitTest(
)
env.Library(
- target='array_filter',
- source=[
- 'array_filter.cpp',
- ],
- LIBDEPS=[
- "$BUILD_DIR/mongo/db/matcher/expressions",
- ],
-)
-
-env.CppUnitTest(
- target='array_filter_test',
- source='array_filter_test.cpp',
- LIBDEPS=[
- 'array_filter',
- '$BUILD_DIR/mongo/db/query/collation/collator_interface_mock',
- ],
-)
-
-env.Library(
target="write_ops",
source=[
"delete.cpp",
@@ -297,14 +196,14 @@ env.Library(
"write_ops_exec.cpp",
],
LIBDEPS=[
- 'array_filter',
- 'update_driver',
'$BUILD_DIR/mongo/base',
'$BUILD_DIR/mongo/db/concurrency/lock_manager',
'$BUILD_DIR/mongo/db/matcher/expressions_mongod_only',
'$BUILD_DIR/mongo/db/query/query',
'$BUILD_DIR/mongo/db/repl/repl_coordinator_impl',
'$BUILD_DIR/mongo/db/service_context',
+ '$BUILD_DIR/mongo/db/update/array_filter',
+ '$BUILD_DIR/mongo/db/update/update_driver',
'$BUILD_DIR/mongo/db/introspect',
'$BUILD_DIR/mongo/db/curop_metrics',
#'$BUILD_DIR/mongo/db/catalog/catalog', # CYCLE
diff --git a/src/mongo/db/ops/modifier_add_to_set.cpp b/src/mongo/db/ops/modifier_add_to_set.cpp
index a565800d749..fbe87014526 100644
--- a/src/mongo/db/ops/modifier_add_to_set.cpp
+++ b/src/mongo/db/ops/modifier_add_to_set.cpp
@@ -30,10 +30,10 @@
#include "mongo/base/error_codes.h"
#include "mongo/bson/mutable/algorithm.h"
-#include "mongo/db/ops/field_checker.h"
-#include "mongo/db/ops/log_builder.h"
-#include "mongo/db/ops/path_support.h"
#include "mongo/db/query/collation/collator_interface.h"
+#include "mongo/db/update/field_checker.h"
+#include "mongo/db/update/log_builder.h"
+#include "mongo/db/update/path_support.h"
#include "mongo/util/mongoutils/str.h"
namespace mongo {
diff --git a/src/mongo/db/ops/modifier_add_to_set_test.cpp b/src/mongo/db/ops/modifier_add_to_set_test.cpp
index 235a65239e6..dce3d2a3772 100644
--- a/src/mongo/db/ops/modifier_add_to_set_test.cpp
+++ b/src/mongo/db/ops/modifier_add_to_set_test.cpp
@@ -36,8 +36,8 @@
#include "mongo/bson/mutable/mutable_bson_test_utils.h"
#include "mongo/db/jsobj.h"
#include "mongo/db/json.h"
-#include "mongo/db/ops/log_builder.h"
#include "mongo/db/query/collation/collator_interface_mock.h"
+#include "mongo/db/update/log_builder.h"
#include "mongo/unittest/unittest.h"
namespace {
diff --git a/src/mongo/db/ops/modifier_bit.cpp b/src/mongo/db/ops/modifier_bit.cpp
index fb7ae3f45eb..2e59b8a2f4e 100644
--- a/src/mongo/db/ops/modifier_bit.cpp
+++ b/src/mongo/db/ops/modifier_bit.cpp
@@ -31,9 +31,9 @@
#include "mongo/base/error_codes.h"
#include "mongo/bson/mutable/algorithm.h"
#include "mongo/bson/mutable/document.h"
-#include "mongo/db/ops/field_checker.h"
-#include "mongo/db/ops/log_builder.h"
-#include "mongo/db/ops/path_support.h"
+#include "mongo/db/update/field_checker.h"
+#include "mongo/db/update/log_builder.h"
+#include "mongo/db/update/path_support.h"
#include "mongo/util/mongoutils/str.h"
namespace mongo {
diff --git a/src/mongo/db/ops/modifier_bit_test.cpp b/src/mongo/db/ops/modifier_bit_test.cpp
index dbc4d7ba0b2..3c8fed4330e 100644
--- a/src/mongo/db/ops/modifier_bit_test.cpp
+++ b/src/mongo/db/ops/modifier_bit_test.cpp
@@ -36,7 +36,7 @@
#include "mongo/bson/mutable/mutable_bson_test_utils.h"
#include "mongo/db/jsobj.h"
#include "mongo/db/json.h"
-#include "mongo/db/ops/log_builder.h"
+#include "mongo/db/update/log_builder.h"
#include "mongo/platform/decimal128.h"
#include "mongo/unittest/unittest.h"
diff --git a/src/mongo/db/ops/modifier_compare.cpp b/src/mongo/db/ops/modifier_compare.cpp
index 4e366f90ee2..fdf73982adf 100644
--- a/src/mongo/db/ops/modifier_compare.cpp
+++ b/src/mongo/db/ops/modifier_compare.cpp
@@ -30,10 +30,10 @@
#include "mongo/base/error_codes.h"
#include "mongo/bson/mutable/document.h"
-#include "mongo/db/ops/field_checker.h"
-#include "mongo/db/ops/log_builder.h"
-#include "mongo/db/ops/path_support.h"
#include "mongo/db/query/collation/collator_interface.h"
+#include "mongo/db/update/field_checker.h"
+#include "mongo/db/update/log_builder.h"
+#include "mongo/db/update/path_support.h"
#include "mongo/util/mongoutils/str.h"
namespace mongo {
diff --git a/src/mongo/db/ops/modifier_compare_test.cpp b/src/mongo/db/ops/modifier_compare_test.cpp
index 9bc036b776b..c454e741368 100644
--- a/src/mongo/db/ops/modifier_compare_test.cpp
+++ b/src/mongo/db/ops/modifier_compare_test.cpp
@@ -35,8 +35,8 @@
#include "mongo/bson/mutable/mutable_bson_test_utils.h"
#include "mongo/db/jsobj.h"
#include "mongo/db/json.h"
-#include "mongo/db/ops/log_builder.h"
#include "mongo/db/query/collation/collator_interface_mock.h"
+#include "mongo/db/update/log_builder.h"
#include "mongo/unittest/unittest.h"
namespace {
diff --git a/src/mongo/db/ops/modifier_current_date.cpp b/src/mongo/db/ops/modifier_current_date.cpp
index 78dc3c57d4f..a7d301bbe86 100644
--- a/src/mongo/db/ops/modifier_current_date.cpp
+++ b/src/mongo/db/ops/modifier_current_date.cpp
@@ -34,10 +34,10 @@
#include "mongo/bson/mutable/document.h"
#include "mongo/db/logical_clock.h"
#include "mongo/db/logical_time.h"
-#include "mongo/db/ops/field_checker.h"
-#include "mongo/db/ops/log_builder.h"
-#include "mongo/db/ops/path_support.h"
#include "mongo/db/service_context.h"
+#include "mongo/db/update/field_checker.h"
+#include "mongo/db/update/log_builder.h"
+#include "mongo/db/update/path_support.h"
#include "mongo/util/mongoutils/str.h"
namespace mongo {
diff --git a/src/mongo/db/ops/modifier_current_date_test.cpp b/src/mongo/db/ops/modifier_current_date_test.cpp
index a9f0865c8be..0c6241eba90 100644
--- a/src/mongo/db/ops/modifier_current_date_test.cpp
+++ b/src/mongo/db/ops/modifier_current_date_test.cpp
@@ -36,7 +36,7 @@
#include "mongo/db/jsobj.h"
#include "mongo/db/json.h"
#include "mongo/db/logical_clock_test_fixture.h"
-#include "mongo/db/ops/log_builder.h"
+#include "mongo/db/update/log_builder.h"
#include "mongo/unittest/unittest.h"
namespace {
diff --git a/src/mongo/db/ops/modifier_inc.cpp b/src/mongo/db/ops/modifier_inc.cpp
index 314ac6a5024..1692d71260f 100644
--- a/src/mongo/db/ops/modifier_inc.cpp
+++ b/src/mongo/db/ops/modifier_inc.cpp
@@ -31,9 +31,9 @@
#include "mongo/base/error_codes.h"
#include "mongo/bson/mutable/algorithm.h"
#include "mongo/bson/mutable/document.h"
-#include "mongo/db/ops/field_checker.h"
-#include "mongo/db/ops/log_builder.h"
-#include "mongo/db/ops/path_support.h"
+#include "mongo/db/update/field_checker.h"
+#include "mongo/db/update/log_builder.h"
+#include "mongo/db/update/path_support.h"
#include "mongo/util/mongoutils/str.h"
namespace mongo {
diff --git a/src/mongo/db/ops/modifier_inc_test.cpp b/src/mongo/db/ops/modifier_inc_test.cpp
index 02fbbd4474a..ec12b8deb66 100644
--- a/src/mongo/db/ops/modifier_inc_test.cpp
+++ b/src/mongo/db/ops/modifier_inc_test.cpp
@@ -38,7 +38,7 @@
#include "mongo/bson/mutable/mutable_bson_test_utils.h"
#include "mongo/db/jsobj.h"
#include "mongo/db/json.h"
-#include "mongo/db/ops/log_builder.h"
+#include "mongo/db/update/log_builder.h"
#include "mongo/platform/decimal128.h"
#include "mongo/unittest/unittest.h"
diff --git a/src/mongo/db/ops/modifier_object_replace.cpp b/src/mongo/db/ops/modifier_object_replace.cpp
index e74617ea7ef..e77759e6997 100644
--- a/src/mongo/db/ops/modifier_object_replace.cpp
+++ b/src/mongo/db/ops/modifier_object_replace.cpp
@@ -33,8 +33,8 @@
#include "mongo/bson/mutable/document.h"
#include "mongo/db/logical_clock.h"
#include "mongo/db/logical_time.h"
-#include "mongo/db/ops/log_builder.h"
#include "mongo/db/service_context.h"
+#include "mongo/db/update/log_builder.h"
#include "mongo/util/mongoutils/str.h"
namespace mongo {
diff --git a/src/mongo/db/ops/modifier_object_replace_test.cpp b/src/mongo/db/ops/modifier_object_replace_test.cpp
index c661246e7f5..5b7165f600d 100644
--- a/src/mongo/db/ops/modifier_object_replace_test.cpp
+++ b/src/mongo/db/ops/modifier_object_replace_test.cpp
@@ -40,7 +40,7 @@
#include "mongo/db/jsobj.h"
#include "mongo/db/json.h"
#include "mongo/db/logical_clock_test_fixture.h"
-#include "mongo/db/ops/log_builder.h"
+#include "mongo/db/update/log_builder.h"
#include "mongo/unittest/unittest.h"
namespace {
diff --git a/src/mongo/db/ops/modifier_pop.cpp b/src/mongo/db/ops/modifier_pop.cpp
index 07682c976bf..faac70222d5 100644
--- a/src/mongo/db/ops/modifier_pop.cpp
+++ b/src/mongo/db/ops/modifier_pop.cpp
@@ -31,9 +31,9 @@
#include "mongo/base/error_codes.h"
#include "mongo/bson/mutable/algorithm.h"
#include "mongo/bson/mutable/document.h"
-#include "mongo/db/ops/field_checker.h"
-#include "mongo/db/ops/log_builder.h"
-#include "mongo/db/ops/path_support.h"
+#include "mongo/db/update/field_checker.h"
+#include "mongo/db/update/log_builder.h"
+#include "mongo/db/update/path_support.h"
#include "mongo/util/mongoutils/str.h"
namespace mongo {
diff --git a/src/mongo/db/ops/modifier_pop_test.cpp b/src/mongo/db/ops/modifier_pop_test.cpp
index 8e288c73aa4..75cb61fac71 100644
--- a/src/mongo/db/ops/modifier_pop_test.cpp
+++ b/src/mongo/db/ops/modifier_pop_test.cpp
@@ -38,7 +38,7 @@
#include "mongo/bson/mutable/mutable_bson_test_utils.h"
#include "mongo/db/jsobj.h"
#include "mongo/db/json.h"
-#include "mongo/db/ops/log_builder.h"
+#include "mongo/db/update/log_builder.h"
#include "mongo/unittest/unittest.h"
namespace {
diff --git a/src/mongo/db/ops/modifier_pull.cpp b/src/mongo/db/ops/modifier_pull.cpp
index 9a7b8608555..75bfaa4aa30 100644
--- a/src/mongo/db/ops/modifier_pull.cpp
+++ b/src/mongo/db/ops/modifier_pull.cpp
@@ -32,10 +32,10 @@
#include "mongo/bson/mutable/algorithm.h"
#include "mongo/db/matcher/expression_parser.h"
#include "mongo/db/matcher/extensions_callback_disallow_extensions.h"
-#include "mongo/db/ops/field_checker.h"
-#include "mongo/db/ops/log_builder.h"
-#include "mongo/db/ops/path_support.h"
#include "mongo/db/query/collation/collator_interface.h"
+#include "mongo/db/update/field_checker.h"
+#include "mongo/db/update/log_builder.h"
+#include "mongo/db/update/path_support.h"
#include "mongo/util/mongoutils/str.h"
namespace mongo {
diff --git a/src/mongo/db/ops/modifier_pull_all.cpp b/src/mongo/db/ops/modifier_pull_all.cpp
index 2d57bea1cb5..26a3d6d24ff 100644
--- a/src/mongo/db/ops/modifier_pull_all.cpp
+++ b/src/mongo/db/ops/modifier_pull_all.cpp
@@ -31,10 +31,10 @@
#include "mongo/base/error_codes.h"
#include "mongo/bson/mutable/algorithm.h"
#include "mongo/bson/mutable/document.h"
-#include "mongo/db/ops/field_checker.h"
-#include "mongo/db/ops/log_builder.h"
-#include "mongo/db/ops/path_support.h"
#include "mongo/db/query/collation/collator_interface.h"
+#include "mongo/db/update/field_checker.h"
+#include "mongo/db/update/log_builder.h"
+#include "mongo/db/update/path_support.h"
#include "mongo/util/mongoutils/str.h"
namespace mongo {
diff --git a/src/mongo/db/ops/modifier_pull_all_test.cpp b/src/mongo/db/ops/modifier_pull_all_test.cpp
index 02fd8b7fd7f..f24c770aa48 100644
--- a/src/mongo/db/ops/modifier_pull_all_test.cpp
+++ b/src/mongo/db/ops/modifier_pull_all_test.cpp
@@ -38,8 +38,8 @@
#include "mongo/bson/mutable/mutable_bson_test_utils.h"
#include "mongo/db/jsobj.h"
#include "mongo/db/json.h"
-#include "mongo/db/ops/log_builder.h"
#include "mongo/db/query/collation/collator_interface_mock.h"
+#include "mongo/db/update/log_builder.h"
#include "mongo/unittest/unittest.h"
namespace {
diff --git a/src/mongo/db/ops/modifier_pull_test.cpp b/src/mongo/db/ops/modifier_pull_test.cpp
index 4e23c9beab4..6d465442dfe 100644
--- a/src/mongo/db/ops/modifier_pull_test.cpp
+++ b/src/mongo/db/ops/modifier_pull_test.cpp
@@ -36,8 +36,8 @@
#include "mongo/bson/mutable/mutable_bson_test_utils.h"
#include "mongo/db/jsobj.h"
#include "mongo/db/json.h"
-#include "mongo/db/ops/log_builder.h"
#include "mongo/db/query/collation/collator_interface_mock.h"
+#include "mongo/db/update/log_builder.h"
#include "mongo/unittest/unittest.h"
namespace {
diff --git a/src/mongo/db/ops/modifier_push.cpp b/src/mongo/db/ops/modifier_push.cpp
index d2d816776fa..6be330cc98f 100644
--- a/src/mongo/db/ops/modifier_push.cpp
+++ b/src/mongo/db/ops/modifier_push.cpp
@@ -36,9 +36,9 @@
#include "mongo/base/error_codes.h"
#include "mongo/bson/mutable/algorithm.h"
-#include "mongo/db/ops/field_checker.h"
-#include "mongo/db/ops/log_builder.h"
-#include "mongo/db/ops/path_support.h"
+#include "mongo/db/update/field_checker.h"
+#include "mongo/db/update/log_builder.h"
+#include "mongo/db/update/path_support.h"
#include "mongo/util/assert_util.h"
#include "mongo/util/log.h"
#include "mongo/util/mongoutils/str.h"
diff --git a/src/mongo/db/ops/modifier_push_test.cpp b/src/mongo/db/ops/modifier_push_test.cpp
index c4a05aafa7f..008bb140933 100644
--- a/src/mongo/db/ops/modifier_push_test.cpp
+++ b/src/mongo/db/ops/modifier_push_test.cpp
@@ -42,8 +42,8 @@
#include "mongo/db/bson/dotted_path_support.h"
#include "mongo/db/jsobj.h"
#include "mongo/db/json.h"
-#include "mongo/db/ops/log_builder.h"
#include "mongo/db/query/collation/collator_interface_mock.h"
+#include "mongo/db/update/log_builder.h"
#include "mongo/unittest/unittest.h"
#include "mongo/util/mongoutils/str.h"
diff --git a/src/mongo/db/ops/modifier_rename.cpp b/src/mongo/db/ops/modifier_rename.cpp
index c2935fb1906..20ca8d67e49 100644
--- a/src/mongo/db/ops/modifier_rename.cpp
+++ b/src/mongo/db/ops/modifier_rename.cpp
@@ -31,9 +31,9 @@
#include "mongo/base/error_codes.h"
#include "mongo/bson/mutable/algorithm.h"
#include "mongo/bson/mutable/document.h"
-#include "mongo/db/ops/field_checker.h"
-#include "mongo/db/ops/log_builder.h"
-#include "mongo/db/ops/path_support.h"
+#include "mongo/db/update/field_checker.h"
+#include "mongo/db/update/log_builder.h"
+#include "mongo/db/update/path_support.h"
#include "mongo/util/mongoutils/str.h"
namespace mongo {
diff --git a/src/mongo/db/ops/modifier_rename_test.cpp b/src/mongo/db/ops/modifier_rename_test.cpp
index aab70c00376..fc1c4ee108d 100644
--- a/src/mongo/db/ops/modifier_rename_test.cpp
+++ b/src/mongo/db/ops/modifier_rename_test.cpp
@@ -37,7 +37,7 @@
#include "mongo/bson/mutable/mutable_bson_test_utils.h"
#include "mongo/db/jsobj.h"
#include "mongo/db/json.h"
-#include "mongo/db/ops/log_builder.h"
+#include "mongo/db/update/log_builder.h"
#include "mongo/unittest/unittest.h"
namespace mongo {
diff --git a/src/mongo/db/ops/modifier_set.cpp b/src/mongo/db/ops/modifier_set.cpp
index 59f59c555ce..77575fc76a9 100644
--- a/src/mongo/db/ops/modifier_set.cpp
+++ b/src/mongo/db/ops/modifier_set.cpp
@@ -30,9 +30,9 @@
#include "mongo/base/error_codes.h"
#include "mongo/bson/mutable/document.h"
-#include "mongo/db/ops/field_checker.h"
-#include "mongo/db/ops/log_builder.h"
-#include "mongo/db/ops/path_support.h"
+#include "mongo/db/update/field_checker.h"
+#include "mongo/db/update/log_builder.h"
+#include "mongo/db/update/path_support.h"
#include "mongo/util/mongoutils/str.h"
namespace mongo {
diff --git a/src/mongo/db/ops/modifier_set_test.cpp b/src/mongo/db/ops/modifier_set_test.cpp
index 1579b096722..354aae01929 100644
--- a/src/mongo/db/ops/modifier_set_test.cpp
+++ b/src/mongo/db/ops/modifier_set_test.cpp
@@ -38,7 +38,7 @@
#include "mongo/bson/mutable/mutable_bson_test_utils.h"
#include "mongo/db/jsobj.h"
#include "mongo/db/json.h"
-#include "mongo/db/ops/log_builder.h"
+#include "mongo/db/update/log_builder.h"
#include "mongo/unittest/unittest.h"
namespace {
diff --git a/src/mongo/db/ops/modifier_unset.cpp b/src/mongo/db/ops/modifier_unset.cpp
index 453b2d60d1c..a70db3c8fd4 100644
--- a/src/mongo/db/ops/modifier_unset.cpp
+++ b/src/mongo/db/ops/modifier_unset.cpp
@@ -30,9 +30,9 @@
#include "mongo/base/error_codes.h"
#include "mongo/bson/mutable/document.h"
-#include "mongo/db/ops/field_checker.h"
-#include "mongo/db/ops/log_builder.h"
-#include "mongo/db/ops/path_support.h"
+#include "mongo/db/update/field_checker.h"
+#include "mongo/db/update/log_builder.h"
+#include "mongo/db/update/path_support.h"
#include "mongo/util/mongoutils/str.h"
namespace mongo {
diff --git a/src/mongo/db/ops/modifier_unset_test.cpp b/src/mongo/db/ops/modifier_unset_test.cpp
index af6ad9581a7..dfffe5be383 100644
--- a/src/mongo/db/ops/modifier_unset_test.cpp
+++ b/src/mongo/db/ops/modifier_unset_test.cpp
@@ -38,7 +38,7 @@
#include "mongo/bson/mutable/mutable_bson_test_utils.h"
#include "mongo/db/jsobj.h"
#include "mongo/db/json.h"
-#include "mongo/db/ops/log_builder.h"
+#include "mongo/db/update/log_builder.h"
#include "mongo/unittest/unittest.h"
namespace {
diff --git a/src/mongo/db/ops/parsed_update.h b/src/mongo/db/ops/parsed_update.h
index 8c448bd8e58..1c41b07f257 100644
--- a/src/mongo/db/ops/parsed_update.h
+++ b/src/mongo/db/ops/parsed_update.h
@@ -30,10 +30,10 @@
#include "mongo/base/disallow_copying.h"
#include "mongo/base/status.h"
-#include "mongo/db/ops/array_filter.h"
-#include "mongo/db/ops/update_driver.h"
#include "mongo/db/query/collation/collator_interface.h"
#include "mongo/db/query/plan_executor.h"
+#include "mongo/db/update/array_filter.h"
+#include "mongo/db/update/update_driver.h"
namespace mongo {
diff --git a/src/mongo/db/ops/update.cpp b/src/mongo/db/ops/update.cpp
index eaeb014009b..0e5a11e2a0f 100644
--- a/src/mongo/db/ops/update.cpp
+++ b/src/mongo/db/ops/update.cpp
@@ -44,13 +44,13 @@
#include "mongo/db/concurrency/write_conflict_exception.h"
#include "mongo/db/exec/update.h"
#include "mongo/db/op_observer.h"
-#include "mongo/db/ops/update_driver.h"
#include "mongo/db/ops/update_lifecycle.h"
#include "mongo/db/query/explain.h"
#include "mongo/db/query/get_executor.h"
#include "mongo/db/query/plan_summary_stats.h"
#include "mongo/db/repl/repl_client_info.h"
#include "mongo/db/repl/replication_coordinator_global.h"
+#include "mongo/db/update/update_driver.h"
#include "mongo/db/update_index_data.h"
#include "mongo/util/log.h"
#include "mongo/util/scopeguard.h"
diff --git a/src/mongo/db/query/get_executor.h b/src/mongo/db/query/get_executor.h
index 6a13341c111..daf079bb56f 100644
--- a/src/mongo/db/query/get_executor.h
+++ b/src/mongo/db/query/get_executor.h
@@ -29,7 +29,6 @@
#include "mongo/db/ops/delete_request.h"
#include "mongo/db/ops/parsed_delete.h"
#include "mongo/db/ops/parsed_update.h"
-#include "mongo/db/ops/update_driver.h"
#include "mongo/db/ops/update_request.h"
#include "mongo/db/query/canonical_query.h"
#include "mongo/db/query/parsed_distinct.h"
@@ -37,6 +36,7 @@
#include "mongo/db/query/query_planner_params.h"
#include "mongo/db/query/query_settings.h"
#include "mongo/db/query/query_solution.h"
+#include "mongo/db/update/update_driver.h"
namespace mongo {
diff --git a/src/mongo/db/update/SConscript b/src/mongo/db/update/SConscript
new file mode 100644
index 00000000000..2bf1d3b756b
--- /dev/null
+++ b/src/mongo/db/update/SConscript
@@ -0,0 +1,135 @@
+# -*- mode: python -*-
+
+Import("env")
+
+env = env.Clone()
+
+env.Library(
+ target='update_common',
+ source=[
+ 'field_checker.cpp',
+ 'log_builder.cpp',
+ 'path_support.cpp',
+ ],
+ LIBDEPS=[
+ '$BUILD_DIR/mongo/base',
+ '$BUILD_DIR/mongo/bson/mutable/mutable_bson',
+ '$BUILD_DIR/mongo/db/common',
+ '$BUILD_DIR/mongo/db/matcher/expressions',
+ ],
+)
+
+env.CppUnitTest(
+ target='field_checker_test',
+ source=[
+ 'field_checker_test.cpp',
+ ],
+ LIBDEPS=[
+ 'update_common',
+ ],
+)
+
+env.CppUnitTest(
+ target='log_builder_test',
+ source=[
+ 'log_builder_test.cpp',
+ ],
+ LIBDEPS=[
+ '$BUILD_DIR/mongo/bson/mutable/mutable_bson_test_utils',
+ 'update_common',
+ ],
+)
+
+env.CppUnitTest(
+ target='path_support_test',
+ source=[
+ 'path_support_test.cpp',
+ ],
+ LIBDEPS=[
+ '$BUILD_DIR/mongo/bson/mutable/mutable_bson_test_utils',
+ '$BUILD_DIR/mongo/db/matcher/expressions',
+ 'update_common',
+ ],
+)
+
+env.Library(
+ target='update',
+ source=[
+ 'modifier_table.cpp',
+ 'set_node.cpp',
+ 'update_object_node.cpp'
+ ],
+ LIBDEPS=[
+ '$BUILD_DIR/mongo/db/ops/update',
+ 'update_common',
+ ],
+)
+
+env.CppUnitTest(
+ target='modifier_table_test',
+ source='modifier_table_test.cpp',
+ LIBDEPS=[
+ 'update',
+ ],
+)
+
+env.CppUnitTest(
+ target='set_node_test',
+ source='set_node_test.cpp',
+ LIBDEPS=[
+ 'update',
+ ],
+)
+
+env.CppUnitTest(
+ target='update_object_node_test',
+ source='update_object_node_test.cpp',
+ LIBDEPS=[
+ 'update',
+ ],
+)
+
+env.Library(
+ target='update_driver',
+ source=[
+ 'update_driver.cpp',
+ ],
+ LIBDEPS=[
+ '$BUILD_DIR/mongo/base',
+ '$BUILD_DIR/mongo/db/common',
+ '$BUILD_DIR/mongo/db/ops/update',
+ '$BUILD_DIR/mongo/db/query/query_planner',
+ '$BUILD_DIR/mongo/db/update_index_data',
+ 'update',
+ ],
+)
+
+env.CppUnitTest(
+ target='update_driver_test',
+ source='update_driver_test.cpp',
+ LIBDEPS=[
+ '$BUILD_DIR/mongo/bson/mutable/mutable_bson_test_utils',
+ '$BUILD_DIR/mongo/db/query/query_planner',
+ '$BUILD_DIR/mongo/db/query/query_test_service_context',
+ 'update_driver',
+ ],
+)
+
+env.Library(
+ target='array_filter',
+ source=[
+ 'array_filter.cpp',
+ ],
+ LIBDEPS=[
+ "$BUILD_DIR/mongo/db/matcher/expressions",
+ ],
+)
+
+env.CppUnitTest(
+ target='array_filter_test',
+ source='array_filter_test.cpp',
+ LIBDEPS=[
+ 'array_filter',
+ '$BUILD_DIR/mongo/db/query/collation/collator_interface_mock',
+ ],
+)
diff --git a/src/mongo/db/ops/array_filter.cpp b/src/mongo/db/update/array_filter.cpp
index 55c42c7e0a1..4ebaf734498 100644
--- a/src/mongo/db/ops/array_filter.cpp
+++ b/src/mongo/db/update/array_filter.cpp
@@ -28,7 +28,7 @@
#include "mongo/platform/basic.h"
-#include "mongo/db/ops/array_filter.h"
+#include "mongo/db/update/array_filter.h"
#include "mongo/db/matcher/expression_parser.h"
diff --git a/src/mongo/db/ops/array_filter.h b/src/mongo/db/update/array_filter.h
index fc9685ce520..fc9685ce520 100644
--- a/src/mongo/db/ops/array_filter.h
+++ b/src/mongo/db/update/array_filter.h
diff --git a/src/mongo/db/ops/array_filter_test.cpp b/src/mongo/db/update/array_filter_test.cpp
index d79ffc2e683..a0c24ba2875 100644
--- a/src/mongo/db/ops/array_filter_test.cpp
+++ b/src/mongo/db/update/array_filter_test.cpp
@@ -28,7 +28,7 @@
#include "mongo/platform/basic.h"
-#include "mongo/db/ops/array_filter.h"
+#include "mongo/db/update/array_filter.h"
#include "mongo/db/json.h"
#include "mongo/db/matcher/extensions_callback_disallow_extensions.h"
diff --git a/src/mongo/db/ops/field_checker.cpp b/src/mongo/db/update/field_checker.cpp
index 4e8c8b82de6..9821ba168b2 100644
--- a/src/mongo/db/ops/field_checker.cpp
+++ b/src/mongo/db/update/field_checker.cpp
@@ -26,7 +26,7 @@
* it in the license file.
*/
-#include "mongo/db/ops/field_checker.h"
+#include "mongo/db/update/field_checker.h"
#include "mongo/base/error_codes.h"
#include "mongo/db/field_ref.h"
diff --git a/src/mongo/db/ops/field_checker.h b/src/mongo/db/update/field_checker.h
index 772034d4773..772034d4773 100644
--- a/src/mongo/db/ops/field_checker.h
+++ b/src/mongo/db/update/field_checker.h
diff --git a/src/mongo/db/ops/field_checker_test.cpp b/src/mongo/db/update/field_checker_test.cpp
index 5ee608688e9..ff35815a254 100644
--- a/src/mongo/db/ops/field_checker_test.cpp
+++ b/src/mongo/db/update/field_checker_test.cpp
@@ -26,7 +26,7 @@
* then also delete it in the license file.
*/
-#include "mongo/db/ops/field_checker.h"
+#include "mongo/db/update/field_checker.h"
#include "mongo/base/error_codes.h"
#include "mongo/base/status.h"
diff --git a/src/mongo/db/ops/log_builder.cpp b/src/mongo/db/update/log_builder.cpp
index 355ccb092e8..deddbab3840 100644
--- a/src/mongo/db/ops/log_builder.cpp
+++ b/src/mongo/db/update/log_builder.cpp
@@ -26,7 +26,7 @@
* it in the license file.
*/
-#include "mongo/db/ops/log_builder.h"
+#include "mongo/db/update/log_builder.h"
#include "mongo/util/mongoutils/str.h"
namespace mongo {
diff --git a/src/mongo/db/ops/log_builder.h b/src/mongo/db/update/log_builder.h
index 0d667f94151..0d667f94151 100644
--- a/src/mongo/db/ops/log_builder.h
+++ b/src/mongo/db/update/log_builder.h
diff --git a/src/mongo/db/ops/log_builder_test.cpp b/src/mongo/db/update/log_builder_test.cpp
index a957194e56f..27757de756f 100644
--- a/src/mongo/db/ops/log_builder_test.cpp
+++ b/src/mongo/db/update/log_builder_test.cpp
@@ -26,7 +26,7 @@
* then also delete it in the license file.
*/
-#include "mongo/db/ops/log_builder.h"
+#include "mongo/db/update/log_builder.h"
#include "mongo/base/status.h"
#include "mongo/bson/mutable/mutable_bson_test_utils.h"
diff --git a/src/mongo/db/ops/modifier_table.cpp b/src/mongo/db/update/modifier_table.cpp
index cd4f0670184..008973980d8 100644
--- a/src/mongo/db/ops/modifier_table.cpp
+++ b/src/mongo/db/update/modifier_table.cpp
@@ -26,7 +26,7 @@
* it in the license file.
*/
-#include "mongo/db/ops/modifier_table.h"
+#include "mongo/db/update/modifier_table.h"
#include <string>
#include <utility>
@@ -46,7 +46,9 @@
#include "mongo/db/ops/modifier_rename.h"
#include "mongo/db/ops/modifier_set.h"
#include "mongo/db/ops/modifier_unset.h"
+#include "mongo/db/update/set_node.h"
#include "mongo/platform/unordered_map.h"
+#include "mongo/stdx/memory.h"
namespace mongo {
@@ -175,5 +177,14 @@ ModifierInterface* makeUpdateMod(ModifierType modType) {
}
}
+std::unique_ptr<UpdateLeafNode> makeUpdateLeafNode(ModifierType modType) {
+ switch (modType) {
+ case MOD_SET:
+ return stdx::make_unique<SetNode>();
+ default:
+ return nullptr;
+ }
+}
+
} // namespace modifiertable
} // namespace mongo
diff --git a/src/mongo/db/ops/modifier_table.h b/src/mongo/db/update/modifier_table.h
index acefc3290dc..ad5262fb1b0 100644
--- a/src/mongo/db/ops/modifier_table.h
+++ b/src/mongo/db/update/modifier_table.h
@@ -29,6 +29,7 @@
#pragma once
#include "mongo/db/ops/modifier_interface.h"
+#include "mongo/db/update/update_leaf_node.h"
namespace mongo {
namespace modifiertable {
@@ -66,5 +67,10 @@ ModifierType getType(StringData typeStr);
*/
ModifierInterface* makeUpdateMod(ModifierType modType);
+/**
+ * Instantiate an UpdateLeafNode that corresponds to 'modType' or nullptr if 'modType' is not valid.
+ */
+std::unique_ptr<UpdateLeafNode> makeUpdateLeafNode(ModifierType modType);
+
} // namespace modifiertable
} // namespace mongo
diff --git a/src/mongo/db/ops/modifier_table_test.cpp b/src/mongo/db/update/modifier_table_test.cpp
index c5225142668..ca3f82cc1c5 100644
--- a/src/mongo/db/ops/modifier_table_test.cpp
+++ b/src/mongo/db/update/modifier_table_test.cpp
@@ -26,7 +26,7 @@
* it in the license file.
*/
-#include "mongo/db/ops/modifier_table.h"
+#include "mongo/db/update/modifier_table.h"
#include <memory>
diff --git a/src/mongo/db/ops/path_support.cpp b/src/mongo/db/update/path_support.cpp
index a95b700acd0..5e336bb8202 100644
--- a/src/mongo/db/ops/path_support.cpp
+++ b/src/mongo/db/update/path_support.cpp
@@ -26,7 +26,7 @@
* it in the license file.
*/
-#include "mongo/db/ops/path_support.h"
+#include "mongo/db/update/path_support.h"
#include "mongo/base/string_data.h"
#include "mongo/bson/mutable/algorithm.h"
diff --git a/src/mongo/db/ops/path_support.h b/src/mongo/db/update/path_support.h
index 6fbd95ec0a9..6fbd95ec0a9 100644
--- a/src/mongo/db/ops/path_support.h
+++ b/src/mongo/db/update/path_support.h
diff --git a/src/mongo/db/ops/path_support_test.cpp b/src/mongo/db/update/path_support_test.cpp
index 527384ab7bb..5091a2b8cba 100644
--- a/src/mongo/db/ops/path_support_test.cpp
+++ b/src/mongo/db/update/path_support_test.cpp
@@ -26,7 +26,7 @@
* then also delete it in the license file.
*/
-#include "mongo/db/ops/path_support.h"
+#include "mongo/db/update/path_support.h"
#include <cstdint>
#include <memory>
diff --git a/src/mongo/db/update/set_node.cpp b/src/mongo/db/update/set_node.cpp
new file mode 100644
index 00000000000..26c6be59ee3
--- /dev/null
+++ b/src/mongo/db/update/set_node.cpp
@@ -0,0 +1,43 @@
+/**
+ * Copyright (C) 2017 MongoDB Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * As a special exception, the copyright holders give permission to link the
+ * code of portions of this program with the OpenSSL library under certain
+ * conditions as described in each individual source file and distribute
+ * linked combinations including the program with the OpenSSL library. You
+ * must comply with the GNU Affero General Public License in all respects
+ * for all of the code used other than as permitted herein. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you do not
+ * wish to do so, delete this exception statement from your version. If you
+ * delete this exception statement from all source files in the program,
+ * then also delete it in the license file.
+ */
+
+#include "mongo/platform/basic.h"
+
+#include "mongo/db/update/set_node.h"
+
+namespace mongo {
+
+Status SetNode::init(BSONElement modExpr, const CollatorInterface* collator) {
+ invariant(modExpr.ok());
+
+ _val = modExpr;
+
+ return Status::OK();
+}
+
+} // namespace mongo
diff --git a/src/mongo/db/update/set_node.h b/src/mongo/db/update/set_node.h
new file mode 100644
index 00000000000..8ad64010a50
--- /dev/null
+++ b/src/mongo/db/update/set_node.h
@@ -0,0 +1,48 @@
+/**
+ * Copyright (C) 2017 MongoDB Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * As a special exception, the copyright holders give permission to link the
+ * code of portions of this program with the OpenSSL library under certain
+ * conditions as described in each individual source file and distribute
+ * linked combinations including the program with the OpenSSL library. You
+ * must comply with the GNU Affero General Public License in all respects
+ * for all of the code used other than as permitted herein. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you do not
+ * wish to do so, delete this exception statement from your version. If you
+ * delete this exception statement from all source files in the program,
+ * then also delete it in the license file.
+ */
+
+#pragma once
+
+#include "mongo/db/update/update_leaf_node.h"
+
+namespace mongo {
+
+/**
+ * Represents the application of a $set to the value at the end of a path.
+ */
+class SetNode : public UpdateLeafNode {
+public:
+ Status init(BSONElement modExpr, const CollatorInterface* collator) final;
+
+ void setCollator(const CollatorInterface* collator) final {}
+
+private:
+ BSONElement _val;
+};
+
+} // namespace mongo
diff --git a/src/mongo/db/update/set_node_test.cpp b/src/mongo/db/update/set_node_test.cpp
new file mode 100644
index 00000000000..c600af34158
--- /dev/null
+++ b/src/mongo/db/update/set_node_test.cpp
@@ -0,0 +1,55 @@
+/**
+ * Copyright (C) 2017 MongoDB Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * As a special exception, the copyright holders give permission to link the
+ * code of portions of this program with the OpenSSL library under certain
+ * conditions as described in each individual source file and distribute
+ * linked combinations including the program with the OpenSSL library. You
+ * must comply with the GNU Affero General Public License in all respects
+ * for all of the code used other than as permitted herein. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you do not
+ * wish to do so, delete this exception statement from your version. If you
+ * delete this exception statement from all source files in the program,
+ * then also delete it in the license file.
+ */
+
+#include "mongo/platform/basic.h"
+
+#include "mongo/db/update/set_node.h"
+
+#include "mongo/db/json.h"
+#include "mongo/unittest/death_test.h"
+#include "mongo/unittest/unittest.h"
+
+namespace {
+
+using namespace mongo;
+
+DEATH_TEST(SetNodeTest, InitFailsForEmptyElement, "Invariant failure modExpr.ok()") {
+ auto update = fromjson("{$set: {}}");
+ const CollatorInterface* collator = nullptr;
+ SetNode node;
+ node.init(update["$set"].embeddedObject().firstElement(), collator);
+}
+
+TEST(SetNodeTest, InitSucceedsForNonemptyElement) {
+ auto update = fromjson("{$set: {a: 5}}");
+ const CollatorInterface* collator = nullptr;
+ SetNode node;
+ ASSERT_OK(node.init(update["$set"]["a"], collator));
+}
+
+} // namespace
diff --git a/src/mongo/db/ops/update_driver.cpp b/src/mongo/db/update/update_driver.cpp
index f94f520f032..d13118e4ed4 100644
--- a/src/mongo/db/ops/update_driver.cpp
+++ b/src/mongo/db/update/update_driver.cpp
@@ -26,7 +26,7 @@
* it in the license file.
*/
-#include "mongo/db/ops/update_driver.h"
+#include "mongo/db/update/update_driver.h"
#include "mongo/base/error_codes.h"
@@ -36,10 +36,10 @@
#include "mongo/db/field_ref.h"
#include "mongo/db/matcher/expression_leaf.h"
#include "mongo/db/matcher/extensions_callback_noop.h"
-#include "mongo/db/ops/log_builder.h"
#include "mongo/db/ops/modifier_object_replace.h"
-#include "mongo/db/ops/modifier_table.h"
-#include "mongo/db/ops/path_support.h"
+#include "mongo/db/update/log_builder.h"
+#include "mongo/db/update/modifier_table.h"
+#include "mongo/db/update/path_support.h"
#include "mongo/util/embedded_builder.h"
#include "mongo/util/mongoutils/str.h"
diff --git a/src/mongo/db/ops/update_driver.h b/src/mongo/db/update/update_driver.h
index 73f231f9764..6152e22cefb 100644
--- a/src/mongo/db/ops/update_driver.h
+++ b/src/mongo/db/update/update_driver.h
@@ -37,8 +37,8 @@
#include "mongo/db/field_ref_set.h"
#include "mongo/db/jsobj.h"
#include "mongo/db/ops/modifier_interface.h"
-#include "mongo/db/ops/modifier_table.h"
#include "mongo/db/query/canonical_query.h"
+#include "mongo/db/update/modifier_table.h"
#include "mongo/db/update_index_data.h"
namespace mongo {
diff --git a/src/mongo/db/ops/update_driver_test.cpp b/src/mongo/db/update/update_driver_test.cpp
index c7ef14b3e9f..b2e98556d16 100644
--- a/src/mongo/db/ops/update_driver_test.cpp
+++ b/src/mongo/db/update/update_driver_test.cpp
@@ -26,7 +26,7 @@
* it in the license file.
*/
-#include "mongo/db/ops/update_driver.h"
+#include "mongo/db/update/update_driver.h"
#include <map>
diff --git a/src/mongo/db/update/update_leaf_node.h b/src/mongo/db/update/update_leaf_node.h
new file mode 100644
index 00000000000..2b378036c7d
--- /dev/null
+++ b/src/mongo/db/update/update_leaf_node.h
@@ -0,0 +1,58 @@
+/**
+ * Copyright (C) 2017 MongoDB Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * As a special exception, the copyright holders give permission to link the
+ * code of portions of this program with the OpenSSL library under certain
+ * conditions as described in each individual source file and distribute
+ * linked combinations including the program with the OpenSSL library. You
+ * must comply with the GNU Affero General Public License in all respects
+ * for all of the code used other than as permitted herein. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you do not
+ * wish to do so, delete this exception statement from your version. If you
+ * delete this exception statement from all source files in the program,
+ * then also delete it in the license file.
+ */
+
+#pragma once
+
+#include "mongo/bson/bsonelement.h"
+#include "mongo/db/update/update_node.h"
+
+namespace mongo {
+
+/**
+ * A leaf node in the prefix tree of update modifier expressions, representing an update to the
+ * value at the end of a path. See comment in class definition of UpdateNode for more details.
+ */
+class UpdateLeafNode : public UpdateNode {
+public:
+ UpdateLeafNode() : UpdateNode(Type::Leaf) {}
+
+ /**
+ * Initializes the leaf node with the value in 'modExpr'. 'modExpr' is a single modifier
+ * expression in the update expression. For example, if the update expression is root = {$set:
+ * {'a.b': 5, c: 6}, $inc: {'a.c': 1}}, then a single modifier expression would be
+ * root["$set"]["a.b"]. Returns a non-OK status if the value in 'modExpr' is invalid for the
+ * type of leaf node. 'modExpr' must not be empty.
+ *
+ * Some leaf nodes require a collator during initialization. For example, $pull requires a
+ * collator to construct a MatchExpression that will be used for applying updates across
+ * multiple documents.
+ */
+ virtual Status init(BSONElement modExpr, const CollatorInterface* collator) = 0;
+};
+
+} // namespace mongo
diff --git a/src/mongo/db/update/update_node.h b/src/mongo/db/update/update_node.h
new file mode 100644
index 00000000000..4336ab17cd5
--- /dev/null
+++ b/src/mongo/db/update/update_node.h
@@ -0,0 +1,68 @@
+/**
+ * Copyright (C) 2017 MongoDB Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * As a special exception, the copyright holders give permission to link the
+ * code of portions of this program with the OpenSSL library under certain
+ * conditions as described in each individual source file and distribute
+ * linked combinations including the program with the OpenSSL library. You
+ * must comply with the GNU Affero General Public License in all respects
+ * for all of the code used other than as permitted herein. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you do not
+ * wish to do so, delete this exception statement from your version. If you
+ * delete this exception statement from all source files in the program,
+ * then also delete it in the license file.
+ */
+
+#pragma once
+
+namespace mongo {
+
+class CollatorInterface;
+
+/**
+ * Update modifier expressions are stored as a prefix tree of UpdateNodes, where two modifiers that
+ * share a field path prefix share a path prefix in the tree. The prefix tree is used to enforce
+ * that no update modifier's field path is a prefix of (or equal to) another update modifier's field
+ * path. The root of the UpdateNode tree is always an UpdateObjectNode. The leaves are always
+ * UpdateLeafNodes.
+ *
+ * Example: {$set: {'a.b': 5, c: 6}, $inc: {'a.c': 1}}
+ *
+ * UpdateObjectNode
+ * a / \ c
+ * UpdateObjectNode SetNode: _val = 6
+ * b / \ c
+ * SetNode: _val = 5 IncNode: _val = 1
+ */
+class UpdateNode {
+public:
+ enum class Type { Object, Leaf };
+
+ explicit UpdateNode(Type type) : type(type) {}
+
+ /**
+ * Set the collation on the node and all descendants. This is a noop if no leaf nodes require a
+ * collator. If setCollator() is called, it is required that the current collator of all leaf
+ * nodes is the simple collator (nullptr). The collator must outlive the modifier interface.
+ * This is used to override the collation after obtaining a collection lock if the update did
+ * not specify a collation and the collection has a non-simple default collation.
+ */
+ virtual void setCollator(const CollatorInterface* collator) = 0;
+
+ const Type type;
+};
+
+} // namespace mongo
diff --git a/src/mongo/db/update/update_object_node.cpp b/src/mongo/db/update/update_object_node.cpp
new file mode 100644
index 00000000000..12794c5b0dc
--- /dev/null
+++ b/src/mongo/db/update/update_object_node.cpp
@@ -0,0 +1,153 @@
+/**
+ * Copyright (C) 2017 MongoDB Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * As a special exception, the copyright holders give permission to link the
+ * code of portions of this program with the OpenSSL library under certain
+ * conditions as described in each individual source file and distribute
+ * linked combinations including the program with the OpenSSL library. You
+ * must comply with the GNU Affero General Public License in all respects
+ * for all of the code used other than as permitted herein. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you do not
+ * wish to do so, delete this exception statement from your version. If you
+ * delete this exception statement from all source files in the program,
+ * then also delete it in the license file.
+ */
+
+#include "mongo/platform/basic.h"
+
+#include "mongo/db/update/update_object_node.h"
+
+#include "mongo/db/update/field_checker.h"
+#include "mongo/db/update/modifier_table.h"
+#include "mongo/db/update/update_leaf_node.h"
+#include "mongo/stdx/memory.h"
+
+namespace mongo {
+
+namespace {
+
+bool isPositionalElement(const std::string& field) {
+ return field.length() == 1 && field[0] == '$';
+}
+
+} // namespace
+
+// static
+StatusWith<bool> UpdateObjectNode::parseAndMerge(UpdateObjectNode* root,
+ modifiertable::ModifierType type,
+ BSONElement modExpr,
+ const CollatorInterface* collator) {
+ // Check that the path is updatable.
+ FieldRef fieldRef(modExpr.fieldNameStringData());
+ auto status = fieldchecker::isUpdatable(fieldRef);
+ if (!status.isOK()) {
+ return status;
+ }
+
+ // Check that there is at most one positional ($) part of the path and it is not in the first
+ // position.
+ size_t positionalIndex;
+ size_t positionalCount;
+ bool positional = fieldchecker::isPositional(fieldRef, &positionalIndex, &positionalCount);
+
+ if (positional && positionalCount > 1) {
+ return Status(ErrorCodes::BadValue,
+ str::stream() << "Too many positional (i.e. '$') elements found in path '"
+ << fieldRef.dottedField()
+ << "'");
+ }
+
+ if (positional && positionalIndex == 0) {
+ return Status(
+ ErrorCodes::BadValue,
+ str::stream()
+ << "Cannot have positional (i.e. '$') element in the first position in path '"
+ << fieldRef.dottedField()
+ << "'");
+ }
+
+ // Construct the leaf node.
+ // TODO SERVER-28777: This should never fail because all modifiers are implemented.
+ auto leaf = modifiertable::makeUpdateLeafNode(type);
+ if (!leaf) {
+ return Status(ErrorCodes::FailedToParse,
+ str::stream() << "Cannot construct modifier of type " << type);
+ }
+
+ // Initialize the leaf node.
+ status = leaf->init(modExpr, collator);
+ if (!status.isOK()) {
+ return status;
+ }
+
+ // Create UpdateObjectNodes along the path.
+ UpdateObjectNode* current = root;
+ for (size_t i = 0; i < fieldRef.numParts() - 1; ++i) {
+ auto field = fieldRef.getPart(i).toString();
+ auto child = current->getChild(field);
+ if (child) {
+ if (child->type != UpdateNode::Type::Object) {
+ return Status(ErrorCodes::ConflictingUpdateOperators,
+ str::stream() << "Updating the path '" << fieldRef.dottedField()
+ << "' would create a conflict at '"
+ << fieldRef.dottedSubstring(0, i + 1)
+ << "'");
+ }
+ } else {
+ auto ownedChild = stdx::make_unique<UpdateObjectNode>();
+ child = ownedChild.get();
+ current->setChild(std::move(field), std::move(ownedChild));
+ }
+ current = static_cast<UpdateObjectNode*>(child);
+ }
+
+ // Add the leaf node to the end of the path.
+ auto field = fieldRef.getPart(fieldRef.numParts() - 1).toString();
+ if (current->getChild(field)) {
+ return Status(ErrorCodes::ConflictingUpdateOperators,
+ str::stream() << "Updating the path '" << fieldRef.dottedField()
+ << "' would create a conflict at '"
+ << fieldRef.dottedField()
+ << "'");
+ }
+ current->setChild(std::move(field), std::move(leaf));
+
+ return positional;
+}
+
+UpdateNode* UpdateObjectNode::getChild(const std::string& field) const {
+ if (isPositionalElement(field)) {
+ return _positionalChild.get();
+ }
+
+ auto child = _children.find(field);
+ if (child == _children.end()) {
+ return nullptr;
+ }
+ return child->second.get();
+}
+
+void UpdateObjectNode::setChild(std::string field, std::unique_ptr<UpdateNode> child) {
+ if (isPositionalElement(field)) {
+ invariant(!_positionalChild);
+ _positionalChild = std::move(child);
+ } else {
+ invariant(_children.find(field) == _children.end());
+ _children[std::move(field)] = std::move(child);
+ }
+}
+
+} // namespace mongo
diff --git a/src/mongo/db/update/update_object_node.h b/src/mongo/db/update/update_object_node.h
new file mode 100644
index 00000000000..55d305a1d30
--- /dev/null
+++ b/src/mongo/db/update/update_object_node.h
@@ -0,0 +1,80 @@
+/**
+ * Copyright (C) 2017 MongoDB Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * As a special exception, the copyright holders give permission to link the
+ * code of portions of this program with the OpenSSL library under certain
+ * conditions as described in each individual source file and distribute
+ * linked combinations including the program with the OpenSSL library. You
+ * must comply with the GNU Affero General Public License in all respects
+ * for all of the code used other than as permitted herein. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you do not
+ * wish to do so, delete this exception statement from your version. If you
+ * delete this exception statement from all source files in the program,
+ * then also delete it in the license file.
+ */
+
+#pragma once
+
+#include "mongo/bson/bsonelement.h"
+#include "mongo/db/update/modifier_table.h"
+#include "mongo/db/update/update_node.h"
+
+namespace mongo {
+
+/**
+ * An internal node in the prefix tree of update modifier expressions, representing updates to an
+ * object. See comment in class definition of UpdateNode for more details.
+ */
+class UpdateObjectNode : public UpdateNode {
+
+public:
+ /**
+ * Parses 'modExpr' as an update modifier expression and merges with it with 'root'. Returns a
+ * non-OK status if 'modExpr' is not a valid update modifier expression, or if merging would
+ * cause a conflict. Returns true if the path of 'modExpr' contains a positional $ element, e.g.
+ * 'a.$.b'.
+ */
+ static StatusWith<bool> parseAndMerge(UpdateObjectNode* root,
+ modifiertable::ModifierType type,
+ BSONElement modExpr,
+ const CollatorInterface* collator);
+
+ UpdateObjectNode() : UpdateNode(Type::Object) {}
+
+ void setCollator(const CollatorInterface* collator) final {
+ for (auto&& child : _children) {
+ child.second->setCollator(collator);
+ }
+ _positionalChild->setCollator(collator);
+ }
+
+ /**
+ * Returns the child with field name 'field' or nullptr if there is no such child.
+ */
+ UpdateNode* getChild(const std::string& field) const;
+
+ /**
+ * Adds a child with field name 'field'. The node must not already have a child with field
+ * name 'field'.
+ */
+ void setChild(std::string field, std::unique_ptr<UpdateNode> child);
+
+private:
+ std::map<std::string, std::unique_ptr<UpdateNode>> _children;
+ std::unique_ptr<UpdateNode> _positionalChild;
+};
+
+} // namespace mongo
diff --git a/src/mongo/db/update/update_object_node_test.cpp b/src/mongo/db/update/update_object_node_test.cpp
new file mode 100644
index 00000000000..6143cd5f29c
--- /dev/null
+++ b/src/mongo/db/update/update_object_node_test.cpp
@@ -0,0 +1,333 @@
+/**
+ * Copyright (C) 2017 MongoDB Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * As a special exception, the copyright holders give permission to link the
+ * code of portions of this program with the OpenSSL library under certain
+ * conditions as described in each individual source file and distribute
+ * linked combinations including the program with the OpenSSL library. You
+ * must comply with the GNU Affero General Public License in all respects
+ * for all of the code used other than as permitted herein. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you do not
+ * wish to do so, delete this exception statement from your version. If you
+ * delete this exception statement from all source files in the program,
+ * then also delete it in the license file.
+ */
+
+#include "mongo/platform/basic.h"
+
+#include "mongo/db/update/update_object_node.h"
+
+#include "mongo/db/json.h"
+#include "mongo/unittest/unittest.h"
+
+namespace {
+
+using namespace mongo;
+
+TEST(UpdateObjectNodeTest, InvalidPathFailsToParse) {
+ auto update = fromjson("{$set: {'': 5}}");
+ const CollatorInterface* collator = nullptr;
+ UpdateObjectNode root;
+ auto result = UpdateObjectNode::parseAndMerge(
+ &root, modifiertable::ModifierType::MOD_SET, update["$set"][""], collator);
+ ASSERT_NOT_OK(result);
+ ASSERT_EQ(result.getStatus().code(), ErrorCodes::EmptyFieldName);
+ ASSERT_EQ(result.getStatus().reason(), "An empty update path is not valid.");
+}
+
+TEST(UpdateObjectNodeTest, ValidPathParsesSuccessfully) {
+ auto update = fromjson("{$set: {'a.b': 5}}");
+ const CollatorInterface* collator = nullptr;
+ UpdateObjectNode root;
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(
+ &root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.b"], collator));
+}
+
+TEST(UpdateObjectNodeTest, MultiplePositionalElementsFailToParse) {
+ auto update = fromjson("{$set: {'a.$.b.$': 5}}");
+ const CollatorInterface* collator = nullptr;
+ UpdateObjectNode root;
+ auto result = UpdateObjectNode::parseAndMerge(
+ &root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.$.b.$"], collator);
+ ASSERT_NOT_OK(result);
+ ASSERT_EQ(result.getStatus().code(), ErrorCodes::BadValue);
+ ASSERT_EQ(result.getStatus().reason(),
+ "Too many positional (i.e. '$') elements found in path 'a.$.b.$'");
+}
+
+TEST(UpdateObjectNodeTest, ParsingSetsPositionalTrue) {
+ auto update = fromjson("{$set: {'a.$.b': 5}}");
+ const CollatorInterface* collator = nullptr;
+ UpdateObjectNode root;
+ auto result = UpdateObjectNode::parseAndMerge(
+ &root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.$.b"], collator);
+ ASSERT_OK(result);
+ ASSERT_TRUE(result.getValue());
+}
+
+TEST(UpdateObjectNodeTest, ParsingSetsPositionalFalse) {
+ auto update = fromjson("{$set: {'a.b': 5}}");
+ const CollatorInterface* collator = nullptr;
+ UpdateObjectNode root;
+ auto result = UpdateObjectNode::parseAndMerge(
+ &root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.b"], collator);
+ ASSERT_OK(result);
+ ASSERT_FALSE(result.getValue());
+}
+
+TEST(UpdateObjectNodeTest, PositionalElementFirstPositionFailsToParse) {
+ auto update = fromjson("{$set: {'$': 5}}");
+ const CollatorInterface* collator = nullptr;
+ UpdateObjectNode root;
+ auto result = UpdateObjectNode::parseAndMerge(
+ &root, modifiertable::ModifierType::MOD_SET, update["$set"]["$"], collator);
+ ASSERT_NOT_OK(result);
+ ASSERT_EQ(result.getStatus().code(), ErrorCodes::BadValue);
+ ASSERT_EQ(result.getStatus().reason(),
+ "Cannot have positional (i.e. '$') element in the first position in path '$'");
+}
+
+// TODO SERVER-28777: All modifier types should succeed.
+TEST(UpdateObjectNodeTest, IncFailsToParse) {
+ auto update = fromjson("{$inc: {a: 5}}");
+ const CollatorInterface* collator = nullptr;
+ UpdateObjectNode root;
+ auto result = UpdateObjectNode::parseAndMerge(
+ &root, modifiertable::ModifierType::MOD_INC, update["$inc"]["a"], collator);
+ ASSERT_NOT_OK(result);
+ ASSERT_EQ(result.getStatus().code(), ErrorCodes::FailedToParse);
+ ASSERT_EQ(result.getStatus().reason(), "Cannot construct modifier of type 3");
+}
+
+TEST(UpdateObjectNodeTest, TwoModifiersOnSameFieldFailToParse) {
+ auto update = fromjson("{$set: {a: 5}}");
+ const CollatorInterface* collator = nullptr;
+ UpdateObjectNode root;
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(
+ &root, modifiertable::ModifierType::MOD_SET, update["$set"]["a"], collator));
+ auto result = UpdateObjectNode::parseAndMerge(
+ &root, modifiertable::ModifierType::MOD_SET, update["$set"]["a"], collator);
+ ASSERT_NOT_OK(result);
+ ASSERT_EQ(result.getStatus().code(), ErrorCodes::ConflictingUpdateOperators);
+ ASSERT_EQ(result.getStatus().reason(), "Updating the path 'a' would create a conflict at 'a'");
+}
+
+TEST(UpdateObjectNodeTest, TwoModifiersOnDifferentFieldsParseSuccessfully) {
+ auto update = fromjson("{$set: {a: 5, b: 6}}");
+ const CollatorInterface* collator = nullptr;
+ UpdateObjectNode root;
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(
+ &root, modifiertable::ModifierType::MOD_SET, update["$set"]["a"], collator));
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(
+ &root, modifiertable::ModifierType::MOD_SET, update["$set"]["b"], collator));
+}
+
+TEST(UpdateObjectNodeTest, TwoModifiersWithSameDottedPathFailToParse) {
+ auto update = fromjson("{$set: {'a.b': 5}}");
+ const CollatorInterface* collator = nullptr;
+ UpdateObjectNode root;
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(
+ &root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.b"], collator));
+ auto result = UpdateObjectNode::parseAndMerge(
+ &root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.b"], collator);
+ ASSERT_NOT_OK(result);
+ ASSERT_EQ(result.getStatus().code(), ErrorCodes::ConflictingUpdateOperators);
+ ASSERT_EQ(result.getStatus().reason(),
+ "Updating the path 'a.b' would create a conflict at 'a.b'");
+}
+
+TEST(UpdateObjectNodeTest, FirstModifierPrefixOfSecondFailToParse) {
+ auto update = fromjson("{$set: {a: 5, 'a.b': 6}}");
+ const CollatorInterface* collator = nullptr;
+ UpdateObjectNode root;
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(
+ &root, modifiertable::ModifierType::MOD_SET, update["$set"]["a"], collator));
+ auto result = UpdateObjectNode::parseAndMerge(
+ &root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.b"], collator);
+ ASSERT_NOT_OK(result);
+ ASSERT_EQ(result.getStatus().code(), ErrorCodes::ConflictingUpdateOperators);
+ ASSERT_EQ(result.getStatus().reason(),
+ "Updating the path 'a.b' would create a conflict at 'a'");
+}
+
+TEST(UpdateObjectNodeTest, FirstModifierDottedPrefixOfSecondFailsToParse) {
+ auto update = fromjson("{$set: {'a.b': 5, 'a.b.c': 6}}");
+ const CollatorInterface* collator = nullptr;
+ UpdateObjectNode root;
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(
+ &root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.b"], collator));
+ auto result = UpdateObjectNode::parseAndMerge(
+ &root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.b.c"], collator);
+ ASSERT_NOT_OK(result);
+ ASSERT_EQ(result.getStatus().code(), ErrorCodes::ConflictingUpdateOperators);
+ ASSERT_EQ(result.getStatus().reason(),
+ "Updating the path 'a.b.c' would create a conflict at 'a.b'");
+}
+
+TEST(UpdateObjectNodeTest, SecondModifierPrefixOfFirstFailsToParse) {
+ auto update = fromjson("{$set: {'a.b': 5, a: 6}}");
+ const CollatorInterface* collator = nullptr;
+ UpdateObjectNode root;
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(
+ &root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.b"], collator));
+ auto result = UpdateObjectNode::parseAndMerge(
+ &root, modifiertable::ModifierType::MOD_SET, update["$set"]["a"], collator);
+ ASSERT_NOT_OK(result);
+ ASSERT_EQ(result.getStatus().code(), ErrorCodes::ConflictingUpdateOperators);
+ ASSERT_EQ(result.getStatus().reason(), "Updating the path 'a' would create a conflict at 'a'");
+}
+
+TEST(UpdateObjectNodeTest, SecondModifierDottedPrefixOfFirstFailsToParse) {
+ auto update = fromjson("{$set: {'a.b.c': 5, 'a.b': 6}}");
+ const CollatorInterface* collator = nullptr;
+ UpdateObjectNode root;
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(
+ &root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.b.c"], collator));
+ auto result = UpdateObjectNode::parseAndMerge(
+ &root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.b"], collator);
+ ASSERT_NOT_OK(result);
+ ASSERT_EQ(result.getStatus().code(), ErrorCodes::ConflictingUpdateOperators);
+ ASSERT_EQ(result.getStatus().reason(),
+ "Updating the path 'a.b' would create a conflict at 'a.b'");
+}
+
+TEST(UpdateObjectNodeTest, ModifiersWithCommonPrefixParseSuccessfully) {
+ auto update = fromjson("{$set: {'a.b': 5, 'a.c': 6}}");
+ const CollatorInterface* collator = nullptr;
+ UpdateObjectNode root;
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(
+ &root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.b"], collator));
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(
+ &root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.c"], collator));
+}
+
+TEST(UpdateObjectNodeTest, ModifiersWithCommonDottedPrefixParseSuccessfully) {
+ auto update = fromjson("{$set: {'a.b.c': 5, 'a.b.d': 6}}");
+ const CollatorInterface* collator = nullptr;
+ UpdateObjectNode root;
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(
+ &root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.b.c"], collator));
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(
+ &root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.b.d"], collator));
+}
+
+TEST(UpdateObjectNodeTest, ModifiersWithCommonPrefixDottedSuffixParseSuccessfully) {
+ auto update = fromjson("{$set: {'a.b.c': 5, 'a.d.e': 6}}");
+ const CollatorInterface* collator = nullptr;
+ UpdateObjectNode root;
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(
+ &root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.b.c"], collator));
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(
+ &root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.d.e"], collator));
+}
+
+TEST(UpdateObjectNodeTest, TwoModifiersOnSamePositionalFieldFailToParse) {
+ auto update = fromjson("{$set: {'a.$': 5}}");
+ const CollatorInterface* collator = nullptr;
+ UpdateObjectNode root;
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(
+ &root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.$"], collator));
+ auto result = UpdateObjectNode::parseAndMerge(
+ &root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.$"], collator);
+ ASSERT_NOT_OK(result);
+ ASSERT_EQ(result.getStatus().code(), ErrorCodes::ConflictingUpdateOperators);
+ ASSERT_EQ(result.getStatus().reason(),
+ "Updating the path 'a.$' would create a conflict at 'a.$'");
+}
+
+TEST(UpdateObjectNodeTest, PositionalFieldsWithDifferentPrefixesParseSuccessfully) {
+ auto update = fromjson("{$set: {'a.$': 5, 'b.$': 6}}");
+ const CollatorInterface* collator = nullptr;
+ UpdateObjectNode root;
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(
+ &root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.$"], collator));
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(
+ &root, modifiertable::ModifierType::MOD_SET, update["$set"]["b.$"], collator));
+}
+
+TEST(UpdateObjectNodeTest, PositionalAndNonpositionalFieldWithCommonPrefixParseSuccessfully) {
+ auto update = fromjson("{$set: {'a.$': 5, 'a.0': 6}}");
+ const CollatorInterface* collator = nullptr;
+ UpdateObjectNode root;
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(
+ &root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.$"], collator));
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(
+ &root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.0"], collator));
+}
+
+TEST(UpdateObjectNodeTest, TwoModifiersWithSamePositionalDottedPathFailToParse) {
+ auto update = fromjson("{$set: {'a.$.b': 5}}");
+ const CollatorInterface* collator = nullptr;
+ UpdateObjectNode root;
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(
+ &root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.$.b"], collator));
+ auto result = UpdateObjectNode::parseAndMerge(
+ &root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.$.b"], collator);
+ ASSERT_NOT_OK(result);
+ ASSERT_EQ(result.getStatus().code(), ErrorCodes::ConflictingUpdateOperators);
+ ASSERT_EQ(result.getStatus().reason(),
+ "Updating the path 'a.$.b' would create a conflict at 'a.$.b'");
+}
+
+TEST(UpdateObjectNodeTest, FirstModifierPositionalPrefixOfSecondFailsToParse) {
+ auto update = fromjson("{$set: {'a.$': 5, 'a.$.b': 6}}");
+ const CollatorInterface* collator = nullptr;
+ UpdateObjectNode root;
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(
+ &root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.$"], collator));
+ auto result = UpdateObjectNode::parseAndMerge(
+ &root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.$.b"], collator);
+ ASSERT_NOT_OK(result);
+ ASSERT_EQ(result.getStatus().code(), ErrorCodes::ConflictingUpdateOperators);
+ ASSERT_EQ(result.getStatus().reason(),
+ "Updating the path 'a.$.b' would create a conflict at 'a.$'");
+}
+
+TEST(UpdateObjectNodeTest, SecondModifierPositionalPrefixOfFirstFailsToParse) {
+ auto update = fromjson("{$set: {'a.$.b': 5, 'a.$': 6}}");
+ const CollatorInterface* collator = nullptr;
+ UpdateObjectNode root;
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(
+ &root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.$.b"], collator));
+ auto result = UpdateObjectNode::parseAndMerge(
+ &root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.$"], collator);
+ ASSERT_NOT_OK(result);
+ ASSERT_EQ(result.getStatus().code(), ErrorCodes::ConflictingUpdateOperators);
+ ASSERT_EQ(result.getStatus().reason(),
+ "Updating the path 'a.$' would create a conflict at 'a.$'");
+}
+
+TEST(UpdateObjectNodeTest, FirstModifierFieldPrefixOfSecondParsesSuccessfully) {
+ auto update = fromjson("{$set: {'a': 5, 'ab': 6}}");
+ const CollatorInterface* collator = nullptr;
+ UpdateObjectNode root;
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(
+ &root, modifiertable::ModifierType::MOD_SET, update["$set"]["a"], collator));
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(
+ &root, modifiertable::ModifierType::MOD_SET, update["$set"]["ab"], collator));
+}
+
+TEST(UpdateObjectNodeTest, SecondModifierFieldPrefixOfSecondParsesSuccessfully) {
+ auto update = fromjson("{$set: {'ab': 5, 'a': 6}}");
+ const CollatorInterface* collator = nullptr;
+ UpdateObjectNode root;
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(
+ &root, modifiertable::ModifierType::MOD_SET, update["$set"]["ab"], collator));
+ ASSERT_OK(UpdateObjectNode::parseAndMerge(
+ &root, modifiertable::ModifierType::MOD_SET, update["$set"]["a"], collator));
+}
+
+} // namespace
diff --git a/src/mongo/dbtests/query_stage_update.cpp b/src/mongo/dbtests/query_stage_update.cpp
index 429180205fc..c0c692473a6 100644
--- a/src/mongo/dbtests/query_stage_update.cpp
+++ b/src/mongo/dbtests/query_stage_update.cpp
@@ -47,11 +47,11 @@
#include "mongo/db/json.h"
#include "mongo/db/matcher/extensions_callback_disallow_extensions.h"
#include "mongo/db/namespace_string.h"
-#include "mongo/db/ops/update_driver.h"
#include "mongo/db/ops/update_lifecycle_impl.h"
#include "mongo/db/ops/update_request.h"
#include "mongo/db/query/canonical_query.h"
#include "mongo/db/service_context.h"
+#include "mongo/db/update/update_driver.h"
#include "mongo/dbtests/dbtests.h"
#include "mongo/stdx/memory.h"
diff --git a/src/mongo/s/SConscript b/src/mongo/s/SConscript
index c5c7e32c73d..badffd70d6f 100644
--- a/src/mongo/s/SConscript
+++ b/src/mongo/s/SConscript
@@ -95,10 +95,10 @@ env.Library(
'$BUILD_DIR/mongo/client/connection_string',
'$BUILD_DIR/mongo/db/common',
'$BUILD_DIR/mongo/db/matcher/expressions',
- '$BUILD_DIR/mongo/db/ops/update_common',
'$BUILD_DIR/mongo/db/query/query_planner',
'$BUILD_DIR/mongo/db/query/query_request',
'$BUILD_DIR/mongo/db/repl/optime',
+ '$BUILD_DIR/mongo/db/update/update_common',
'$BUILD_DIR/mongo/rpc/metadata',
]
)
diff --git a/src/mongo/s/shard_key_pattern.cpp b/src/mongo/s/shard_key_pattern.cpp
index 3518a7e9cc2..4cef9efdec4 100644
--- a/src/mongo/s/shard_key_pattern.cpp
+++ b/src/mongo/s/shard_key_pattern.cpp
@@ -37,8 +37,8 @@
#include "mongo/db/hasher.h"
#include "mongo/db/index_names.h"
#include "mongo/db/matcher/extensions_callback_noop.h"
-#include "mongo/db/ops/path_support.h"
#include "mongo/db/query/canonical_query.h"
+#include "mongo/db/update/path_support.h"
#include "mongo/util/mongoutils/str.h"
#include "mongo/util/transitional_tools_do_not_use/vector_spooling.h"