From 38ca9305080cca91d5f4d231adb0e9429f78e886 Mon Sep 17 00:00:00 2001 From: dantleech Date: Tue, 2 Dec 2014 09:23:06 +0100 Subject: [PATCH] Allow sorting on numerical columns - New column "numerical_props" which is populated by numerical properies and which is used exlusively for ordering. --- .../Transport/DoctrineDBAL/Client.php | 141 ++++++++--- .../DoctrineDBAL/Query/QOMWalker.php | 50 ++-- .../DoctrineDBAL/RepositorySchema.php | 1 + .../Transport/DoctrineDBAL/ClientTest.php | 222 ++++++++++++++++-- .../DoctrineDBAL/Query/QOMWalkerTest.php | 47 +++- tests/bootstrap.php | 8 +- 6 files changed, 381 insertions(+), 88 deletions(-) diff --git a/src/Jackalope/Transport/DoctrineDBAL/Client.php b/src/Jackalope/Transport/DoctrineDBAL/Client.php index daeda26d..9b3429cc 100644 --- a/src/Jackalope/Transport/DoctrineDBAL/Client.php +++ b/src/Jackalope/Transport/DoctrineDBAL/Client.php @@ -207,6 +207,10 @@ public function __construct(FactoryInterface $factory, Connection $conn) private function registerSqliteFunctions(PDOConnection $sqliteConnection) { $sqliteConnection->sqliteCreateFunction('EXTRACTVALUE', function ($string, $expression) { + if (null === $string) { + return null; + } + $dom = new \DOMDocument('1.0', 'UTF-8'); $dom->loadXML($string); $xpath = new \DOMXPath($dom); @@ -571,10 +575,20 @@ public function copyNode($srcAbsPath, $dstAbsPath, $srcWorkspace = null) foreach ($stmt->fetchAll(\PDO::FETCH_ASSOC) as $row) { $newPath = str_replace($srcAbsPath, $dstAbsPath, $row['path']); - $dom = new \DOMDocument('1.0', 'UTF-8'); - $dom->loadXML($row['props']); + $stringDom = new \DOMDocument('1.0', 'UTF-8'); + $stringDom->loadXML($row['props']); + + $numericalDom = null; - $propsData = array('dom' => $dom); + if ($row['numerical_props']) { + $numericalDom = new \DOMDocument('1.0', 'UTF-8'); + $numericalDom->loadXML($row['numerical_props']); + } + + $propsData = array( + 'stringDom' => $stringDom, + 'numericalDom' => $numericalDom + ); // when copying a node, the copy is always a new node. set $isNewNode to true $newNodeId = $this->syncNode(null, $newPath, $row['type'], true, array(), $propsData); @@ -646,25 +660,27 @@ private function syncNode($uuid, $path, $type, $isNewNode, $props = array(), $pr $qb = $this->conn->createQueryBuilder(); - $qb->select(':identifier, :type, :path, :local_name, :namespace, :parent, :workspace_name, :props, :depth, COALESCE(MAX(n.sort_order), 0) + 1') + $qb->select(':identifier, :type, :path, :local_name, :namespace, :parent, :workspace_name, :props, :numerical_props, :depth, COALESCE(MAX(n.sort_order), 0) + 1') ->from('phpcr_nodes', 'n') ->where('n.parent = :parent_a'); $sql = $qb->getSql(); try { - $insert = "INSERT INTO phpcr_nodes (identifier, type, path, local_name, namespace, parent, workspace_name, props, depth, sort_order) " . $sql; - $this->conn->executeUpdate($insert, array( - 'identifier' => $uuid, - 'type' => $type, - 'path' => $path, - 'local_name' => $localName, - 'namespace' => $namespace, - 'parent' => PathHelper::getParentPath($path), + $insert = "INSERT INTO phpcr_nodes (identifier, type, path, local_name, namespace, parent, workspace_name, props, numerical_props, depth, sort_order) " . $sql; + + $this->conn->executeUpdate($insert, $data = array( + 'identifier' => $uuid, + 'type' => $type, + 'path' => $path, + 'local_name' => $localName, + 'namespace' => $namespace, + 'parent' => PathHelper::getParentPath($path), 'workspace_name' => $this->workspaceName, - 'props' => $propsData['dom']->saveXML(), - 'depth' => PathHelper::getPathDepth($path), - 'parent_a' => PathHelper::getParentPath($path), + 'props' => $propsData['stringDom']->saveXML(), + 'numerical_props' => $propsData['numericalDom'] ? $propsData['numericalDom']->saveXML() : null, + 'depth' => PathHelper::getPathDepth($path), + 'parent_a' => PathHelper::getParentPath($path), )); } catch(\Exception $e) { if ($e instanceof \PDOException || $e instanceof DBALException) { @@ -684,7 +700,13 @@ private function syncNode($uuid, $path, $type, $isNewNode, $props = array(), $pr if (!$nodeId) { throw new RepositoryException("nodeId for $path not found"); } - $this->conn->update('phpcr_nodes', array('props' => $propsData['dom']->saveXML()), array('id' => $nodeId)); + + $this->conn->update('phpcr_nodes', array( + 'props' => $propsData['stringDom']->saveXML(), + 'numerical_props' => $propsData['numericalDom'] ? $propsData['numericalDom']->saveXML() : null, + ), + array('id' => $nodeId) + ); } $this->nodeIdentifiers[$path] = $uuid; @@ -853,6 +875,7 @@ public static function xmlToProps($xml, ValueConverter $valueConverter, $filter } $values = array(); + $type = PropertyType::valueFromName($propertyNode->getAttribute('sv:type')); foreach ($propertyNode->childNodes as $valueNode) { switch ($type) { @@ -912,7 +935,11 @@ public static function xmlToProps($xml, ValueConverter $valueConverter, $filter * @param array $properties * @param boolean $inlineBinaries * - * @return array ('dom' => $dom, 'binaryData' => streams, 'references' => array('type' => INT, 'values' => array(UUIDs))) + * @return array ( + * 'stringDom' => $stringDom, + * 'numericalDom' => $numericalDom', + * 'binaryData' => streams, + * 'references' => array('type' => INT, 'values' => array(UUIDs))) */ private function propsToXML($properties, $inlineBinaries = false) { @@ -925,20 +952,16 @@ private function propsToXML($properties, $inlineBinaries = false) 'rep' => "internal", ); - $dom = new \DOMDocument('1.0', 'UTF-8'); - $rootNode = $dom->createElement('sv:node'); - foreach ($namespaces as $namespace => $uri) { - $rootNode->setAttribute('xmlns:' . $namespace, $uri); - } - $dom->appendChild($rootNode); + $doms = array( + 'stringDom' => array(), + 'numericalDom' => array(), + ); $binaryData = $references = array(); + foreach ($properties as $property) { - /* @var $property Property */ - $propertyNode = $dom->createElement('sv:property'); - $propertyNode->setAttribute('sv:name', $property->getName()); - $propertyNode->setAttribute('sv:type', PropertyType::nameFromValue($property->getType())); - $propertyNode->setAttribute('sv:multi-valued', $property->isMultiple() ? '1' : '0'); + + $targetDoms = array('stringDom'); switch ($property->getType()) { case PropertyType::WEAKREFERENCE: @@ -955,12 +978,14 @@ private function propsToXML($properties, $inlineBinaries = false) break; case PropertyType::DECIMAL: $values = $property->getDecimal(); + $targetDoms[] = 'numericalDom'; break; case PropertyType::BOOLEAN: $values = array_map('intval', (array) $property->getBoolean()); break; case PropertyType::LONG: $values = $property->getLong(); + $targetDoms[] = 'numericalDom'; break; case PropertyType::BINARY: if ($property->isNew() || $property->isModified()) { @@ -998,26 +1023,66 @@ private function propsToXML($properties, $inlineBinaries = false) break; case PropertyType::DOUBLE: $values = $property->getDouble(); + $targetDoms[] = 'numericalDom'; break; default: throw new RepositoryException('unknown type '.$property->getType()); } - $lengths = (array) $property->getLength(); - foreach ((array) $values as $key => $value) { - $element = $propertyNode->appendChild($dom->createElement('sv:value')); - $element->appendChild($dom->createTextNode($value)); - if (isset($lengths[$key])) { - $lengthAttribute = $dom->createAttribute('length'); - $lengthAttribute->value = $lengths[$key]; - $element->appendChild($lengthAttribute); + foreach ($targetDoms as $targetDom) { + $doms[$targetDom][] = array( + 'name' => $property->getName(), + 'type' => PropertyType::nameFromValue($property->getType()), + 'multiple' => $property->isMultiple(), + 'lengths' => (array) $property->getLength(), + 'values' => $values, + ); + } + } + + $ret = array( + 'stringDom' => null, + 'numericalDom' => null, + 'binaryData' => $binaryData, + 'references' => $references + ); + + foreach ($doms as $targetDom => $properties) { + + $dom = new \DOMDocument('1.0', 'UTF-8'); + $rootNode = $dom->createElement('sv:node'); + foreach ($namespaces as $namespace => $uri) { + $rootNode->setAttribute('xmlns:' . $namespace, $uri); + } + $dom->appendChild($rootNode); + + foreach ($properties as $property) { + + /* @var $property Property */ + $propertyNode = $dom->createElement('sv:property'); + $propertyNode->setAttribute('sv:name', $property['name']); + $propertyNode->setAttribute('sv:type', $property['type']); + $propertyNode->setAttribute('sv:multi-valued', $property['multiple'] ? '1' : '0'); + $lengths = (array) $property['lengths']; + foreach ((array) $property['values'] as $key => $value) { + $element = $propertyNode->appendChild($dom->createElement('sv:value')); + $element->appendChild($dom->createTextNode($value)); + if (isset($lengths[$key])) { + $lengthAttribute = $dom->createAttribute('length'); + $lengthAttribute->value = $lengths[$key]; + $element->appendChild($lengthAttribute); + } } + + $rootNode->appendChild($propertyNode); } - $rootNode->appendChild($propertyNode); + if (count($properties)) { + $ret[$targetDom] = $dom; + } } - return array('dom' => $dom, 'binaryData' => $binaryData, 'references' => $references); + return $ret; } /** diff --git a/src/Jackalope/Transport/DoctrineDBAL/Query/QOMWalker.php b/src/Jackalope/Transport/DoctrineDBAL/Query/QOMWalker.php index 0211405f..a49e9d13 100644 --- a/src/Jackalope/Transport/DoctrineDBAL/Query/QOMWalker.php +++ b/src/Jackalope/Transport/DoctrineDBAL/Query/QOMWalker.php @@ -743,7 +743,26 @@ public function walkOrdering(QOM\OrderingInterface $ordering) $direction = 'DESC'; } - return $this->walkOperand($ordering->getOperand()) . " " . $direction; + $sql = $this->walkOperand($ordering->getOperand()); + + if ($ordering->getOperand() instanceof QOM\PropertyValueInterface) { + $operand = $ordering->getOperand(); + $property = $ordering->getOperand()->getPropertyName(); + if ($property !== 'jcr:path' && $property !== 'jcr:uuid') { + $alias = $this->getTableAlias($operand->getSelectorName() . '.' . $property); + + $numericalSelector = $this->sqlXpathExtractValue($alias, $property, 'numerical_props'); + + $sql = sprintf('CAST(%s AS DECIMAL), %s', + $numericalSelector, + $sql + ); + } + } + + $sql .= ' ' .$direction; + + return $sql; } /** @@ -791,16 +810,16 @@ private function sqlXpathValueExists($alias, $property) * * @return string */ - private function sqlXpathExtractValue($alias, $property) + private function sqlXpathExtractValue($alias, $property, $column = 'props') { if ($this->platform instanceof MySqlPlatform) { - return "EXTRACTVALUE($alias.props, '//sv:property[@sv:name=\"" . $property . "\"]/sv:value[1]')"; + return "EXTRACTVALUE($alias.$column, '//sv:property[@sv:name=\"" . $property . "\"]/sv:value[1]')"; } if ($this->platform instanceof PostgreSqlPlatform) { - return "(xpath('//sv:property[@sv:name=\"" . $property . "\"]/sv:value[1]/text()', CAST($alias.props AS xml), ".$this->sqlXpathPostgreSQLNamespaces()."))[1]::text"; + return "(xpath('//sv:property[@sv:name=\"" . $property . "\"]/sv:value[1]/text()', CAST($alias.$column AS xml), ".$this->sqlXpathPostgreSQLNamespaces()."))[1]::text"; } if ($this->platform instanceof SqlitePlatform) { - return "EXTRACTVALUE($alias.props, '//sv:property[@sv:name=\"" . $property . "\"]/sv:value[1]')"; + return "EXTRACTVALUE($alias.$column, '//sv:property[@sv:name=\"" . $property . "\"]/sv:value[1]')"; } throw new NotImplementedException("Xpath evaluations cannot be executed with '" . $this->platform->getName() . "' yet."); @@ -868,27 +887,6 @@ private function sqlXpathPostgreSQLNamespaces() return "ARRAY[ARRAY['sv', 'http://www.jcp.org/jcr/sv/1.0']]"; } - /** - * Returns the SQL part to select the given property - * - * @param string $alias - * @param string $propertyName - * - * @return string - */ - private function sqlProperty($alias, $propertyName) - { - if ('jcr:uuid' === $propertyName) { - return "$alias.identifier"; - } - - if ('jcr:path' === $propertyName) { - return "$alias.path"; - } - - return $this->sqlXpathExtractValue($alias, $propertyName); - } - /** * @param QOM\SelectorInterface $source * @param string $alias diff --git a/src/Jackalope/Transport/DoctrineDBAL/RepositorySchema.php b/src/Jackalope/Transport/DoctrineDBAL/RepositorySchema.php index 5e826fb7..657cb753 100644 --- a/src/Jackalope/Transport/DoctrineDBAL/RepositorySchema.php +++ b/src/Jackalope/Transport/DoctrineDBAL/RepositorySchema.php @@ -92,6 +92,7 @@ protected function addNodesTable() $nodes->addColumn('identifier', 'string'); $nodes->addColumn('type', 'string'); $nodes->addColumn('props', 'text'); + $nodes->addColumn('numerical_props', 'text', array('notnull' => false)); $nodes->addColumn('depth', 'integer'); $nodes->addColumn('sort_order', 'integer', array('notnull' => false)); $nodes->setPrimaryKey(array('id')); diff --git a/tests/Jackalope/Transport/DoctrineDBAL/ClientTest.php b/tests/Jackalope/Transport/DoctrineDBAL/ClientTest.php index d8175bbe..952aeb4f 100644 --- a/tests/Jackalope/Transport/DoctrineDBAL/ClientTest.php +++ b/tests/Jackalope/Transport/DoctrineDBAL/ClientTest.php @@ -6,6 +6,7 @@ use Jackalope\Test\TestCase; use PHPCR\PropertyType; use PHPCR\Util\NodeHelper; +use PHPCR\Util\PathHelper; class ClientTest extends TestCase { @@ -26,22 +27,16 @@ class ClientTest extends TestCase public function setUp() { + static $initialized = false; parent::setUp(); $conn = $this->getConnection(); $options = array('disable_fks' => $conn->getDatabasePlatform() instanceof SqlitePlatform); $schema = new RepositorySchema($options, $conn); - // do not use reset as we want to ignore exceptions on drop - foreach ($schema->toDropSql($conn->getDatabasePlatform()) as $statement) { - try { - $conn->exec($statement); - } catch (\Exception $e) { - // ignore - } - } + $tables = $schema->getTables(); - foreach ($schema->toSql($conn->getDatabasePlatform()) as $statement) { - $conn->exec($statement); + foreach ($tables as $table) { + $conn->exec('DELETE FROM ' . $table->getName()); } $this->transport = new \Jackalope\Transport\DoctrineDBAL\Client(new \Jackalope\Factory(), $conn); @@ -305,19 +300,31 @@ public function testPropertyLengthAttribute() $this->session->save(); - $statement = $this->getConnection()->executeQuery('SELECT props FROM phpcr_nodes WHERE path = ?', array('/testLengthAttribute')); - $xml = $statement->fetchColumn(); + $statement = $this->getConnection()->executeQuery('SELECT props, numerical_props FROM phpcr_nodes WHERE path = ?', array('/testLengthAttribute')); + $row = $statement->fetch(\PDO::FETCH_ASSOC); + $props = $row['props']; + $decimalProps = $row['numerical_props']; - $this->assertNotEquals(false, $xml); + foreach ($data as $propertyName => $propertyInfo) { + $propertyElement = null; - $doc = new \DOMDocument('1.0', 'utf-8'); - $doc->loadXML($xml); + foreach (array($props, $decimalProps) as $propXml) { + if (null == $propXml) { + continue; + } - $xpath = new \DOMXPath($doc); - foreach ($data as $propertyName => $propertyInfo) { + $doc = new \DOMDocument('1.0', 'utf-8'); + $doc->loadXML($propXml); + + $xpath = new \DOMXPath($doc); + $propertyElement = $xpath->query(sprintf('sv:property[@sv:name="%s"]', $propertyName)); + + if ($propertyElement->length > 0) { + break; + } + } - $propertyElement = $xpath->query(sprintf('sv:property[@sv:name="%s"]', $propertyName)); - $this->assertEquals(1, $propertyElement->length); + $this->assertEquals(1, $propertyElement->length, 'Property ' . $propertyName . ' exists'); $values = $xpath->query('sv:value', $propertyElement->item(0)); @@ -388,4 +395,181 @@ public function testCaseInsensativeRename() $this->session->move('/topic', '/Topic'); $this->session->save(); } + + public function testStoreTypes() + { + $rootNode = $this->session->getRootNode(); + $node = $rootNode->addNode('testStoreTypes'); + + $data = array( + array('string_1', 'string_1', PropertyType::STRING), + array('string_2', 'string_1', PropertyType::STRING), + array('long_1', '10', PropertyType::LONG), + array('long_2', '20', PropertyType::LONG), + array('decimal_1', '10.0', PropertyType::DECIMAL), + array('decimal_2', '20.0', PropertyType::DECIMAL), + ); + + foreach ($data as $propertyData) { + $node->setProperty($propertyData[0], $propertyData[1], $propertyData[2]); + } + + $this->session->save(); + $this->session->refresh(false); + + foreach ($data as $propertyData) { + list($propName) = $propertyData; + $this->assertTrue($node->hasProperty($propName), 'Node has property "' . $propName .'"'); + } + } + + public function provideOrder() + { + return array( + array( + array( + 'one' => array( + 'value' => 'AAA', + ), + 'two' => array( + 'value' => 'BBB', + ), + 'three' => array( + 'value' => 'CCC', + ), + ), + 'value DESC', + array('three', 'two', 'one'), + ), + + // longs + array( + array( + 'one' => array( + 'value' => 30, + ), + 'two' => array( + 'value' => 20, + ), + 'three' => array( + 'value' => 10, + ), + ), + 'value', + array('three', 'two', 'one'), + ), + + // longs (ensure that values are not cast as strings) + array( + array( + 'one' => array( + 'value' => 10, + ), + 'two' => array( + 'value' => 100, + ), + 'three' => array( + 'value' => 20, + ), + ), + 'value', + array('one', 'three', 'two'), + ), + + // decimals + array( + array( + 'one' => array( + 'value' => 10.01, + ), + 'two' => array( + 'value' => 0.01, + ), + 'three' => array( + 'value' => 5.05, + ), + ), + 'value', + array('two', 'three', 'one'), + ), + + // mixed + array( + array( + 'one' => array( + 'title' => 'AAA', + 'value' => 10.01, + ), + 'two' => array( + 'title' => 'AAA', + 'value' => 0.01, + ), + 'three' => array( + 'title' => 'CCC', + 'value' => 5.05, + ), + 'four' => array( + 'title' => 'BBB', + 'value' => 5.05, + ), + ), + 'title, value ASC', + array('two', 'one', 'four', 'three'), + ), + ); + } + + /** + * @dataProvider provideOrder + */ + public function testOrder($nodes, $orderBy, $expectedOrder) + { + $rootNode = $this->session->getNode('/'); + + foreach ($nodes as $nodeName => $nodeProperties) { + $node = $rootNode->addNode($nodeName); + foreach ($nodeProperties as $name => $value) { + $node->setProperty($name, $value); + } + } + + $this->session->save(); + + $qm = $this->session->getWorkspace()->getQueryManager(); + $query = $qm->createQuery('SELECT * FROM [nt:unstructured] WHERE value IS NOT NULL ORDER BY ' . $orderBy, \PHPCR\Query\QueryInterface::JCR_SQL2); + $result = $query->execute(); + + $rows = $result->getRows(); + $this->assertGreaterThan(0, count($rows)); + + foreach ($rows as $index => $row) { + $path = $row->getNode()->getPath(); + $name = PathHelper::getNodeName($path); + + $expectedName = $expectedOrder[$index]; + $this->assertEquals($expectedName, $name); + } + } + + public function testCopy() + { + $rootNode = $this->session->getNode('/'); + $child1 = $rootNode->addNode('child1'); + $child1->setProperty('string', 'Hello'); + $child1->setProperty('number', 1234); + + $this->session->save(); + + $this->session->getWorkspace()->copy('/child1', '/child2'); + + $stmt = $this->conn->query("SELECT * FROM phpcr_nodes WHERE path = '/child1' OR path = '/child2'"); + $child1 = $stmt->fetch(); + $child2 = $stmt->fetch(); + + $this->assertNotNull($child1); + $this->assertNotNull($child2); + + $this->assertEquals($child1['props'], $child2['props']); + $this->assertEquals($child1['numerical_props'], $child2['numerical_props']); + } } diff --git a/tests/Jackalope/Transport/DoctrineDBAL/Query/QOMWalkerTest.php b/tests/Jackalope/Transport/DoctrineDBAL/Query/QOMWalkerTest.php index 8a946a93..8f52b27a 100644 --- a/tests/Jackalope/Transport/DoctrineDBAL/Query/QOMWalkerTest.php +++ b/tests/Jackalope/Transport/DoctrineDBAL/Query/QOMWalkerTest.php @@ -40,7 +40,7 @@ public function setUp() ; $this->factory = new QueryObjectModelFactory(new Factory); $this->walker = new QOMWalker($this->nodeTypeManager, $conn); - $this->defaultColumns = 'n0.id AS n0_id, n0.path AS n0_path, n0.parent AS n0_parent, n0.local_name AS n0_local_name, n0.namespace AS n0_namespace, n0.workspace_name AS n0_workspace_name, n0.identifier AS n0_identifier, n0.type AS n0_type, n0.props AS n0_props, n0.depth AS n0_depth, n0.sort_order AS n0_sort_order'; + $this->defaultColumns = 'n0.id AS n0_id, n0.path AS n0_path, n0.parent AS n0_parent, n0.local_name AS n0_local_name, n0.namespace AS n0_namespace, n0.workspace_name AS n0_workspace_name, n0.identifier AS n0_identifier, n0.type AS n0_type, n0.props AS n0_props, n0.numerical_props AS n0_numerical_props, n0.depth AS n0_depth, n0.sort_order AS n0_sort_order'; } public function testDefaultQuery() @@ -186,7 +186,7 @@ public function testQueryWithOperator($const, $op) $this->assertEquals(sprintf("SELECT %s FROM phpcr_nodes n0 WHERE n0.workspace_name = ? AND n0.type IN ('nt:unstructured') AND n0.path $op '/'", $this->defaultColumns), $sql); } - public function testQueryWithOrderings() + public function testQueryWithPathOrder() { $this->nodeTypeManager->expects($this->once())->method('getSubtypes')->will($this->returnValue( array() )); @@ -205,6 +205,49 @@ public function testQueryWithOrderings() ); } + public function testQueryWithOrderings() + { + $driver = $this->conn->getDriver()->getName(); + + $this->nodeTypeManager->expects($this->once())->method('getSubtypes')->will($this->returnValue( array() )); + + $query = $this->factory->createQuery( + $this->factory->selector('nt:unstructured', 'nt:unstructured'), + null, + array($this->factory->ascending($this->factory->propertyValue('nt:unstructured', "foobar"))), + array() + ); + + $res = $this->walker->walkQOMQuery($query); + + + switch ($driver) { + case 'pdo_pgsql': + $ordering = + "CAST((xpath('//sv:property[@sv:name=\"foobar\"]/sv:value[1]/text()', CAST(n0.numerical_props AS xml), ARRAY[ARRAY['sv', 'http://www.jcp.org/jcr/sv/1.0']]))[1]::text AS DECIMAL), " . + "(xpath('//sv:property[@sv:name=\"foobar\"]/sv:value[1]/text()', CAST(n0.props AS xml), ARRAY[ARRAY['sv', 'http://www.jcp.org/jcr/sv/1.0']]))[1]::text ASC"; + break; + default: + $ordering = + "CAST(EXTRACTVALUE(n0.numerical_props, '//sv:property[@sv:name=\"foobar\"]/sv:value[1]') AS DECIMAL), " . + "EXTRACTVALUE(n0.props, '//sv:property[@sv:name=\"foobar\"]/sv:value[1]') ASC"; + } + + + $this->assertEquals( + sprintf( + implode(' ', array( + "SELECT %s FROM phpcr_nodes n0 WHERE n0.workspace_name = ?", + "AND n0.type IN ('nt:unstructured')", + "ORDER BY", + $ordering + )), + $this->defaultColumns + ), + $res[2] + ); + } + public function testDescendantQuery() { $this->nodeTypeManager->expects($this->exactly(2))->method('getSubtypes')->will($this->returnValue( array() )); diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 30bad506..630d1d99 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -40,9 +40,11 @@ )); // recreate database schema -$options = array('disable_fks' => $dbConn->getDatabasePlatform() instanceof \Doctrine\DBAL\Platforms\SqlitePlatform); -$repositorySchema = new \Jackalope\Transport\DoctrineDBAL\RepositorySchema($options, $dbConn); -$repositorySchema->reset(); +if (!getenv('JACKALOPE_NO_TEST_DB_INIT')) { + $options = array('disable_fks' => $dbConn->getDatabasePlatform() instanceof \Doctrine\DBAL\Platforms\SqlitePlatform); + $repositorySchema = new \Jackalope\Transport\DoctrineDBAL\RepositorySchema($options, $dbConn); + $repositorySchema->reset(); +} // some constants define('SPEC_VERSION_DESC', 'jcr.specification.version');