modifs.mineures sans commentaires

This commit is contained in:
Jephté Clain 2024-06-07 11:57:15 +04:00
parent f35b0a400d
commit 2fbe3ec09c
9 changed files with 137 additions and 68 deletions

View File

@ -11,6 +11,7 @@ use nur\sery\db\Capacitor;
use nur\sery\db\CapacitorChannel;
use nur\sery\db\mysql\MysqlStorage;
use nur\sery\db\sqlite\SqliteStorage;
use nur\sery\file\Stream;
use nur\yaml;
Application::run(new class extends Application {
@ -68,12 +69,17 @@ Application::run(new class extends Application {
$args = $this->args;
if (!$args) {
# lister les id
$rows = $storage->mysql()->all([
"select id_",
$out = new Stream(STDOUT);
$primaryKeys = $storage->getPrimaryKeys($channel);
$rows = $storage->db()->all([
"select",
"cols" => $primaryKeys,
"from" => $channel->getTableName(),
]);
$out->fputcsv($primaryKeys);
foreach ($rows as $row) {
echo "$row[id_]\n";
$rowIds = $storage->getRowIds($channel, $row);
$out->fputcsv($rowIds);
}
} else {
# afficher les lignes correspondantes

View File

@ -9,6 +9,7 @@ use nur\path;
use nur\sery\db\Capacitor;
use nur\sery\db\CapacitorChannel;
use nur\sery\db\sqlite\SqliteStorage;
use nur\sery\file\Stream;
use nur\yaml;
Application::run(new class extends Application {
@ -64,12 +65,17 @@ Application::run(new class extends Application {
$args = $this->args;
if (!$args) {
# lister les id
$rows = $storage->sqlite()->all([
"select id_",
$out = new Stream(STDOUT);
$primaryKeys = $storage->getPrimaryKeys($channel);
$rows = $storage->db()->all([
"select",
"cols" => $primaryKeys,
"from" => $channel->getTableName(),
]);
$out->fputcsv($primaryKeys);
foreach ($rows as $row) {
echo "$row[id_]\n";
$rowIds = $storage->getRowIds($channel, $row);
$out->fputcsv($rowIds);
}
} else {
# afficher les lignes correspondantes

View File

@ -153,7 +153,7 @@ class CapacitorChannel {
const SUM_DEFINITION = "varchar(40)";
final function sum(string $string): string {
final function sum(?string $string): string {
return sha1($string);
}

View File

@ -93,13 +93,13 @@ abstract class CapacitorStorage {
return $values;
}
protected function getPrimaryKeys(CapacitorChannel $channel): array {
function getPrimaryKeys(CapacitorChannel $channel): array {
$primaryKeys = $channel->getPrimaryKeys();
if ($primaryKeys === null) $primaryKeys = ["id_"];
return $primaryKeys;
}
protected function getRowIds(CapacitorChannel $channel, ?array $row, ?array &$primaryKeys=null): ?array {
function getRowIds(CapacitorChannel $channel, ?array $row, ?array &$primaryKeys=null): ?array {
$primaryKeys = $this->getPrimaryKeys($channel);
$rowIds = cl::select($row, $primaryKeys);
if (cl::all_n($rowIds)) return null;

View File

@ -84,70 +84,88 @@ abstract class _base {
$condkey++;
}
$op = strtolower($op);
$condvalues = null;
switch ($op) {
case "between":
# ["between", $upper, $lower]
$condsep = " and ";
$values = null;
if (array_key_exists("lower", $cond)) {
$values[] = $cond["lower"];
$condvalues[] = $cond["lower"];
} elseif (array_key_exists($condkey, $condkeys)) {
$values[] = $cond[$condkeys[$condkey]];
$condvalues[] = $cond[$condkeys[$condkey]];
$condkey++;
}
if (array_key_exists("upper", $cond)) {
$values[] = $cond["upper"];
$condvalues[] = $cond["upper"];
} elseif (array_key_exists($condkey, $condkeys)) {
$values[] = $cond[$condkeys[$condkey]];
$condvalues[] = $cond[$condkeys[$condkey]];
$condkey++;
}
break;
case "in":
# ["in", $values]
$condprefix = "(";
$condsep = ", ";
$condsuffix = ")";
$values = null;
$condvalues = null;
if (array_key_exists("values", $cond)) {
$values = cl::with($cond["values"]);
$condvalues = cl::with($cond["values"]);
} elseif (array_key_exists($condkey, $condkeys)) {
$values = cl::with($cond[$condkeys[$condkey]]);
$condvalues = cl::with($cond[$condkeys[$condkey]]);
$condkey++;
}
break;
case "null":
case "is null":
$op = "is null";
$values = null;
break;
case "not null":
case "is not null":
$op = "is not null";
$values = null;
break;
default:
$values = null;
if (array_key_exists("value", $cond)) {
$values = [$cond["value"]];
$condvalues = [$cond["value"]];
} elseif (array_key_exists($condkey, $condkeys)) {
$values = [$cond[$condkeys[$condkey]]];
$condvalues = [$cond[$condkeys[$condkey]]];
$condkey++;
}
}
} elseif ($cond !== null) {
$op = "=";
$values = [$cond];
$condvalues = [$cond];
} else {
$op = "is null";
$values = null;
$condvalues = null;
}
$cond = [$key, $op];
if ($values !== null) {
if ($condvalues !== null) {
$parts = [];
foreach ($values as $value) {
$param = "$key$i";
$parts[] = ":$param";
$bindings[$param] = $value;
if ($i === false) $i = 2;
else $i++;
foreach ($condvalues as $condvalue) {
if (is_array($condvalue)) {
$first = true;
foreach ($condvalue as $value) {
if ($first) {
$first = false;
} else {
if ($sep === null) $sep = "and";
$parts[] = " $sep ";
$parts[] = $key;
$parts[] = " $op ";
}
$param = "$key$i";
$parts[] = ":$param";
$bindings[$param] = $value;
if ($i === false) $i = 2;
else $i++;
}
} else {
$param = "$key$i";
$parts[] = ":$param";
$bindings[$param] = $condvalue;
if ($i === false) $i = 2;
else $i++;
}
}
$cond[] = $condprefix.implode($condsep, $parts).$condsuffix;
}
@ -183,7 +201,7 @@ abstract class _base {
# paramètre
$param = $key;
if ($bindings !== null && array_key_exists($param, $bindings)) {
$i = 1;
$i = 2;
while (array_key_exists("$key$i", $bindings)) {
$i++;
}

View File

@ -12,14 +12,14 @@ use nur\sery\ValueException;
*/
class MysqlStorage extends CapacitorStorage {
function __construct($mysql) {
$this->mysql = Mysql::with($mysql);
$this->db = Mysql::with($mysql);
}
/** @var Mysql */
protected $mysql;
protected $db;
function mysql(): Mysql {
return $this->mysql;
function db(): Mysql {
return $this->db;
}
const PRIMARY_KEY_DEFINITION = [
@ -29,7 +29,7 @@ class MysqlStorage extends CapacitorStorage {
protected function _create(CapacitorChannel $channel): void {
if (!$channel->isCreated()) {
$cols = $this->ColumnDefinitions($channel);
$this->mysql->exec([
$this->db->exec([
"create table if not exists",
"table" => $channel->getTableName(),
"cols" => $cols,
@ -39,7 +39,7 @@ class MysqlStorage extends CapacitorStorage {
}
function _exists(CapacitorChannel $channel): bool {
$mysql = $this->mysql;
$mysql = $this->db;
$tableName = $mysql->get([
"select table_name from information_schema.tables",
"where" => [
@ -55,7 +55,7 @@ class MysqlStorage extends CapacitorStorage {
}
function _reset(CapacitorChannel $channel): void {
$this->mysql->exec([
$this->db->exec([
"drop table if exists",
$channel->getTableName(),
]);
@ -73,7 +73,7 @@ class MysqlStorage extends CapacitorStorage {
$rowIds = $this->getRowIds($channel, $row, $primaryKeys);
if ($rowIds !== null) {
# modification
$prow = $this->mysql->one([
$prow = $this->db->one([
"select",
"from" => $tableName,
"where" => $rowIds,
@ -120,13 +120,13 @@ class MysqlStorage extends CapacitorStorage {
# aucune modification
return 0;
} elseif ($insert) {
$this->mysql->exec([
$this->db->exec([
"insert",
"into" => $tableName,
"values" => $row,
]);
} else {
$this->mysql->exec([
$this->db->exec([
"update",
"table" => $tableName,
"values" => $row,
@ -137,7 +137,7 @@ class MysqlStorage extends CapacitorStorage {
}
function _discharge(CapacitorChannel $channel, bool $reset=true): iterable {
$rows = $this->mysql->all([
$rows = $this->db->all([
"select item__",
"from" => $channel->getTableName(),
]);
@ -158,7 +158,7 @@ class MysqlStorage extends CapacitorStorage {
function _count(CapacitorChannel $channel, $filter): int {
$this->verifixFilter($channel, $filter);
return $this->mysql->get([
return $this->db->get([
"select count(*)",
"from" => $channel->getTableName(),
"where" => $filter,
@ -168,7 +168,7 @@ class MysqlStorage extends CapacitorStorage {
function _one(CapacitorChannel $channel, $filter): ?array {
if ($filter === null) throw ValueException::null("filter");
$this->verifixFilter($channel, $filter);
$row = $this->mysql->one([
$row = $this->db->one([
"select",
"from" => $channel->getTableName(),
"where" => $filter,
@ -178,7 +178,7 @@ class MysqlStorage extends CapacitorStorage {
function _all(CapacitorChannel $channel, $filter): iterable {
$this->verifixFilter($channel, $filter);
$rows = $this->mysql->all([
$rows = $this->db->all([
"select",
"from" => $channel->getTableName(),
"where" => $filter,
@ -192,7 +192,7 @@ class MysqlStorage extends CapacitorStorage {
if ($func === null) $func = "->onEach";
func::ensure_func($func, $channel, $args);
$onEach = func::_prepare($func);
$mysql = $this->mysql;
$mysql = $this->db;
$tableName = $channel->getTableName();
$commited = false;
$count = 0;
@ -233,6 +233,6 @@ class MysqlStorage extends CapacitorStorage {
}
function close(): void {
$this->mysql->close();
$this->db->close();
}
}

View File

@ -12,14 +12,14 @@ use nur\sery\ValueException;
*/
class SqliteStorage extends CapacitorStorage {
function __construct($sqlite) {
$this->sqlite = Sqlite::with($sqlite);
$this->db = Sqlite::with($sqlite);
}
/** @var Sqlite */
protected $sqlite;
protected $db;
function sqlite(): Sqlite {
return $this->sqlite;
function db(): Sqlite {
return $this->db;
}
const PRIMARY_KEY_DEFINITION = [
@ -29,7 +29,7 @@ class SqliteStorage extends CapacitorStorage {
protected function _create(CapacitorChannel $channel): void {
if (!$channel->isCreated()) {
$cols = $this->ColumnDefinitions($channel);
$this->sqlite->exec([
$this->db->exec([
"create table if not exists",
"table" => $channel->getTableName(),
"cols" => $cols,
@ -39,7 +39,7 @@ class SqliteStorage extends CapacitorStorage {
}
function _exists(CapacitorChannel $channel): bool {
$tableName = $this->sqlite->get([
$tableName = $this->db->get([
"select name from sqlite_schema",
"where" => [
"name" => $channel->getTableName(),
@ -53,7 +53,7 @@ class SqliteStorage extends CapacitorStorage {
}
function _reset(CapacitorChannel $channel): void {
$this->sqlite->exec([
$this->db->exec([
"drop table if exists",
$channel->getTableName(),
]);
@ -71,7 +71,7 @@ class SqliteStorage extends CapacitorStorage {
$rowIds = $this->getRowIds($channel, $row, $primaryKeys);
if ($rowIds !== null) {
# modification
$prow = $this->sqlite->one([
$prow = $this->db->one([
"select",
"from" => $tableName,
"where" => $rowIds,
@ -118,13 +118,13 @@ class SqliteStorage extends CapacitorStorage {
# aucune modification
return 0;
} elseif ($insert) {
$this->sqlite->exec([
$this->db->exec([
"insert",
"into" => $tableName,
"values" => $row,
]);
} else {
$this->sqlite->exec([
$this->db->exec([
"update",
"table" => $tableName,
"values" => $row,
@ -135,7 +135,7 @@ class SqliteStorage extends CapacitorStorage {
}
function _discharge(CapacitorChannel $channel, bool $reset=true): iterable {
$rows = $this->sqlite->all([
$rows = $this->db->all([
"select item__",
"from" => $channel->getTableName(),
]);
@ -156,7 +156,7 @@ class SqliteStorage extends CapacitorStorage {
function _count(CapacitorChannel $channel, $filter): int {
$this->verifixFilter($channel, $filter);
return $this->sqlite->get([
return $this->db->get([
"select count(*)",
"from" => $channel->getTableName(),
"where" => $filter,
@ -166,7 +166,7 @@ class SqliteStorage extends CapacitorStorage {
function _one(CapacitorChannel $channel, $filter): ?array {
if ($filter === null) throw ValueException::null("filter");
$this->verifixFilter($channel, $filter);
$row = $this->sqlite->one([
$row = $this->db->one([
"select",
"from" => $channel->getTableName(),
"where" => $filter,
@ -176,7 +176,7 @@ class SqliteStorage extends CapacitorStorage {
function _all(CapacitorChannel $channel, $filter): iterable {
$this->verifixFilter($channel, $filter);
$rows = $this->sqlite->all([
$rows = $this->db->all([
"select",
"from" => $channel->getTableName(),
"where" => $filter,
@ -190,7 +190,7 @@ class SqliteStorage extends CapacitorStorage {
if ($func === null) $func = "->onEach";
func::ensure_func($func, $channel, $args);
$onEach = func::_prepare($func);
$sqlite = $this->sqlite;
$sqlite = $this->db;
$tableName = $channel->getTableName();
$commited = false;
$count = 0;
@ -231,6 +231,6 @@ class SqliteStorage extends CapacitorStorage {
}
function close(): void {
$this->sqlite->close();
$this->db->close();
}
}

View File

@ -16,6 +16,23 @@ use nur\sery\ValueException;
class Stream extends AbstractIterator implements IReader, IWriter {
use TStreamFilter;
protected static function probe_fd($fd, ?bool &$seekable=null, ?bool &$readable=null): void {
$md = stream_get_meta_data($fd);
$seekable = $md["seekable"];
$mode = $md["mode"];
$readable = strpos($mode, "r") !== false || strpos($mode, "+") !== false;
}
protected static function fd_is_seekable($fd): bool {
self::probe_fd($fd, $seekable);
return $seekable;
}
protected static function fd_is_readable($fd): bool {
$mode = stream_get_meta_data($fd)["mode"];
return strpos($mode, "r") !== false || strpos($mode, "+") !== false;
}
/** @var bool les opérations de verrouillages sont-elle activées? */
const USE_LOCKING = false;
@ -153,6 +170,8 @@ class Stream extends AbstractIterator implements IReader, IWriter {
protected function getCsvParams($fd): array {
$flavour = $this->csvFlavour;
if ($flavour === null) {
self::probe_fd($fd, $seekable, $readable);
if (!$seekable || !$readable) $fd = null;
if ($fd === null) {
# utiliser la valeur par défaut
$flavour = static::DEFAULT_CSV_FLAVOUR;
@ -309,8 +328,8 @@ class Stream extends AbstractIterator implements IReader, IWriter {
}
private function _rewindFd(): void {
$md = stream_get_meta_data($this->fd);
if ($md["seekable"]) $this->fseek(0);
self::probe_fd($this->fd, $seekable);
if ($seekable) $this->fseek(0);
}
protected function _teardown(): void {

View File

@ -64,6 +64,26 @@ class _queryTest extends TestCase {
_query_base::parse_conds(["col" => ["in", ["one", "two"]]], $sql, $params);
self::assertSame(["col in (:col, :col2)"], $sql);
self::assertSame(["col" => "one", "col2" => "two"], $params);
$sql = $params = null;
_query_base::parse_conds(["col" => ["=", ["one", "two"]]], $sql, $params);
self::assertSame(["col = :col and col = :col2"], $sql);
self::assertSame(["col" => "one", "col2" => "two"], $params);
$sql = $params = null;
_query_base::parse_conds(["or", "col" => ["=", ["one", "two"]]], $sql, $params);
self::assertSame(["col = :col or col = :col2"], $sql);
self::assertSame(["col" => "one", "col2" => "two"], $params);
$sql = $params = null;
_query_base::parse_conds(["col" => ["<>", ["one", "two"]]], $sql, $params);
self::assertSame(["col <> :col and col <> :col2"], $sql);
self::assertSame(["col" => "one", "col2" => "two"], $params);
$sql = $params = null;
_query_base::parse_conds(["or", "col" => ["<>", ["one", "two"]]], $sql, $params);
self::assertSame(["col <> :col or col <> :col2"], $sql);
self::assertSame(["col" => "one", "col2" => "two"], $params);
}
function testParseValues(): void {
@ -99,7 +119,7 @@ class _queryTest extends TestCase {
$sql = $params = null;
_query_base::parse_set_values([["int" => 42, "string" => "value"], ["int" => 24, "string" => "eulav"]], $sql, $params);
self::assertSame(["int = :int", "string = :string", "int = :int1", "string = :string1"], $sql);
self::assertSame(["int" => 42, "string" => "value", "int1" => 24, "string1" => "eulav"], $params);
self::assertSame(["int = :int", "string = :string", "int = :int2", "string = :string2"], $sql);
self::assertSame(["int" => 42, "string" => "value", "int2" => 24, "string2" => "eulav"], $params);
}
}