implémenter group by et having
This commit is contained in:
		
							parent
							
								
									5e760ce71b
								
							
						
					
					
						commit
						86cab90788
					
				@ -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");
 | 
			
		||||
 | 
			
		||||
@ -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,
 | 
			
		||||
 | 
			
		||||
@ -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);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user