Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in
Toggle navigation
M
mongo-php-library
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
sinan
mongo-php-library
Commits
2628c098
Unverified
Commit
2628c098
authored
Aug 12, 2019
by
Andreas Braun
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
PHPLIB-418: Add the ability to specify a pipeline to an update command
parent
67ffd336
Show whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
102 additions
and
26 deletions
+102
-26
apiargs-MongoDBCollection-common-param.yaml
docs/includes/apiargs-MongoDBCollection-common-param.yaml
+3
-1
FindAndModify.php
src/Operation/FindAndModify.php
+8
-1
FindOneAndUpdate.php
src/Operation/FindOneAndUpdate.php
+3
-2
ReplaceOne.php
src/Operation/ReplaceOne.php
+5
-0
Update.php
src/Operation/Update.php
+2
-1
UpdateMany.php
src/Operation/UpdateMany.php
+3
-2
UpdateOne.php
src/Operation/UpdateOne.php
+3
-2
functions.php
src/functions.php
+41
-0
FunctionsTest.php
tests/FunctionsTest.php
+30
-0
FindOneAndUpdateTest.php
tests/Operation/FindOneAndUpdateTest.php
+2
-2
UpdateManyTest.php
tests/Operation/UpdateManyTest.php
+1
-1
UpdateOneTest.php
tests/Operation/UpdateOneTest.php
+1
-1
CrudSpecTest.php
tests/SpecTests/CrudSpecTest.php
+0
-13
No files found.
docs/includes/apiargs-MongoDBCollection-common-param.yaml
View file @
2628c098
...
...
@@ -24,7 +24,9 @@ type: array|object
description
:
|
Specifies the field and value combinations to update and any relevant update
operators. ``$update`` uses MongoDB's :method:`update operators
</reference/operator/update>`.
</reference/operator/update>`. Starting with MongoDB 4.2, an `aggregation
pipeline <https://docs.mongodb.com/master/reference/command/update/#update-with-an-aggregation-pipeline>`_
can be passed as this parameter.
interface
:
phpmethod
operation
:
~
optional
:
false
...
...
src/Operation/FindAndModify.php
View file @
2628c098
...
...
@@ -31,6 +31,7 @@ use function is_bool;
use
function
is_integer
;
use
function
is_object
;
use
function
MongoDB
\create_field_path_type_map
;
use
function
MongoDB
\is_pipeline
;
use
function
MongoDB
\server_supports_feature
;
/**
...
...
@@ -255,12 +256,18 @@ class FindAndModify implements Executable, Explainable
$cmd
[
'upsert'
]
=
$this
->
options
[
'upsert'
];
}
foreach
([
'collation'
,
'fields'
,
'query'
,
'sort'
,
'update'
]
as
$option
)
{
foreach
([
'collation'
,
'fields'
,
'query'
,
'sort'
]
as
$option
)
{
if
(
isset
(
$this
->
options
[
$option
]))
{
$cmd
[
$option
]
=
(
object
)
$this
->
options
[
$option
];
}
}
if
(
isset
(
$this
->
options
[
'update'
]))
{
$cmd
[
'update'
]
=
is_pipeline
(
$this
->
options
[
'update'
])
?
$this
->
options
[
'update'
]
:
(
object
)
$this
->
options
[
'update'
];
}
if
(
isset
(
$this
->
options
[
'arrayFilters'
]))
{
$cmd
[
'arrayFilters'
]
=
$this
->
options
[
'arrayFilters'
];
}
...
...
src/Operation/FindOneAndUpdate.php
View file @
2628c098
...
...
@@ -25,6 +25,7 @@ use function is_array;
use
function
is_integer
;
use
function
is_object
;
use
function
MongoDB
\is_first_key_operator
;
use
function
MongoDB
\is_pipeline
;
/**
* Operation for updating a document with the findAndModify command.
...
...
@@ -105,8 +106,8 @@ class FindOneAndUpdate implements Executable, Explainable
throw
InvalidArgumentException
::
invalidType
(
'$update'
,
$update
,
'array or object'
);
}
if
(
!
is_first_key_operator
(
$update
))
{
throw
new
InvalidArgumentException
(
'
First key in $update argument is not an update operator
'
);
if
(
!
is_first_key_operator
(
$update
)
&&
!
is_pipeline
(
$update
)
)
{
throw
new
InvalidArgumentException
(
'
Expected an update document with operator as first key or a pipeline
'
);
}
$options
+=
[
...
...
src/Operation/ReplaceOne.php
View file @
2628c098
...
...
@@ -25,6 +25,7 @@ use MongoDB\UpdateResult;
use
function
is_array
;
use
function
is_object
;
use
function
MongoDB
\is_first_key_operator
;
use
function
MongoDB
\is_pipeline
;
/**
* Operation for replacing a single document with the update command.
...
...
@@ -79,6 +80,10 @@ class ReplaceOne implements Executable
throw
new
InvalidArgumentException
(
'First key in $replacement argument is an update operator'
);
}
if
(
is_pipeline
(
$replacement
))
{
throw
new
InvalidArgumentException
(
'$replacement argument is a pipeline'
);
}
$this
->
update
=
new
Update
(
$databaseName
,
$collectionName
,
...
...
src/Operation/Update.php
View file @
2628c098
...
...
@@ -29,6 +29,7 @@ use function is_array;
use
function
is_bool
;
use
function
is_object
;
use
function
MongoDB
\is_first_key_operator
;
use
function
MongoDB
\is_pipeline
;
use
function
MongoDB
\server_supports_feature
;
/**
...
...
@@ -126,7 +127,7 @@ class Update implements Executable, Explainable
throw
InvalidArgumentException
::
invalidType
(
'"multi" option'
,
$options
[
'multi'
],
'boolean'
);
}
if
(
$options
[
'multi'
]
&&
!
is_first_key_operator
(
$update
))
{
if
(
$options
[
'multi'
]
&&
!
is_first_key_operator
(
$update
)
&&
!
is_pipeline
(
$update
)
)
{
throw
new
InvalidArgumentException
(
'"multi" option cannot be true if $update is a replacement document'
);
}
...
...
src/Operation/UpdateMany.php
View file @
2628c098
...
...
@@ -25,6 +25,7 @@ use MongoDB\UpdateResult;
use
function
is_array
;
use
function
is_object
;
use
function
MongoDB
\is_first_key_operator
;
use
function
MongoDB
\is_pipeline
;
/**
* Operation for updating multiple documents with the update command.
...
...
@@ -81,8 +82,8 @@ class UpdateMany implements Executable, Explainable
throw
InvalidArgumentException
::
invalidType
(
'$update'
,
$update
,
'array or object'
);
}
if
(
!
is_first_key_operator
(
$update
))
{
throw
new
InvalidArgumentException
(
'
First key in $update argument is not an update operator
'
);
if
(
!
is_first_key_operator
(
$update
)
&&
!
is_pipeline
(
$update
)
)
{
throw
new
InvalidArgumentException
(
'
Expected an update document with operator as first key or a pipeline
'
);
}
$this
->
update
=
new
Update
(
...
...
src/Operation/UpdateOne.php
View file @
2628c098
...
...
@@ -25,6 +25,7 @@ use MongoDB\UpdateResult;
use
function
is_array
;
use
function
is_object
;
use
function
MongoDB
\is_first_key_operator
;
use
function
MongoDB
\is_pipeline
;
/**
* Operation for updating a single document with the update command.
...
...
@@ -81,8 +82,8 @@ class UpdateOne implements Executable, Explainable
throw
InvalidArgumentException
::
invalidType
(
'$update'
,
$update
,
'array or object'
);
}
if
(
!
is_first_key_operator
(
$update
))
{
throw
new
InvalidArgumentException
(
'
First key in $update argument is not an update operator
'
);
if
(
!
is_first_key_operator
(
$update
)
&&
!
is_pipeline
(
$update
)
)
{
throw
new
InvalidArgumentException
(
'
Expected an update document with operator as first key or a pipeline
'
);
}
$this
->
update
=
new
Update
(
...
...
src/functions.php
View file @
2628c098
...
...
@@ -119,6 +119,47 @@ function is_first_key_operator($document)
return
isset
(
$firstKey
[
0
])
&&
$firstKey
[
0
]
===
'$'
;
}
/**
* Returns whether an update specification is a valid aggregation pipeline.
*
* @internal
* @param mixed $pipeline
* @return boolean
*/
function
is_pipeline
(
$pipeline
)
{
if
(
!
is_array
(
$pipeline
))
{
return
false
;
}
if
(
$pipeline
===
[])
{
return
false
;
}
$expectedKey
=
0
;
foreach
(
$pipeline
as
$key
=>
$stage
)
{
if
(
!
is_array
(
$stage
)
&&
!
is_object
(
$stage
))
{
return
false
;
}
if
(
$expectedKey
!==
$key
)
{
return
false
;
}
$expectedKey
++
;
$stage
=
(
array
)
$stage
;
reset
(
$stage
);
$key
=
key
(
$stage
);
if
(
!
isset
(
$key
[
0
])
||
$key
[
0
]
!==
'$'
)
{
return
false
;
}
}
return
true
;
}
/**
* Returns whether we are currently in a transaction.
*
...
...
tests/FunctionsTest.php
View file @
2628c098
...
...
@@ -10,6 +10,7 @@ use function MongoDB\create_field_path_type_map;
use
function
MongoDB
\generate_index_name
;
use
function
MongoDB
\is_first_key_operator
;
use
function
MongoDB
\is_mapreduce_output_inline
;
use
function
MongoDB
\is_pipeline
;
/**
* Unit tests for utility functions.
...
...
@@ -224,4 +225,33 @@ class FunctionsTest extends TestCase
],
];
}
/**
* @dataProvider providePipelines
*/
public
function
testIsPipeline
(
$expected
,
$pipeline
)
{
$this
->
assertSame
(
$expected
,
is_pipeline
(
$pipeline
));
}
public
function
providePipelines
()
{
return
[
'Not an array'
=>
[
false
,
(
object
)
[]],
'Empty array'
=>
[
false
,
[]],
'Non-sequential indexes in array'
=>
[
false
,
[
1
=>
[
'$group'
=>
[]]]],
'Update document instead of pipeline'
=>
[
false
,
[
'$set'
=>
[
'foo'
=>
'bar'
]]],
'Invalid pipeline stage'
=>
[
false
,
[[
'group'
=>
[]]]],
'Update with DbRef'
=>
[
false
,
[
'x'
=>
[
'$ref'
=>
'foo'
,
'$id'
=>
'bar'
]]],
'Valid pipeline'
=>
[
true
,
[
[
'$match'
=>
[
'foo'
=>
'bar'
]],
[
'$group'
=>
[
'_id'
=>
1
]],
],
],
'False positive with DbRef in numeric field'
=>
[
true
,
[
'0'
=>
[
'$ref'
=>
'foo'
,
'$id'
=>
'bar'
]]],
'DbRef in numeric field as object'
=>
[
false
,
(
object
)
[
'0'
=>
[
'$ref'
=>
'foo'
,
'$id'
=>
'bar'
]]],
];
}
}
tests/Operation/FindOneAndUpdateTest.php
View file @
2628c098
...
...
@@ -25,10 +25,10 @@ class FindOneAndUpdateTest extends TestCase
new
FindOneAndUpdate
(
$this
->
getDatabaseName
(),
$this
->
getCollectionName
(),
[],
$update
);
}
public
function
testConstructorUpdateArgumentRequiresOperators
()
public
function
testConstructorUpdateArgumentRequiresOperators
OrPipeline
()
{
$this
->
expectException
(
InvalidArgumentException
::
class
);
$this
->
expectExceptionMessage
(
'
First key in $update argument is not an update operator
'
);
$this
->
expectExceptionMessage
(
'
Expected an update document with operator as first key or a pipeline
'
);
new
FindOneAndUpdate
(
$this
->
getDatabaseName
(),
$this
->
getCollectionName
(),
[],
[]);
}
...
...
tests/Operation/UpdateManyTest.php
View file @
2628c098
...
...
@@ -41,7 +41,7 @@ class UpdateManyTest extends TestCase
public
function
testConstructorUpdateArgumentRequiresOperators
(
$replacement
)
{
$this
->
expectException
(
InvalidArgumentException
::
class
);
$this
->
expectExceptionMessage
(
'
First key in $update argument is not an update operator
'
);
$this
->
expectExceptionMessage
(
'
Expected an update document with operator as first key or a pipeline
'
);
new
UpdateMany
(
$this
->
getDatabaseName
(),
$this
->
getCollectionName
(),
[
'x'
=>
1
],
$replacement
);
}
...
...
tests/Operation/UpdateOneTest.php
View file @
2628c098
...
...
@@ -41,7 +41,7 @@ class UpdateOneTest extends TestCase
public
function
testConstructorUpdateArgumentRequiresOperators
(
$replacement
)
{
$this
->
expectException
(
InvalidArgumentException
::
class
);
$this
->
expectExceptionMessage
(
'
First key in $update argument is not an update operator
'
);
$this
->
expectExceptionMessage
(
'
Expected an update document with operator as first key or a pipeline
'
);
new
UpdateOne
(
$this
->
getDatabaseName
(),
$this
->
getCollectionName
(),
[
'x'
=>
1
],
$replacement
);
}
...
...
tests/SpecTests/CrudSpecTest.php
View file @
2628c098
...
...
@@ -14,15 +14,6 @@ use function glob;
*/
class
CrudSpecTest
extends
FunctionalTestCase
{
/* These should all pass before the driver can be considered compatible with
* MongoDB 4.2. */
private
static
$incompleteTests
=
[
'bulkWrite-arrayFilters: BulkWrite with arrayFilters'
=>
'Fails due to command assertions'
,
'updateWithPipelines: UpdateOne using pipelines'
=>
'PHPLIB-418'
,
'updateWithPipelines: UpdateMany using pipelines'
=>
'PHPLIB-418'
,
'updateWithPipelines: FindOneAndUpdate using pipelines'
=>
'PHPLIB-418'
,
];
/**
* Assert that the expected and actual command documents match.
*
...
...
@@ -48,10 +39,6 @@ class CrudSpecTest extends FunctionalTestCase
*/
public
function
testCrud
(
stdClass
$test
,
array
$runOn
=
null
,
array
$data
,
$databaseName
=
null
,
$collectionName
=
null
)
{
if
(
isset
(
self
::
$incompleteTests
[
$this
->
dataDescription
()]))
{
$this
->
markTestIncomplete
(
self
::
$incompleteTests
[
$this
->
dataDescription
()]);
}
if
(
isset
(
$runOn
))
{
$this
->
checkServerRequirements
(
$runOn
);
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment