Skip to content

Commit a9c5009

Browse files
author
Marc-Etienne Barrut
committed
Add better bitwise operators support
1 parent a150549 commit a9c5009

File tree

4 files changed

+99
-2
lines changed

4 files changed

+99
-2
lines changed

src/Illuminate/Database/Query/Builder.php

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,15 @@ class Builder
203203
'not similar to', 'not ilike', '~~*', '!~~*',
204204
];
205205

206+
/**
207+
* All of the available binary operators.
208+
*
209+
* @var string[]
210+
*/
211+
public $binaryOperators = [
212+
'&', '|', '^', '<<', '>>', '&~',
213+
];
214+
206215
/**
207216
* Whether to use write pdo for the select.
208217
*
@@ -754,6 +763,10 @@ public function where($column, $operator = null, $value = null, $boolean = 'and'
754763
}
755764
}
756765

766+
if ($this->isBinaryOperator($operator)) {
767+
$type = 'Binary';
768+
}
769+
757770
// Now that we are working with just a simple query we can put the elements
758771
// in our array and add the query binding to our array of bindings that
759772
// will be bound to each SQL statements when it is finally executed.
@@ -837,6 +850,12 @@ protected function invalidOperator($operator)
837850
! in_array(strtolower($operator), $this->grammar->getOperators(), true);
838851
}
839852

853+
protected function isBinaryOperator($operator)
854+
{
855+
return in_array(strtolower($operator), $this->binaryOperators, true) ||
856+
in_array(strtolower($operator), $this->grammar->getBinaryOperators(), true);
857+
}
858+
840859
/**
841860
* Add an "or where" clause to the query.
842861
*
@@ -1915,6 +1934,10 @@ public function having($column, $operator = null, $value = null, $boolean = 'and
19151934
[$value, $operator] = [$operator, '='];
19161935
}
19171936

1937+
if ($this->isBinaryOperator($operator)) {
1938+
$type = 'binary';
1939+
}
1940+
19181941
$this->havings[] = compact('type', 'column', 'operator', 'value', 'boolean');
19191942

19201943
if (! $value instanceof Expression) {

src/Illuminate/Database/Query/Grammars/Grammar.php

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,13 @@ class Grammar extends BaseGrammar
1818
*/
1919
protected $operators = [];
2020

21+
/**
22+
* The grammar specific binary operators.
23+
*
24+
* @var array
25+
*/
26+
protected $binaryOperators = [];
27+
2128
/**
2229
* The components that make up a select clause.
2330
*
@@ -255,6 +262,15 @@ protected function whereBasic(Builder $query, $where)
255262
return $this->wrap($where['column']).' '.$operator.' '.$value;
256263
}
257264

265+
protected function whereBinary(Builder $query, $where)
266+
{
267+
$value = $this->parameter($where['value']);
268+
269+
$operator = str_replace('?', '??', $where['operator']);
270+
271+
return '('.$this->wrap($where['column']).' '.$operator.' '.$value.') != 0';
272+
}
273+
258274
/**
259275
* Compile a "where in" clause.
260276
*
@@ -571,7 +587,8 @@ protected function whereJsonContains(Builder $query, $where)
571587
$not = $where['not'] ? 'not ' : '';
572588

573589
return $not.$this->compileJsonContains(
574-
$where['column'], $this->parameter($where['value'])
590+
$where['column'],
591+
$this->parameter($where['value'])
575592
);
576593
}
577594

@@ -610,7 +627,9 @@ public function prepareBindingForJsonContains($binding)
610627
protected function whereJsonLength(Builder $query, $where)
611628
{
612629
return $this->compileJsonLength(
613-
$where['column'], $where['operator'], $this->parameter($where['value'])
630+
$where['column'],
631+
$where['operator'],
632+
$this->parameter($where['value'])
614633
);
615634
}
616635

@@ -682,6 +701,8 @@ protected function compileHaving(array $having)
682701
return $having['boolean'].' '.$having['sql'];
683702
} elseif ($having['type'] === 'between') {
684703
return $this->compileHavingBetween($having);
704+
} elseif ($having['type'] === 'binary') {
705+
return $this->compileHavingBinary($having);
685706
}
686707

687708
return $this->compileBasicHaving($having);
@@ -721,6 +742,21 @@ protected function compileHavingBetween($having)
721742
return $having['boolean'].' '.$column.' '.$between.' '.$min.' and '.$max;
722743
}
723744

745+
/**
746+
* Compile a having clause involving a binary operator.
747+
*
748+
* @param array $having
749+
* @return string
750+
*/
751+
protected function compileHavingBinary($having)
752+
{
753+
$column = $this->wrap($having['column']);
754+
755+
$parameter = $this->parameter($having['value']);
756+
757+
return $having['boolean'].' ('.$column.' '.$having['operator'].' '.$parameter.') != 0';
758+
}
759+
724760
/**
725761
* Compile the "order by" portions of the query.
726762
*
@@ -1296,4 +1332,14 @@ public function getOperators()
12961332
{
12971333
return $this->operators;
12981334
}
1335+
1336+
/**
1337+
* Get the grammar specific binary operators.
1338+
*
1339+
* @return array
1340+
*/
1341+
public function getBinaryOperators()
1342+
{
1343+
return $this->binaryOperators;
1344+
}
12991345
}

src/Illuminate/Database/Query/Grammars/PostgresGrammar.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,15 @@ class PostgresGrammar extends Grammar
2121
'is distinct from', 'is not distinct from',
2222
];
2323

24+
/**
25+
* The grammar specific binary operators.
26+
*
27+
* @var array
28+
*/
29+
protected $binaryOperators = [
30+
'~', '&', '|', '#', '<<', '>>', '<<=', '>>=',
31+
];
32+
2433
/**
2534
* {@inheritdoc}
2635
*

tests/Database/DatabaseQueryBuilderTest.php

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3209,6 +3209,25 @@ public function testMySqlSoundsLikeOperator()
32093209
$this->assertEquals(['John Doe'], $builder->getBindings());
32103210
}
32113211

3212+
public function testBinaryOperators()
3213+
{
3214+
$builder = $this->getBuilder();
3215+
$builder->select('*')->from('users')->where('bar', '&', 1);
3216+
$this->assertSame('select * from "users" where ("bar" & ?) != 0', $builder->toSql());
3217+
3218+
$builder = $this->getPostgresBuilder();
3219+
$builder->select('*')->from('users')->where('bar', '#', 1);
3220+
$this->assertSame('select * from "users" where ("bar" # ?) != 0', $builder->toSql());
3221+
3222+
$builder = $this->getBuilder();
3223+
$builder->select('*')->from('users')->having('bar', '&', 1);
3224+
$this->assertSame('select * from "users" having ("bar" & ?) != 0', $builder->toSql());
3225+
3226+
$builder = $this->getPostgresBuilder();
3227+
$builder->select('*')->from('users')->having('bar', '#', 1);
3228+
$this->assertSame('select * from "users" having ("bar" # ?) != 0', $builder->toSql());
3229+
}
3230+
32123231
public function testMergeWheresCanMergeWheresAndBindings()
32133232
{
32143233
$builder = $this->getBuilder();

0 commit comments

Comments
 (0)