modifs.mineures sans commentaires
This commit is contained in:
		
							parent
							
								
									c4e1496b82
								
							
						
					
					
						commit
						a38fc17607
					
				
							
								
								
									
										45
									
								
								src/db/Capacitor.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								src/db/Capacitor.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,45 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace nur\sery\db;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Class Capacitor: un objet permettant d'attaquer un canal spécique d'une
 | 
			
		||||
 * instance de {@link ICapacitor}
 | 
			
		||||
 */
 | 
			
		||||
class Capacitor {
 | 
			
		||||
  function __construct(ICapacitor $capacitor, CapacitorChannel $channel) {
 | 
			
		||||
    $this->capacitor = $capacitor;
 | 
			
		||||
    $this->channel = $channel;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected $capacitor;
 | 
			
		||||
 | 
			
		||||
  protected $channel;
 | 
			
		||||
 | 
			
		||||
  function exists(): bool {
 | 
			
		||||
    return $this->capacitor->_exists($this->channel);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function reset(): void {
 | 
			
		||||
    $this->capacitor->_reset($this->channel);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function charge($item) {
 | 
			
		||||
    $this->capacitor->_charge($item, $this->channel);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function discharge($keys=null, ?bool $reset=null): iterable {
 | 
			
		||||
    return $this->capacitor->_discharge($keys, $this->channel, $reset);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function get($keys) {
 | 
			
		||||
    return $this->capacitor->_get($keys, $this->channel);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function each($keys, callable $func, ?array $args=null): void {
 | 
			
		||||
    $this->capacitor->_each($keys, $func, $args, $this->channel);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function close(): void {
 | 
			
		||||
    $this->capacitor->close();
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										48
									
								
								src/db/CapacitorChannel.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								src/db/CapacitorChannel.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,48 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace nur\sery\db;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Class CapacitorChannel: un canal d'une instance de {@link ICapacitor}
 | 
			
		||||
 */
 | 
			
		||||
class CapacitorChannel {
 | 
			
		||||
  const NAME = null;
 | 
			
		||||
 | 
			
		||||
  static function verifix_name(?string $name): string {
 | 
			
		||||
    if ($name === null) $name = "default";
 | 
			
		||||
    return strtolower($name);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function __construct(?string $name=null) {
 | 
			
		||||
    $this->name = self::verifix_name($name ?? static::NAME);
 | 
			
		||||
    $this->created = false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /** @var string */
 | 
			
		||||
  protected $name;
 | 
			
		||||
 | 
			
		||||
  function getName(): string {
 | 
			
		||||
    return $this->name;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function getTableName(): string {
 | 
			
		||||
    return $this->name."_channel";
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected $created;
 | 
			
		||||
 | 
			
		||||
  function isCreated(): bool {
 | 
			
		||||
    return $this->created;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function setCreated(bool $created=true): void {
 | 
			
		||||
    $this->created = $created;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function getKeyDefinitions(): ?array {
 | 
			
		||||
    return null;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function getKeyValues($item): ?array {
 | 
			
		||||
    return null;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										39
									
								
								src/db/ICapacitor.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								src/db/ICapacitor.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,39 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace nur\sery\db;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Interface ICapacitor: objet permettant d'accumuler des données pour les
 | 
			
		||||
 * réutiliser plus tard
 | 
			
		||||
 */
 | 
			
		||||
interface ICapacitor {
 | 
			
		||||
  /** tester si le canal spécifié existe */
 | 
			
		||||
  function exists(?string $channel=null): bool;
 | 
			
		||||
 | 
			
		||||
  /** supprimer le canal spécifié */
 | 
			
		||||
  function reset(?string $channel=null): void;
 | 
			
		||||
 | 
			
		||||
  /** charger une valeur dans le canal */
 | 
			
		||||
  function charge($item, ?string $channel=null): void;
 | 
			
		||||
 | 
			
		||||
  /** décharger les données du canal spécifié */
 | 
			
		||||
  function discharge($keys=null, ?string $channel=null, ?bool $reset=null): iterable;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * obtenir l'élément identifié par les clés spécifiées sur le canal spécifié
 | 
			
		||||
   *
 | 
			
		||||
   * si $keys n'est pas un tableau, il est transformé en ["_id" => $keys]
 | 
			
		||||
   */
 | 
			
		||||
  function get($keys, ?string $channel=null);
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * appeler une fonction pour chaque élément du canal spécifié.
 | 
			
		||||
   *
 | 
			
		||||
   * $keys permet de filtrer parmi les élements chargés
 | 
			
		||||
   *
 | 
			
		||||
   * si $func retourne un tableau, il est utilisé pour mettre à jour
 | 
			
		||||
   * l'enregistrement.
 | 
			
		||||
   */
 | 
			
		||||
  function each($keys, callable $func, ?array $args=null, ?string $channel=null): void;
 | 
			
		||||
 | 
			
		||||
  function close(): void;
 | 
			
		||||
}
 | 
			
		||||
@ -2,14 +2,15 @@
 | 
			
		||||
namespace nur\sery\db\sqlite;
 | 
			
		||||
 | 
			
		||||
use nur\sery\cl;
 | 
			
		||||
use nur\sery\db\CapacitorChannel;
 | 
			
		||||
use nur\sery\db\ICapacitor;
 | 
			
		||||
use nur\sery\php\func;
 | 
			
		||||
use nur\sery\ValueException;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Class SqliteCapacitor: objet permettant d'accumuler des données pour les
 | 
			
		||||
 * réutiliser plus tard
 | 
			
		||||
 * Class SqliteCapacitor
 | 
			
		||||
 */
 | 
			
		||||
class SqliteCapacitor {
 | 
			
		||||
class SqliteCapacitor implements ICapacitor {
 | 
			
		||||
  function __construct($sqlite) {
 | 
			
		||||
    $this->sqlite = Sqlite::with($sqlite);
 | 
			
		||||
  }
 | 
			
		||||
@ -21,87 +22,114 @@ class SqliteCapacitor {
 | 
			
		||||
    return $this->sqlite;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected function getTableName(?string $channel): string {
 | 
			
		||||
    return ($channel ?? "default")."_channel";
 | 
			
		||||
  protected function _create(CapacitorChannel $channel): void {
 | 
			
		||||
    if (!$channel->isCreated()) {
 | 
			
		||||
      $columns = cl::merge([
 | 
			
		||||
        "_id" => "integer primary key autoincrement",
 | 
			
		||||
        "_item" => "text",
 | 
			
		||||
      ], $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 channel(?string $name=null): 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;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /** tester si le canal spécifié existe */
 | 
			
		||||
  function exists(?string $channel=null): bool {
 | 
			
		||||
    #XXX maintenir une table channels avec la liste des canaux valides
 | 
			
		||||
    return $this->_exists($this->channel($channel));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function _reset(CapacitorChannel $channel): void {
 | 
			
		||||
    $this->sqlite->exec([
 | 
			
		||||
      "drop table if exists",
 | 
			
		||||
      $channel->getTableName(),
 | 
			
		||||
    ]);
 | 
			
		||||
    $channel->setCreated(false);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /** supprimer le canal spécifié */
 | 
			
		||||
  function reset(?string $channel=null) {
 | 
			
		||||
    $tableName = $this->getTableName($channel);
 | 
			
		||||
    $this->sqlite->exec("drop table if exists $tableName");
 | 
			
		||||
    #XXX maj de la tables channels dans une transaction
 | 
			
		||||
  function reset(?string $channel=null): void {
 | 
			
		||||
    $this->_reset($this->channel($channel));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /** @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);
 | 
			
		||||
    #XXX maj de la tables channels dans une transaction
 | 
			
		||||
    $this->created[$channel] = true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function charge($item, ?string $channel=null) {
 | 
			
		||||
    $this->create($channel);
 | 
			
		||||
    $values = cl::merge($this->getKeyValues($item, $channel), [
 | 
			
		||||
  function _charge($item, CapacitorChannel $channel): void {
 | 
			
		||||
    $this->_create($channel);
 | 
			
		||||
    $values = cl::merge($channel->getKeyValues($item), [
 | 
			
		||||
      "_item" => serialize($item),
 | 
			
		||||
    ]);
 | 
			
		||||
    $this->sqlite->exec([
 | 
			
		||||
      "insert",
 | 
			
		||||
      "into" => $this->getTableName($channel),
 | 
			
		||||
      "into" => $channel->getTableName(),
 | 
			
		||||
      "values" => $values,
 | 
			
		||||
    ]);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /** décharger les données du canal spécifié */
 | 
			
		||||
  function discharge($keys=null, ?string $channel=null, ?bool $reset=null): iterable {
 | 
			
		||||
  /** charger une valeur dans le canal */
 | 
			
		||||
  function charge($item, ?string $channel=null): void {
 | 
			
		||||
    $this->_charge($item, $this->channel($channel));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function _discharge($keys=null, CapacitorChannel $channel=null, ?bool $reset=null): iterable {
 | 
			
		||||
    if ($keys !== null && !is_array($keys)) $keys = ["_id" => $keys];
 | 
			
		||||
    if ($reset === null) $reset = $keys === null;
 | 
			
		||||
    $rows = $this->sqlite->all([
 | 
			
		||||
      "select _item",
 | 
			
		||||
      "from" => $this->getTableName($channel),
 | 
			
		||||
      "from" => $channel->getTableName(),
 | 
			
		||||
      "where" => $keys,
 | 
			
		||||
    ]);
 | 
			
		||||
    foreach ($rows as $row) {
 | 
			
		||||
      $item = unserialize($row['_item']);
 | 
			
		||||
      yield $item;
 | 
			
		||||
    }
 | 
			
		||||
    if ($reset) $this->reset($channel);
 | 
			
		||||
    if ($reset) $this->_reset($channel);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /** décharger les données du canal spécifié */
 | 
			
		||||
  function discharge($keys=null, ?string $channel=null, ?bool $reset=null): iterable {
 | 
			
		||||
    return $this->_discharge($keys, $this->channel($channel), $reset);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function _get($keys, CapacitorChannel $channel=null) {
 | 
			
		||||
    if ($keys === null) throw ValueException::null("keys");
 | 
			
		||||
    if (!is_array($keys)) $keys = ["_id" => $keys];
 | 
			
		||||
    $row = $this->sqlite->one([
 | 
			
		||||
      "select _item",
 | 
			
		||||
      "from" => $channel->getTableName(),
 | 
			
		||||
      "where" => $keys,
 | 
			
		||||
    ]);
 | 
			
		||||
    if ($row === null) return null;
 | 
			
		||||
    else return unserialize($row["_item"]);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
@ -110,30 +138,14 @@ class SqliteCapacitor {
 | 
			
		||||
   * si $keys n'est pas un tableau, il est transformé en ["_id" => $keys]
 | 
			
		||||
   */
 | 
			
		||||
  function get($keys, ?string $channel=null) {
 | 
			
		||||
    if ($keys === null) throw ValueException::null("keys");
 | 
			
		||||
    if (!is_array($keys)) $keys = ["_id" => $keys];
 | 
			
		||||
    $row = $this->sqlite->one([
 | 
			
		||||
      "select _item",
 | 
			
		||||
      "from" => $this->getTableName($channel),
 | 
			
		||||
      "where" => $keys,
 | 
			
		||||
    ]);
 | 
			
		||||
    if ($row === null) return null;
 | 
			
		||||
    else return unserialize($row["_item"]);
 | 
			
		||||
    return $this->_get($keys, $this->channel($channel));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * appeler une fonction pour chaque élément du canal spécifié.
 | 
			
		||||
   *
 | 
			
		||||
   * $keys permet de filtrer parmi les élements chargés
 | 
			
		||||
   *
 | 
			
		||||
   * si $func retourne un tableau, il est utilisé pour mettre à jour
 | 
			
		||||
   * l'enregistrement.
 | 
			
		||||
   */
 | 
			
		||||
  function each($keys, callable $func, ?array $args=null, ?string $channel=null): void {
 | 
			
		||||
  function _each($keys, callable $func, ?array $args=null, CapacitorChannel $channel=null): void {
 | 
			
		||||
    if ($keys !== null && !is_array($keys)) $keys = ["_id" => $keys];
 | 
			
		||||
    $context = func::_prepare($func);
 | 
			
		||||
    $sqlite = $this->sqlite;
 | 
			
		||||
    $tableName = $this->getTableName($channel);
 | 
			
		||||
    $tableName = $channel->getTableName();
 | 
			
		||||
    $rows = $sqlite->all([
 | 
			
		||||
      "select",
 | 
			
		||||
      "from" => $tableName,
 | 
			
		||||
@ -147,20 +159,28 @@ class SqliteCapacitor {
 | 
			
		||||
        if (array_key_exists("_item", $updates)) {
 | 
			
		||||
          $updates["_item"] = serialize($updates["_item"]);
 | 
			
		||||
        }
 | 
			
		||||
        #XXXvvv migrer vers la syntaxe tableau de update
 | 
			
		||||
        $params = null;
 | 
			
		||||
        $sql = ["update", $tableName, "set"];
 | 
			
		||||
        _query::parse_set_values($updates, $setsql, $params);
 | 
			
		||||
        $sql[] = implode(", ", $setsql);
 | 
			
		||||
        $sql[] = "where";
 | 
			
		||||
        _query::parse_conds(["_id" => $row["_id"]], $wheresql, $params);
 | 
			
		||||
        $sql[] = implode(" and ", $wheresql);
 | 
			
		||||
        $sqlite->exec(implode(" ", $sql), $params);
 | 
			
		||||
        #XXX^^^ migrer vers la syntaxe tableau de update
 | 
			
		||||
        $sqlite->exec([
 | 
			
		||||
          "update",
 | 
			
		||||
          "table" => $tableName,
 | 
			
		||||
          "values" => $updates,
 | 
			
		||||
          "where" => ["_id" => $row["_id"]],
 | 
			
		||||
        ]);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * appeler une fonction pour chaque élément du canal spécifié.
 | 
			
		||||
   *
 | 
			
		||||
   * $keys permet de filtrer parmi les élements chargés
 | 
			
		||||
   *
 | 
			
		||||
   * si $func retourne un tableau, il est utilisé pour mettre à jour
 | 
			
		||||
   * l'enregistrement.
 | 
			
		||||
   */
 | 
			
		||||
  function each($keys, callable $func, ?array $args=null, ?string $channel=null): void {
 | 
			
		||||
    $this->_each($keys, $func, $args, $this->channel($channel));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function close(): void {
 | 
			
		||||
    $this->sqlite->close();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@ -23,6 +23,8 @@ class _query {
 | 
			
		||||
        $query = _query_update::parse($query, $params);
 | 
			
		||||
      } elseif (_query_delete::isa($prefix)) {
 | 
			
		||||
        $query = _query_delete::parse($query, $params);
 | 
			
		||||
      } elseif (_query_generic::isa($prefix)) {
 | 
			
		||||
        $query = _query_generic::parse($query, $params);
 | 
			
		||||
      } else {
 | 
			
		||||
        throw SqliteException::wrap(ValueException::invalid_kind($query, "query"));
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
@ -11,9 +11,37 @@ class _query_create extends _query {
 | 
			
		||||
  ];
 | 
			
		||||
 | 
			
		||||
  static function isa(string $sql): bool {
 | 
			
		||||
    return false;
 | 
			
		||||
    //return preg_match("/^create(?:\s+table)?\b/i", $sql);
 | 
			
		||||
    #XXX implémentation minimale
 | 
			
		||||
    return preg_match("/^create\s+table\b/i", $sql);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  static function parse(array $query, ?array &$params=null): string {
 | 
			
		||||
    #XXX implémentation minimale
 | 
			
		||||
    $sql = [self::merge_seq($query)];
 | 
			
		||||
 | 
			
		||||
    ## préfixe
 | 
			
		||||
    if (($prefix = $query["prefix"] ?? null) !== null) $sql[] = $prefix;
 | 
			
		||||
 | 
			
		||||
    ## table
 | 
			
		||||
    $sql[] = $query["table"];
 | 
			
		||||
 | 
			
		||||
    ## columns
 | 
			
		||||
    $cols = $query["cols"];
 | 
			
		||||
    $index = 0;
 | 
			
		||||
    foreach ($cols as $col => &$definition) {
 | 
			
		||||
      if ($col === $index) {
 | 
			
		||||
        $index++;
 | 
			
		||||
      } else {
 | 
			
		||||
        $definition = "$col $definition";
 | 
			
		||||
      }
 | 
			
		||||
    }; unset($definition);
 | 
			
		||||
    $sql[] = "(".implode(", ", $cols).")";
 | 
			
		||||
 | 
			
		||||
    ## suffixe
 | 
			
		||||
    if (($suffix = $query["suffix"] ?? null) !== null) $sql[] = $suffix;
 | 
			
		||||
 | 
			
		||||
    ## fin de la requête
 | 
			
		||||
    return implode(" ", $sql);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -10,9 +10,35 @@ class _query_delete extends _query {
 | 
			
		||||
  ];
 | 
			
		||||
 | 
			
		||||
  static function isa(string $sql): bool {
 | 
			
		||||
    return false;
 | 
			
		||||
    //return preg_match("/^delete(?:\s+from)?\b/i", $sql);
 | 
			
		||||
    #XXX implémentation minimale
 | 
			
		||||
    return preg_match("/^delete\s+from\b/i", $sql);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  static function parse(array $query, ?array &$params=null): string {
 | 
			
		||||
    #XXX implémentation minimale
 | 
			
		||||
    $sql = [self::merge_seq($query)];
 | 
			
		||||
 | 
			
		||||
    ## préfixe
 | 
			
		||||
    if (($prefix = $query["prefix"] ?? null) !== null) $sql[] = $prefix;
 | 
			
		||||
 | 
			
		||||
    ## table
 | 
			
		||||
    $sql[] = $query["table"];
 | 
			
		||||
 | 
			
		||||
    ## where
 | 
			
		||||
    $where = $query["where"] ?? null;
 | 
			
		||||
    if ($where !== null) {
 | 
			
		||||
      _query::parse_conds($where, $wheresql, $params);
 | 
			
		||||
      if ($wheresql) {
 | 
			
		||||
        $sql[] = "where";
 | 
			
		||||
        $sql[] = implode(" and ", $wheresql);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ## suffixe
 | 
			
		||||
    if (($suffix = $query["suffix"] ?? null) !== null) $sql[] = $suffix;
 | 
			
		||||
 | 
			
		||||
    ## fin de la requête
 | 
			
		||||
    return implode(" ", $sql);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										18
									
								
								src/db/sqlite/_query_generic.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								src/db/sqlite/_query_generic.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,18 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace nur\sery\db\sqlite;
 | 
			
		||||
 | 
			
		||||
use nur\sery\cl;
 | 
			
		||||
use nur\sery\ValueException;
 | 
			
		||||
 | 
			
		||||
class _query_generic extends _query {
 | 
			
		||||
  static function isa(string $sql): bool {
 | 
			
		||||
    return preg_match('/^(?:drop\s+table)\b/i', $sql);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  static function parse(array $query, ?array &$params=null): string {
 | 
			
		||||
    if (!cl::is_list($query)) {
 | 
			
		||||
      throw new ValueException("Seuls les tableaux séquentiels sont supportés");
 | 
			
		||||
    }
 | 
			
		||||
    return self::merge_seq($query);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -13,9 +13,38 @@ class _query_update extends _query {
 | 
			
		||||
  ];
 | 
			
		||||
 | 
			
		||||
  static function isa(string $sql): bool {
 | 
			
		||||
    return false;
 | 
			
		||||
    return preg_match("/^update\b/i", $sql);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  static function parse(array $query, ?array &$params=null): string {
 | 
			
		||||
    #XXX implémentation minimale
 | 
			
		||||
    $sql = [self::merge_seq($query)];
 | 
			
		||||
 | 
			
		||||
    ## préfixe
 | 
			
		||||
    if (($prefix = $query["prefix"] ?? null) !== null) $sql[] = $prefix;
 | 
			
		||||
 | 
			
		||||
    ## table
 | 
			
		||||
    $sql[] = $query["table"];
 | 
			
		||||
 | 
			
		||||
    ## set
 | 
			
		||||
    _query::parse_set_values($query["values"], $setsql, $params);
 | 
			
		||||
    $sql[] = "set";
 | 
			
		||||
    $sql[] = implode(", ", $setsql);
 | 
			
		||||
 | 
			
		||||
    ## where
 | 
			
		||||
    $where = $query["where"] ?? null;
 | 
			
		||||
    if ($where !== null) {
 | 
			
		||||
      _query::parse_conds($where, $wheresql, $params);
 | 
			
		||||
      if ($wheresql) {
 | 
			
		||||
        $sql[] = "where";
 | 
			
		||||
        $sql[] = implode(" and ", $wheresql);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ## suffixe
 | 
			
		||||
    if (($suffix = $query["suffix"] ?? null) !== null) $sql[] = $suffix;
 | 
			
		||||
 | 
			
		||||
    ## fin de la requête
 | 
			
		||||
    return implode(" ", $sql);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,7 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace nur\sery\db\sqlite;
 | 
			
		||||
 | 
			
		||||
use nur\sery\db\CapacitorChannel;
 | 
			
		||||
use PHPUnit\Framework\TestCase;
 | 
			
		||||
 | 
			
		||||
class SqliteCapacitorTest extends TestCase {
 | 
			
		||||
@ -26,20 +27,16 @@ class SqliteCapacitorTest extends TestCase {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  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);
 | 
			
		||||
    $capacitor = new SqliteCapacitor(__DIR__.'/capacitor.db');
 | 
			
		||||
    $capacitor->addChannel(new class extends CapacitorChannel {
 | 
			
		||||
      const NAME = "arrays";
 | 
			
		||||
      function getKeyDefinitions(): ?array {
 | 
			
		||||
        return ["id" => "integer"];
 | 
			
		||||
      }
 | 
			
		||||
      protected function getKeyValues($item, ?string $channel): ?array {
 | 
			
		||||
        if ($channel === "arrays") {
 | 
			
		||||
          return ["id" => $item["id"] ?? null];
 | 
			
		||||
        }
 | 
			
		||||
        return parent::getKeyValues($item, $channel);
 | 
			
		||||
      function getKeyValues($item): ?array {
 | 
			
		||||
        return ["id" => $item["id"] ?? null];
 | 
			
		||||
      }
 | 
			
		||||
    };
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    $this->_testChargeStrings($capacitor, "strings");
 | 
			
		||||
    $this->_testChargeArrays($capacitor, "arrays");
 | 
			
		||||
@ -47,19 +44,21 @@ class SqliteCapacitorTest extends TestCase {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function testEach() {
 | 
			
		||||
    $capacitor = new class(__DIR__.'/capacitor.db') extends SqliteCapacitor {
 | 
			
		||||
      protected function getKeyDefinitions(?string $channel): ?array {
 | 
			
		||||
    $capacitor = new SqliteCapacitor(__DIR__.'/capacitor.db');
 | 
			
		||||
    $capacitor->addChannel(new class extends CapacitorChannel {
 | 
			
		||||
      const NAME = "each";
 | 
			
		||||
      function getKeyDefinitions(): ?array {
 | 
			
		||||
        return [
 | 
			
		||||
          "age" => "integer",
 | 
			
		||||
          "done" => "integer default 0",
 | 
			
		||||
        ];
 | 
			
		||||
      }
 | 
			
		||||
      protected function getKeyValues($item, ?string $channel): ?array {
 | 
			
		||||
      function getKeyValues($item): ?array {
 | 
			
		||||
        return [
 | 
			
		||||
          "age" => $item["age"],
 | 
			
		||||
        ];
 | 
			
		||||
      }
 | 
			
		||||
    };
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    $channel = "each";
 | 
			
		||||
    $capacitor->reset($channel);
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user