From 96e046d5bffaec2edf6cecad98dd863f9077334d Mon Sep 17 00:00:00 2001 From: Jephte Clain Date: Mon, 15 Sep 2025 17:30:25 +0400 Subject: [PATCH] modifs.mineures sans commentaires --- .idea/php-docker-settings.xml | 15 +++ php/src/db/Capacitor.php | 68 +++++++----- php/src/db/CapacitorChannel.php | 17 +-- php/tests/db/sqlite/ChannelMigrationTest.php | 16 +-- php/tests/db/sqlite/SqliteCapacitorTest.php | 107 ++++++++++--------- 5 files changed, 135 insertions(+), 88 deletions(-) diff --git a/.idea/php-docker-settings.xml b/.idea/php-docker-settings.xml index bd786be..047d43d 100644 --- a/.idea/php-docker-settings.xml +++ b/.idea/php-docker-settings.xml @@ -17,6 +17,21 @@ + + + + + + + diff --git a/php/src/db/Capacitor.php b/php/src/db/Capacitor.php index f136fae..de8d1a1 100644 --- a/php/src/db/Capacitor.php +++ b/php/src/db/Capacitor.php @@ -21,6 +21,14 @@ abstract class Capacitor { return $this; } + function newChannel($channel): CapacitorChannel { + if (!($channel instanceof CapacitorChannel)) { + if (!is_array($channel)) $channel = ["name" => $channel]; + $channel = new CapacitorChannel($channel); + } + return $channel->initCapacitor($this); + } + # les définitions sont par défaut pour MariaDB/MySQL const CDATA_DEFINITION = "mediumtext"; const CSUM_DEFINITION = "varchar(40)"; @@ -179,6 +187,9 @@ abstract class Capacitor { else return $rowIds; } + ############################################################################# + # Migration et metadata + abstract protected function tableExists(string $tableName): bool; const METADATA_TABLE = "_metadata"; @@ -216,6 +227,9 @@ abstract class Capacitor { abstract function getMigration(CapacitorChannel $channel): _migration; + ############################################################################# + # Catalogue + const CATALOG_TABLE = "_channels"; const CATALOG_COLS = [ "name" => "varchar not null primary key", @@ -259,21 +273,7 @@ abstract class Capacitor { return $raw !== null; } - function _create(CapacitorChannel $channel): void { - if (!$this->tableExists($channel->getTableName())) { - $this->prepareMetadata(); - $this->getMigration($channel)->migrate($this->db()); - $this->afterCreate($channel); - } - } - - function create(CapacitorChannel $channel, bool $force=false): void { - if ($force || !$channel->isCreated()) { - $channel->ensureSetup(); - $this->_create($channel); - $channel->setCreated(); - } - } + ############################################################################# protected function afterCreate(CapacitorChannel $channel): void { $db = $this->db(); @@ -281,6 +281,20 @@ abstract class Capacitor { $db->exec($this->addToCatalogSql($channel)); } + function create(CapacitorChannel $channel): void { + $this->prepareMetadata(); + $this->getMigration($channel)->migrate($this->db()); + $this->afterCreate($channel); + } + + function autocreate(CapacitorChannel $channel, bool $force=false): void { + if ($force || !$channel->isCreated()) { + $channel->ensureSetup(); + $this->create($channel); + $channel->setCreated(); + } + } + /** tester si le canal spécifié existe */ function exists(CapacitorChannel $channel): bool { return $this->tableExists($channel->getTableName()); @@ -313,7 +327,7 @@ abstract class Capacitor { $channel->getTableName(), ]); $channel->setCreated(false); - if ($recreate) $this->create($channel); + if ($recreate) $this->autocreate($channel); } /** @@ -341,7 +355,8 @@ abstract class Capacitor { * déjà à l'identique dans le canal */ function charge(CapacitorChannel $channel, $item, $func=null, ?array $args=null, ?array &$row=null): int { - $this->create($channel); + $channel->initCapacitor($this); + $tableName = $channel->getTableName(); $db = $this->db(); $args ??= []; @@ -488,7 +503,8 @@ abstract class Capacitor { * fournie */ function discharge(CapacitorChannel $channel, bool $reset=true): Traversable { - $this->create($channel); + $channel->initCapacitor($this); + $raws = $this->db()->all([ "select item__", "from" => $channel->getTableName(), @@ -537,8 +553,9 @@ abstract class Capacitor { /** indiquer le nombre d'éléments du canal spécifié */ function count(CapacitorChannel $channel, $filter): int { - $this->create($channel); + $channel->initCapacitor($this); $this->verifixFilter($channel, $filter); + return $this->db()->get([ "select count(*)", "from" => $channel->getTableName(), @@ -552,9 +569,9 @@ abstract class Capacitor { * si $filter n'est pas un tableau, il est transformé en ["id_" => $filter] */ function one(CapacitorChannel $channel, $filter, ?array $mergeQuery=null): ?array { - if ($filter === null) throw ValueException::null("filter"); - $this->create($channel); + $channel->initCapacitor($this); $this->verifixFilter($channel, $filter); + $raw = $this->db()->one(cl::merge([ "select", "from" => $channel->getTableName(), @@ -569,8 +586,9 @@ abstract class Capacitor { * si $filter n'est pas un tableau, il est transformé en ["id_" => $filter] */ function all(CapacitorChannel $channel, $filter, ?array $mergeQuery=null): Traversable { - $this->create($channel); + $channel->initCapacitor($this); $this->verifixFilter($channel, $filter); + $raws = $this->db()->all(cl::merge([ "select", "from" => $channel->getTableName(), @@ -594,7 +612,8 @@ abstract class Capacitor { * @return int le nombre de lignes parcourues */ function each(CapacitorChannel $channel, $filter, $func=null, ?array $args=null, ?array $mergeQuery=null, ?int &$nbUpdated=null): int { - $this->create($channel); + $channel->initCapacitor($this); + if ($func === null) $func = CapacitorChannel::onEach; $onEach = func::with($func)->bind($channel); $db = $this->db(); @@ -660,7 +679,8 @@ abstract class Capacitor { * @return int le nombre de lignes parcourues */ function delete(CapacitorChannel $channel, $filter, $func=null, ?array $args=null): int { - $this->create($channel); + $channel->initCapacitor($this); + if ($func === null) $func = CapacitorChannel::onDelete; $onDelete = func::with($func)->bind($channel); $db = $this->db(); diff --git a/php/src/db/CapacitorChannel.php b/php/src/db/CapacitorChannel.php index f3aa911..8151abf 100644 --- a/php/src/db/CapacitorChannel.php +++ b/php/src/db/CapacitorChannel.php @@ -55,9 +55,8 @@ class CapacitorChannel implements ITransactor { return $eachCommitThreshold; } - function __construct(?Capacitor $capacitor=null, ?array $params=null) { - $capacitor ??= $params["storage"] ?? null; - $this->capacitor = $capacitor; + function __construct(?array $params=null) { + $this->capacitor = null; $name = $params["name"] ?? static::NAME; $tableName = $params["tableName"] ?? static::TABLE_NAME; @@ -65,8 +64,9 @@ class CapacitorChannel implements ITransactor { $this->name = $name; $this->tableName = $tableName; - $autocreate = $params["autocreate"] ?? null; - $autocreate ??= !app::get()->isProductionMode(); + #$autocreate = $params["autocreate"] ?? null; + #$autocreate ??= !app::get()->isProductionMode(); + $autocreate = true; #XXX $this->created = !$autocreate; $this->setup = false; @@ -423,8 +423,9 @@ class CapacitorChannel implements ITransactor { return $this->capacitor; } - function initCapacitor(Capacitor $capacitor): self { - $this->capacitor = $capacitor; + function initCapacitor(Capacitor $capacitor, bool $autocreate=true): self { + if ($this->capacitor === null) $this->capacitor = $capacitor; + if ($autocreate) $this->capacitor->autocreate($this); return $this; } @@ -530,7 +531,7 @@ class CapacitorChannel implements ITransactor { } function charge($item, $func=null, ?array $args=null, ?array &$row=null): int { - return $this->capacitor->charge($item, $func, $args, $row); + return $this->capacitor->charge($this, $item, $func, $args, $row); } function chargeAll(?iterable $items, $func=null, ?array $args=null): int { diff --git a/php/tests/db/sqlite/ChannelMigrationTest.php b/php/tests/db/sqlite/ChannelMigrationTest.php index e399d15..799cf18 100644 --- a/php/tests/db/sqlite/ChannelMigrationTest.php +++ b/php/tests/db/sqlite/ChannelMigrationTest.php @@ -30,23 +30,23 @@ class ChannelMigrationTest extends TestCase { } function testMigration() { - $storage = new SqliteCapacitor(__DIR__.'/capacitor.db'); + $capacitor = new SqliteCapacitor(__DIR__.'/capacitor.db'); $data = [ ["first", "premier", new DateTime(), new DateTime(), 15], ["second", "deuxieme", new DateTime(), new DateTime(), 15], ]; - new Capacitor($storage, $channel = new MyChannel()); + $capacitor->newChannel($channel = new MyChannel()); $channel->reset(true); $this->addData($channel, $data); - new Capacitor($storage, $channel = new MyChannelV2()); + $capacitor->newChannel($channel = new MyChannelV2()); $this->addData($channel, $data); - new Capacitor($storage, $channel = new MyChannelV3()); + $capacitor->newChannel($channel = new MyChannelV3()); $this->addData($channel, $data); - $sql = $channel->getCapacitor()->getCreateChannelSql(); + $sql = $channel->getCreateSql(); $class = MyChannelV3::class; $expected = <<newChannel($channel = new MyIndexChannel()); $channel->reset(true); $channel->chargeAll($data); - $sql = $channel->getCapacitor()->getCreateChannelSql(); + $sql = $channel->getCreateSql(); $class = MyIndexChannel::class; $expected = <<newChannel(null); $this->_testChargeStrings($capacitor, $channel); + self::Txx(cl::all($capacitor->discharge($channel, false))); + + $channel = $capacitor->newChannel("strings"); + $this->_testChargeStrings($capacitor, $channel); + self::Txx(cl::all($capacitor->discharge($channel, false))); + $capacitor->close(); + self::assertTrue(true); } function testChargeArrays() { $capacitor = new SqliteCapacitor(__DIR__.'/capacitor.db'); - $channel = new class extends CapacitorChannel { + + $channel = $capacitor->newChannel(new class extends CapacitorChannel { const NAME = "arrays"; const COLUMN_DEFINITIONS = ["id" => "integer"]; function getItemValues($item): ?array { return ["id" => $item["id"] ?? null]; } - }; + }); + $this->_testChargeArrays($capacitor, $channel); + self::Txx(cl::all($capacitor->discharge($channel, false))); - $this->_testChargeStrings($capacitor, "strings"); - $this->_testChargeArrays($capacitor, "arrays"); $capacitor->close(); + self::assertTrue(true); } function testEach() { - $storage = new SqliteCapacitor(__DIR__.'/capacitor.db'); - $capacitor = new Capacitor($storage, new class extends CapacitorChannel { + $capacitor = new SqliteCapacitor(__DIR__.'/capacitor.db'); + $each = $capacitor->newChannel(new class extends CapacitorChannel { const NAME = "each"; const COLUMN_DEFINITIONS = [ "age" => "integer", @@ -68,11 +78,11 @@ class SqliteCapacitorTest extends TestCase { } }); - $capacitor->reset(); - $capacitor->charge(["name" => "first", "age" => 5]); - $capacitor->charge(["name" => "second", "age" => 10]); - $capacitor->charge(["name" => "third", "age" => 15]); - $capacitor->charge(["name" => "fourth", "age" => 20]); + $capacitor->reset($each); + $capacitor->charge($each, ["name" => "first", "age" => 5]); + $capacitor->charge($each, ["name" => "second", "age" => 10]); + $capacitor->charge($each, ["name" => "third", "age" => 15]); + $capacitor->charge($each, ["name" => "fourth", "age" => 20]); $setDone = function ($row, $suffix=null) { $item = $row["item"]; @@ -83,17 +93,18 @@ class SqliteCapacitorTest extends TestCase { } return $updates; }; - $capacitor->each(["age" => [">", 10]], $setDone, ["++"]); - $capacitor->each(["done" => 0], $setDone); + $capacitor->each($each, ["age" => [">", 10]], $setDone, ["++"]); + $capacitor->each($each, ["done" => 0], $setDone); + + self::Txx(cl::all($capacitor->discharge($each, false))); - self::Txx(cl::all($capacitor->discharge(false))); $capacitor->close(); self::assertTrue(true); } function testPrimayKey() { - $storage = new SqliteCapacitor(__DIR__.'/capacitor.db'); - $capacitor = new Capacitor($storage, new class extends CapacitorChannel { + $capacitor = new SqliteCapacitor(__DIR__.'/capacitor.db'); + $channel = $capacitor->newChannel(new class extends CapacitorChannel { const NAME = "pk"; const COLUMN_DEFINITIONS = [ "id_" => "varchar primary key", @@ -107,21 +118,23 @@ class SqliteCapacitorTest extends TestCase { } }); - $capacitor->charge(["numero" => "a", "name" => "first", "age" => 5]); - $capacitor->charge(["numero" => "b", "name" => "second", "age" => 10]); - $capacitor->charge(["numero" => "c", "name" => "third", "age" => 15]); - $capacitor->charge(["numero" => "d", "name" => "fourth", "age" => 20]); + $capacitor->charge($channel, ["numero" => "a", "name" => "first", "age" => 5]); + $capacitor->charge($channel, ["numero" => "b", "name" => "second", "age" => 10]); + $capacitor->charge($channel, ["numero" => "c", "name" => "third", "age" => 15]); + $capacitor->charge($channel, ["numero" => "d", "name" => "fourth", "age" => 20]); sleep(2); - $capacitor->charge(["numero" => "b", "name" => "second", "age" => 100]); - $capacitor->charge(["numero" => "d", "name" => "fourth", "age" => 200]); + $capacitor->charge($channel, ["numero" => "b", "name" => "second", "age" => 100]); + $capacitor->charge($channel, ["numero" => "d", "name" => "fourth", "age" => 200]); + + self::Txx(cl::all($capacitor->discharge($channel, false))); $capacitor->close(); self::assertTrue(true); } function testSum() { - $storage = new SqliteCapacitor(__DIR__.'/capacitor.db'); - $capacitor = new Capacitor($storage, new class extends CapacitorChannel { + $capacitor = new SqliteCapacitor(__DIR__.'/capacitor.db'); + $channel = $capacitor->newChannel(new class extends CapacitorChannel { const NAME = "sum"; const COLUMN_DEFINITIONS = [ "a__" => "varchar", @@ -137,19 +150,17 @@ class SqliteCapacitorTest extends TestCase { } }); - $capacitor->reset(); - $capacitor->charge(["a" => null, "b" => null]); - $capacitor->charge(["a" => "first", "b" => "second"]); + $capacitor->reset($channel); + $capacitor->charge($channel, ["a" => null, "b" => null]); + $capacitor->charge($channel, ["a" => "first", "b" => "second"]); self::Txx("=== all"); - /** @var Sqlite $sqlite */ - $sqlite = $capacitor->getStorage()->db(); - self::Txx(cl::all($sqlite->all([ + self::Txx(cl::all($capacitor->db()->all([ "select", - "from" => $capacitor->getChannel()->getTableName(), + "from" => $channel->getTableName(), ]))); self::Txx("=== each"); - $capacitor->each(null, function ($row) { + $capacitor->each($channel, null, function ($row) { self::Txx($row); }); @@ -159,8 +170,8 @@ class SqliteCapacitorTest extends TestCase { function testEachValues() { # tester que values contient bien toutes les valeurs de la ligne - $storage = new SqliteCapacitor(__DIR__.'/capacitor.db'); - $capacitor = new Capacitor($storage, new class extends CapacitorChannel { + $capacitor = new SqliteCapacitor(__DIR__.'/capacitor.db'); + $channel = $capacitor->newChannel(new class extends CapacitorChannel { const NAME = "each_values"; const COLUMN_DEFINITIONS = [ "name" => "varchar primary key", @@ -177,8 +188,8 @@ class SqliteCapacitorTest extends TestCase { } }); - $capacitor->reset(); - $capacitor->charge(["name" => "first", "age" => 5], function($item, ?array $row, ?array $prow) { + $capacitor->reset($channel); + $capacitor->charge($channel, ["name" => "first", "age" => 5], function($item, ?array $row, ?array $prow) { self::assertSame("first", $item["name"]); self::assertSame(5, $item["age"]); self::assertnotnull($row); @@ -190,7 +201,7 @@ class SqliteCapacitorTest extends TestCase { ], cl::select($row, ["name", "age", "item"])); self::assertNull($prow); }); - $capacitor->charge(["name" => "first", "age" => 10], function($item, ?array $row, ?array $prow) { + $capacitor->charge($channel, ["name" => "first", "age" => 10], function($item, ?array $row, ?array $prow) { self::assertSame("first", $item["name"]); self::assertSame(10, $item["age"]); self::assertnotnull($row); @@ -212,7 +223,7 @@ class SqliteCapacitorTest extends TestCase { ], cl::select($prow, ["name", "age", "done", "notes", "item"])); }); - $capacitor->each(null, function(array $row) { + $capacitor->each($channel, null, function(array $row) { $item = $row["item"]; self::assertSame("first", $item["name"]); self::assertSame(10, $item["age"]); @@ -230,7 +241,7 @@ class SqliteCapacitorTest extends TestCase { "notes" => "modified", ]; }); - $capacitor->charge(["name" => "first", "age" => 10], function($item, ?array $row, ?array $prow) { + $capacitor->charge($channel, ["name" => "first", "age" => 10], function($item, ?array $row, ?array $prow) { self::assertSame("first", $item["name"]); self::assertSame(10, $item["age"]); self::assertnotnull($row); @@ -252,7 +263,7 @@ class SqliteCapacitorTest extends TestCase { ], cl::select($prow, ["name", "age", "done", "notes", "item"])); }); - $capacitor->charge(["name" => "first", "age" => 20], function($item, ?array $row, ?array $prow) { + $capacitor->charge($channel, ["name" => "first", "age" => 20], function($item, ?array $row, ?array $prow) { self::assertSame("first", $item["name"]); self::assertSame(20, $item["age"]); self::assertnotnull($row); @@ -277,8 +288,8 @@ class SqliteCapacitorTest extends TestCase { function testSetItemNull() { # tester le forçage de $îtem à null pour économiser la place - $storage = new SqliteCapacitor(__DIR__.'/capacitor.db'); - $capacitor = new Capacitor($storage, new class extends CapacitorChannel { + $capacitor = new SqliteCapacitor(__DIR__.'/capacitor.db'); + $channel = $capacitor->newChannel(new class extends CapacitorChannel { const NAME = "set_item_null"; const COLUMN_DEFINITIONS = [ "name" => "varchar primary key", @@ -295,8 +306,8 @@ class SqliteCapacitorTest extends TestCase { } }); - $capacitor->reset(); - $nbModified = $capacitor->charge(["name" => "first", "age" => 5], function ($item, ?array $row, ?array $prow) { + $capacitor->reset($channel); + $nbModified = $capacitor->charge($channel, ["name" => "first", "age" => 5], function ($item, ?array $row, ?array $prow) { self::assertSame([ "name" => "first", "age" => 5, "item" => $item, @@ -307,7 +318,7 @@ class SqliteCapacitorTest extends TestCase { sleep(1); # nb: on met des sleep() pour que la date de modification soit systématiquement différente - $nbModified = $capacitor->charge(["name" => "first", "age" => 10], function ($item, ?array $row, ?array $prow) { + $nbModified = $capacitor->charge($channel, ["name" => "first", "age" => 10], function ($item, ?array $row, ?array $prow) { self::assertSame([ "name" => "first", "age" => 10, "item" => $item, "item__sum_" => "9181336dfca20c86313d6065d89aa2ad5070b0fc", @@ -322,7 +333,7 @@ class SqliteCapacitorTest extends TestCase { sleep(1); # pas de modification ici - $nbModified = $capacitor->charge(["name" => "first", "age" => 10], function ($item, ?array $row, ?array $prow) { + $nbModified = $capacitor->charge($channel, ["name" => "first", "age" => 10], function ($item, ?array $row, ?array $prow) { self::assertSame([ "name" => "first", "age" => 10, "item" => $item, "item__sum_" => "9181336dfca20c86313d6065d89aa2ad5070b0fc", @@ -336,7 +347,7 @@ class SqliteCapacitorTest extends TestCase { self::assertSame(0, $nbModified); sleep(1); - $nbModified = $capacitor->charge(["name" => "first", "age" => 20], function ($item, ?array $row, ?array $prow) { + $nbModified = $capacitor->charge($channel, ["name" => "first", "age" => 20], function ($item, ?array $row, ?array $prow) { self::assertSame([ "name" => "first", "age" => 20, "item" => $item, "item__sum_" => "001b91982b4e0883b75428c0eb28573a5dc5f7a5",