début d'implémentation capacitor
This commit is contained in:
		
							parent
							
								
									52700ee53b
								
							
						
					
					
						commit
						a3ae6847d4
					
				@ -11,6 +11,25 @@ use SQLite3Stmt;
 | 
			
		||||
 * Class Sqlite: frontend vers une base de données sqlite3
 | 
			
		||||
 */
 | 
			
		||||
class Sqlite {
 | 
			
		||||
  static function with($sqlite, ?array $params=null): self {
 | 
			
		||||
    if ($sqlite instanceof static) {
 | 
			
		||||
      return $sqlite;
 | 
			
		||||
    } elseif ($sqlite instanceof self) {
 | 
			
		||||
      # recréer avec les mêmes paramètres
 | 
			
		||||
      return new static(null, cl::merge([
 | 
			
		||||
        "file" => $sqlite->file,
 | 
			
		||||
        "flags" => $sqlite->flags,
 | 
			
		||||
        "encryption_key" => $sqlite->encryptionKey,
 | 
			
		||||
        "config" => $sqlite->config,
 | 
			
		||||
        "migrate" => $sqlite->migration,
 | 
			
		||||
      ], $params));
 | 
			
		||||
    } elseif (is_array($sqlite)) {
 | 
			
		||||
      return new static(null, cl::merge($sqlite, $params));
 | 
			
		||||
    } else {
 | 
			
		||||
      return new static($sqlite, $params);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  static function config_enableExceptions(self $sqlite) {
 | 
			
		||||
    $sqlite->db->enableExceptions(true);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										137
									
								
								src/db/sqlite/SqliteCapacitor.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										137
									
								
								src/db/sqlite/SqliteCapacitor.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,137 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace nur\sery\db\sqlite;
 | 
			
		||||
 | 
			
		||||
use nur\sery\cl;
 | 
			
		||||
use nur\sery\php\func;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Class SqliteCapacitor: objet permettant d'accumuler des données pour les
 | 
			
		||||
 * réutiliser plus tard
 | 
			
		||||
 */
 | 
			
		||||
class SqliteCapacitor {
 | 
			
		||||
  function __construct($sqlite) {
 | 
			
		||||
    $this->sqlite = Sqlite::with($sqlite);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /** @var Sqlite */
 | 
			
		||||
  protected $sqlite;
 | 
			
		||||
 | 
			
		||||
  protected function getTableName(?string $channel): string {
 | 
			
		||||
    return ($channel ?? "default")."_channel";
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /** tester si le canal spécifié existe */
 | 
			
		||||
  function exists(?string $channel=null): bool {
 | 
			
		||||
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /** supprimer le canal spécifié */
 | 
			
		||||
  function reset(?string $channel=null) {
 | 
			
		||||
    $tableName = $this->getTableName($channel);
 | 
			
		||||
    $this->sqlite->exec("drop table if exists $tableName");
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /** @var array */
 | 
			
		||||
  protected $created;
 | 
			
		||||
 | 
			
		||||
  protected function getKeyDefinitions(?string $channel): ?array {
 | 
			
		||||
    return null;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected function getKeyValues($item, ?string $channel): ?array {
 | 
			
		||||
    return null;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected function create(?string $channel): void {
 | 
			
		||||
    if ($this->created[$channel] ?? false) return;
 | 
			
		||||
    $columns = cl::merge([
 | 
			
		||||
      "_id" => "integer primary key autoincrement",
 | 
			
		||||
      "_item" => "text",
 | 
			
		||||
    ], $this->getKeyDefinitions($channel));
 | 
			
		||||
    #XXXvvv migrer vers la syntaxe tableau de create
 | 
			
		||||
    $index = 0;
 | 
			
		||||
    foreach ($columns as $column => &$definition) {
 | 
			
		||||
      if ($column === $index) {
 | 
			
		||||
        $index++;
 | 
			
		||||
      } else {
 | 
			
		||||
        $definition = "$column $definition";
 | 
			
		||||
      }
 | 
			
		||||
    }; unset($definition);
 | 
			
		||||
    $query = implode("", [
 | 
			
		||||
      "create table if not exists ",
 | 
			
		||||
      $this->getTableName($channel),
 | 
			
		||||
      " (",
 | 
			
		||||
      implode(", ", $columns),
 | 
			
		||||
      ")",
 | 
			
		||||
    ]);
 | 
			
		||||
    #XXX^^^ migrer vers la syntaxe tableau de create
 | 
			
		||||
    $this->sqlite->exec($query);
 | 
			
		||||
    $this->created[$channel] = true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function charge($item, ?string $channel=null) {
 | 
			
		||||
    $this->create($channel);
 | 
			
		||||
    $values = cl::merge([
 | 
			
		||||
      "_item" => serialize($item),
 | 
			
		||||
    ], $this->getKeyValues($item, $channel));
 | 
			
		||||
    $this->sqlite->exec([
 | 
			
		||||
      "insert",
 | 
			
		||||
      "into" => $this->getTableName($channel),
 | 
			
		||||
      "values" => $values,
 | 
			
		||||
    ]);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /** décharger les données du canal spécifié */
 | 
			
		||||
  function discharge(?string $channel=null, bool $reset=true): iterable {
 | 
			
		||||
    $rows = $this->sqlite->all([
 | 
			
		||||
      "select _item",
 | 
			
		||||
      "from" => $this->getTableName($channel),
 | 
			
		||||
    ]);
 | 
			
		||||
    foreach ($rows as $row) {
 | 
			
		||||
      $item = unserialize($row['_item']);
 | 
			
		||||
      yield $item;
 | 
			
		||||
    }
 | 
			
		||||
    if ($reset) $this->reset($channel);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /** appeler une fonction pour chaque élément du canal spécifié */
 | 
			
		||||
  function each(callable $func, ?string $channel=null): void {
 | 
			
		||||
    $context = func::_prepare($func);
 | 
			
		||||
    foreach ($this->discharge($channel, false) as $item) {
 | 
			
		||||
      func::_call($context, [$item]);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /** obtenir l'élément identifié par les clés spécifiées sur le canal spécifié */
 | 
			
		||||
  function get(?array $keys, ?string $channel=null) {
 | 
			
		||||
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function close(): void {
 | 
			
		||||
    $this->sqlite->close();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function sqlite__exec(string $query): bool {
 | 
			
		||||
    return $this->sqlite->_exec($query);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function sqlite_exec($query, ?array $params=null): bool {
 | 
			
		||||
    return $this->sqlite->exec($query, $params);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function sqlite__get(string $query, bool $entireRow=false) {
 | 
			
		||||
    return $this->sqlite->_get($query, $entireRow);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function sqlite_get($query, ?array $params=null, bool $entireRow=false) {
 | 
			
		||||
    return $this->sqlite->get($query, $params, $entireRow);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function sqlite_one($query, ?array $params=null): ?array {
 | 
			
		||||
    return $this->sqlite->one($query, $params);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function sqlite_all($query, ?array $params=null): iterable {
 | 
			
		||||
    return $this->sqlite->all($query, $params);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -5,8 +5,13 @@ use nur\sery\php\func;
 | 
			
		||||
 | 
			
		||||
class _migration {
 | 
			
		||||
  static function with($migrations): self {
 | 
			
		||||
    if ($migrations instanceof static) return $migrations;
 | 
			
		||||
    return new static($migrations);
 | 
			
		||||
    if ($migrations instanceof static) {
 | 
			
		||||
      return $migrations;
 | 
			
		||||
    } elseif ($migrations instanceof self) {
 | 
			
		||||
      return new static($migrations->migrations);
 | 
			
		||||
    } else {
 | 
			
		||||
      return new static($migrations);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  const MIGRATE = null;
 | 
			
		||||
 | 
			
		||||
@ -60,7 +60,7 @@ class _query {
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected static function parse_conds(?array $conds, ?array &$sql, ?array &$params): void {
 | 
			
		||||
  static function parse_conds(?array $conds, ?array &$sql, ?array &$params): void {
 | 
			
		||||
    if (!$conds) return;
 | 
			
		||||
    $sep = null;
 | 
			
		||||
    $index = 0;
 | 
			
		||||
@ -126,7 +126,7 @@ class _query {
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected static function parse_set_values(?array $values, ?array &$sql, ?array &$params): void {
 | 
			
		||||
  static function parse_set_values(?array $values, ?array &$sql, ?array &$params): void {
 | 
			
		||||
    if (!$values) return;
 | 
			
		||||
    $index = 0;
 | 
			
		||||
    $parts = [];
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										1
									
								
								tests/db/sqlite/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								tests/db/sqlite/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1 @@
 | 
			
		||||
/capacitor.db
 | 
			
		||||
							
								
								
									
										48
									
								
								tests/db/sqlite/SqliteCapacitorTest.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								tests/db/sqlite/SqliteCapacitorTest.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,48 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace nur\sery\db\sqlite;
 | 
			
		||||
 | 
			
		||||
use PHPUnit\Framework\TestCase;
 | 
			
		||||
 | 
			
		||||
class SqliteCapacitorTest extends TestCase {
 | 
			
		||||
  function _testChargeStrings(SqliteCapacitor $capacitor, ?string $channel) {
 | 
			
		||||
    $capacitor->reset($channel);
 | 
			
		||||
    $capacitor->charge("first", $channel);
 | 
			
		||||
    $capacitor->charge("second", $channel);
 | 
			
		||||
    $capacitor->charge("third", $channel);
 | 
			
		||||
    $items = iterator_to_array($capacitor->discharge($channel, false));
 | 
			
		||||
    self::assertSame(["first", "second", "third"], $items);
 | 
			
		||||
  }
 | 
			
		||||
  function _testChargeArrays(SqliteCapacitor $capacitor, ?string $channel) {
 | 
			
		||||
    $capacitor->reset($channel);
 | 
			
		||||
    $capacitor->charge(["id" => 10, "name" => "first"], $channel);
 | 
			
		||||
    $capacitor->charge(["name" => "second", "id" => 20], $channel);
 | 
			
		||||
    $capacitor->charge(["name" => "third", "id" => "30"], $channel);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function testChargeStrings() {
 | 
			
		||||
    $capacitor = new SqliteCapacitor(__DIR__.'/capacitor.db');
 | 
			
		||||
    $this->_testChargeStrings($capacitor, null);
 | 
			
		||||
    $capacitor->close();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function testChargeArrays() {
 | 
			
		||||
    $capacitor = new class(__DIR__.'/capacitor.db') extends SqliteCapacitor {
 | 
			
		||||
      protected function getKeyDefinitions(?string $channel): ?array {
 | 
			
		||||
        if ($channel === "arrays") {
 | 
			
		||||
          return ["id" => "integer"];
 | 
			
		||||
        }
 | 
			
		||||
        return parent::getKeyDefinitions($channel);
 | 
			
		||||
      }
 | 
			
		||||
      protected function getKeyValues($item, ?string $channel): ?array {
 | 
			
		||||
        if ($channel === "arrays") {
 | 
			
		||||
          return ["id" => $item["id"] ?? null];
 | 
			
		||||
        }
 | 
			
		||||
        return parent::getKeyValues($item, $channel);
 | 
			
		||||
      }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    $this->_testChargeStrings($capacitor, "strings");
 | 
			
		||||
    $this->_testChargeArrays($capacitor, "arrays");
 | 
			
		||||
    $capacitor->close();
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -41,6 +41,12 @@ class SqliteTest extends TestCase {
 | 
			
		||||
    self::assertException(SqliteException::class, [$sqlite, "exec"], ["prout"]);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected function assertInserted(Sqlite $sqlite, array $row, array $query): void {
 | 
			
		||||
    $sqlite->exec($query);
 | 
			
		||||
    self::assertSame($row, $sqlite->one("select * from mapping where i = :i", [
 | 
			
		||||
      "i" => $query["values"]["i"],
 | 
			
		||||
    ]));
 | 
			
		||||
  }
 | 
			
		||||
  function testInsert() {
 | 
			
		||||
    $sqlite = new Sqlite(":memory:", [
 | 
			
		||||
      "migrate" => "create table mapping (i integer, s varchar)",
 | 
			
		||||
 | 
			
		||||
@ -3,7 +3,7 @@ namespace nur\sery\db\sqlite;
 | 
			
		||||
 | 
			
		||||
use PHPUnit\Framework\TestCase;
 | 
			
		||||
 | 
			
		||||
class _QueryTest extends TestCase {
 | 
			
		||||
class _queryTest extends TestCase {
 | 
			
		||||
  function testParseConds(): void {
 | 
			
		||||
    $sql = $params = null;
 | 
			
		||||
    _query::parse_conds(null, $sql, $params);
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user