diff --git a/php/src/db/Capacitor.php b/php/src/db/Capacitor.php index 6177bc4..743cfd7 100644 --- a/php/src/db/Capacitor.php +++ b/php/src/db/Capacitor.php @@ -34,16 +34,20 @@ class Capacitor { return $this->storage->_charge($this->channel, $item, $func, $args); } + function discharge($filter=null, ?bool $reset=null): iterable { + return $this->storage->_discharge($this->channel, $reset); + } + function count($filter=null): int { return $this->storage->_count($this->channel, $filter); } - function discharge($filter=null, ?bool $reset=null): iterable { - return $this->storage->_discharge($this->channel, $filter, $reset); + function one($filter): ?array { + return $this->storage->_one($this->channel, $filter); } - function get($filter) { - return $this->storage->_get($this->channel, $filter); + function all($filter): iterable { + return $this->storage->_all($this->channel, $filter); } function each($filter, ?callable $func=null, ?array $args=null): int { diff --git a/php/src/db/CapacitorChannel.php b/php/src/db/CapacitorChannel.php index b14308c..82620a3 100644 --- a/php/src/db/CapacitorChannel.php +++ b/php/src/db/CapacitorChannel.php @@ -56,9 +56,17 @@ class CapacitorChannel { * retourner un ensemble de définitions pour des colonnes supplémentaires à * insérer lors du chargement d'une valeur * - * la colonne "_id" de définition "integer primary key autoincrement" est la - * clé primaire par défaut. elle peut être redéfinie, et dans ce cas la valeur - * à utiliser doit être retournée par {@link getKeyValues()} + * la clé primaire "id_" a pour définition "integer primary key autoincrement". + * elle peut être redéfinie, et dans ce cas la valeur à utiliser doit être + * retournée par {@link getKeyValues()} + * + * la colonne "item__" contient la valeur sérialisée de l'élément chargé. bien + * que ce soit possible techniquement, cette colonne n'a pas à être redéfinie + * + * les colonnes dont le nom se termine par "_" sont réservées. + * les colonnes dont le nom se termine par "__" sont automatiquement sérialisées + * 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 null; @@ -68,28 +76,38 @@ class CapacitorChannel { * calculer les valeurs des colonnes supplémentaires à insérer pour le * chargement de $item * - * Si "_id" est retourné, la ligne existante est mise à jour le cas échéant. + * Cette méthode est utilisée par {@link Capacitor::charge()}. Si une valeur + * "id_" est retourné, la ligne correspondate existante est mise à jour */ function getKeyValues($item): ?array { return null; } + /** + * Avant d'utiliser un id pour rechercher dans la base de donnée, corriger sa + * valeur le cas échéant. + */ + function verifixId(string &$id): void { + } + /** * méthode appelée lors du chargement d'un élément avec * {@link Capacitor::charge()} * * @param mixed $item l'élément à charger - * @param array $values les valeurs calculées par {@link getKeyValues()} + * @param array $updates les valeurs calculées par {@link getKeyValues()} * @param ?array $row la ligne à mettre à jour. vaut null s'il faut insérer * une nouvelle ligne - * @return ?array le cas échéant, un tableau non null à marger dans $values et - * utiliser pour provisionner la ligne nouvelle créée, ou mettre à jour la - * ligne existante + * @return ?array le cas échéant, un tableau non null à merger dans $updates + * et utilisé pour provisionner la ligne nouvellement créée, ou mettre à jour + * la ligne existante * * Si $item est modifié dans cette méthode, il est possible de le retourner - * avec la clé "_item" pour mettre à jour la ligne correspondante + * avec la clé "item" pour mettre à jour la ligne correspondante. + * La colonne "id_" ne peut pas être modifiée: si "id_" est retourné, il est + * ignoré */ - function onCharge($item, array $values, ?array $row): ?array { + function onCharge($item, array $updates, ?array $row): ?array { return null; } @@ -98,12 +116,14 @@ class CapacitorChannel { * {@link Capacitor::each()} * * @param mixed $item l'élément courant - * @param ?array $row la ligne à mettre à jour + * @param ?array $row la ligne à mettre à jour. * @return ?array le cas échéant, un tableau non null utilisé pour mettre à * jour la ligne courante * * Si $item est modifié dans cette méthode, il est possible de le retourner - * avec la clé "_item" pour mettre à jour la ligne correspondante + * avec la clé "item" pour mettre à jour la ligne correspondante + * La colonne "id_" ne peut pas être modifiée: si "id_" est retourné, il est + * ignoré */ function onEach($item, array $row): ?array { return null; diff --git a/php/src/db/CapacitorStorage.php b/php/src/db/CapacitorStorage.php index ed71dbd..110cb29 100644 --- a/php/src/db/CapacitorStorage.php +++ b/php/src/db/CapacitorStorage.php @@ -1,6 +1,9 @@ _charge($this->getChannel($channel), $item, $func, $args); } + abstract function _discharge(CapacitorChannel $channel, bool $reset=true): iterable; + + /** décharger les données du canal spécifié */ + function discharge(?string $channel, bool $reset=true): iterable { + return $this->_discharge($this->getChannel($channel), $reset); + } + abstract function _count(CapacitorChannel $channel, $filter): int; /** indiquer le nombre d'éléments du canal spécifié */ @@ -54,22 +64,26 @@ abstract class CapacitorStorage { return $this->_count($this->getChannel($channel), $filter); } - abstract function _discharge(CapacitorChannel $channel, $filter, ?bool $reset): iterable; - - /** décharger les données du canal spécifié */ - function discharge(?string $channel, $filter=null, ?bool $reset=null): iterable { - return $this->_discharge($this->getChannel($channel), $filter, $reset); - } - - abstract function _get(CapacitorChannel $channel, $filter); + abstract function _one(CapacitorChannel $channel, $filter): ?array; /** - * obtenir l'élément identifié par les clés spécifiées sur le canal spécifié + * obtenir la ligne correspondant au filtre sur le canal spécifié * - * si $filter n'est pas un tableau, il est transformé en ["_id" => $filter] + * si $filter n'est pas un tableau, il est transformé en ["id_" => $filter] */ - function get(?string $channel, $filter) { - return $this->_get($this->getChannel($channel), $filter); + function one(?string $channel, $filter): ?array { + return $this->_one($this->getChannel($channel), $filter); + } + + abstract function _all(CapacitorChannel $channel, $filter): iterable; + + /** + * obtenir les lignes correspondant au filtre sur le canal spécifié + * + * si $filter n'est pas un tableau, il est transformé en ["id_" => $filter] + */ + function all(?string $channel, $filter): iterable { + return $this->_one($this->getChannel($channel), $filter); } abstract function _each(CapacitorChannel $channel, $filter, ?callable $func, ?array $args): int; diff --git a/php/src/db/sqlite/SqliteCapacitor.php b/php/src/db/sqlite/SqliteCapacitor.php deleted file mode 100644 index fed1b16..0000000 --- a/php/src/db/sqlite/SqliteCapacitor.php +++ /dev/null @@ -1,242 +0,0 @@ -sqlite = Sqlite::with($sqlite); - } - - /** @var Sqlite */ - protected $sqlite; - - function sqlite(): Sqlite { - return $this->sqlite; - } - - protected function _create(CapacitorChannel $channel): void { - if (!$channel->isCreated()) { - $columns = cl::merge([ - "_id" => "integer primary key autoincrement", - "_item" => "text", - "_sum" => "varchar(40)", - "_created" => "datetime", - "_modified" => "datetime", - ], $channel->getKeyDefinitions()); - $this->sqlite->exec([ - "create table if not exists", - "table" => $channel->getTableName(), - "cols" => $columns, - ]); - $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", - "where" => [ - "name" => $channel->getTableName(), - ], - ]); - return $tableName !== null; - } - - function _ensureExists(CapacitorChannel $channel): void { - $this->_create($channel); - } - - function _reset(CapacitorChannel $channel): void { - $this->sqlite->exec([ - "drop table if exists", - $channel->getTableName(), - ]); - $channel->setCreated(false); - } - - function _charge(CapacitorChannel $channel, $item, ?callable $func, ?array $args): int { - $this->_create($channel); - $now = date("Y-m-d H:i:s"); - $_item = serialize($item); - $_sum = sha1($_item); - $values = cl::merge([ - "_item" => $_item, - "_sum" => $_sum, - ], $channel->getKeyValues($item)); - $row = null; - $id = $values["_id"] ?? null; - if ($id !== null) { - # modification - $row = $this->sqlite->one([ - "select _item, _sum, _created, _modified", - "from" => $channel->getTableName(), - "where" => ["_id" => $id], - ]); - } - $insert = null; - if ($row === null) { - # création - $values = cl::merge($values, [ - "_created" => $now, - "_modified" => $now, - ]); - $insert = true; - } elseif ($_sum !== $row["_sum"]) { - # modification - $values = cl::merge($values, [ - "_modified" => $now, - ]); - $insert = false; - } - - if ($func === null) $func = [$channel, "onCharge"]; - $onCharge = func::_prepare($func); - $args ??= []; - $updates = func::_call($onCharge, [$item, $values, $row, ...$args]); - if (is_array($updates)) { - if (array_key_exists("_item", $updates)) { - $_item = serialize($updates["_item"]); - $updates["_item"] = $_item; - $updates["_sum"] = sha1($_item); - if (!array_key_exists("_modified", $updates)) { - $updates["_modified"] = $now; - } - } - $values = cl::merge($values, $updates); - } - - if ($insert === null) { - # aucune modification - return 0; - } elseif ($insert) { - $this->sqlite->exec([ - "insert", - "into" => $channel->getTableName(), - "values" => $values, - ]); - } else { - $this->sqlite->exec([ - "update", - "table" => $channel->getTableName(), - "values" => $values, - "where" => ["_id" => $id], - ]); - } - return 1; - } - - function _count(CapacitorChannel $channel, $filter): int { - if ($filter !== null && !is_array($filter)) $filter = ["_id" => $filter]; - return $this->sqlite->get([ - "select count(*)", - "from" => $channel->getTableName(), - "where" => $filter, - ]); - } - - function _discharge(CapacitorChannel $channel, $filter, ?bool $reset): iterable { - if ($filter !== null && !is_array($filter)) $filter = ["_id" => $filter]; - if ($reset === null) $reset = $filter === null; - $rows = $this->sqlite->all([ - "select _item", - "from" => $channel->getTableName(), - "where" => $filter, - ]); - foreach ($rows as $row) { - $item = unserialize($row['_item']); - yield $item; - } - if ($reset) $this->_reset($channel); - } - - function _get(CapacitorChannel $channel, $filter) { - if ($filter === null) throw ValueException::null("keys"); - if (!is_array($filter)) $filter = ["_id" => $filter]; - $row = $this->sqlite->one([ - "select _item", - "from" => $channel->getTableName(), - "where" => $filter, - ]); - if ($row === null) return null; - else return unserialize($row["_item"]); - } - - function _each(CapacitorChannel $channel, $filter, ?callable $func, ?array $args): int { - if ($func === null) $func = [$channel, "onEach"]; - $onEach = func::_prepare($func); - if ($filter !== null && !is_array($filter)) $filter = ["_id" => $filter]; - $sqlite = $this->sqlite; - $tableName = $channel->getTableName(); - $commited = false; - $count = 0; - $sqlite->beginTransaction(); - $commitThreshold = $channel->getEachCommitThreshold(); - try { - $rows = $sqlite->all([ - "select", - "from" => $tableName, - "where" => $filter, - ]); - $args ??= []; - foreach ($rows as $row) { - $item = unserialize($row['_item']); - $updates = func::_call($onEach, [$item, $row, ...$args]); - if (is_array($updates)) { - if (array_key_exists("_item", $updates)) { - $updates["_item"] = serialize($updates["_item"]); - } - $sqlite->exec([ - "update", - "table" => $tableName, - "values" => $updates, - "where" => ["_id" => $row["_id"]], - ]); - if ($commitThreshold !== null) { - $commitThreshold--; - if ($commitThreshold == 0) { - $sqlite->commit(); - $sqlite->beginTransaction(); - $commitThreshold = $channel->getEachCommitThreshold(); - } - } - } - $count++; - } - $sqlite->commit(); - $commited = true; - return $count; - } finally { - if (!$commited) $sqlite->rollback(); - } - } - - function close(): void { - $this->sqlite->close(); - } -} diff --git a/php/src/db/sqlite/SqliteStorage.php b/php/src/db/sqlite/SqliteStorage.php new file mode 100644 index 0000000..ca23c88 --- /dev/null +++ b/php/src/db/sqlite/SqliteStorage.php @@ -0,0 +1,309 @@ +sqlite = Sqlite::with($sqlite); + } + + /** @var Sqlite */ + protected $sqlite; + + function sqlite(): Sqlite { + 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()); + $this->sqlite->exec([ + "create table if not exists", + "table" => $channel->getTableName(), + "cols" => $columns, + ]); + $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", + "where" => [ + "name" => $channel->getTableName(), + ], + ]); + return $tableName !== null; + } + + function _ensureExists(CapacitorChannel $channel): void { + $this->_create($channel); + } + + function _reset(CapacitorChannel $channel): void { + $this->sqlite->exec([ + "drop table if exists", + $channel->getTableName(), + ]); + $channel->setCreated(false); + } + + function _charge(CapacitorChannel $channel, $item, ?callable $func, ?array $args): int { + $this->_create($channel); + $now = date("Y-m-d H:i:s"); + $item__ = serialize($item); + $sum_ = sha1($item__); + $row = cl::merge([ + "item__" => $item__, + "sum_" => $sum_, + ], $this->unserialize($channel, $channel->getKeyValues($item))); + $prow = null; + $id_ = $row["id_"] ?? null; + if ($id_ !== null) { + # modification + $prow = $this->sqlite->one([ + "select id_, item__, sum_, created_, modified_", + "from" => $channel->getTableName(), + "where" => ["id_" => $id_], + ]); + } + $insert = null; + if ($prow === null) { + # création + $row = cl::merge($row, [ + "created_" => $now, + "modified_" => $now, + ]); + $insert = true; + } elseif ($sum_ !== $prow["sum_"]) { + # modification + $row = cl::merge($row, [ + "modified_" => $now, + ]); + $insert = false; + } + + if ($func === null) $func = [$channel, "onCharge"]; + $onCharge = func::_prepare($func); + $args ??= []; + $values = $this->unserialize($channel, $row); + $pvalues = $this->unserialize($channel, $prow); + $updates = func::_call($onCharge, [$item, $values, $pvalues, ...$args]); + if (is_array($updates)) { + $updates = $this->serialize($channel, $updates); + if (array_key_exists("item__", $updates)) { + # si item a été mis à jour, il faut mettre à jour sum_ + $updates["sum_"] = sha1($updates["item__"]); + if (!array_key_exists("modified_", $updates)) { + $updates["modified_"] = $now; + } + } + $row = cl::merge($row, $updates); + } + + if ($insert === null) { + # aucune modification + return 0; + } elseif ($insert) { + $this->sqlite->exec([ + "insert", + "into" => $channel->getTableName(), + "values" => $row, + ]); + } else { + $this->sqlite->exec([ + "update", + "table" => $channel->getTableName(), + "values" => $row, + "where" => ["id_" => $id_], + ]); + } + return 1; + } + + function _discharge(CapacitorChannel $channel, bool $reset=true): iterable { + $rows = $this->sqlite->all([ + "select item__", + "from" => $channel->getTableName(), + ]); + foreach ($rows as $row) { + yield unserialize($row['item__']); + } + if ($reset) $this->_reset($channel); + } + + protected function verifixFilter(CapacitorChannel $channel, &$filter): void { + if ($filter !== null && !is_array($filter)) { + $id = $filter; + $channel->verifixId($id); + $filter = ["id_" => $id]; + } + $filter = $this->serialize($channel, $filter); + } + + function _count(CapacitorChannel $channel, $filter): int { + $this->verifixFilter($channel, $filter); + return $this->sqlite->get([ + "select count(*)", + "from" => $channel->getTableName(), + "where" => $filter, + ]); + } + + function _one(CapacitorChannel $channel, $filter): ?array { + if ($filter === null) throw ValueException::null("filter"); + $this->verifixFilter($channel, $filter); + $row = $this->sqlite->one([ + "select", + "from" => $channel->getTableName(), + "where" => $filter, + ]); + return $this->unserialize($channel, $row); + } + + function _all(CapacitorChannel $channel, $filter): iterable { + $this->verifixFilter($channel, $filter); + $rows = $this->sqlite->all([ + "select", + "from" => $channel->getTableName(), + "where" => $filter, + ]); + foreach ($rows as $row) { + yield $this->unserialize($channel, $row); + } + } + + function _each(CapacitorChannel $channel, $filter, ?callable $func, ?array $args): int { + if ($func === null) $func = [$channel, "onEach"]; + $onEach = func::_prepare($func); + $sqlite = $this->sqlite; + $tableName = $channel->getTableName(); + $commited = false; + $count = 0; + $sqlite->beginTransaction(); + $commitThreshold = $channel->getEachCommitThreshold(); + try { + $args ??= []; + foreach ($this->_all($channel, $filter) as $row) { + $updates = func::_call($onEach, [$row["item"], $row, ...$args]); + if (is_array($updates)) { + $updates = $this->serialize($channel, $updates); + if (array_key_exists("item__", $updates)) { + # si item a été mis à jour, il faut mettre à jour sum_ + $updates["sum_"] = sha1($updates["item__"]); + if (!array_key_exists("modified_", $updates)) { + $updates["modified_"] = date("Y-m-d H:i:s"); + } + } + $sqlite->exec([ + "update", + "table" => $tableName, + "values" => $updates, + "where" => ["id_" => $row["id_"]], + ]); + if ($commitThreshold !== null) { + $commitThreshold--; + if ($commitThreshold == 0) { + $sqlite->commit(); + $sqlite->beginTransaction(); + $commitThreshold = $channel->getEachCommitThreshold(); + } + } + } + $count++; + } + $sqlite->commit(); + $commited = true; + return $count; + } finally { + if (!$commited) $sqlite->rollback(); + } + } + + function close(): void { + $this->sqlite->close(); + } +} diff --git a/php/src/db/sqlite/_query.php b/php/src/db/sqlite/_query.php index 647cd6b..9f4f038 100644 --- a/php/src/db/sqlite/_query.php +++ b/php/src/db/sqlite/_query.php @@ -109,9 +109,12 @@ class _query { $value = $cond[$condkeys[$condkey]]; $condkey++; } - } else { + } elseif ($cond !== null) { $op = "="; $value = $cond; + } else { + $op = "is null"; + $value = null; } $cond = [$key, $op]; if ($value !== null) { diff --git a/php/src/file/app/RunFile.php b/php/src/file/app/RunFile.php index 501930d..52679be 100644 --- a/php/src/file/app/RunFile.php +++ b/php/src/file/app/RunFile.php @@ -39,6 +39,8 @@ class RunFile { $dateStart = $withDateStart? new DateTime(): null; return [ "name" => $this->name, + "id" => bin2hex(random_bytes(16)), + "pid" => posix_getpid(), "serial" => 0, "date_start" => $dateStart, "date_stop" => null, diff --git a/php/src/text/Word.php b/php/src/text/Word.php index b514872..4c73019 100644 --- a/php/src/text/Word.php +++ b/php/src/text/Word.php @@ -44,7 +44,7 @@ class Word { $spec = substr($spec, strlen($ms[0])); } elseif (preg_match('/^m(asc(ulin)?)?\s*:\s*/i', $spec, $ms)) { $fem = false; - $spec = substr($spec, $ms[0]); + $spec = substr($spec, strlen($ms[0])); } elseif (preg_match('/\s*\|f(?:[eé]m(?:inin)?)?\s*$/iu', $spec, $ms, PREG_OFFSET_CAPTURE)) { $fem = true; $spec = substr($spec, 0, $ms[0][1]); diff --git a/php/tests/db/sqlite/SqliteCapacitorTest.php b/php/tests/db/sqlite/SqliteStorageTest.php similarity index 61% rename from php/tests/db/sqlite/SqliteCapacitorTest.php rename to php/tests/db/sqlite/SqliteStorageTest.php index 1d324c7..65ac92f 100644 --- a/php/tests/db/sqlite/SqliteCapacitorTest.php +++ b/php/tests/db/sqlite/SqliteStorageTest.php @@ -5,32 +5,32 @@ use nulib\tests\TestCase; use nulib\db\Capacitor; use nulib\db\CapacitorChannel; -class SqliteCapacitorTest extends TestCase { - function _testChargeStrings(SqliteCapacitor $capacitor, ?string $channel) { - $capacitor->reset($channel); - $capacitor->charge($channel, "first"); - $capacitor->charge($channel, "second"); - $capacitor->charge($channel, "third"); - $items = iterator_to_array($capacitor->discharge($channel, null, false)); +class SqliteStorageTest extends TestCase { + function _testChargeStrings(SqliteStorage $storage, ?string $channel) { + $storage->reset($channel); + $storage->charge($channel, "first"); + $storage->charge($channel, "second"); + $storage->charge($channel, "third"); + $items = iterator_to_array($storage->discharge($channel, false)); self::assertSame(["first", "second", "third"], $items); } - function _testChargeArrays(SqliteCapacitor $capacitor, ?string $channel) { - $capacitor->reset($channel); - $capacitor->charge($channel, ["id" => 10, "name" => "first"]); - $capacitor->charge($channel, ["name" => "second", "id" => 20]); - $capacitor->charge($channel, ["name" => "third", "id" => "30"]); + function _testChargeArrays(SqliteStorage $storage, ?string $channel) { + $storage->reset($channel); + $storage->charge($channel, ["id" => 10, "name" => "first"]); + $storage->charge($channel, ["name" => "second", "id" => 20]); + $storage->charge($channel, ["name" => "third", "id" => "30"]); } function testChargeStrings() { - $capacitor = new SqliteCapacitor(__DIR__.'/capacitor.db'); - $this->_testChargeStrings($capacitor, null); - $capacitor->close(); + $storage = new SqliteStorage(__DIR__.'/capacitor.db'); + $this->_testChargeStrings($storage, null); + $storage->close(); } function testChargeArrays() { - $capacitor = new SqliteCapacitor(__DIR__.'/capacitor.db'); - $capacitor->addChannel(new class extends CapacitorChannel { + $storage = new SqliteStorage(__DIR__.'/capacitor.db'); + $storage->addChannel(new class extends CapacitorChannel { const NAME = "arrays"; function getKeyDefinitions(): ?array { return ["id" => "integer"]; @@ -40,14 +40,14 @@ class SqliteCapacitorTest extends TestCase { } }); - $this->_testChargeStrings($capacitor, "strings"); - $this->_testChargeArrays($capacitor, "arrays"); - $capacitor->close(); + $this->_testChargeStrings($storage, "strings"); + $this->_testChargeArrays($storage, "arrays"); + $storage->close(); } function testEach() { - $capacitor = new SqliteCapacitor(__DIR__.'/capacitor.db'); - $capacitor = new Capacitor($capacitor, new class extends CapacitorChannel { + $storage = new SqliteStorage(__DIR__.'/capacitor.db'); + $capacitor = new Capacitor($storage, new class extends CapacitorChannel { const NAME = "each"; function getKeyDefinitions(): ?array { @@ -73,7 +73,7 @@ class SqliteCapacitorTest extends TestCase { $updates = ["done" => 1]; if ($suffix !== null) { $item["name"] .= $suffix; - $updates["_item"] = $item; + $updates["item"] = $item; } return $updates; }; @@ -86,19 +86,19 @@ class SqliteCapacitorTest extends TestCase { } function testPrimayKey() { - $capacitor = new SqliteCapacitor(__DIR__.'/capacitor.db'); - $capacitor = new Capacitor($capacitor, new class extends CapacitorChannel { + $storage = new SqliteStorage(__DIR__.'/capacitor.db'); + $capacitor = new Capacitor($storage, new class extends CapacitorChannel { const NAME = "pk"; function getKeyDefinitions(): ?array { return [ - "_id" => "varchar primary key", + "id_" => "varchar primary key", "done" => "integer default 0", ]; } function getKeyValues($item): ?array { return [ - "_id" => $item["numero"], + "id_" => $item["numero"], ]; } }); diff --git a/php/tests/db/sqlite/_queryTest.php b/php/tests/db/sqlite/_queryTest.php index 30290de..92c232d 100644 --- a/php/tests/db/sqlite/_queryTest.php +++ b/php/tests/db/sqlite/_queryTest.php @@ -15,6 +15,11 @@ class _queryTest extends TestCase { self::assertNull($sql); self::assertNull($params); + $sql = $params = null; + _query::parse_conds(["col" => null], $sql, $params); + self::assertSame(["col is null"], $sql); + self::assertNull($params); + $sql = $params = null; _query::parse_conds(["col = 'value'"], $sql, $params); self::assertSame(["col = 'value'"], $sql);