Skip to content

Commit 064d85b

Browse files
authored
Merge pull request #2257 from michalsn/feature/having_like
Several updates to the HAVING clauses
2 parents 6fc1af2 + b9e13e0 commit 064d85b

4 files changed

Lines changed: 1173 additions & 7 deletions

File tree

system/Database/BaseBuilder.php

Lines changed: 254 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -829,6 +829,82 @@ public function orWhereNotIn(string $key = null, $values = null, bool $escape =
829829

830830
//--------------------------------------------------------------------
831831

832+
/**
833+
* HAVING IN
834+
*
835+
* Generates a HAVING field IN('item', 'item') SQL query,
836+
* joined with 'AND' if appropriate.
837+
*
838+
* @param string $key The field to search
839+
* @param array|string|Closure $values The values searched on, or anonymous function with subquery
840+
* @param boolean $escape
841+
*
842+
* @return BaseBuilder
843+
*/
844+
public function havingIn(string $key = null, $values = null, bool $escape = null)
845+
{
846+
return $this->_whereIn($key, $values, false, 'AND ', $escape, 'QBHaving');
847+
}
848+
849+
//--------------------------------------------------------------------
850+
851+
/**
852+
* OR HAVING IN
853+
*
854+
* Generates a HAVING field IN('item', 'item') SQL query,
855+
* joined with 'OR' if appropriate.
856+
*
857+
* @param string $key The field to search
858+
* @param array|string|Closure $values The values searched on, or anonymous function with subquery
859+
* @param boolean $escape
860+
*
861+
* @return BaseBuilder
862+
*/
863+
public function orHavingIn(string $key = null, $values = null, bool $escape = null)
864+
{
865+
return $this->_whereIn($key, $values, false, 'OR ', $escape, 'QBHaving');
866+
}
867+
868+
//--------------------------------------------------------------------
869+
870+
/**
871+
* HAVING NOT IN
872+
*
873+
* Generates a HAVING field NOT IN('item', 'item') SQL query,
874+
* joined with 'AND' if appropriate.
875+
*
876+
* @param string $key The field to search
877+
* @param array|string|Closure $values The values searched on, or anonymous function with subquery
878+
* @param boolean $escape
879+
*
880+
* @return BaseBuilder
881+
*/
882+
public function havingNotIn(string $key = null, $values = null, bool $escape = null)
883+
{
884+
return $this->_whereIn($key, $values, true, 'AND ', $escape, 'QBHaving');
885+
}
886+
887+
//--------------------------------------------------------------------
888+
889+
/**
890+
* OR HAVING NOT IN
891+
*
892+
* Generates a HAVING field NOT IN('item', 'item') SQL query,
893+
* joined with 'OR' if appropriate.
894+
*
895+
* @param string $key The field to search
896+
* @param array|string|Closure $values The values searched on, or anonymous function with subquery
897+
* @param boolean $escape
898+
*
899+
* @return BaseBuilder
900+
*/
901+
public function orHavingNotIn(string $key = null, $values = null, bool $escape = null)
902+
{
903+
return $this->_whereIn($key, $values, true, 'OR ', $escape, 'QBHaving');
904+
}
905+
906+
//--------------------------------------------------------------------
907+
832908
/**
833909
* Internal WHERE IN
834910
*
@@ -842,10 +918,11 @@ public function orWhereNotIn(string $key = null, $values = null, bool $escape =
842918
* @param boolean $not If the statement would be IN or NOT IN
843919
* @param string $type
844920
* @param boolean $escape
921+
* @param string $clause (Internal use only)
845922
*
846923
* @return BaseBuilder
847924
*/
848-
protected function _whereIn(string $key = null, $values = null, bool $not = false, string $type = 'AND ', bool $escape = null)
925+
protected function _whereIn(string $key = null, $values = null, bool $not = false, string $type = 'AND ', bool $escape = null, string $clause = 'QBWhere')
849926
{
850927
if ($key === null || $values === null || (! is_array($values) && ! ($values instanceof Closure)))
851928
{
@@ -874,14 +951,14 @@ protected function _whereIn(string $key = null, $values = null, bool $not = fals
874951
$ok = $this->setBind($ok, $whereIn, $escape);
875952
}
876953

877-
$prefix = empty($this->QBWhere) ? $this->groupGetType('') : $this->groupGetType($type);
954+
$prefix = empty($this->$clause) ? $this->groupGetType('') : $this->groupGetType($type);
878955

879956
$whereIn = [
880957
'condition' => $prefix . $key . $not . ($values instanceof Closure ? " IN ($ok)" : " IN :{$ok}:"),
881958
'escape' => false,
882959
];
883960

884-
$this->QBWhere[] = $whereIn;
961+
$this->{$clause}[] = $whereIn;
885962

886963
return $this;
887964
}
@@ -970,6 +1047,86 @@ public function orNotLike($field, string $match = '', string $side = 'both', boo
9701047
return $this->_like($field, $match, 'OR ', $side, 'NOT', $escape, $insensitiveSearch);
9711048
}
9721049

1050+
// --------------------------------------------------------------------
1051+
1052+
/**
1053+
* LIKE with HAVING clause
1054+
*
1055+
* Generates a %LIKE% portion of the query.
1056+
* Separates multiple calls with 'AND'.
1057+
*
1058+
* @param mixed $field
1059+
* @param string $match
1060+
* @param string $side
1061+
* @param boolean $escape
1062+
*
1063+
* @return BaseBuilder
1064+
*/
1065+
public function havingLike($field, string $match = '', string $side = 'both', bool $escape = null, bool $insensitiveSearch = false)
1066+
{
1067+
return $this->_like($field, $match, 'AND ', $side, '', $escape, $insensitiveSearch, 'QBHaving');
1068+
}
1069+
1070+
// --------------------------------------------------------------------
1071+
1072+
/**
1073+
* NOT LIKE with HAVING clause
1074+
*
1075+
* Generates a NOT LIKE portion of the query.
1076+
* Separates multiple calls with 'AND'.
1077+
*
1078+
* @param mixed $field
1079+
* @param string $match
1080+
* @param string $side
1081+
* @param boolean $escape
1082+
*
1083+
* @return BaseBuilder
1084+
*/
1085+
public function notHavingLike($field, string $match = '', string $side = 'both', bool $escape = null, bool $insensitiveSearch = false)
1086+
{
1087+
return $this->_like($field, $match, 'AND ', $side, 'NOT', $escape, $insensitiveSearch, 'QBHaving');
1088+
}
1089+
1090+
// --------------------------------------------------------------------
1091+
1092+
/**
1093+
* OR LIKE with HAVING clause
1094+
*
1095+
* Generates a %LIKE% portion of the query.
1096+
* Separates multiple calls with 'OR'.
1097+
*
1098+
* @param mixed $field
1099+
* @param string $match
1100+
* @param string $side
1101+
* @param boolean $escape
1102+
*
1103+
* @return BaseBuilder
1104+
*/
1105+
public function orHavingLike($field, string $match = '', string $side = 'both', bool $escape = null, bool $insensitiveSearch = false)
1106+
{
1107+
return $this->_like($field, $match, 'OR ', $side, '', $escape, $insensitiveSearch, 'QBHaving');
1108+
}
1109+
1110+
// --------------------------------------------------------------------
1111+
1112+
/**
1113+
* OR NOT LIKE with HAVING clause
1114+
*
1115+
* Generates a NOT LIKE portion of the query.
1116+
* Separates multiple calls with 'OR'.
1117+
*
1118+
* @param mixed $field
1119+
* @param string $match
1120+
* @param string $side
1121+
* @param boolean $escape
1122+
*
1123+
* @return BaseBuilder
1124+
*/
1125+
public function orNotHavingLike($field, string $match = '', string $side = 'both', bool $escape = null, bool $insensitiveSearch = false)
1126+
{
1127+
return $this->_like($field, $match, 'OR ', $side, 'NOT', $escape, $insensitiveSearch, 'QBHaving');
1128+
}
1129+
9731130
//--------------------------------------------------------------------
9741131

9751132
/**
@@ -979,6 +1136,10 @@ public function orNotLike($field, string $match = '', string $side = 'both', boo
9791136
* @used-by orLike()
9801137
* @used-by notLike()
9811138
* @used-by orNotLike()
1139+
* @used-by havingLike()
1140+
* @used-by orHavingLike()
1141+
* @used-by notHavingLike()
1142+
* @used-by orNotHavingLike()
9821143
*
9831144
* @param mixed $field
9841145
* @param string $match
@@ -987,10 +1148,11 @@ public function orNotLike($field, string $match = '', string $side = 'both', boo
9871148
* @param string $not
9881149
* @param boolean $escape
9891150
* @param boolean $insensitiveSearch IF true, will force a case-insensitive search
1151+
* @param string $clause (Internal use only)
9901152
*
9911153
* @return BaseBuilder
9921154
*/
993-
protected function _like($field, string $match = '', string $type = 'AND ', string $side = 'both', string $not = '', bool $escape = null, bool $insensitiveSearch = false)
1155+
protected function _like($field, string $match = '', string $type = 'AND ', string $side = 'both', string $not = '', bool $escape = null, bool $insensitiveSearch = false, string $clause = 'QBWhere')
9941156
{
9951157
if (! is_array($field))
9961158
{
@@ -1004,13 +1166,13 @@ protected function _like($field, string $match = '', string $type = 'AND ', stri
10041166

10051167
foreach ($field as $k => $v)
10061168
{
1007-
$prefix = empty($this->QBWhere) ? $this->groupGetType('') : $this->groupGetType($type);
1008-
10091169
if ($insensitiveSearch === true)
10101170
{
10111171
$v = strtolower($v);
10121172
}
10131173

1174+
$prefix = empty($this->$clause) ? $this->groupGetType('') : $this->groupGetType($type);
1175+
10141176
if ($side === 'none')
10151177
{
10161178
$bind = $this->setBind($k, $v, $escape);
@@ -1036,7 +1198,7 @@ protected function _like($field, string $match = '', string $type = 'AND ', stri
10361198
$like_statement .= sprintf($this->db->likeEscapeStr, $this->db->likeEscapeChar);
10371199
}
10381200

1039-
$this->QBWhere[] = [
1201+
$this->{$clause}[] = [
10401202
'condition' => $like_statement,
10411203
'escape' => $escape,
10421204
];
@@ -1152,6 +1314,90 @@ public function groupEnd()
11521314
return $this;
11531315
}
11541316

1317+
// --------------------------------------------------------------------
1318+
1319+
/**
1320+
* Starts a query group for HAVING clause.
1321+
*
1322+
* @param string $not (Internal use only)
1323+
* @param string $type (Internal use only)
1324+
*
1325+
* @return BaseBuilder
1326+
*/
1327+
public function havingGroupStart(string $not = '', string $type = 'AND ')
1328+
{
1329+
$type = $this->groupGetType($type);
1330+
1331+
$this->QBWhereGroupStarted = true;
1332+
$prefix = empty($this->QBHaving) ? '' : $type;
1333+
$having = [
1334+
'condition' => $prefix . $not . str_repeat(' ', ++$this->QBWhereGroupCount) . ' (',
1335+
'value' => null,
1336+
'escape' => false,
1337+
];
1338+
1339+
$this->QBHaving[] = $having;
1340+
1341+
return $this;
1342+
}
1343+
1344+
// --------------------------------------------------------------------
1345+
1346+
/**
1347+
* Starts a query group for HAVING clause, but ORs the group.
1348+
*
1349+
* @return BaseBuilder
1350+
*/
1351+
public function orHavingGroupStart()
1352+
{
1353+
return $this->havingGroupStart('', 'OR ');
1354+
}
1355+
1356+
// --------------------------------------------------------------------
1357+
1358+
/**
1359+
* Starts a query group for HAVING clause, but NOTs the group.
1360+
*
1361+
* @return BaseBuilder
1362+
*/
1363+
public function notHavingGroupStart()
1364+
{
1365+
return $this->havingGroupStart('NOT ', 'AND ');
1366+
}
1367+
1368+
// --------------------------------------------------------------------
1369+
1370+
/**
1371+
* Starts a query group for HAVING clause, but OR NOTs the group.
1372+
*
1373+
* @return BaseBuilder
1374+
*/
1375+
public function orNotHavingGroupStart()
1376+
{
1377+
return $this->havingGroupStart('NOT ', 'OR ');
1378+
}
1379+
1380+
// --------------------------------------------------------------------
1381+
1382+
/**
1383+
* Ends a query group for HAVING clause.
1384+
*
1385+
* @return BaseBuilder
1386+
*/
1387+
public function havingGroupEnd()
1388+
{
1389+
$this->QBWhereGroupStarted = false;
1390+
$having = [
1391+
'condition' => str_repeat(' ', $this->QBWhereGroupCount -- ) . ')',
1392+
'value' => null,
1393+
'escape' => false,
1394+
];
1395+
1396+
$this->QBHaving[] = $having;
1397+
1398+
return $this;
1399+
}
1400+
11551401
//--------------------------------------------------------------------
11561402

11571403
/**
@@ -1161,6 +1407,7 @@ public function groupEnd()
11611407
* @used-by _like()
11621408
* @used-by whereHaving()
11631409
* @used-by _whereIn()
1410+
* @used-by havingGroupStart()
11641411
*
11651412
* @param string $type
11661413
*

0 commit comments

Comments
 (0)