diff --git a/src/mongo/Config.class.php b/src/mongo/Config.class.php index 0a6f570..d56e5dd 100644 --- a/src/mongo/Config.class.php +++ b/src/mongo/Config.class.php @@ -247,11 +247,24 @@ protected function loadConfig(array $config) // Ensure indexes are legal if (array_key_exists("indexes", $podConfig)) { $this->indexes[$storeName][$podName] = []; + foreach ($podConfig["indexes"] as $indexName => $indexFields) { + + $this->indexes[$storeName][$podName][$indexName] = $indexFields; + + $indexKeys = array_keys($indexFields); + if (is_numeric($indexKeys[0])) { + // New format config - two arrays, where second is index options (e.g. unique=>true, sparse=>true) + $cardinalityIndexFields = $indexFields[0]; + } else { + // Standard format config - single array + $cardinalityIndexFields = $indexFields; + } + // check no more than 1 indexField is an array to ensure Mongo will be able to create compound indexes - if (count($indexFields) > 1) { + if (count($cardinalityIndexFields) > 1) { $fieldsThatAreArrays = 0; - foreach ($indexFields as $field => $fieldVal) { + foreach ($cardinalityIndexFields as $field => $fieldVal) { $cardinalityField = str_replace('.value', '', $field); if (!array_key_exists($cardinalityField, $this->cardinality[$storeName][$podName]) || $this->cardinality[$storeName][$podName][$cardinalityField] != 1) { @@ -261,10 +274,7 @@ protected function loadConfig(array $config) throw new \Tripod\Exceptions\ConfigException("Compound index $indexName has more than one field with cardinality > 1 - mongo will not be able to build this index"); } } - } // @codeCoverageIgnoreStart - // @codeCoverageIgnoreEnd - - $this->indexes[$storeName][$podName][$indexName] = $indexFields; + } } } } diff --git a/src/mongo/util/IndexUtils.class.php b/src/mongo/util/IndexUtils.class.php index 295d4bc..30c8018 100644 --- a/src/mongo/util/IndexUtils.class.php +++ b/src/mongo/util/IndexUtils.class.php @@ -29,6 +29,7 @@ public function ensureIndexes($reindex=false,$storeName=null,$background=true) { continue; } + if ($reindex) { $collection = $config->getCollectionForCBD($storeName, $collectionName); @@ -37,32 +38,37 @@ public function ensureIndexes($reindex=false,$storeName=null,$background=true) $reindexedCollections[] = $collection->getNamespace(); } } + foreach ($indexes as $indexName=>$fields) { $indexName = substr($indexName,0,127); // ensure max 128 chars - if (is_numeric($indexName)) + + $indexOptions = [ + 'background'=>$background + ]; + + if (!is_numeric($indexName)) { - // no name - $config->getCollectionForCBD($storeName, $collectionName) - ->createIndex( - $fields, - array( - "background"=>$background - ) - ); + // Named index vs. unnamed index + $indexOptions['name'] = $indexName; } - else - { - $config->getCollectionForCBD($storeName, $collectionName) - ->createIndex( - $fields, - array( - 'name'=>$indexName, - "background"=>$background - ) - ); + + $indexKeys = array_keys($fields); + if (is_numeric($indexKeys[0])) { + // New format config - two arrays, where second is index options (e.g. unique=>true, sparse=>true) + $indexFields = $fields[0]; + $indexOptions = array_merge($indexOptions, $fields[1]); + } else { + // Standard format config - single array + $indexFields = $fields; } - } + + $config->getCollectionForCBD($storeName, $collectionName) + ->createIndex( + $indexFields, + $indexOptions + ); + } } // Index views diff --git a/test/unit/mongo/IndexUtilsTest.php b/test/unit/mongo/IndexUtilsTest.php index 03e1b9e..34f8bf3 100644 --- a/test/unit/mongo/IndexUtilsTest.php +++ b/test/unit/mongo/IndexUtilsTest.php @@ -21,6 +21,26 @@ public function testCBDCollectionIndexesAreCreated() $indexUtils->ensureIndexes(false, 'tripod_php_testing', true); } + public function testCBDCollectionIndexesAreCreatedWithIndexOptions() + { + $config = $this->createMockConfig(); + $collection = $this->createMockCollection(); + $indexUtils = $this->createMockIndexUtils($config); + + $indexOptions = ['unique' => true]; + + $this->setConfigForCBDIndexes($config, $indexOptions); + $this->dropIndexesShouldNeverBeCalled($collection); + $this->oneCustomAndThreeInternalTripodCBDIndexesShouldBeCreated($collection, true, $indexOptions); + $this->getCollectionForCBDShouldBeCalled_n_Times(4, $config, $collection); + $this->getCollectionForViewShouldNeverBeCalled($config); + $this->getCollectionForTableShouldNeverBeCalled($config); + $this->getCollectionForSearchDocumentShouldNeverBeCalled($config); + + $indexUtils->ensureIndexes(false, 'tripod_php_testing', true); + } + + public function testCBDCollectionIndexesAreCreatedInForeground() { $config = $this->createMockConfig(); @@ -38,6 +58,25 @@ public function testCBDCollectionIndexesAreCreatedInForeground() $indexUtils->ensureIndexes(false, 'tripod_php_testing', false); } + public function testCBDCollectionIndexesAreCreatedInForegroundWithIndexOptions() + { + $config = $this->createMockConfig(); + $collection = $this->createMockCollection(); + $indexUtils = $this->createMockIndexUtils($config); + + $indexOptions = ['unique' => true]; + + $this->setConfigForCBDIndexes($config, $indexOptions); + $this->dropIndexesShouldNeverBeCalled($collection); + $this->oneCustomAndThreeInternalTripodCBDIndexesShouldBeCreated($collection, false, $indexOptions); + $this->getCollectionForCBDShouldBeCalled_n_Times(4, $config, $collection); + $this->getCollectionForViewShouldNeverBeCalled($config); + $this->getCollectionForTableShouldNeverBeCalled($config); + $this->getCollectionForSearchDocumentShouldNeverBeCalled($config); + + $indexUtils->ensureIndexes(false, 'tripod_php_testing', false); + } + public function testCBDCollectionIndexesAreReindexed() { $config = $this->createMockConfig(); @@ -55,6 +94,25 @@ public function testCBDCollectionIndexesAreReindexed() $indexUtils->ensureIndexes(true, 'tripod_php_testing', true); } + public function testCBDCollectionIndexesAreReindexedWithIndexOptions() + { + $config = $this->createMockConfig(); + $collection = $this->createMockCollection(); + $indexUtils = $this->createMockIndexUtils($config); + + $indexOptions = ['unique' => true]; + + $this->setConfigForCBDIndexes($config, $indexOptions); + $this->dropIndexesShouldBeCalled($collection); + $this->oneCustomAndThreeInternalTripodCBDIndexesShouldBeCreated($collection, true, $indexOptions); + $this->getCollectionForCBDShouldBeCalled_n_Times(5, $config, $collection); + $this->getCollectionForViewShouldNeverBeCalled($config); + $this->getCollectionForTableShouldNeverBeCalled($config); + $this->getCollectionForSearchDocumentShouldNeverBeCalled($config); + + $indexUtils->ensureIndexes(true, 'tripod_php_testing', true); + } + public function testViewIndexesAreCreated() { $config = $this->createMockConfig(); @@ -407,7 +465,7 @@ protected function getCollectionForCBDShouldNeverBeCalled($mockConfig) * @param bool $background create indexes in the background * @return void */ - protected function oneCustomAndThreeInternalTripodCBDIndexesShouldBeCreated($mockCollection, $background = true) + protected function oneCustomAndThreeInternalTripodCBDIndexesShouldBeCreated($mockCollection, $background = true, array $indexOptions = []) { // create index is called 4 times, each time with a different set of // params that we know. @@ -416,7 +474,7 @@ protected function oneCustomAndThreeInternalTripodCBDIndexesShouldBeCreated($moc $mockCollection->expects($this->exactly(4)) ->method('createIndex') ->withConsecutive( - [['rdf:type.u' => 1], ['name' => 'rdf_type', 'background' => $background]], + [['rdf:type.u' => 1], array_merge(['name' => 'rdf_type', 'background' => $background], $indexOptions)], [[_ID_KEY => 1, _LOCKED_FOR_TRANS => 1], ['name' => '_lockedForTransIdx', 'background' => $background]], [[_ID_KEY => 1, _UPDATED_TS => 1], ['name' => '_updatedTsIdx', 'background' => $background]], [[_ID_KEY => 1, _CREATED_TS => 1], ['name' => '_createdTsIdx', 'background' => $background]] @@ -496,7 +554,7 @@ protected function threeInternalTripodSearchDocIndexesShouldBeCreated($mockColle * @param MockObject&\TripodTestConfig $mockConfig mock Config object * @return void */ - protected function setConfigForCBDIndexes($mockConfig) + protected function setConfigForCBDIndexes($mockConfig, array $indexOptions = []) { // minimal config to verify that $config = []; @@ -509,22 +567,34 @@ protected function setConfigForCBDIndexes($mockConfig) 'mongo' => ['type' => 'mongo', 'connection' => 'mongodb://localhost'], ]; $config['defaultContext'] = 'http://talisaspire.com/'; + $config['stores'] = [ 'tripod_php_testing' => [ 'type' => 'mongo', 'data_source' => 'mongo', 'pods' => [ - 'CBD_testing' => [ - 'indexes' => [ - 'rdf_type' => [ - 'rdf:type.u' => 1, - ], - ], - ], + 'CBD_testing' => [] ], ], ]; + if (empty($indexOptions)) { + $config['stores']['tripod_php_testing']['pods']['CBD_testing']['indexes'] = [ + 'rdf_type' => [ + 'rdf:type.u' => 1, + ], + ]; + } else { + $config['stores']['tripod_php_testing']['pods']['CBD_testing']['indexes'] = [ + 'rdf_type' => [ + [ + 'rdf:type.u' => 1, + ], + $indexOptions + ], + ]; + } + $config['transaction_log'] = [ 'database' => 'transactions', 'collection' => 'transaction_log',