From 8d8106d721e2fb827ee29a83a61533d461c7f514 Mon Sep 17 00:00:00 2001 From: Ross Singer Date: Fri, 7 Sep 2018 09:40:24 -0400 Subject: [PATCH] Provide option to return a cursor for table row results (#129) * Give option to return a cursor rather than array * Give option to pass in custom cursor * Get the verbiage correct: we're manipulating the documents * Expose $options parameter on Driver->getTableRows() * Need to abstract out getConfigInstance() for testing downstream * Add the same behavior to the constructor * Add tests * consistent uri --- src/IDriver.php | 12 +++- src/mongo/Driver.class.php | 19 ++++++- src/mongo/delegates/Tables.class.php | 69 ++++++++++++++++------- src/mongo/documents/Tables.php | 36 ++++++++++++ test/unit/mongo/MongoTripodTablesTest.php | 66 ++++++++++++++++++++++ 5 files changed, 176 insertions(+), 26 deletions(-) create mode 100644 src/mongo/documents/Tables.php diff --git a/src/IDriver.php b/src/IDriver.php index a0b5c32d..1873aa4a 100644 --- a/src/IDriver.php +++ b/src/IDriver.php @@ -82,9 +82,17 @@ public function select($filter,$fields,$sortBy=null,$limit=null,$context=null); * @param array $sortBy * @param int $offset * @param int $limit + * @param array $options * @return array */ - public function getTableRows($tableType,$filter=array(),$sortBy=array(),$offset=0,$limit=10); + public function getTableRows( + $tableType, + array $filter = [], + array $sortBy = [], + $offset = 0, + $limit = 10, + array $options = [] + ); /** * todo: work out what this does @@ -181,4 +189,4 @@ public function removeInertLocks($transaction_id, $reason); /* END Deprecated methods that will be removed in 1.x.x */ -} \ No newline at end of file +} diff --git a/src/mongo/Driver.class.php b/src/mongo/Driver.class.php index e249d985..51844151 100755 --- a/src/mongo/Driver.class.php +++ b/src/mongo/Driver.class.php @@ -199,9 +199,22 @@ public function getViews(Array $filter, $viewType) * @param int $limit * @return array */ - public function getTableRows($tableType, $filter = array(), $sortBy = array(), $offset = 0, $limit = 10) - { - return $this->getTripodTables()->getTableRows($tableType,$filter,$sortBy,$offset,$limit); + public function getTableRows( + $tableType, + array $filter = [], + array $sortBy = [], + $offset = 0, + $limit = 10, + array $options = [] + ) { + return $this->getTripodTables()->getTableRows( + $tableType, + $filter, + $sortBy, + $offset, + $limit, + $options + ); } /** diff --git a/src/mongo/delegates/Tables.class.php b/src/mongo/delegates/Tables.class.php index 40b81945..a850da80 100644 --- a/src/mongo/delegates/Tables.class.php +++ b/src/mongo/delegates/Tables.class.php @@ -233,45 +233,72 @@ public function getOperationType() * @param array $sortBy * @param int $offset * @param int $limit + * @param array $options Table query options * @return array */ - public function getTableRows($tableSpecId,$filter=[],$sortBy=[],$offset=0,$limit=10) - { + public function getTableRows( + $tableSpecId, + array $filter = [], + array $sortBy = [], + $offset = 0, + $limit = 10, + array $options = [] + ) { $t = new \Tripod\Timer(); $t->start(); - $filter["_id." . _ID_TYPE] = $tableSpecId; + $options = array_merge( + [ + 'returnCursor' => false, + 'includeCount' => true, + 'documentType' => '\Tripod\Mongo\Documents\Tables' + ], + $options + ); - $collection = $this->config->getCollectionForTable($this->storeName, $tableSpecId, $this->readPreference); + $filter['_id.' . _ID_TYPE] = $tableSpecId; + + $collection = $this->getConfigInstance()->getCollectionForTable( + $this->storeName, + $tableSpecId, + $this->readPreference + ); $findOptions = []; if (!empty($limit)) { - $findOptions['skip'] = (int) $offset; - $findOptions['limit'] = (int) $limit; + $findOptions['skip'] = (int) $offset; + $findOptions['limit'] = (int) $limit; } if (isset($sortBy)) { $findOptions['sort'] = $sortBy; } + $results = $collection->find($filter, $findOptions); - $rows = []; - foreach ($results as $doc) - { - if (array_key_exists(_IMPACT_INDEX,$doc['value'])) unset($doc['value'][_IMPACT_INDEX]); // remove impact index from client - $rows[] = $doc['value']; + if ($options['includeCount']) { + $count = $collection->count($filter); + } else { + $count = -1; } - $t->stop(); - $this->timingLog(MONGO_TABLE_ROWS, array('duration'=>$t->result(), 'query'=>$filter, 'collection'=>TABLE_ROWS_COLLECTION)); - $this->getStat()->timer(MONGO_TABLE_ROWS.".$tableSpecId",$t->result()); - return array( - "head"=>array( - "count" => $collection->count($filter), - "offset"=>$offset, - "limit"=>$limit - ), - "results"=>$rows); + $results->setTypeMap(['root' => $options['documentType'], 'document' => 'array', 'array' => 'array']); + + $t->stop(); + $this->timingLog( + MONGO_TABLE_ROWS, + ['duration' => $t->result(), 'query' => $filter, 'collection' => TABLE_ROWS_COLLECTION] + ); + $this->getStat()->timer(MONGO_TABLE_ROWS . ".$tableSpecId", $t->result()); + + return [ + 'head' => [ + 'count' => $count, + 'offset' => $offset, + 'limit' => $limit + ], + 'results' => $options['returnCursor'] ? $results : $results->toArray() + ]; } /** diff --git a/src/mongo/documents/Tables.php b/src/mongo/documents/Tables.php new file mode 100644 index 00000000..7de6e7e4 --- /dev/null +++ b/src/mongo/documents/Tables.php @@ -0,0 +1,36 @@ +toTableRow($input)); + } + /** + * Sets the array value to the modeled table row value + * + * @param array $data DB document array + * @return void + */ + public function bsonUnserialize(array $data) + { + $this->exchangeArray($this->toTableRow($data)); + } + + /** + * Models the table row from the source data + * + * @param array $doc Database document + * @return array + */ + protected function toTableRow(array $doc) + { + $result = isset($doc['value']) ? $doc['value'] : []; + if (isset($result[_IMPACT_INDEX])) { + unset($result[_IMPACT_INDEX]); + } + return $result; + } +} diff --git a/test/unit/mongo/MongoTripodTablesTest.php b/test/unit/mongo/MongoTripodTablesTest.php index c184309a..3ecd4e93 100644 --- a/test/unit/mongo/MongoTripodTablesTest.php +++ b/test/unit/mongo/MongoTripodTablesTest.php @@ -1839,4 +1839,70 @@ public function testDeleteTableRowsByTableIdWithTimestamp() $this->assertEquals(11, $tables->deleteTableRowsByTableId('t_source_count', $timestamp)); } + + public function testTablesDocuments() + { + $dbDoc = [ + '_id' => [ + 'r' => 'http://talis.com/modules/xmen-004', + 'c' => 'tenantContexts:DefaultGraph', + 'type' => 't_report_hierarchy' + ], + '_cts' => new \MongoDB\BSON\UTCDateTime(1535454036), + 'value' => [ + '_id' => [ + 'r' => 'http://talis.com/modules/xmen-004', + 'c' => 'tenantContexts:DefaultGraph' + ], + '_impactIndex' => [ + [ 'r' => 'http://talis.com/modules/xmen-004', 'c' => 'tenantContexts:DefaultGraph' ], + [ 'r' => 'http://talis.com/schools/xmen-001', 'c' => 'tenantContexts:DefaultGraph' ] + ], + 'code' => 'XMEN-004', + 'nodeUrl' => 'http://talis.com/modules/xmen-004', + 'name' => 'Psychology: Living with The Voices', + 'description' => 'Professor Deadpool will attempt to give you the ability to embrace your mental disorder and use it to your advantage. Whether you suffer from Schizophrenia, Dissociative Identity Disorder or plain old Comic Awareness, Wade Wilson has probably suffered through it himself. And while Deadpool can\'t solve your problem, he can teach you how to make it one of your most marketable qualities.', + 'parentCode' => 'XMEN-001', + 'parentNodeUrl' => 'http://talis.com/schools/xmen-001', + 'listCount' => 0, + 'type' => 'Module', + 'hasLinkedLists' => 'false' + ] + ]; + $doc = new \Tripod\Mongo\Documents\Tables(); + $this->assertInstanceOf('MongoDB\Model\BSONDocument', $doc); + $this->assertEquals([], $doc->getArrayCopy()); + $doc = new \Tripod\Mongo\Documents\Tables($dbDoc); + $this->assertEquals('XMEN-004', $doc['code']); + $this->assertEquals('http://talis.com/modules/xmen-004', $doc['_id']['r']); + $this->assertArrayNotHasKey('_cts', $doc); + $this->assertArrayNotHasKey('_impactIndex', $doc); + $this->assertArrayNotHasKey('type', $doc['_id']); + } + + public function testGetTableRowsNoCount() + { + $this->tripodTables->generateTableRows('t_resource'); + + $tableRows = $this->tripodTables->getTableRows('t_resource', [], [], 0, 1, ['includeCount' => false]); + + $this->assertCount(1, $tableRows['results']); + $this->assertEquals(-1, $tableRows['head']['count']); + } + + public function testGetTableRowsReturnCursor() + { + $this->tripodTables->generateTableRows('t_resource'); + + $tableRows = $this->tripodTables->getTableRows('t_resource', [], [], 0, 1, ['returnCursor' => true]); + + $this->assertInstanceOf('\MongoDB\Driver\Cursor', $tableRows['results']); + $count = 0; + foreach ($tableRows['results'] as $result) { + $this->assertInstanceOf('\Tripod\Mongo\Documents\Tables', $result); + $count++; + } + $this->assertEquals(1, $count); + $this->assertGreaterThan(1, $tableRows['head']['count']); + } }