Skip to content

PHPLIB-869: Support viewOn and pipeline options in createCollection helper #935

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
Jun 6, 2022
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,20 @@ source:
file: apiargs-common-option.yaml
ref: maxTimeMS
---
arg_name: option
name: pipeline
type: array
description: |
An array that consists of the aggregation pipeline stage(s), which will be
applied to the collection or view specified by ``viewOn``. See the
:manual:`create </reference/command/create>` command documentation for more
information.

.. versionadded:: 1.13
interface: phpmethod
operation: ~
optional: true
---
source:
file: apiargs-common-option.yaml
ref: session
Expand Down Expand Up @@ -295,6 +309,23 @@ interface: phpmethod
operation: ~
optional: true
---
arg_name: option
name: viewOn
type: string
description: |
The name of the source collection or view from which to create the view.

.. note::

The name is not the full namespace of the collection or view (i.e. it does
not include the database name). Views must be created in the same databases
as the source collection or view.

.. versionadded:: 1.13
interface: phpmethod
operation: ~
optional: true
---
source:
file: apiargs-MongoDBDatabase-common-option.yaml
ref: writeConcern
Expand Down
34 changes: 33 additions & 1 deletion src/Operation/CreateCollection.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
use function is_integer;
use function is_object;
use function is_string;
use function sprintf;
use function trigger_error;

use const E_USER_DEPRECATED;
Expand Down Expand Up @@ -100,6 +101,10 @@ class CreateCollection implements Executable
* * maxTimeMS (integer): The maximum amount of time to allow the query to
* run.
*
* * pipeline (array): An array that consists of the aggregation pipeline
* stage(s), which will be applied to the collection or view specified by
* viewOn.
*
* * session (MongoDB\Driver\Session): Client session.
*
* * size (integer): The maximum number of bytes for a capped collection.
Expand All @@ -119,6 +124,9 @@ class CreateCollection implements Executable
*
* * validator (document): Validation rules or expressions.
*
* * viewOn (string): The name of the source collection or view from which
* to create the view.
*
* * writeConcern (MongoDB\Driver\WriteConcern): Write concern.
*
* @see https://source.wiredtiger.com/2.4.1/struct_w_t___s_e_s_s_i_o_n.html#a358ca4141d59c345f401c58501276bbb
Expand Down Expand Up @@ -170,6 +178,10 @@ public function __construct($databaseName, $collectionName, array $options = [])
throw InvalidArgumentException::invalidType('"maxTimeMS" option', $options['maxTimeMS'], 'integer');
}

if (isset($options['pipeline']) && ! is_array($options['pipeline'])) {
throw InvalidArgumentException::invalidType('"pipeline" option', $options['pipeline'], 'array');
}

if (isset($options['session']) && ! $options['session'] instanceof Session) {
throw InvalidArgumentException::invalidType('"session" option', $options['session'], Session::class);
}
Expand Down Expand Up @@ -202,6 +214,10 @@ public function __construct($databaseName, $collectionName, array $options = [])
throw InvalidArgumentException::invalidType('"validator" option', $options['validator'], 'array or object');
}

if (isset($options['viewOn']) && ! is_string($options['viewOn'])) {
throw InvalidArgumentException::invalidType('"viewOn" option', $options['viewOn'], 'string');
}

if (isset($options['writeConcern']) && ! $options['writeConcern'] instanceof WriteConcern) {
throw InvalidArgumentException::invalidType('"writeConcern" option', $options['writeConcern'], WriteConcern::class);
}
Expand All @@ -214,6 +230,22 @@ public function __construct($databaseName, $collectionName, array $options = [])
trigger_error('The "autoIndexId" option is deprecated and will be removed in a future release', E_USER_DEPRECATED);
}

if (isset($options['pipeline'])) {
$expectedIndex = 0;

foreach ($options['pipeline'] as $i => $operation) {
if ($i !== $expectedIndex) {
throw new InvalidArgumentException(sprintf('The "pipeline" option is not a list (unexpected index: "%s")', $i));
}

if (! is_array($operation) && ! is_object($operation)) {
throw InvalidArgumentException::invalidType(sprintf('$options["pipeline"][%d]', $i), $operation, 'array or object');
}

$expectedIndex += 1;
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was copied from Aggregate.php, but the exception messages were not updated to reflect that pipeline is an option and not a constructor parameter. Please apply the suggestions above.

I also created PHPLIB-881 to refactor this to share common code with other instances of pipeline validation.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code updated in #1078


$this->databaseName = (string) $databaseName;
$this->collectionName = (string) $collectionName;
$this->options = $options;
Expand Down Expand Up @@ -247,7 +279,7 @@ private function createCommand()
{
$cmd = ['create' => $this->collectionName];

foreach (['autoIndexId', 'capped', 'expireAfterSeconds', 'flags', 'max', 'maxTimeMS', 'size', 'validationAction', 'validationLevel'] as $option) {
foreach (['autoIndexId', 'capped', 'expireAfterSeconds', 'flags', 'max', 'maxTimeMS', 'pipeline', 'size', 'validationAction', 'validationLevel', 'viewOn'] as $option) {
if (isset($this->options[$option])) {
$cmd[$option] = $this->options[$option];
}
Expand Down
15 changes: 15 additions & 0 deletions tests/Operation/CreateCollectionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,13 @@

class CreateCollectionTest extends TestCase
{
public function testConstructorPipelineArgumentMustBeAList(): void
{
$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage('The "pipeline" option is not a list (unexpected index: "1")');
new CreateCollection($this->getDatabaseName(), $this->getCollectionName(), ['pipeline' => [1 => ['$match' => ['x' => 1]]]]);
}

/**
* @dataProvider provideInvalidConstructorOptions
*/
Expand Down Expand Up @@ -60,6 +67,10 @@ public function provideInvalidConstructorOptions()
$options[][] = ['maxTimeMS' => $value];
}

foreach ($this->getInvalidArrayValues() as $value) {
$options[][] = ['pipeline' => $value];
}

foreach ($this->getInvalidSessionValues() as $value) {
$options[][] = ['session' => $value];
}
Expand Down Expand Up @@ -92,6 +103,10 @@ public function provideInvalidConstructorOptions()
$options[][] = ['validator' => $value];
}

foreach ($this->getInvalidStringValues() as $value) {
$options[][] = ['viewOn' => $value];
}

foreach ($this->getInvalidWriteConcernValues() as $value) {
$options[][] = ['writeConcern' => $value];
}
Expand Down
2 changes: 0 additions & 2 deletions tests/UnifiedSpecTests/UnifiedSpecTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -111,8 +111,6 @@ class UnifiedSpecTest extends FunctionalTestCase
'crud/aggregate: aggregate with comment sets comment on getMore' => 'Not yet implemented (PHPC-2049, PHPLIB-749)',
'crud/aggregate: aggregate with a document comment' => 'Not yet implemented (PHPC-2049, PHPLIB-749)',
'crud/aggregate: aggregate with a document comment - pre 4.4' => 'Not yet implemented (PHPC-2049, PHPLIB-749)',
// CreateCollection "viewOn" and "pipeline" options are not yet implemented
'crud/estimatedDocumentCount: estimatedDocumentCount works correctly on views' => 'Not yet implemented (PHPLIB-869)',
];

/** @var UnifiedTestRunner */
Expand Down
2 changes: 1 addition & 1 deletion tests/UnifiedSpecTests/Util.php
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ final class Util
Database::class => [
'aggregate' => ['pipeline', 'session', 'useCursor', 'allowDiskUse', 'batchSize', 'bypassDocumentValidation', 'collation', 'comment', 'explain', 'hint', 'let', 'maxAwaitTimeMS', 'maxTimeMS'],
'createChangeStream' => ['pipeline', 'session', 'fullDocument', 'resumeAfter', 'startAfter', 'startAtOperationTime', 'batchSize', 'collation', 'maxAwaitTimeMS'],
'createCollection' => ['collection', 'session', 'autoIndexId', 'capped', 'changeStreamPreAndPostImages', 'clusteredIndex', 'collation', 'expireAfterSeconds', 'flags', 'indexOptionDefaults', 'max', 'maxTimeMS', 'size', 'storageEngine', 'timeseries', 'validationAction', 'validationLevel', 'validator'],
'createCollection' => ['collection', 'session', 'autoIndexId', 'capped', 'changeStreamPreAndPostImages', 'clusteredIndex', 'collation', 'expireAfterSeconds', 'flags', 'indexOptionDefaults', 'max', 'maxTimeMS', 'pipeline', 'size', 'storageEngine', 'timeseries', 'validationAction', 'validationLevel', 'validator', 'viewOn'],
'dropCollection' => ['collection', 'session'],
'listCollectionNames' => ['authorizedCollections', 'filter', 'maxTimeMS', 'session'],
'listCollections' => ['authorizedCollections', 'filter', 'maxTimeMS', 'session'],
Expand Down