169 lines
4.8 KiB
PHP
169 lines
4.8 KiB
PHP
<?php
|
|
namespace nulib\db\_private;
|
|
|
|
use nulib\cl;
|
|
use nulib\str;
|
|
use nulib\ValueException;
|
|
|
|
trait Tselect {
|
|
static function isa(string $sql): bool {
|
|
return preg_match("/^select\b/i", $sql);
|
|
}
|
|
|
|
private static function add_prefix(string $col, ?string $prefix): string {
|
|
if ($prefix === null) return $col;
|
|
if (strpos($col, ".") !== false) return $col;
|
|
return "$prefix$col";
|
|
}
|
|
|
|
/**
|
|
* parser une chaine de la forme
|
|
* "select [COLS] [from TABLE] [where CONDS] [order by ORDERS] [group by GROUPS] [having CONDS]"
|
|
*/
|
|
static function parse(array $query, ?array &$bindings=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
|
|
$sql = [];
|
|
|
|
## préfixe
|
|
if (($prefix = $query["prefix"] ?? null) !== null) $sql[] = $prefix;
|
|
|
|
## select
|
|
self::consume('(select(?:\s*distinct)?)\s*', $tmpsql, $ms);
|
|
$sql[] = $ms[1];
|
|
|
|
## cols
|
|
$usercols = [];
|
|
if (self::consume('(.*?)\s*(?=$|\bfrom\b)', $tmpsql, $ms)) {
|
|
if ($ms[1]) $usercols[] = $ms[1];
|
|
}
|
|
$colPrefix = $query["col_prefix"] ?? null;
|
|
if ($colPrefix !== null) str::add_suffix($colPrefix, ".");
|
|
$tmpcols = cl::withn($query["cols"] ?? null);
|
|
$schema = $query["schema"] ?? null;
|
|
if ($tmpcols !== null) {
|
|
$cols = [];
|
|
$index = 0;
|
|
foreach ($tmpcols as $key => $col) {
|
|
if ($key === $index) {
|
|
$index++;
|
|
$cols[] = $col;
|
|
$usercols[] = self::add_prefix($col, $colPrefix);
|
|
} else {
|
|
$cols[] = $key;
|
|
$usercols[] = self::add_prefix($col, $colPrefix)." as $key";
|
|
}
|
|
}
|
|
} else {
|
|
$cols = null;
|
|
if ($schema && is_array($schema) && !in_array("*", $usercols)) {
|
|
$cols = array_keys($schema);
|
|
foreach ($cols as $col) {
|
|
$usercols[] = self::add_prefix($col, $colPrefix);
|
|
}
|
|
}
|
|
}
|
|
if (!$usercols && !$cols) $usercols = [self::add_prefix("*", $colPrefix)];
|
|
$sql[] = implode(", ", $usercols);
|
|
|
|
## from
|
|
$from = $query["from"] ?? null;
|
|
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
|
|
$userwhere = [];
|
|
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);
|
|
if ($where !== null) self::parse_conds($where, $userwhere, $bindings);
|
|
if ($userwhere) {
|
|
$sql[] = "where";
|
|
$sql[] = implode(" and ", $userwhere);
|
|
}
|
|
|
|
## 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++;
|
|
} else {
|
|
if ($value === null) $value = false;
|
|
if (!is_bool($value)) {
|
|
$userorderby[] = "$key $value";
|
|
} elseif ($value) {
|
|
$userorderby[] = $key;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
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++;
|
|
} else {
|
|
if ($value === null) $value = false;
|
|
if (!is_bool($value)) {
|
|
$usergroupby[] = "$key $value";
|
|
} elseif ($value) {
|
|
$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, $bindings);
|
|
if ($userhaving) {
|
|
$sql[] = "having";
|
|
$sql[] = implode(" and ", $userhaving);
|
|
}
|
|
|
|
## suffixe
|
|
if (($suffix = $query["suffix"] ?? null) !== null) $sql[] = $suffix;
|
|
|
|
## fin de la requête
|
|
self::check_eof($tmpsql, $usersql);
|
|
return implode(" ", $sql);
|
|
}
|
|
}
|