Added support for extra database fields.

This commit is contained in:
flash 2024-06-03 22:58:45 +00:00
parent 572b46580a
commit 8a563ba73b
2 changed files with 110 additions and 27 deletions

View file

@ -24,13 +24,29 @@ class DbConfig implements IConfig {
/** @var array<string, DbConfigValueInfo> */ /** @var array<string, DbConfigValueInfo> */
private array $values = []; private array $values = [];
/** @var string[] */
private array $extraFieldNames;
/** @var mixed[] */
private array $extraFieldValues;
/**
* @param IDbConnection $dbConn
* @param string $tableName
* @param string $nameField
* @param string $valueField
* @param array<string, mixed> $extraFields
*/
public function __construct( public function __construct(
IDbConnection $dbConn, IDbConnection $dbConn,
private string $tableName, private string $tableName,
private string $nameField = 'config_name', private string $nameField = 'config_name',
private string $valueField = 'config_value' private string $valueField = 'config_value',
array $extraFields = [],
) { ) {
$this->cache = new DbStatementCache($dbConn); $this->cache = new DbStatementCache($dbConn);
$this->extraFieldNames = array_keys($extraFields);
$this->extraFieldValues = array_values($extraFields);
} }
public static function validateName(string $name): bool { public static function validateName(string $name): bool {
@ -90,15 +106,23 @@ class DbConfig implements IConfig {
$names = array_values($names); $names = array_values($names);
$nameCount = count($names); $nameCount = count($names);
$stmt = $this->cache->get(sprintf( $query = sprintf(
'SELECT COUNT(*) FROM %s WHERE %s IN (%s)', 'SELECT COUNT(*) FROM %s WHERE %s IN (%s)',
$this->tableName, $this->nameField, $this->tableName, $this->nameField,
DbTools::prepareListString($nameCount) DbTools::prepareListString($nameCount)
)); );
for($i = 0; $i < $nameCount; ++$i) foreach($this->extraFieldNames as $extraFieldName)
$stmt->addParameter($i + 1, $names[$i]); $query .= sprintf(' AND %s = ?', $extraFieldName);
$stmt->execute();
$stmt = $this->cache->get($query);
$args = 0;
foreach($names as $name)
$stmt->addParameter(++$args, $name);
foreach($this->extraFieldValues as $extraFieldValue)
$stmt->addParameter(++$args, $extraFieldValue);
$stmt->execute();
$result = $stmt->getResult(); $result = $stmt->getResult();
if($result->next()) if($result->next())
return $result->getInteger(0) >= $nameCount; return $result->getInteger(0) >= $nameCount;
@ -117,14 +141,21 @@ class DbConfig implements IConfig {
unset($this->values[$name]); unset($this->values[$name]);
$nameCount = count($names); $nameCount = count($names);
$stmt = $this->cache->get(sprintf( $query = sprintf(
'DELETE FROM %s WHERE %s IN (%s)', 'DELETE FROM %s WHERE %s IN (%s)',
$this->tableName, $this->nameField, $this->tableName, $this->nameField,
DbTools::prepareListString($nameCount) DbTools::prepareListString($nameCount)
)); );
foreach($this->extraFieldNames as $extraFieldName)
$query .= sprintf(' AND %s = ?', $extraFieldName);
for($i = 0; $i < $nameCount; ++$i) $stmt = $this->cache->get($query);
$stmt->addParameter($i + 1, $names[$i]);
$args = 0;
foreach($names as $name)
$stmt->addParameter(++$args, $name);
foreach($this->extraFieldValues as $extraFieldValue)
$stmt->addParameter(++$args, $extraFieldValue);
$stmt->execute(); $stmt->execute();
} }
@ -136,6 +167,8 @@ class DbConfig implements IConfig {
$hasRange = $range !== 0; $hasRange = $range !== 0;
$query = sprintf('SELECT %s, %s FROM %s', $this->nameField, $this->valueField, $this->tableName); $query = sprintf('SELECT %s, %s FROM %s', $this->nameField, $this->valueField, $this->tableName);
foreach($this->extraFieldNames as $i => $extraFieldName)
$query .= sprintf(' %s %s = ?', $i < 1 ? 'WHERE' : 'AND', $extraFieldName);
if($hasRange) { if($hasRange) {
if($range < 0) if($range < 0)
throw new InvalidArgumentException('$range must be a positive integer.'); throw new InvalidArgumentException('$range must be a positive integer.');
@ -146,10 +179,15 @@ class DbConfig implements IConfig {
} }
$stmt = $this->cache->get($query); $stmt = $this->cache->get($query);
$args = 0;
foreach($this->extraFieldValues as $extraFieldValue)
$stmt->addParameter(++$args, $extraFieldValue);
if($hasRange) { if($hasRange) {
$stmt->addParameter(1, $range); $stmt->addParameter(++$args, $range);
$stmt->addParameter(2, $offset); $stmt->addParameter(++$args, $offset);
} }
$stmt->execute(); $stmt->execute();
$result = $stmt->getResult(); $result = $stmt->getResult();
@ -184,13 +222,22 @@ class DbConfig implements IConfig {
$names = array_values($names); $names = array_values($names);
$nameCount = count($names); $nameCount = count($names);
$stmt = $this->cache->get(sprintf( $query = sprintf(
'SELECT %s, %s FROM %s WHERE config_name IN (%s)', 'SELECT %s, %s FROM %s WHERE %s IN (%s)',
$this->nameField, $this->valueField, $this->tableName, $this->nameField, $this->valueField, $this->tableName, $this->nameField,
DbTools::prepareListString($nameCount) DbTools::prepareListString($nameCount)
)); );
for($i = 0; $i < $nameCount; ++$i) foreach($this->extraFieldNames as $extraFieldName)
$stmt->addParameter($i + 1, $names[$i]); $query .= sprintf(' AND %s = ?', $extraFieldName);
$stmt = $this->cache->get($query);
$args = 0;
foreach($names as $name)
$stmt->addParameter(++$args, $name);
foreach($this->extraFieldValues as $extraFieldValue)
$stmt->addParameter(++$args, $extraFieldValue);
$stmt->execute(); $stmt->execute();
$result = $stmt->getResult(); $result = $stmt->getResult();
@ -207,9 +254,16 @@ class DbConfig implements IConfig {
if(empty($values)) if(empty($values))
return; return;
$fields = [$this->nameField, $this->valueField];
if(count($this->extraFieldNames) > 0)
$fields = array_merge($fields, $this->extraFieldNames);
$fieldCount = count($fields);
$fields = implode(', ', $fields);
$stmt = $this->cache->get(sprintf( $stmt = $this->cache->get(sprintf(
'INSERT INTO %s (%s, %s) VALUES (?, ?)', 'INSERT INTO %s (%s) VALUES (%s)',
$this->tableName, $this->nameField, $this->valueField $this->tableName, $fields,
DbTools::prepareListString($fieldCount)
)); ));
foreach($values as $name => $value) { foreach($values as $name => $value) {
@ -225,8 +279,12 @@ class DbConfig implements IConfig {
$this->removeValues($name); $this->removeValues($name);
$stmt->addParameter(1, $name); $args = 0;
$stmt->addParameter(2, serialize($value)); $stmt->addParameter(++$args, $name);
$stmt->addParameter(++$args, serialize($value));
foreach($this->extraFieldValues as $extraFieldValue)
$stmt->addParameter(++$args, $extraFieldValue);
$stmt->execute(); $stmt->execute();
} }
} }

View file

@ -15,6 +15,7 @@ use PHPUnit\Framework\TestCase;
* @covers \Syokuhou\GetValuesTrait * @covers \Syokuhou\GetValuesTrait
*/ */
final class DbConfigTest extends TestCase { final class DbConfigTest extends TestCase {
private \Index\Data\IDbConnection $dbConn;
private \Syokuhou\DbConfig $config; private \Syokuhou\DbConfig $config;
private const VALUES = [ private const VALUES = [
@ -34,18 +35,33 @@ final class DbConfigTest extends TestCase {
'test.int' => 'i:243230;', 'test.int' => 'i:243230;',
]; ];
protected function setUp(): void { private const USER_VALUES = [
$dbConn = \Index\Data\DbTools::create('sqlite::memory:'); 'mobile.left_handed' => ['b:0;', 'b:1;'],
$dbConn->execute('CREATE TABLE skh_config (config_name TEXT NOT NULL COLLATE NOCASE, config_value BLOB NOT NULL, PRIMARY KEY (config_name))'); 'profile.allow_indexing' => ['b:1;', 'b:0;'],
];
$stmt = $dbConn->prepare('INSERT INTO skh_config (config_name, config_value) VALUES (?, ?)'); protected function setUp(): void {
$this->dbConn = \Index\Data\DbTools::create('sqlite::memory:');
$this->dbConn->execute('CREATE TABLE skh_config (config_name TEXT NOT NULL COLLATE NOCASE, config_value BLOB NOT NULL, PRIMARY KEY (config_name))');
$this->dbConn->execute('CREATE TABLE skh_user_settings (user_id INTEGER NOT NULL, setting_name TEXT NOT NULL COLLATE NOCASE, setting_value BLOB NOT NULL, PRIMARY KEY (user_id, setting_name))');
$stmt = $this->dbConn->prepare('INSERT INTO skh_config (config_name, config_value) VALUES (?, ?)');
foreach(self::VALUES as $name => $value) { foreach(self::VALUES as $name => $value) {
$stmt->addParameter(1, $name); $stmt->addParameter(1, $name);
$stmt->addParameter(2, $value); $stmt->addParameter(2, $value);
$stmt->execute(); $stmt->execute();
} }
$this->config = new \Syokuhou\DbConfig($dbConn, 'skh_config'); $stmt = $this->dbConn->prepare('INSERT INTO skh_user_settings (user_id, setting_name, setting_value) VALUES (?, ?, ?)');
for($i = 1; $i <= 10; ++$i)
foreach(self::USER_VALUES as $name => $value) {
$stmt->addParameter(1, $i);
$stmt->addParameter(2, $name);
$stmt->addParameter(3, $value[$i % 2]);
$stmt->execute();
}
$this->config = new \Syokuhou\DbConfig($this->dbConn, 'skh_config');
} }
public function testScoping(): void { public function testScoping(): void {
@ -152,4 +168,13 @@ final class DbConfigTest extends TestCase {
$this->assertFalse(\Syokuhou\DbConfig::validateName('this..is.not.valid')); $this->assertFalse(\Syokuhou\DbConfig::validateName('this..is.not.valid'));
$this->assertFalse(\Syokuhou\DbConfig::validateName('First.may.Not.be.uppercase')); $this->assertFalse(\Syokuhou\DbConfig::validateName('First.may.Not.be.uppercase'));
} }
public function testUserSettings(): void {
for($i = 1; $i <= 10; ++$i) {
$config = new \Syokuhou\DbConfig($this->dbConn, 'skh_user_settings', 'setting_name', 'setting_value', ['user_id' => $i]);
foreach(self::USER_VALUES as $name => $value)
$this->assertEquals(unserialize($value[$i % 2]), $config->getBoolean($name));
}
}
} }