Merge pull request #7559 from silverstripe/pulls/3/auto-index-sort

NEW Add sort columns to DB index automatically
This commit is contained in:
Loz Calver 2017-12-06 16:13:48 +00:00 committed by GitHub
commit aac828a6ee
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 100 additions and 2 deletions

View File

@ -50,6 +50,9 @@ In order to use more database specific or complex index notations, we also suppo
); );
} }
As of 3.7.0 `default_sort` fields will automatically become database indexes as this provides significant performance
benefits.
## API Documentation ## API Documentation
* [api:DataObject] * [api:DataObject]

View File

@ -348,8 +348,8 @@ class ArrayList extends ViewableData implements SS_List, SS_Filterable, SS_Sorta
/** /**
* Parses a specified column into a sort field and direction * Parses a specified column into a sort field and direction
* *
* @param type $column String to parse containing the column name * @param string $column String to parse containing the column name
* @param type $direction Optional Additional argument which may contain the direction * @param string $direction Optional Additional argument which may contain the direction
* @return array Sort specification in the form array("Column", SORT_ASC). * @return array Sort specification in the form array("Column", SORT_ASC).
*/ */
protected function parseSortColumn($column, $direction = null) { protected function parseSortColumn($column, $direction = null) {

View File

@ -3387,6 +3387,7 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
public function databaseIndexes() { public function databaseIndexes() {
$has_one = $this->uninherited('has_one',true); $has_one = $this->uninherited('has_one',true);
$classIndexes = $this->uninherited('indexes',true); $classIndexes = $this->uninherited('indexes',true);
$sort = $this->uninherited('default_sort',true);
//$fileIndexes = $this->uninherited('fileIndexes', true); //$fileIndexes = $this->uninherited('fileIndexes', true);
$indexes = array(); $indexes = array();
@ -3403,6 +3404,27 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
} }
} }
if ($sort && is_string($sort)) {
$sort = preg_split('/,(?![^()]*+\\))/', $sort);
foreach ($sort as $value) {
try {
list ($table, $column) = $this->parseSortColumn(trim($value));
$table = trim($table, '"');
$column = trim($column, '"');
if ($table && strtolower($table) !== strtolower($this->class)) {
continue;
}
if ($this->hasOwnTableDatabaseField($column) && !array_key_exists($column, $indexes)) {
$indexes[$column] = true;
}
} catch (InvalidArgumentException $e) { }
}
}
if(get_parent_class($this) == "DataObject") { if(get_parent_class($this) == "DataObject") {
$indexes['ClassName'] = true; $indexes['ClassName'] = true;
} }
@ -3410,6 +3432,25 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
return $indexes; return $indexes;
} }
/**
* Parses a specified column into a sort field and direction
*
* @param string $column String to parse containing the column name
* @return array Resolved table and column.
*/
protected function parseSortColumn($column) {
// Parse column specification, considering possible ansi sql quoting
// Note that table prefix is allowed, but discarded
if(preg_match('/^("?(?<table>[^"\s]+)"?\\.)?"?(?<column>[^"\s]+)"?(\s+(?<direction>((asc)|(desc))(ending)?))?$/i', $column, $match)) {
$table = $match['table'];
$column = $match['column'];
} else {
throw new InvalidArgumentException("Invalid sort() column");
}
return array($table, $column);
}
/** /**
* Check the database schema and update it as necessary. * Check the database schema and update it as necessary.
* *

View File

@ -172,6 +172,51 @@ class DataObjectSchemaGenerationTest extends SapphireTest {
$item1->delete(); $item1->delete();
$item2->delete(); $item2->delete();
} }
public function testSortFieldBecomeIndexes()
{
$object = new DataObjectSchemaGenerationTest_Sorted();
$indexes = $object->databaseIndexes();
$this->assertArrayHasKey('Sort', $indexes);
$this->assertTrue($indexes['Sort']);
Config::inst()->update('DataObjectSchemaGenerationTest_Sorted', 'default_sort', 'Sort ASC');
$indexes = $object->databaseIndexes();
$this->assertArrayHasKey('Sort', $indexes);
$this->assertTrue($indexes['Sort']);
Config::inst()->update('DataObjectSchemaGenerationTest_Sorted', 'default_sort', 'Sort DESC');
$indexes = $object->databaseIndexes();
$this->assertArrayHasKey('Sort', $indexes);
$this->assertTrue($indexes['Sort']);
Config::inst()->update('DataObjectSchemaGenerationTest_Sorted', 'default_sort', '"Sort" DESC');
$indexes = $object->databaseIndexes();
$this->assertArrayHasKey('Sort', $indexes);
$this->assertTrue($indexes['Sort']);
Config::inst()->update('DataObjectSchemaGenerationTest_Sorted', 'default_sort', '"DataObjectSchemaGenerationTest_Sorted"."Sort" ASC');
$indexes = $object->databaseIndexes();
$this->assertArrayHasKey('Sort', $indexes);
$this->assertTrue($indexes['Sort']);
Config::inst()->update('DataObjectSchemaGenerationTest_Sorted', 'default_sort', '"Sort" DESC, "Title" ASC');
$indexes = $object->databaseIndexes();
$this->assertArrayHasKey('Sort', $indexes);
$this->assertTrue($indexes['Sort']);
$this->assertArrayHasKey('Title', $indexes);
$this->assertTrue($indexes['Title']);
// make sure that specific indexes aren't overwritten
Config::inst()->update('DataObjectSchemaGenerationTest_Sorted', 'indexes', array(
'Sort' => 'unique',
));
$indexes = $object->databaseIndexes();
$this->assertArrayHasKey('Sort', $indexes);
$this->assertEquals('unique', $indexes['Sort']);
}
} }
class DataObjectSchemaGenerationTest_DO extends DataObject implements TestOnly { class DataObjectSchemaGenerationTest_DO extends DataObject implements TestOnly {
@ -212,3 +257,12 @@ class DataObjectSchemaGenerationTest_IndexDO extends DataObjectSchemaGenerationT
'SearchFields' => 'fulltext ("Title","Content")' 'SearchFields' => 'fulltext ("Title","Content")'
); );
} }
class DataObjectSchemaGenerationTest_Sorted extends DataObject implements TestOnly {
private static $db = array(
'Title' => 'Varchar',
'Sort' => 'Int',
);
private static $default_sort = "Sort";
}