Commit b480c525 authored by catch's avatar catch

Issue #2247379 by yched, alexpott, Berdir: Optimize config entity query conditions on ID

parent 62f4de68
......@@ -128,6 +128,8 @@ protected function loadRecords() {
// Search the conditions for restrictions on configuration object names.
$names = FALSE;
$id_condition = NULL;
$id_key = $this->entityType->getKey('id');
if ($this->condition->getConjunction() == 'AND') {
$lookup_keys = $this->entityType->getLookupKeys();
$conditions = $this->condition->conditions();
......@@ -135,7 +137,7 @@ protected function loadRecords() {
$operator = $condition['operator'] ?: (is_array($condition['value']) ? 'IN' : '=');
if (is_string($condition['field']) && ($operator == 'IN' || $operator == '=')) {
// Special case ID lookups.
if ($condition['field'] == $this->entityType->getKey('id')) {
if ($condition['field'] == $id_key) {
$ids = (array) $condition['value'];
$names = array_map(function ($id) use ($prefix) {
return $prefix . $id;
......@@ -154,6 +156,11 @@ protected function loadRecords() {
}
}
}
// Save the first ID condition that is not an 'IN' or '=' for narrowing
// down later.
elseif (!$id_condition && $condition['field'] == $id_key) {
$id_condition = $condition;
}
// We stop at the first restricting condition on name. In the case where
// there are additional restricting conditions, results will be
// eliminated when the conditions are checked on the loaded records.
......@@ -169,6 +176,41 @@ protected function loadRecords() {
if ($names === FALSE) {
$names = $this->configFactory->listAll($prefix);
}
// In case we have an ID condition, try to narrow down the list of config
// objects to load.
if ($id_condition && !empty($names)) {
$value = $id_condition['value'];
$filter = NULL;
switch ($id_condition['operator']) {
case '<>':
$filter = function ($name) use ($value, $prefix_length) {
$id = substr($name, $prefix_length);
return $id !== $value;
};
break;
case 'STARTS_WITH':
$filter = function ($name) use ($value, $prefix_length) {
$id = substr($name, $prefix_length);
return strpos($id, $value) === 0;
};
break;
case 'CONTAINS':
$filter = function ($name) use ($value, $prefix_length) {
$id = substr($name, $prefix_length);
return strpos($id, $value) !== FALSE;
};
break;
case 'ENDS_WITH':
$filter = function ($name) use ($value, $prefix_length) {
$id = substr($name, $prefix_length);
return strrpos($id, $value) === strlen($id) - strlen($value);
};
break;
}
if ($filter) {
$names = array_filter($names, $filter);
}
}
// Load the corresponding records.
$records = array();
......
......@@ -343,6 +343,62 @@ public function testConfigEntityQuery() {
$this->assertResults(array('1', '2', '3', '4', '5'));
}
/**
* Tests ID conditions.
*/
public function testStringIdConditions() {
// We need an entity with a non-numeric ID.
$entity = entity_create('config_query_test', array(
'label' => $this->randomMachineName(),
'id' => 'foo.bar',
));
$this->entities[] = $entity;
$entity->enforceIsNew();
$entity->save();
// Test 'STARTS_WITH' condition.
$this->queryResults = $this->factory->get('config_query_test')
->condition('id', 'foo.bar', 'STARTS_WITH')
->execute();
$this->assertResults(array('foo.bar'));
$this->queryResults = $this->factory->get('config_query_test')
->condition('id', 'f', 'STARTS_WITH')
->execute();
$this->assertResults(array('foo.bar'));
$this->queryResults = $this->factory->get('config_query_test')
->condition('id', 'miss', 'STARTS_WITH')
->execute();
$this->assertResults(array());
// Test 'CONTAINS' condition.
$this->queryResults = $this->factory->get('config_query_test')
->condition('id', 'foo.bar', 'CONTAINS')
->execute();
$this->assertResults(array('foo.bar'));
$this->queryResults = $this->factory->get('config_query_test')
->condition('id', 'oo.ba', 'CONTAINS')
->execute();
$this->assertResults(array('foo.bar'));
$this->queryResults = $this->factory->get('config_query_test')
->condition('id', 'miss', 'CONTAINS')
->execute();
$this->assertResults(array());
// Test 'ENDS_WITH' condition.
$this->queryResults = $this->factory->get('config_query_test')
->condition('id', 'foo.bar', 'ENDS_WITH')
->execute();
$this->assertResults(array('foo.bar'));
$this->queryResults = $this->factory->get('config_query_test')
->condition('id', 'r', 'ENDS_WITH')
->execute();
$this->assertResults(array('foo.bar'));
$this->queryResults = $this->factory->get('config_query_test')
->condition('id', 'miss', 'ENDS_WITH')
->execute();
$this->assertResults(array());
}
/**
* Tests count query.
*/
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment