modifs.mineures sans commentaires
This commit is contained in:
parent
604d9c1fe3
commit
fdf19326b0
|
@ -12,7 +12,7 @@ class CapacitorChannel {
|
|||
|
||||
const TABLE_NAME = null;
|
||||
|
||||
const KEY_DEFINITIONS = null;
|
||||
const COLUMN_DEFINITIONS = null;
|
||||
|
||||
const PRIMARY_KEYS = null;
|
||||
|
||||
|
@ -27,11 +27,11 @@ class CapacitorChannel {
|
|||
$this->name = self::verifix_name($name ?? static::NAME);
|
||||
$this->eachCommitThreshold = $eachCommitThreshold ?? static::EACH_COMMIT_THRESHOLD;
|
||||
$this->created = false;
|
||||
$keyDefinitions = cl::withn(static::KEY_DEFINITIONS);
|
||||
$columnDefinitions = cl::withn(static::COLUMN_DEFINITIONS);
|
||||
$primaryKeys = cl::withn(static::PRIMARY_KEYS);
|
||||
if ($primaryKeys === null && $keyDefinitions !== null) {
|
||||
if ($primaryKeys === null && $columnDefinitions !== null) {
|
||||
$index = 0;
|
||||
foreach ($keyDefinitions as $col => $def) {
|
||||
foreach ($columnDefinitions as $col => $def) {
|
||||
if ($col == $index) {
|
||||
$index++;
|
||||
if (preg_match('/\bprimary\s+key\s+\((.+)\)/i', $def, $ms)) {
|
||||
|
@ -44,7 +44,7 @@ class CapacitorChannel {
|
|||
}
|
||||
}
|
||||
}
|
||||
$this->keyDefinitions = $keyDefinitions;
|
||||
$this->columnDefinitions = $columnDefinitions;
|
||||
$this->primaryKeys = $primaryKeys;
|
||||
}
|
||||
|
||||
|
@ -80,7 +80,7 @@ class CapacitorChannel {
|
|||
$this->created = $created;
|
||||
}
|
||||
|
||||
protected ?array $keyDefinitions;
|
||||
protected ?array $columnDefinitions;
|
||||
|
||||
/**
|
||||
* retourner un ensemble de définitions pour des colonnes supplémentaires à
|
||||
|
@ -98,8 +98,8 @@ class CapacitorChannel {
|
|||
* lors de l'insertion dans la base de données, et automatiquement désérialisées
|
||||
* avant d'être retournées à l'utilisateur (sans le suffixe "__")
|
||||
*/
|
||||
function getKeyDefinitions(): ?array {
|
||||
return $this->keyDefinitions;
|
||||
function getColumnDefinitions(): ?array {
|
||||
return $this->columnDefinitions;
|
||||
}
|
||||
|
||||
protected ?array $primaryKeys;
|
||||
|
@ -122,6 +122,9 @@ class CapacitorChannel {
|
|||
/**
|
||||
* Avant d'utiliser un id pour rechercher dans la base de donnée, corriger sa
|
||||
* valeur le cas échéant.
|
||||
*
|
||||
* Cette fonction assume que l'unique clé primaire est id_. Elle n'est pas
|
||||
* utilisée si une clé primaire multiple est définie.
|
||||
*/
|
||||
function verifixId(string &$id): void {
|
||||
}
|
||||
|
|
|
@ -3,13 +3,112 @@ namespace nur\sery\db;
|
|||
|
||||
use nur\sery\cl;
|
||||
use nur\sery\php\func;
|
||||
use nur\sery\str;
|
||||
|
||||
/**
|
||||
* Class CapacitorStorage: objet permettant d'accumuler des données pour les
|
||||
* réutiliser plus tard
|
||||
*/
|
||||
abstract class CapacitorStorage {
|
||||
abstract protected function getChannel(?string $name): CapacitorChannel;
|
||||
/** @var CapacitorChannel[] */
|
||||
protected $channels;
|
||||
|
||||
function addChannel(CapacitorChannel $channel): CapacitorChannel {
|
||||
$this->_create($channel);
|
||||
$this->channels[$channel->getName()] = $channel;
|
||||
return $channel;
|
||||
}
|
||||
|
||||
protected function getChannel(?string $name): CapacitorChannel {
|
||||
$name = CapacitorChannel::verifix_name($name);
|
||||
$channel = $this->channels[$name] ?? null;
|
||||
if ($channel === null) {
|
||||
$channel = $this->addChannel(new CapacitorChannel($name));
|
||||
}
|
||||
return $channel;
|
||||
}
|
||||
|
||||
const PRIMARY_KEY_DEFINITION = [
|
||||
"id_" => "integer primary key autoincrement",
|
||||
];
|
||||
|
||||
const COLUMN_DEFINITIONS = [
|
||||
"item__" => "text",
|
||||
"sum_" => "varchar(40)",
|
||||
"created_" => "datetime",
|
||||
"modified_" => "datetime",
|
||||
];
|
||||
|
||||
protected function ColumnDefinitions(CapacitorChannel $channel): array {
|
||||
$definitions = [];
|
||||
if ($channel->getPrimaryKeys() === null) {
|
||||
$definitions[] = self::PRIMARY_KEY_DEFINITION;
|
||||
}
|
||||
$definitions[] = self::COLUMN_DEFINITIONS;
|
||||
$definitions[] = $channel->getColumnDefinitions();
|
||||
return cl::merge(...$definitions);
|
||||
}
|
||||
|
||||
/** sérialiser les valeurs qui doivent l'être dans $values */
|
||||
protected function serialize(CapacitorChannel $channel, ?array $values): ?array {
|
||||
if ($values === null) return null;
|
||||
$cols = $this->ColumnDefinitions($channel);
|
||||
$index = 0;
|
||||
$row = [];
|
||||
foreach (array_keys($cols) as $col) {
|
||||
$key = $col;
|
||||
if ($key === $index) {
|
||||
$index++;
|
||||
continue;
|
||||
} elseif (str::del_suffix($key, "__")) {
|
||||
if (!array_key_exists($key, $values)) continue;
|
||||
$value = $values[$key];
|
||||
if ($value !== null) $value = serialize($value);
|
||||
} else {
|
||||
if (!array_key_exists($key, $values)) continue;
|
||||
$value = $values[$key];
|
||||
}
|
||||
$row[$col] = $value;
|
||||
}
|
||||
return $row;
|
||||
}
|
||||
|
||||
/** désérialiser les valeurs qui doivent l'être dans $values */
|
||||
protected function unserialize(CapacitorChannel $channel, ?array $row): ?array {
|
||||
if ($row === null) return null;
|
||||
$cols = $this->ColumnDefinitions($channel);
|
||||
$index = 0;
|
||||
$values = [];
|
||||
foreach (array_keys($cols) as $col) {
|
||||
$key = $col;
|
||||
if ($key === $index) {
|
||||
$index++;
|
||||
continue;
|
||||
} elseif (!array_key_exists($col, $row)) {
|
||||
continue;
|
||||
} elseif (str::del_suffix($key, "__")) {
|
||||
$value = $row[$col];
|
||||
if ($value !== null) $value = unserialize($value);
|
||||
} else {
|
||||
$value = $row[$col];
|
||||
}
|
||||
$values[$key] = $value;
|
||||
}
|
||||
return $values;
|
||||
}
|
||||
|
||||
protected function getPrimaryKeys(CapacitorChannel $channel): array {
|
||||
$primaryKeys = $channel->getPrimaryKeys();
|
||||
if ($primaryKeys === null) $primaryKeys = ["id_"];
|
||||
return $primaryKeys;
|
||||
}
|
||||
|
||||
protected function getRowIds(CapacitorChannel $channel, ?array $row, ?array &$primaryKeys=null): ?array {
|
||||
$primaryKeys = $this->getPrimaryKeys($channel);
|
||||
$rowIds = cl::select($row, $primaryKeys);
|
||||
if (cl::all_n($rowIds)) return null;
|
||||
else return $rowIds;
|
||||
}
|
||||
|
||||
abstract function _exists(CapacitorChannel $channel): bool;
|
||||
|
||||
|
@ -75,12 +174,6 @@ abstract class CapacitorStorage {
|
|||
return $this->_one($this->getChannel($channel), $filter);
|
||||
}
|
||||
|
||||
protected function getPrimaryKeys(CapacitorChannel $channel): array {
|
||||
$primaryKeys = $channel->getPrimaryKeys();
|
||||
if ($primaryKeys === null) $primaryKeys = ["id_"];
|
||||
return $primaryKeys;
|
||||
}
|
||||
|
||||
abstract function _all(CapacitorChannel $channel, $filter): iterable;
|
||||
|
||||
/**
|
||||
|
|
|
@ -23,92 +23,18 @@ class MysqlStorage extends CapacitorStorage {
|
|||
return $this->mysql;
|
||||
}
|
||||
|
||||
const KEY_DEFINITIONS = [
|
||||
"id_" => "integer primary key autoincrement",
|
||||
"item__" => "text",
|
||||
"sum_" => "varchar(40)",
|
||||
"created_" => "datetime",
|
||||
"modified_" => "datetime",
|
||||
];
|
||||
|
||||
/** sérialiser les valeurs qui doivent l'être dans $values */
|
||||
protected function serialize(CapacitorChannel $channel, ?array $values): ?array {
|
||||
if ($values === null) return null;
|
||||
$columns = cl::merge(self::KEY_DEFINITIONS, $channel->getKeyDefinitions());
|
||||
$index = 0;
|
||||
$row = [];
|
||||
foreach (array_keys($columns) as $column) {
|
||||
$key = $column;
|
||||
if ($key === $index) {
|
||||
$index++;
|
||||
continue;
|
||||
} elseif (str::del_suffix($key, "__")) {
|
||||
if (!array_key_exists($key, $values)) continue;
|
||||
$value = $values[$key];
|
||||
if ($value !== null) $value = serialize($value);
|
||||
} else {
|
||||
if (!array_key_exists($key, $values)) continue;
|
||||
$value = $values[$key];
|
||||
}
|
||||
$row[$column] = $value;
|
||||
}
|
||||
return $row;
|
||||
}
|
||||
|
||||
/** désérialiser les valeurs qui doivent l'être dans $values */
|
||||
protected function unserialize(CapacitorChannel $channel, ?array $row): ?array {
|
||||
if ($row === null) return null;
|
||||
$columns = cl::merge(self::KEY_DEFINITIONS, $channel->getKeyDefinitions());
|
||||
$index = 0;
|
||||
$values = [];
|
||||
foreach (array_keys($columns) as $column) {
|
||||
$key = $column;
|
||||
if ($key === $index) {
|
||||
$index++;
|
||||
continue;
|
||||
} elseif (!array_key_exists($column, $row)) {
|
||||
continue;
|
||||
} elseif (str::del_suffix($key, "__")) {
|
||||
$value = $row[$column];
|
||||
if ($value !== null) $value = unserialize($value);
|
||||
} else {
|
||||
$value = $row[$column];
|
||||
}
|
||||
$values[$key] = $value;
|
||||
}
|
||||
return $values;
|
||||
}
|
||||
|
||||
protected function _create(CapacitorChannel $channel): void {
|
||||
if (!$channel->isCreated()) {
|
||||
$columns = cl::merge(self::KEY_DEFINITIONS, $channel->getKeyDefinitions());
|
||||
$cols = $this->ColumnDefinitions($channel);
|
||||
$this->mysql->exec([
|
||||
"create table if not exists",
|
||||
"table" => $channel->getTableName(),
|
||||
"cols" => $columns,
|
||||
"cols" => $cols,
|
||||
]);
|
||||
$channel->setCreated();
|
||||
}
|
||||
}
|
||||
|
||||
/** @var CapacitorChannel[] */
|
||||
protected $channels;
|
||||
|
||||
function addChannel(CapacitorChannel $channel): CapacitorChannel {
|
||||
$this->_create($channel);
|
||||
$this->channels[$channel->getName()] = $channel;
|
||||
return $channel;
|
||||
}
|
||||
|
||||
protected function getChannel(?string $name): CapacitorChannel {
|
||||
$name = CapacitorChannel::verifix_name($name);
|
||||
$channel = $this->channels[$name] ?? null;
|
||||
if ($channel === null) {
|
||||
$channel = $this->addChannel(new CapacitorChannel($name));
|
||||
}
|
||||
return $channel;
|
||||
}
|
||||
|
||||
function _exists(CapacitorChannel $channel): bool {
|
||||
$tableName = $this->mysql->get([
|
||||
"select table_name from information_schema.tables",
|
||||
|
@ -142,13 +68,19 @@ class MysqlStorage extends CapacitorStorage {
|
|||
"sum_" => $sum_,
|
||||
], $this->unserialize($channel, $channel->getKeyValues($item)));
|
||||
$prow = null;
|
||||
$id_ = $row["id_"] ?? null;
|
||||
if ($id_ !== null) {
|
||||
$rowIds = $this->getRowIds($channel, $row, $primaryKeys);
|
||||
if ($rowIds !== null) {
|
||||
# modification
|
||||
$prow = $this->mysql->one([
|
||||
"select id_, item__, sum_, created_, modified_",
|
||||
"select",
|
||||
"cols" => array_merge($primaryKeys, [
|
||||
"item__",
|
||||
"sum_",
|
||||
"created_",
|
||||
"modified_",
|
||||
]),
|
||||
"from" => $channel->getTableName(),
|
||||
"where" => ["id_" => $id_],
|
||||
"where" => $rowIds,
|
||||
]);
|
||||
}
|
||||
$insert = null;
|
||||
|
@ -199,7 +131,7 @@ class MysqlStorage extends CapacitorStorage {
|
|||
"update",
|
||||
"table" => $channel->getTableName(),
|
||||
"values" => $row,
|
||||
"where" => ["id_" => $id_],
|
||||
"where" => $rowIds,
|
||||
]);
|
||||
}
|
||||
return 1;
|
||||
|
@ -269,6 +201,7 @@ class MysqlStorage extends CapacitorStorage {
|
|||
try {
|
||||
$args ??= [];
|
||||
foreach ($this->_all($channel, $filter) as $row) {
|
||||
$rowIds = $this->getRowIds($channel, $row);
|
||||
$updates = func::_call($onEach, [$row["item"], $row, ...$args]);
|
||||
if (is_array($updates)) {
|
||||
$updates = $this->serialize($channel, $updates);
|
||||
|
@ -283,7 +216,7 @@ class MysqlStorage extends CapacitorStorage {
|
|||
"update",
|
||||
"table" => $tableName,
|
||||
"values" => $updates,
|
||||
"where" => ["id_" => $row["id_"]],
|
||||
"where" => $rowIds,
|
||||
]);
|
||||
if ($commitThreshold !== null) {
|
||||
$commitThreshold--;
|
||||
|
|
|
@ -5,7 +5,6 @@ use nur\sery\cl;
|
|||
use nur\sery\db\CapacitorChannel;
|
||||
use nur\sery\db\CapacitorStorage;
|
||||
use nur\sery\php\func;
|
||||
use nur\sery\str;
|
||||
use nur\sery\ValueException;
|
||||
|
||||
/**
|
||||
|
@ -23,92 +22,18 @@ class SqliteStorage extends CapacitorStorage {
|
|||
return $this->sqlite;
|
||||
}
|
||||
|
||||
const KEY_DEFINITIONS = [
|
||||
"id_" => "integer primary key autoincrement",
|
||||
"item__" => "text",
|
||||
"sum_" => "varchar(40)",
|
||||
"created_" => "datetime",
|
||||
"modified_" => "datetime",
|
||||
];
|
||||
|
||||
/** sérialiser les valeurs qui doivent l'être dans $values */
|
||||
protected function serialize(CapacitorChannel $channel, ?array $values): ?array {
|
||||
if ($values === null) return null;
|
||||
$columns = cl::merge(self::KEY_DEFINITIONS, $channel->getKeyDefinitions());
|
||||
$index = 0;
|
||||
$row = [];
|
||||
foreach (array_keys($columns) as $column) {
|
||||
$key = $column;
|
||||
if ($key === $index) {
|
||||
$index++;
|
||||
continue;
|
||||
} elseif (str::del_suffix($key, "__")) {
|
||||
if (!array_key_exists($key, $values)) continue;
|
||||
$value = $values[$key];
|
||||
if ($value !== null) $value = serialize($value);
|
||||
} else {
|
||||
if (!array_key_exists($key, $values)) continue;
|
||||
$value = $values[$key];
|
||||
}
|
||||
$row[$column] = $value;
|
||||
}
|
||||
return $row;
|
||||
}
|
||||
|
||||
/** désérialiser les valeurs qui doivent l'être dans $values */
|
||||
protected function unserialize(CapacitorChannel $channel, ?array $row): ?array {
|
||||
if ($row === null) return null;
|
||||
$columns = cl::merge(self::KEY_DEFINITIONS, $channel->getKeyDefinitions());
|
||||
$index = 0;
|
||||
$values = [];
|
||||
foreach (array_keys($columns) as $column) {
|
||||
$key = $column;
|
||||
if ($key === $index) {
|
||||
$index++;
|
||||
continue;
|
||||
} elseif (!array_key_exists($column, $row)) {
|
||||
continue;
|
||||
} elseif (str::del_suffix($key, "__")) {
|
||||
$value = $row[$column];
|
||||
if ($value !== null) $value = unserialize($value);
|
||||
} else {
|
||||
$value = $row[$column];
|
||||
}
|
||||
$values[$key] = $value;
|
||||
}
|
||||
return $values;
|
||||
}
|
||||
|
||||
protected function _create(CapacitorChannel $channel): void {
|
||||
if (!$channel->isCreated()) {
|
||||
$columns = cl::merge(self::KEY_DEFINITIONS, $channel->getKeyDefinitions());
|
||||
$cols = $this->ColumnDefinitions($channel);
|
||||
$this->sqlite->exec([
|
||||
"create table if not exists",
|
||||
"table" => $channel->getTableName(),
|
||||
"cols" => $columns,
|
||||
"cols" => $cols,
|
||||
]);
|
||||
$channel->setCreated();
|
||||
}
|
||||
}
|
||||
|
||||
/** @var CapacitorChannel[] */
|
||||
protected $channels;
|
||||
|
||||
function addChannel(CapacitorChannel $channel): CapacitorChannel {
|
||||
$this->_create($channel);
|
||||
$this->channels[$channel->getName()] = $channel;
|
||||
return $channel;
|
||||
}
|
||||
|
||||
protected function getChannel(?string $name): CapacitorChannel {
|
||||
$name = CapacitorChannel::verifix_name($name);
|
||||
$channel = $this->channels[$name] ?? null;
|
||||
if ($channel === null) {
|
||||
$channel = $this->addChannel(new CapacitorChannel($name));
|
||||
}
|
||||
return $channel;
|
||||
}
|
||||
|
||||
function _exists(CapacitorChannel $channel): bool {
|
||||
$tableName = $this->sqlite->get([
|
||||
"select name from sqlite_schema",
|
||||
|
@ -141,13 +66,19 @@ class SqliteStorage extends CapacitorStorage {
|
|||
"sum_" => $sum_,
|
||||
], $this->unserialize($channel, $channel->getKeyValues($item)));
|
||||
$prow = null;
|
||||
$id_ = $row["id_"] ?? null;
|
||||
if ($id_ !== null) {
|
||||
$rowIds = $this->getRowIds($channel, $row, $primaryKeys);
|
||||
if ($rowIds !== null) {
|
||||
# modification
|
||||
$prow = $this->sqlite->one([
|
||||
"select id_, item__, sum_, created_, modified_",
|
||||
"select",
|
||||
"cols" => array_merge($primaryKeys, [
|
||||
"item__",
|
||||
"sum_",
|
||||
"created_",
|
||||
"modified_",
|
||||
]),
|
||||
"from" => $channel->getTableName(),
|
||||
"where" => ["id_" => $id_],
|
||||
"where" => $rowIds,
|
||||
]);
|
||||
}
|
||||
$insert = null;
|
||||
|
@ -198,7 +129,7 @@ class SqliteStorage extends CapacitorStorage {
|
|||
"update",
|
||||
"table" => $channel->getTableName(),
|
||||
"values" => $row,
|
||||
"where" => ["id_" => $id_],
|
||||
"where" => $rowIds,
|
||||
]);
|
||||
}
|
||||
return 1;
|
||||
|
@ -268,6 +199,7 @@ class SqliteStorage extends CapacitorStorage {
|
|||
try {
|
||||
$args ??= [];
|
||||
foreach ($this->_all($channel, $filter) as $row) {
|
||||
$rowIds = $this->getRowIds($channel, $row);
|
||||
$updates = func::_call($onEach, [$row["item"], $row, ...$args]);
|
||||
if (is_array($updates)) {
|
||||
$updates = $this->serialize($channel, $updates);
|
||||
|
@ -282,7 +214,7 @@ class SqliteStorage extends CapacitorStorage {
|
|||
"update",
|
||||
"table" => $tableName,
|
||||
"values" => $updates,
|
||||
"where" => ["id_" => $row["id_"]],
|
||||
"where" => $rowIds,
|
||||
]);
|
||||
if ($commitThreshold !== null) {
|
||||
$commitThreshold--;
|
||||
|
|
|
@ -32,7 +32,7 @@ class SqliteStorageTest extends TestCase {
|
|||
$storage = new SqliteStorage(__DIR__.'/capacitor.db');
|
||||
$storage->addChannel(new class extends CapacitorChannel {
|
||||
const NAME = "arrays";
|
||||
function getKeyDefinitions(): ?array {
|
||||
function getColumnDefinitions(): ?array {
|
||||
return ["id" => "integer"];
|
||||
}
|
||||
function getKeyValues($item): ?array {
|
||||
|
@ -50,7 +50,7 @@ class SqliteStorageTest extends TestCase {
|
|||
$capacitor = new Capacitor($storage, new class extends CapacitorChannel {
|
||||
const NAME = "each";
|
||||
|
||||
function getKeyDefinitions(): ?array {
|
||||
function getColumnDefinitions(): ?array {
|
||||
return [
|
||||
"age" => "integer",
|
||||
"done" => "integer default 0",
|
||||
|
@ -90,7 +90,7 @@ class SqliteStorageTest extends TestCase {
|
|||
$capacitor = new Capacitor($storage, new class extends CapacitorChannel {
|
||||
const NAME = "pk";
|
||||
|
||||
function getKeyDefinitions(): ?array {
|
||||
function getColumnDefinitions(): ?array {
|
||||
return [
|
||||
"id_" => "varchar primary key",
|
||||
"done" => "integer default 0",
|
||||
|
|
|
@ -99,7 +99,7 @@ class _queryTest extends TestCase {
|
|||
|
||||
$sql = $params = null;
|
||||
_query_base::parse_set_values([["int" => 42, "string" => "value"], ["int" => 24, "string" => "eulav"]], $sql, $params);
|
||||
self::assertSame(["int = :int", "string = :string", "int = :int2", "string = :string2"], $sql);
|
||||
self::assertSame(["int" => 42, "string" => "value", "int2" => 24, "string2" => "eulav"], $params);
|
||||
self::assertSame(["int = :int", "string = :string", "int = :int1", "string = :string1"], $sql);
|
||||
self::assertSame(["int" => 42, "string" => "value", "int1" => 24, "string1" => "eulav"], $params);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue