MDL-64820 dml: add object preloading helpers

This commit is contained in:
Ryan Wyllie 2019-03-08 14:44:10 +08:00
parent f98553fc1b
commit a30570c555
2 changed files with 189 additions and 0 deletions

View File

@ -828,6 +828,65 @@ abstract class moodle_database {
return array($sql, $params);
}
/**
* Get the SELECT SQL to preload columns for the specified fieldlist and table alias.
*
* This function is intended to be used in combination with get_preload_columns_sql and extract_from_fields.
*
* @param array $fieldlist The list of fields from get_preload_columns
* @param string $tablealias The table alias used in the FROM/JOIN field
* @return string The SQL to use in the SELECT
*/
public function get_preload_columns_sql(array $fieldlist, string $tablealias) : string {
return implode(', ', array_map(function($fieldname, $alias) use ($tablealias) {
return "{$tablealias}.{$fieldname} AS {$alias}";
}, $fieldlist, array_keys($fieldlist)));
}
/**
* Extract fields from the specified data.
* The fields are removed from the original object.
*
* This function is intended to be used in combination with get_preload_columns and get_preload_columns_sql.
*
* @param array $fieldlist The list of fields from get_preload_columns
* @param \stdClass $data The data retrieved from the database with fields to be extracted
* @return string The SQL to use in the SELECT
*/
public function extract_fields_from_object(array $fieldlist, \stdClass $data) : \stdClass {
$newdata = (object) [];
foreach ($fieldlist as $alias => $fieldname) {
if (property_exists($data, $alias)) {
$newdata->$fieldname = $data->$alias;
unset($data->$alias);
} else {
debugging("Field '{$fieldname}' not found", DEBUG_DEVELOPER);
}
}
return $newdata;
}
/**
* Get the preload columns for the specified table and use the specified prefix in the column alias.
*
* This function is intended to be used in combination with get_preload_columns_sql and extract_from_fields.
*
* @param string $table
* @param string $prefix
* @return array The list of columns in a table. The array key is the column name with an applied prefix.
*/
public function get_preload_columns(string $table, string $prefix) : array {
global $DB;
$fields = [];
foreach (array_keys($this->get_columns($table)) as $fieldname) {
$fields["{$prefix}{$fieldname}"] = $fieldname;
}
return $fields;
}
/**
* Converts short table name {tablename} to the real prefixed table name in given sql.
* @param string $sql The sql to be operated on.

View File

@ -794,6 +794,136 @@ class core_dml_testcase extends database_driver_testcase {
$this->assertFalse($columns['id']->auto_increment);
}
public function test_get_preload_columns() {
$DB = $this->tdb;
$dbman = $this->tdb->get_manager();
$table = $this->get_test_table();
$tablename = $table->getName();
$table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
$table->add_field('course', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
$table->add_field('name', XMLDB_TYPE_CHAR, '255', null, null, null, 'lala');
$table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
$dbman->create_table($table);
$expected = [
'aid' => 'id',
'acourse' => 'course',
'aname' => 'name',
];
$columns = $DB->get_preload_columns($tablename, 'a');
$this->assertCount(3, $columns);
$this->assertEquals($expected, $columns);
}
/**
* Ensure that get_preload_columns_sql works as expected.
*
* @dataProvider get_preload_columns_sql_provider
* @param array $fieldlist The list of fields
* @param string $tablealias The alias to use
* @param string $expected The string to match
*/
public function test_get_preload_columns_sql(array $fieldlist, string $tablealias, string $expected) {
$this->assertEquals($expected, $this->tdb->get_preload_columns_sql($fieldlist, $tablealias));
}
/**
* Data provider for get_preload_columns_sql tests.
*
* @return array
*/
public function get_preload_columns_sql_provider() : array {
return [
'single field' => [
[
'xid' => 'id',
],
'x',
'x.id AS xid',
],
'multiple fields' => [
[
'bananaid' => 'id',
'bananacourse' => 'course',
'bananafoo' => 'foo',
],
'banana',
'banana.id AS bananaid, banana.course AS bananacourse, banana.foo AS bananafoo',
],
];
}
/**
* Ensure that extract_fields_from_object works as expected.
*
* @dataProvider extract_fields_from_object_provider
* @param array $fieldlist The list of fields
* @param stdClass $in Input values for the test
* @param stdClass $out The expected output
* @param stdClass $modified Expected value of $in after it's been modified
*/
public function test_extract_fields_from_object(array $fieldlist, \stdClass $in, \stdClass $out, \stdClass $modified) {
$result = $this->tdb->extract_fields_from_object($fieldlist, $in);
$this->assertEquals($out, $result);
$this->assertEquals($modified, $in);
}
/**
* Data provider for extract_fields_from_object tests.
*
* @return array
*/
public function extract_fields_from_object_provider() : array {
return [
'single table' => [
[
'sid' => 'id',
'scourse' => 'course',
'sflag' => 'flag',
],
(object) [
'sid' => 1,
'scourse' => 42,
'sflag' => 'foo',
],
(object) [
'id' => 1,
'course' => 42,
'flag' => 'foo',
],
(object) [
],
],
'single table amongst others' => [
[
'sid' => 'id',
'scourse' => 'course',
'sflag' => 'flag',
],
(object) [
'sid' => 1,
'scourse' => 42,
'sflag' => 'foo',
'oid' => 'id',
'ocourse' => 'course',
'oflag' => 'flag',
],
(object) [
'id' => 1,
'course' => 42,
'flag' => 'foo',
],
(object) [
'oid' => 'id',
'ocourse' => 'course',
'oflag' => 'flag',
],
],
];
}
public function test_get_manager() {
$DB = $this->tdb;
$dbman = $this->tdb->get_manager();