From 86cab90788f7d10857fd23bbfc29860b594d10f5 Mon Sep 17 00:00:00 2001 From: Jephte Clain Date: Thu, 9 May 2024 11:54:15 +0400 Subject: [PATCH] =?UTF-8?q?impl=C3=A9menter=20group=20by=20et=20having?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/db/sqlite/_Query.php | 71 +++++++++++++++++++++++++++++++--- tests/db/sqlite/SqliteTest.php | 4 ++ tests/db/sqlite/_QueryTest.php | 14 +++---- 3 files changed, 76 insertions(+), 13 deletions(-) diff --git a/src/db/sqlite/_Query.php b/src/db/sqlite/_Query.php index 28d0c0b..9e1ef41 100644 --- a/src/db/sqlite/_Query.php +++ b/src/db/sqlite/_Query.php @@ -126,7 +126,7 @@ class _Query { } } - static function parse_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 = []; @@ -135,7 +135,7 @@ class _Query { ## séquentiel if (is_array($part)) { # paramètres récursifs - self::parse_values($part, $parts, $params); + self::parse_set_values($part, $parts, $params); } else { # paramètre litéral $parts[] = strval($part); @@ -204,8 +204,10 @@ class _Query { ### vérifier la présence des parties nécessaires $sql = []; if (($prefix = $query["prefix"] ?? null) !== null) $sql[] = $prefix; + ## select self::consume('select\s*', $tmpsql); $sql[] = "select"; + ## cols $usercols = []; if (self::consume('(.*?)\s*(?=$|\bfrom\b)', $tmpsql, $ms)) { @@ -235,6 +237,7 @@ class _Query { } if (!$usercols && !$cols) $usercols = ["*"]; $sql[] = implode(" ", $usercols); + ## from $from = $query["from"] ?? null; if (self::consume('from\s+([a-z_][a-z0-9_]*)\s*(?=;?\s*$|\bwhere\b)', $tmpsql, $ms)) { @@ -247,9 +250,10 @@ class _Query { } else { throw new ValueException("expected table name: $usersql"); } + ## where $userwhere = []; - if (self::consume('where\s*(.*?)(?=;?\s*$|\border\s+by\b)', $tmpsql, $ms)) { + if (self::consume('where\b\s*(.*?)(?=;?\s*$|\border\s+by\b)', $tmpsql, $ms)) { if ($ms[1]) $userwhere[] = $ms[1]; } $where = cl::withn($query["where"] ?? null); @@ -258,9 +262,64 @@ class _Query { $sql[] = "where"; $sql[] = implode(" and ", $userwhere); } - # order by - # group by - # having + + ## order by + $userorderby = []; + if (self::consume('order\s+by\b\s*(.*?)(?=;?\s*$|\bgroup\s+by\b)', $tmpsql, $ms)) { + if ($ms[1]) $userorderby[] = $ms[1]; + } + $orderby = cl::withn($query["order by"] ?? null); + if ($orderby !== null) { + $index = 0; + foreach ($orderby as $key => $value) { + if ($key === $index) { + $userorderby[] = $value; + $index++; + } elseif ($value !== null) { + if (is_bool($value)) $value = $value? "asc": "desc"; + $userorderby[] = "$key $value"; + } + } + } + if ($userorderby) { + $sql[] = "order by"; + $sql[] = implode(", ", $userorderby); + } + ## group by + $usergroupby = []; + if (self::consume('group\s+by\b\s*(.*?)(?=;?\s*$|\bhaving\b)', $tmpsql, $ms)) { + if ($ms[1]) $usergroupby[] = $ms[1]; + } + $groupby = cl::withn($query["group by"] ?? null); + if ($groupby !== null) { + $index = 0; + foreach ($groupby as $key => $value) { + if ($key === $index) { + $usergroupby[] = $value; + $index++; + } elseif ($value !== null) { + $usergroupby[] = $key; + } + } + } + if ($usergroupby) { + $sql[] = "group by"; + $sql[] = implode(", ", $usergroupby); + } + + ## having + $userhaving = []; + if (self::consume('having\b\s*(.*?)(?=;?\s*$)', $tmpsql, $ms)) { + if ($ms[1]) $userhaving[] = $ms[1]; + } + $having = cl::withn($query["having"] ?? null); + if ($having !== null) self::parse_conds($having, $userhaving, $params); + if ($userhaving) { + $sql[] = "having"; + $sql[] = implode(" and ", $userhaving); + } + + ## fin de la requête self::consume(';\s*', $tmpsql); if ($tmpsql) { throw new ValueException("unexpected value at end: $usersql"); diff --git a/tests/db/sqlite/SqliteTest.php b/tests/db/sqlite/SqliteTest.php index d3f0f11..55c7563 100644 --- a/tests/db/sqlite/SqliteTest.php +++ b/tests/db/sqlite/SqliteTest.php @@ -92,6 +92,10 @@ class SqliteTest extends TestCase { "name" => "jclain1", "amount" => 1, ], $sqlite->one(["select from user where name = 'jclain1'"])); + self::assertSame([ + "name" => "jclain1", + "amount" => 1, + ], $sqlite->one(["select from user where", "where" => ["name = 'jclain1'"]])); self::assertSame([ "name" => "jclain1", "amount" => 1, diff --git a/tests/db/sqlite/_QueryTest.php b/tests/db/sqlite/_QueryTest.php index d3bb82c..384193e 100644 --- a/tests/db/sqlite/_QueryTest.php +++ b/tests/db/sqlite/_QueryTest.php @@ -48,37 +48,37 @@ class _QueryTest extends TestCase { function testParseValues(): void { $sql = $params = null; - _Query::parse_values(null, $sql, $params); + _Query::parse_set_values(null, $sql, $params); self::assertNull($sql); self::assertNull($params); $sql = $params = null; - _Query::parse_values([], $sql, $params); + _Query::parse_set_values([], $sql, $params); self::assertNull($sql); self::assertNull($params); $sql = $params = null; - _Query::parse_values(["col = 'value'"], $sql, $params); + _Query::parse_set_values(["col = 'value'"], $sql, $params); self::assertSame(["col = 'value'"], $sql); self::assertNull($params); $sql = $params = null; - _Query::parse_values([["col = 'value'"]], $sql, $params); + _Query::parse_set_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); + _Query::parse_set_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); + _Query::parse_set_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); + _Query::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); }