Skip to content

Commit 370b5a2

Browse files
PHPLIB-869: Support viewOn and pipeline options in createCollection helper (#935)
1 parent 75eae8e commit 370b5a2

File tree

5 files changed

+80
-4
lines changed

5 files changed

+80
-4
lines changed

docs/includes/apiargs-MongoDBDatabase-method-createCollection-option.yaml

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,20 @@ source:
145145
file: apiargs-common-option.yaml
146146
ref: maxTimeMS
147147
---
148+
arg_name: option
149+
name: pipeline
150+
type: array
151+
description: |
152+
An array that consists of the aggregation pipeline stage(s), which will be
153+
applied to the collection or view specified by ``viewOn``. See the
154+
:manual:`create </reference/command/create>` command documentation for more
155+
information.
156+
157+
.. versionadded:: 1.13
158+
interface: phpmethod
159+
operation: ~
160+
optional: true
161+
---
148162
source:
149163
file: apiargs-common-option.yaml
150164
ref: session
@@ -295,6 +309,23 @@ interface: phpmethod
295309
operation: ~
296310
optional: true
297311
---
312+
arg_name: option
313+
name: viewOn
314+
type: string
315+
description: |
316+
The name of the source collection or view from which to create the view.
317+
318+
.. note::
319+
320+
The name is not the full namespace of the collection or view (i.e. it does
321+
not include the database name). Views must be created in the same databases
322+
as the source collection or view.
323+
324+
.. versionadded:: 1.13
325+
interface: phpmethod
326+
operation: ~
327+
optional: true
328+
---
298329
source:
299330
file: apiargs-MongoDBDatabase-common-option.yaml
300331
ref: writeConcern

src/Operation/CreateCollection.php

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
use function is_integer;
3131
use function is_object;
3232
use function is_string;
33+
use function sprintf;
3334
use function trigger_error;
3435

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

181+
if (isset($options['pipeline']) && ! is_array($options['pipeline'])) {
182+
throw InvalidArgumentException::invalidType('"pipeline" option', $options['pipeline'], 'array');
183+
}
184+
173185
if (isset($options['session']) && ! $options['session'] instanceof Session) {
174186
throw InvalidArgumentException::invalidType('"session" option', $options['session'], Session::class);
175187
}
@@ -202,6 +214,10 @@ public function __construct($databaseName, $collectionName, array $options = [])
202214
throw InvalidArgumentException::invalidType('"validator" option', $options['validator'], 'array or object');
203215
}
204216

217+
if (isset($options['viewOn']) && ! is_string($options['viewOn'])) {
218+
throw InvalidArgumentException::invalidType('"viewOn" option', $options['viewOn'], 'string');
219+
}
220+
205221
if (isset($options['writeConcern']) && ! $options['writeConcern'] instanceof WriteConcern) {
206222
throw InvalidArgumentException::invalidType('"writeConcern" option', $options['writeConcern'], WriteConcern::class);
207223
}
@@ -214,6 +230,22 @@ public function __construct($databaseName, $collectionName, array $options = [])
214230
trigger_error('The "autoIndexId" option is deprecated and will be removed in a future release', E_USER_DEPRECATED);
215231
}
216232

233+
if (isset($options['pipeline'])) {
234+
$expectedIndex = 0;
235+
236+
foreach ($options['pipeline'] as $i => $operation) {
237+
if ($i !== $expectedIndex) {
238+
throw new InvalidArgumentException(sprintf('The "pipeline" option is not a list (unexpected index: "%s")', $i));
239+
}
240+
241+
if (! is_array($operation) && ! is_object($operation)) {
242+
throw InvalidArgumentException::invalidType(sprintf('$options["pipeline"][%d]', $i), $operation, 'array or object');
243+
}
244+
245+
$expectedIndex += 1;
246+
}
247+
}
248+
217249
$this->databaseName = (string) $databaseName;
218250
$this->collectionName = (string) $collectionName;
219251
$this->options = $options;
@@ -247,7 +279,7 @@ private function createCommand()
247279
{
248280
$cmd = ['create' => $this->collectionName];
249281

250-
foreach (['autoIndexId', 'capped', 'expireAfterSeconds', 'flags', 'max', 'maxTimeMS', 'size', 'validationAction', 'validationLevel'] as $option) {
282+
foreach (['autoIndexId', 'capped', 'expireAfterSeconds', 'flags', 'max', 'maxTimeMS', 'pipeline', 'size', 'validationAction', 'validationLevel', 'viewOn'] as $option) {
251283
if (isset($this->options[$option])) {
252284
$cmd[$option] = $this->options[$option];
253285
}

tests/Operation/CreateCollectionTest.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,13 @@
77

88
class CreateCollectionTest extends TestCase
99
{
10+
public function testConstructorPipelineOptionMustBeAList(): void
11+
{
12+
$this->expectException(InvalidArgumentException::class);
13+
$this->expectExceptionMessage('The "pipeline" option is not a list (unexpected index: "1")');
14+
new CreateCollection($this->getDatabaseName(), $this->getCollectionName(), ['pipeline' => [1 => ['$match' => ['x' => 1]]]]);
15+
}
16+
1017
/**
1118
* @dataProvider provideInvalidConstructorOptions
1219
*/
@@ -60,6 +67,10 @@ public function provideInvalidConstructorOptions()
6067
$options[][] = ['maxTimeMS' => $value];
6168
}
6269

70+
foreach ($this->getInvalidArrayValues() as $value) {
71+
$options[][] = ['pipeline' => $value];
72+
}
73+
6374
foreach ($this->getInvalidSessionValues() as $value) {
6475
$options[][] = ['session' => $value];
6576
}
@@ -92,6 +103,10 @@ public function provideInvalidConstructorOptions()
92103
$options[][] = ['validator' => $value];
93104
}
94105

106+
foreach ($this->getInvalidStringValues() as $value) {
107+
$options[][] = ['viewOn' => $value];
108+
}
109+
95110
foreach ($this->getInvalidWriteConcernValues() as $value) {
96111
$options[][] = ['writeConcern' => $value];
97112
}

tests/UnifiedSpecTests/UnifiedSpecTest.php

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,8 +111,6 @@ class UnifiedSpecTest extends FunctionalTestCase
111111
'crud/aggregate: aggregate with comment sets comment on getMore' => 'Not yet implemented (PHPC-2049, PHPLIB-749)',
112112
'crud/aggregate: aggregate with a document comment' => 'Not yet implemented (PHPC-2049, PHPLIB-749)',
113113
'crud/aggregate: aggregate with a document comment - pre 4.4' => 'Not yet implemented (PHPC-2049, PHPLIB-749)',
114-
// CreateCollection "viewOn" and "pipeline" options are not yet implemented
115-
'crud/estimatedDocumentCount: estimatedDocumentCount works correctly on views' => 'Not yet implemented (PHPLIB-869)',
116114
];
117115

118116
/** @var UnifiedTestRunner */

tests/UnifiedSpecTests/Util.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ final class Util
6262
Database::class => [
6363
'aggregate' => ['pipeline', 'session', 'useCursor', 'allowDiskUse', 'batchSize', 'bypassDocumentValidation', 'collation', 'comment', 'explain', 'hint', 'let', 'maxAwaitTimeMS', 'maxTimeMS'],
6464
'createChangeStream' => ['pipeline', 'session', 'fullDocument', 'resumeAfter', 'startAfter', 'startAtOperationTime', 'batchSize', 'collation', 'maxAwaitTimeMS'],
65-
'createCollection' => ['collection', 'session', 'autoIndexId', 'capped', 'changeStreamPreAndPostImages', 'clusteredIndex', 'collation', 'expireAfterSeconds', 'flags', 'indexOptionDefaults', 'max', 'maxTimeMS', 'size', 'storageEngine', 'timeseries', 'validationAction', 'validationLevel', 'validator'],
65+
'createCollection' => ['collection', 'session', 'autoIndexId', 'capped', 'changeStreamPreAndPostImages', 'clusteredIndex', 'collation', 'expireAfterSeconds', 'flags', 'indexOptionDefaults', 'max', 'maxTimeMS', 'pipeline', 'size', 'storageEngine', 'timeseries', 'validationAction', 'validationLevel', 'validator', 'viewOn'],
6666
'dropCollection' => ['collection', 'session'],
6767
'listCollectionNames' => ['authorizedCollections', 'filter', 'maxTimeMS', 'session'],
6868
'listCollections' => ['authorizedCollections', 'filter', 'maxTimeMS', 'session'],

0 commit comments

Comments
 (0)