implémentation de base de select
This commit is contained in:
parent
ea2449b766
commit
5e760ce71b
|
@ -1,5 +0,0 @@
|
|||
<?php
|
||||
namespace nur\sery\db;
|
||||
|
||||
class filters {
|
||||
}
|
|
@ -141,6 +141,10 @@ class Sqlite {
|
|||
}
|
||||
}
|
||||
|
||||
function one($query, ?array $params=null): ?array {
|
||||
return $this->get($query, $params, true);
|
||||
}
|
||||
|
||||
protected function _fetchResult(SQLite3Result $result): Generator {
|
||||
try {
|
||||
while (($row = $result->fetchArray(SQLITE3_ASSOC)) !== false) {
|
||||
|
|
|
@ -53,6 +53,120 @@ class _Query {
|
|||
return $sql;
|
||||
}
|
||||
|
||||
static function is_sep(&$cond): bool {
|
||||
if (!is_string($cond)) return false;
|
||||
if (!preg_match('/^\s*(and|or|not)\s*$/i', $cond, $ms)) return false;
|
||||
$cond = $ms[1];
|
||||
return true;
|
||||
}
|
||||
|
||||
static function parse_conds(?array $conds, ?array &$sql, ?array &$params): void {
|
||||
if (!$conds) return;
|
||||
$sep = null;
|
||||
$index = 0;
|
||||
$condsql = [];
|
||||
foreach ($conds as $key => $cond) {
|
||||
if ($key === $index) {
|
||||
## séquentiel
|
||||
if ($index === 0 && self::is_sep($cond)) {
|
||||
$sep = $cond;
|
||||
} elseif (is_array($cond)) {
|
||||
# condition récursive
|
||||
self::parse_conds($cond, $condsql, $params);
|
||||
} else {
|
||||
# condition litérale
|
||||
$condsql[] = strval($cond);
|
||||
}
|
||||
$index++;
|
||||
} else {
|
||||
## associatif
|
||||
# paramètre
|
||||
$param = $key;
|
||||
if ($params !== null && array_key_exists($param, $params)) {
|
||||
$i = 1;
|
||||
while (array_key_exists("$key$i", $params)) {
|
||||
$i++;
|
||||
}
|
||||
$param = "$key$i";
|
||||
}
|
||||
# value ou [operator, value]
|
||||
if (is_array($cond)) {
|
||||
$op = null;
|
||||
$value = null;
|
||||
$condkeys = array_keys($cond);
|
||||
if (array_key_exists("op", $cond)) $op = $cond["op"];
|
||||
if (array_key_exists("value", $cond)) $value = $cond["value"];
|
||||
$condkey = 0;
|
||||
if ($op === null && array_key_exists($condkey, $condkeys)) {
|
||||
$op = $cond[$condkeys[$condkey]];
|
||||
$condkey++;
|
||||
}
|
||||
if ($value === null && array_key_exists($condkey, $condkeys)) {
|
||||
$value = $cond[$condkeys[$condkey]];
|
||||
$condkey++;
|
||||
}
|
||||
} else {
|
||||
$op = "=";
|
||||
$value = $cond;
|
||||
}
|
||||
$cond = [$key, $op];
|
||||
if ($value !== null) {
|
||||
$cond[] = ":$param";
|
||||
$params[$param] = $value;
|
||||
}
|
||||
$condsql[] = implode(" ", $cond);
|
||||
}
|
||||
}
|
||||
if ($sep === null) $sep = "and";
|
||||
$count = count($condsql);
|
||||
if ($count > 1) {
|
||||
$sql[] = "(" . implode(" $sep ", $condsql) . ")";
|
||||
} elseif ($count == 1) {
|
||||
$sql[] = $condsql[0];
|
||||
}
|
||||
}
|
||||
|
||||
static function parse_values(?array $values, ?array &$sql, ?array &$params): void {
|
||||
if (!$values) return;
|
||||
$index = 0;
|
||||
$parts = [];
|
||||
foreach ($values as $key => $part) {
|
||||
if ($key === $index) {
|
||||
## séquentiel
|
||||
if (is_array($part)) {
|
||||
# paramètres récursifs
|
||||
self::parse_values($part, $parts, $params);
|
||||
} else {
|
||||
# paramètre litéral
|
||||
$parts[] = strval($part);
|
||||
}
|
||||
$index++;
|
||||
} else {
|
||||
## associatif
|
||||
# paramètre
|
||||
$param = $key;
|
||||
if ($params !== null && array_key_exists($param, $params)) {
|
||||
$i = 1;
|
||||
while (array_key_exists("$key$i", $params)) {
|
||||
$i++;
|
||||
}
|
||||
$param = "$key$i";
|
||||
}
|
||||
# value
|
||||
$value = $part;
|
||||
$part = [$key, "="];
|
||||
if ($value === null) {
|
||||
$part[] = "null";
|
||||
} else {
|
||||
$part[] = ":$param";
|
||||
$params[$param] = $value;
|
||||
}
|
||||
$parts[] = implode(" ", $part);
|
||||
}
|
||||
}
|
||||
$sql = cl::merge($sql, $parts);
|
||||
}
|
||||
|
||||
const create_SCHEMA = [
|
||||
"prefix" => "string",
|
||||
"table" => "string",
|
||||
|
@ -77,7 +191,7 @@ class _Query {
|
|||
"having" => "?array",
|
||||
];
|
||||
static function is_select(string $sql): bool {
|
||||
return false;
|
||||
return preg_match("/^select\b/i", $sql);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -87,14 +201,14 @@ class _Query {
|
|||
static function parse_select(array $query, ?array &$params=null): string {
|
||||
# fusionner d'abord toutes les parties séquentielles
|
||||
$usersql = $tmpsql = self::merge_seq($query);
|
||||
## vérifier la présence des parties nécessaires
|
||||
### vérifier la présence des parties nécessaires
|
||||
$sql = [];
|
||||
if (($prefix = $query["prefix"] ?? null) !== null) $sql[] = $prefix;
|
||||
# select
|
||||
## select
|
||||
self::consume('select\s*', $tmpsql); $sql[] = "select";
|
||||
# cols
|
||||
## cols
|
||||
$usercols = [];
|
||||
if (self::consume('(.*)\s*(?<=$|\bfrom\b)', $tmpsql, $ms)) {
|
||||
if (self::consume('(.*?)\s*(?=$|\bfrom\b)', $tmpsql, $ms)) {
|
||||
if ($ms[1]) $usercols[] = $ms[1];
|
||||
}
|
||||
$tmpcols = cl::withn($query["cols"] ?? null);
|
||||
|
@ -119,24 +233,31 @@ class _Query {
|
|||
$usercols = array_merge($usercols, $cols);
|
||||
}
|
||||
}
|
||||
if (!$usercols && !$cols) $usercols = ["*"];
|
||||
$sql[] = implode(" ", $usercols);
|
||||
# from
|
||||
## from
|
||||
$from = $query["from"] ?? null;
|
||||
if (self::consume('from\s+([a-z_][a-z0-9_]*)\s*(?<=;?\s*$|\bwhere\b)', $tmpsql, $ms)) {
|
||||
if (self::consume('from\s+([a-z_][a-z0-9_]*)\s*(?=;?\s*$|\bwhere\b)', $tmpsql, $ms)) {
|
||||
if ($from === null) $from = $ms[1];
|
||||
$sql[] = "from";
|
||||
$sql[] = $from;
|
||||
} elseif ($from !== null) {
|
||||
$sql[] = "from";
|
||||
$sql[] = $from;
|
||||
} else {
|
||||
throw new ValueException("expected table name: $usersql");
|
||||
}
|
||||
# where
|
||||
## where
|
||||
$userwhere = [];
|
||||
if (self::consume('where\s*(.*)(?<=;?\s*$|\border\s+by\b)', $tmpsql, $ms)) {
|
||||
if (self::consume('where\s*(.*?)(?=;?\s*$|\border\s+by\b)', $tmpsql, $ms)) {
|
||||
if ($ms[1]) $userwhere[] = $ms[1];
|
||||
}
|
||||
$where = cl::withn($query["where"] ?? null);
|
||||
|
||||
if ($where !== null) self::parse_conds($where, $userwhere, $params);
|
||||
if ($userwhere) {
|
||||
$sql[] = "where";
|
||||
$sql[] = implode(" and ", $userwhere);
|
||||
}
|
||||
# order by
|
||||
# group by
|
||||
# having
|
||||
|
|
|
@ -3,7 +3,6 @@ namespace nur\sery\db\sqlite;
|
|||
|
||||
use Exception;
|
||||
use nulib\tests\TestCase;
|
||||
use nur\sery\ValueException;
|
||||
|
||||
class SqliteTest extends TestCase {
|
||||
const CREATE_PERSON = "create table person(nom varchar, prenom varchar, age integer)";
|
||||
|
@ -70,4 +69,52 @@ class SqliteTest extends TestCase {
|
|||
["i" => 10, "s" => null/*"dix"*/],
|
||||
], iterator_to_array($sqlite->all("select * from mapping")));
|
||||
}
|
||||
|
||||
function testSelect() {
|
||||
$sqlite = new Sqlite(":memory:", [
|
||||
"migrate" => "create table user (name varchar, amount integer)",
|
||||
]);
|
||||
$sqlite->exec(["insert into user", "values" => ["name" => "jclain1", "amount" => 1]]);
|
||||
$sqlite->exec(["insert into user", "values" => ["name" => "jclain2", "amount" => 2]]);
|
||||
$sqlite->exec(["insert into user", "values" => ["name" => "jclain5", "amount" => 5]]);
|
||||
$sqlite->exec(["insert into user", "values" => ["name" => "fclain7", "amount" => 7]]);
|
||||
$sqlite->exec(["insert into user", "values" => ["name" => "fclain9", "amount" => 9]]);
|
||||
$sqlite->exec(["insert into user", "values" => ["name" => "fclain10", "amount" => 10]]);
|
||||
self::assertSame([
|
||||
"name" => "jclain1",
|
||||
"amount" => 1,
|
||||
], $sqlite->one("select * from user where name = 'jclain1'"));
|
||||
self::assertSame([
|
||||
"name" => "jclain1",
|
||||
"amount" => 1,
|
||||
], $sqlite->one(["select * from user where name = 'jclain1'"]));
|
||||
self::assertSame([
|
||||
"name" => "jclain1",
|
||||
"amount" => 1,
|
||||
], $sqlite->one(["select from user where name = 'jclain1'"]));
|
||||
self::assertSame([
|
||||
"name" => "jclain1",
|
||||
"amount" => 1,
|
||||
], $sqlite->one(["select from user", "where" => ["name = 'jclain1'"]]));
|
||||
self::assertSame([
|
||||
"name" => "jclain1",
|
||||
"amount" => 1,
|
||||
], $sqlite->one(["select", "from" => "user", "where" => ["name = 'jclain1'"]]));
|
||||
self::assertSame([
|
||||
"name" => "jclain1",
|
||||
"amount" => 1,
|
||||
], $sqlite->one(["select", "from" => "user", "where" => ["name" => "jclain1"]]));
|
||||
self::assertSame([
|
||||
"name" => "jclain1",
|
||||
], $sqlite->one(["select name", "from" => "user", "where" => ["name" => "jclain1"]]));
|
||||
self::assertSame([
|
||||
"name" => "jclain1",
|
||||
], $sqlite->one(["select", "cols" => "name", "from" => "user", "where" => ["name" => "jclain1"]]));
|
||||
self::assertSame([
|
||||
"name" => "jclain1",
|
||||
], $sqlite->one(["select", "cols" => ["name"], "from" => "user", "where" => ["name" => "jclain1"]]));
|
||||
self::assertSame([
|
||||
"plouf" => "jclain1",
|
||||
], $sqlite->one(["select", "cols" => ["plouf" => "name"], "from" => "user", "where" => ["name" => "jclain1"]]));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,86 @@
|
|||
<?php
|
||||
namespace nur\sery\db\sqlite;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class _QueryTest extends TestCase {
|
||||
function testParseConds(): void {
|
||||
$sql = $params = null;
|
||||
_Query::parse_conds(null, $sql, $params);
|
||||
self::assertNull($sql);
|
||||
self::assertNull($params);
|
||||
|
||||
$sql = $params = null;
|
||||
_Query::parse_conds([], $sql, $params);
|
||||
self::assertNull($sql);
|
||||
self::assertNull($params);
|
||||
|
||||
$sql = $params = null;
|
||||
_Query::parse_conds(["col = 'value'"], $sql, $params);
|
||||
self::assertSame(["col = 'value'"], $sql);
|
||||
self::assertNull($params);
|
||||
|
||||
$sql = $params = null;
|
||||
_Query::parse_conds([["col = 'value'"]], $sql, $params);
|
||||
self::assertSame(["col = 'value'"], $sql);
|
||||
self::assertNull($params);
|
||||
|
||||
$sql = $params = null;
|
||||
_Query::parse_conds(["int" => 42, "string" => "value"], $sql, $params);
|
||||
self::assertSame(["(int = :int and string = :string)"], $sql);
|
||||
self::assertSame(["int" => 42, "string" => "value"], $params);
|
||||
|
||||
$sql = $params = null;
|
||||
_Query::parse_conds(["or", "int" => 42, "string" => "value"], $sql, $params);
|
||||
self::assertSame(["(int = :int or string = :string)"], $sql);
|
||||
self::assertSame(["int" => 42, "string" => "value"], $params);
|
||||
|
||||
$sql = $params = null;
|
||||
_Query::parse_conds([["int" => 42, "string" => "value"], ["int" => 24, "string" => "eulav"]], $sql, $params);
|
||||
self::assertSame(["((int = :int and string = :string) and (int = :int1 and string = :string1))"], $sql);
|
||||
self::assertSame(["int" => 42, "string" => "value", "int1" => 24, "string1" => "eulav"], $params);
|
||||
|
||||
$sql = $params = null;
|
||||
_Query::parse_conds(["int" => ["is null"], "string" => ["<>", "value"]], $sql, $params);
|
||||
self::assertSame(["(int is null and string <> :string)"], $sql);
|
||||
self::assertSame(["string" => "value"], $params);
|
||||
}
|
||||
|
||||
function testParseValues(): void {
|
||||
$sql = $params = null;
|
||||
_Query::parse_values(null, $sql, $params);
|
||||
self::assertNull($sql);
|
||||
self::assertNull($params);
|
||||
|
||||
$sql = $params = null;
|
||||
_Query::parse_values([], $sql, $params);
|
||||
self::assertNull($sql);
|
||||
self::assertNull($params);
|
||||
|
||||
$sql = $params = null;
|
||||
_Query::parse_values(["col = 'value'"], $sql, $params);
|
||||
self::assertSame(["col = 'value'"], $sql);
|
||||
self::assertNull($params);
|
||||
|
||||
$sql = $params = null;
|
||||
_Query::parse_values([["col = 'value'"]], $sql, $params);
|
||||
self::assertSame(["col = 'value'"], $sql);
|
||||
self::assertNull($params);
|
||||
|
||||
$sql = $params = null;
|
||||
_Query::parse_values(["int" => 42, "string" => "value"], $sql, $params);
|
||||
self::assertSame(["int = :int", "string = :string"], $sql);
|
||||
self::assertSame(["int" => 42, "string" => "value"], $params);
|
||||
|
||||
$sql = $params = null;
|
||||
_Query::parse_values(["int" => 42, "string" => "value"], $sql, $params);
|
||||
self::assertSame(["int = :int", "string = :string"], $sql);
|
||||
self::assertSame(["int" => 42, "string" => "value"], $params);
|
||||
|
||||
$sql = $params = null;
|
||||
_Query::parse_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);
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue