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
9ccfae84
Commit
9ccfae84
authored
Jun 26, 2018
by
Jeremy Mikola
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
PHPLIB-351: Cluster and DB-level change streams and startAtOperationTime
parent
0f848cbd
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
308 additions
and
31 deletions
+308
-31
Client.php
src/Client.php
+38
-2
Database.php
src/Database.php
+32
-0
Watch.php
src/Operation/Watch.php
+125
-29
WatchFunctionalTest.php
tests/Operation/WatchFunctionalTest.php
+95
-0
WatchTest.php
tests/Operation/WatchTest.php
+18
-0
No files found.
src/Client.php
View file @
9ccfae84
...
...
@@ -29,6 +29,7 @@ use MongoDB\Exception\UnsupportedException;
use
MongoDB\Model\DatabaseInfoIterator
;
use
MongoDB\Operation\DropDatabase
;
use
MongoDB\Operation\ListDatabases
;
use
MongoDB\Operation\Watch
;
class
Client
{
...
...
@@ -37,9 +38,12 @@ class Client
'document'
=>
'MongoDB\Model\BSONDocument'
,
'root'
=>
'MongoDB\Model\BSONDocument'
,
];
private
static
$wireVersionForReadConcern
=
4
;
private
static
$wireVersionForWritableCommandWriteConcern
=
5
;
private
$manager
;
private
$readConcern
;
private
$readPreference
;
private
$uri
;
private
$typeMap
;
private
$writeConcern
;
...
...
@@ -81,6 +85,8 @@ class Client
unset
(
$driverOptions
[
'typeMap'
]);
$this
->
manager
=
new
Manager
(
$uri
,
$uriOptions
,
$driverOptions
);
$this
->
readConcern
=
$this
->
manager
->
getReadConcern
();
$this
->
readPreference
=
$this
->
manager
->
getReadPreference
();
$this
->
writeConcern
=
$this
->
manager
->
getWriteConcern
();
}
...
...
@@ -173,7 +179,7 @@ class Client
*/
public
function
getReadConcern
()
{
return
$this
->
manager
->
getReadConcern
()
;
return
$this
->
readConcern
;
}
/**
...
...
@@ -183,7 +189,7 @@ class Client
*/
public
function
getReadPreference
()
{
return
$this
->
manager
->
getReadPreference
()
;
return
$this
->
readPreference
;
}
/**
...
...
@@ -268,4 +274,34 @@ class Client
{
return
$this
->
manager
->
startSession
(
$options
);
}
/**
* Create a change stream for watching changes to the cluster.
*
* @see Watch::__construct() for supported options
* @param array $pipeline List of pipeline operations
* @param array $options Command options
* @return ChangeStream
* @throws InvalidArgumentException for parameter/option parsing errors
*/
public
function
watch
(
array
$pipeline
=
[],
array
$options
=
[])
{
if
(
!
isset
(
$options
[
'readPreference'
]))
{
$options
[
'readPreference'
]
=
$this
->
readPreference
;
}
$server
=
$this
->
manager
->
selectServer
(
$options
[
'readPreference'
]);
if
(
!
isset
(
$options
[
'readConcern'
])
&&
\MongoDB\server_supports_feature
(
$server
,
self
::
$wireVersionForReadConcern
))
{
$options
[
'readConcern'
]
=
$this
->
readConcern
;
}
if
(
!
isset
(
$options
[
'typeMap'
]))
{
$options
[
'typeMap'
]
=
$this
->
typeMap
;
}
$operation
=
new
Watch
(
$this
->
manager
,
null
,
null
,
$pipeline
,
$options
);
return
$operation
->
execute
(
$server
);
}
}
src/Database.php
View file @
9ccfae84
...
...
@@ -34,6 +34,7 @@ use MongoDB\Operation\DropCollection;
use
MongoDB\Operation\DropDatabase
;
use
MongoDB\Operation\ListCollections
;
use
MongoDB\Operation\ModifyCollection
;
use
MongoDB\Operation\Watch
;
class
Database
{
...
...
@@ -42,6 +43,7 @@ class Database
'document'
=>
'MongoDB\Model\BSONDocument'
,
'root'
=>
'MongoDB\Model\BSONDocument'
,
];
private
static
$wireVersionForReadConcern
=
4
;
private
static
$wireVersionForWritableCommandWriteConcern
=
5
;
private
$databaseName
;
...
...
@@ -409,6 +411,36 @@ class Database
return
new
Bucket
(
$this
->
manager
,
$this
->
databaseName
,
$options
);
}
/**
* Create a change stream for watching changes to the database.
*
* @see Watch::__construct() for supported options
* @param array $pipeline List of pipeline operations
* @param array $options Command options
* @return ChangeStream
* @throws InvalidArgumentException for parameter/option parsing errors
*/
public
function
watch
(
array
$pipeline
=
[],
array
$options
=
[])
{
if
(
!
isset
(
$options
[
'readPreference'
]))
{
$options
[
'readPreference'
]
=
$this
->
readPreference
;
}
$server
=
$this
->
manager
->
selectServer
(
$options
[
'readPreference'
]);
if
(
!
isset
(
$options
[
'readConcern'
])
&&
\MongoDB\server_supports_feature
(
$server
,
self
::
$wireVersionForReadConcern
))
{
$options
[
'readConcern'
]
=
$this
->
readConcern
;
}
if
(
!
isset
(
$options
[
'typeMap'
]))
{
$options
[
'typeMap'
]
=
$this
->
typeMap
;
}
$operation
=
new
Watch
(
$this
->
manager
,
$this
->
databaseName
,
null
,
$pipeline
,
$options
);
return
$operation
->
execute
(
$server
);
}
/**
* Get a clone of this database with different options.
*
...
...
src/Operation/Watch.php
View file @
9ccfae84
This diff is collapsed.
Click to expand it.
tests/Operation/WatchFunctionalTest.php
View file @
9ccfae84
...
...
@@ -3,6 +3,7 @@
namespace
MongoDB\Tests\Operation
;
use
MongoDB\ChangeStream
;
use
MongoDB\BSON\TimestampInterface
;
use
MongoDB\Driver\Manager
;
use
MongoDB\Driver\ReadPreference
;
use
MongoDB\Driver\Server
;
...
...
@@ -130,6 +131,100 @@ class WatchFunctionalTest extends FunctionalTestCase
$this
->
assertSame
(
$expectedCommands
,
$commands
);
}
public
function
testResumeBeforeReceivingAnyResultsIncludesStartAtOperationTime
()
{
$operation
=
new
Watch
(
$this
->
manager
,
$this
->
getDatabaseName
(),
$this
->
getCollectionName
(),
[],
$this
->
defaultOptions
);
$operationTime
=
null
;
$events
=
[];
(
new
CommandObserver
)
->
observe
(
function
()
use
(
$operation
,
&
$changeStream
)
{
$changeStream
=
$operation
->
execute
(
$this
->
getPrimaryServer
());
},
function
(
array
$event
)
use
(
&
$events
)
{
$events
[]
=
$event
;
}
);
$this
->
assertCount
(
1
,
$events
);
$this
->
assertSame
(
'aggregate'
,
$events
[
0
][
'started'
]
->
getCommandName
());
$operationTime
=
$events
[
0
][
'succeeded'
]
->
getReply
()
->
operationTime
;
$this
->
assertInstanceOf
(
TimestampInterface
::
class
,
$operationTime
);
$this
->
assertNull
(
$changeStream
->
current
());
$this
->
killChangeStreamCursor
(
$changeStream
);
$events
=
[];
(
new
CommandObserver
)
->
observe
(
function
()
use
(
$changeStream
)
{
$changeStream
->
rewind
();
},
function
(
array
$event
)
use
(
&
$events
)
{
$events
[]
=
$event
;
}
);
$this
->
assertCount
(
4
,
$events
);
$this
->
assertSame
(
'getMore'
,
$events
[
0
][
'started'
]
->
getCommandName
());
$this
->
arrayHasKey
(
'failed'
,
$events
[
0
]);
$this
->
assertSame
(
'aggregate'
,
$events
[
1
][
'started'
]
->
getCommandName
());
$this
->
assertStartAtOperationTime
(
$operationTime
,
$events
[
1
][
'started'
]
->
getCommand
());
$this
->
arrayHasKey
(
'succeeded'
,
$events
[
1
]);
// Original cursor is freed immediately after the change stream resumes
$this
->
assertSame
(
'killCursors'
,
$events
[
2
][
'started'
]
->
getCommandName
());
$this
->
arrayHasKey
(
'succeeded'
,
$events
[
2
]);
$this
->
assertSame
(
'getMore'
,
$events
[
3
][
'started'
]
->
getCommandName
());
$this
->
arrayHasKey
(
'succeeded'
,
$events
[
3
]);
$this
->
assertNull
(
$changeStream
->
current
());
$this
->
killChangeStreamCursor
(
$changeStream
);
$events
=
[];
(
new
CommandObserver
)
->
observe
(
function
()
use
(
$changeStream
)
{
$changeStream
->
next
();
},
function
(
array
$event
)
use
(
&
$events
)
{
$events
[]
=
$event
;
}
);
$this
->
assertCount
(
4
,
$events
);
$this
->
assertSame
(
'getMore'
,
$events
[
0
][
'started'
]
->
getCommandName
());
$this
->
arrayHasKey
(
'failed'
,
$events
[
0
]);
$this
->
assertSame
(
'aggregate'
,
$events
[
1
][
'started'
]
->
getCommandName
());
$this
->
assertStartAtOperationTime
(
$operationTime
,
$events
[
1
][
'started'
]
->
getCommand
());
$this
->
arrayHasKey
(
'succeeded'
,
$events
[
1
]);
// Original cursor is freed immediately after the change stream resumes
$this
->
assertSame
(
'killCursors'
,
$events
[
2
][
'started'
]
->
getCommandName
());
$this
->
arrayHasKey
(
'succeeded'
,
$events
[
2
]);
$this
->
assertSame
(
'getMore'
,
$events
[
3
][
'started'
]
->
getCommandName
());
$this
->
arrayHasKey
(
'succeeded'
,
$events
[
3
]);
$this
->
assertNull
(
$changeStream
->
current
());
}
private
function
assertStartAtOperationTime
(
TimestampInterface
$expectedOperationTime
,
stdClass
$command
)
{
$this
->
assertObjectHasAttribute
(
'pipeline'
,
$command
);
$this
->
assertInternalType
(
'array'
,
$command
->
pipeline
);
$this
->
assertArrayHasKey
(
0
,
$command
->
pipeline
);
$this
->
assertObjectHasAttribute
(
'$changeStream'
,
$command
->
pipeline
[
0
]);
$this
->
assertObjectHasAttribute
(
'startAtOperationTime'
,
$command
->
pipeline
[
0
]
->
{
'$changeStream'
});
$this
->
assertEquals
(
$expectedOperationTime
,
$command
->
pipeline
[
0
]
->
{
'$changeStream'
}
->
startAtOperationTime
);
}
public
function
testRewindResumesAfterConnectionException
()
{
/* In order to trigger a dropped connection, we'll use a new client with
...
...
tests/Operation/WatchTest.php
View file @
9ccfae84
...
...
@@ -4,6 +4,7 @@ namespace MongoDB\Tests\Operation;
use
MongoDB\Exception\InvalidArgumentException
;
use
MongoDB\Operation\Watch
;
use
stdClass
;
/**
* Although these are unit tests, we extend FunctionalTestCase because Watch is
...
...
@@ -11,6 +12,14 @@ use MongoDB\Operation\Watch;
*/
class
WatchTest
extends
FunctionalTestCase
{
public
function
testConstructorCollectionNameShouldBeNullIfDatabaseNameIsNull
()
{
$this
->
expectException
(
InvalidArgumentException
::
class
);
$this
->
expectExceptionMessage
(
'$collectionName should also be null if $databaseName is null'
);
new
Watch
(
$this
->
manager
,
null
,
'foo'
,
[]);
}
public
function
testConstructorPipelineArgumentMustBeAList
()
{
$this
->
expectException
(
InvalidArgumentException
::
class
);
...
...
@@ -67,10 +76,19 @@ class WatchTest extends FunctionalTestCase
$options
[][]
=
[
'session'
=>
$value
];
}
foreach
(
$this
->
getInvalidTimestampValues
()
as
$value
)
{
$options
[][]
=
[
'startAtOperationTime'
=>
$value
];
}
foreach
(
$this
->
getInvalidArrayValues
()
as
$value
)
{
$options
[][]
=
[
'typeMap'
=>
$value
];
}
return
$options
;
}
private
function
getInvalidTimestampValues
()
{
return
[
123
,
3.14
,
'foo'
,
true
,
[],
new
stdClass
];
}
}
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