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: frontend vers une base de données sqlite3
|
||||||
*/
|
*/
|
||||||
class Sqlite {
|
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) {
|
static function config_enableExceptions(self $sqlite) {
|
||||||
$sqlite->db->enableExceptions(true);
|
$sqlite->db->enableExceptions(true);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {
|
class _migration {
|
||||||
static function with($migrations): self {
|
static function with($migrations): self {
|
||||||
if ($migrations instanceof static) return $migrations;
|
if ($migrations instanceof static) {
|
||||||
return new static($migrations);
|
return $migrations;
|
||||||
|
} elseif ($migrations instanceof self) {
|
||||||
|
return new static($migrations->migrations);
|
||||||
|
} else {
|
||||||
|
return new static($migrations);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const MIGRATE = null;
|
const MIGRATE = null;
|
||||||
|
|
|
@ -60,7 +60,7 @@ class _query {
|
||||||
return true;
|
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;
|
if (!$conds) return;
|
||||||
$sep = null;
|
$sep = null;
|
||||||
$index = 0;
|
$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;
|
if (!$values) return;
|
||||||
$index = 0;
|
$index = 0;
|
||||||
$parts = [];
|
$parts = [];
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
/capacitor.db
|
|
@ -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"]);
|
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() {
|
function testInsert() {
|
||||||
$sqlite = new Sqlite(":memory:", [
|
$sqlite = new Sqlite(":memory:", [
|
||||||
"migrate" => "create table mapping (i integer, s varchar)",
|
"migrate" => "create table mapping (i integer, s varchar)",
|
||||||
|
|
|
@ -3,7 +3,7 @@ namespace nur\sery\db\sqlite;
|
||||||
|
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
class _QueryTest extends TestCase {
|
class _queryTest extends TestCase {
|
||||||
function testParseConds(): void {
|
function testParseConds(): void {
|
||||||
$sql = $params = null;
|
$sql = $params = null;
|
||||||
_query::parse_conds(null, $sql, $params);
|
_query::parse_conds(null, $sql, $params);
|
Loading…
Reference in New Issue