Skip to content

Commit

Permalink
Support where bit functions and operators for database. (#6950)
Browse files Browse the repository at this point in the history

Co-authored-by: 李铭昕 <[email protected]>
  • Loading branch information
littlezo and limingxinleo authored Jul 15, 2024
1 parent 69d10f5 commit 0e1d0fa
Show file tree
Hide file tree
Showing 3 changed files with 178 additions and 0 deletions.
106 changes: 106 additions & 0 deletions src/Query/Builder.php
Original file line number Diff line number Diff line change
Expand Up @@ -1518,6 +1518,112 @@ public function orWhereJsonDoesntOverlap(string $column, mixed $value): static
return $this->whereJsonDoesntOverlap($column, $value, 'or');
}

/**
* Add an "where Bit Functions and Operators" clause to the query.
*/
public function whereBit(string $key, mixed $operator = 'and', mixed $value = null, string $boolean = 'and', bool $not = false): static
{
$type = $not ? '!=' : '=';
[$value, $operator] = $this->prepareValueAndOperator($value, $operator, func_num_args() === 2);
$operator = match ($operator) {
'|', 'or' => '|',
'^', 'xor' => '^',
default => '&'
};
return $this->whereRaw(sprintf('%s %s ? %s ?', $key, $operator, $type), [$value, $value], $boolean);
}

/**
* Add an "where Bit Not Functions and Operators" clause to the query.
*/
public function whereBitNot(string $key, mixed $operator = 'and', mixed $value = null, string $boolean = 'and'): static
{
[$value, $operator] = $this->prepareValueAndOperator($value, $operator, func_num_args() === 2);
return $this->whereBit($key, $operator, $value, $boolean, true);
}

/**
* Add an "or where Bit Functions and Operators" clause to the query.
*/
public function orWhereBit(string $key, mixed $operator = 'and', mixed $value = null, bool $not = false): static
{
[$value, $operator] = $this->prepareValueAndOperator($value, $operator, func_num_args() === 2);
return $this->whereBit($key, $operator, $value, 'or', $not);
}

/**
* Add an "or where Bit Not Functions and Operators" clause to the query.
*/
public function orWhereBitNot(string $key, mixed $operator = 'and', mixed $value = null): static
{
[$value, $operator] = $this->prepareValueAndOperator($value, $operator, func_num_args() === 2);
return $this->orWhereBit($key, $operator, $value, true);
}

/**
* Add an "where Bit Or Functions and Operators" clause to the query.
*/
public function whereBitOr(string $key, mixed $value = null, bool $not = false): static
{
return $this->whereBit($key, 'or', $value, 'and', $not);
}

/**
* Add an "where Bit Or Not Functions and Operators" clause to the query.
*/
public function whereBitOrNot(string $key, mixed $value = null): static
{
return $this->orWhereBit($key, 'or', $value, true);
}

/**
* Add an "or where Bit Or Functions and Operators" clause to the query.
*/
public function orWhereBitOr(string $key, mixed $value = null, bool $not = false): static
{
return $this->orWhereBit($key, 'or', $value, $not);
}

/**
* Add an "or where Bit Or Functions and Operators" clause to the query.
*/
public function orWhereBitOrNot(string $key, mixed $value = null): static
{
return $this->orWhereBitOr($key, $value, true);
}

/**
* Add an "where Bit Xor Functions and Operators" clause to the query.
*/
public function whereBitXor(string $key, mixed $value = null, bool $not = false): static
{
return $this->whereBit($key, 'xor', $value, 'and', $not);
}

/**
* Add an "where Bit Xor Not Functions and Operators" clause to the query.
*/
public function whereBitXorNot(string $key, mixed $value = null): static
{
return $this->whereBitXor($key, $value, true);
}

/**
* Add an "or where Bit Xor Functions and Operators" clause to the query.
*/
public function orWhereBitXor(string $key, mixed $value = null, bool $not = false): static
{
return $this->orWhereBit($key, 'xor', $value, $not);
}

/**
* Add an "or where Bit Xor Not Functions and Operators" clause to the query.
*/
public function orWhereBitXorNot(string $key, mixed $value = null): static
{
return $this->orWhereBitXor($key, $value, true);
}

/**
* Add a "where JSON length" clause to the query.
*
Expand Down
18 changes: 18 additions & 0 deletions tests/ModelRealBuilderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,24 @@ public function testForPageAfterId()
}
}

public function testUserWhereBit()
{
$this->getContainer();

$query = User::query()->whereBit('gender', 1);
$res = $query->get();
$this->assertTrue($res->count() > 0);

$sqls = [
['select * from `user` where gender & ? = ?', [1, 1]],
];
while ($event = $this->channel->pop(0.001)) {
if ($event instanceof QueryExecuted) {
$this->assertSame([$event->sql, $event->bindings], array_shift($sqls));
}
}
}

public function testForceIndexes()
{
$this->getContainer();
Expand Down
54 changes: 54 additions & 0 deletions tests/QueryBuilderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -3006,6 +3006,60 @@ public function testFromRawWithWhereOnTheMainQuery()
$this->assertEquals(['1520652582'], $builder->getBindings());
}

public function testBitWheres()
{
$type = 16;
$flags = 32;
$builder = $this->getBuilder();
$clone = $builder->clone();

$builder->select('*')->from('users')->whereBit('type', $type);
$this->assertEquals('select * from "users" where type & ? = ?', $builder->toSql());
$builder->select('*')->from('users')->orWhereBit('flags', $flags);
$this->assertEquals('select * from "users" where type & ? = ? or flags & ? = ?', $builder->toSql());

$clone->select('*')->from('users')->whereBitNot('type', $type);
$this->assertEquals('select * from "users" where type & ? != ?', $clone->toSql());
$clone->select('*')->from('users')->orWhereBitNot('flags', $flags);
$this->assertEquals('select * from "users" where type & ? != ? or flags & ? != ?', $clone->toSql());
}

public function testBitWheresOr()
{
$type = 16;
$flags = 32;
$builder = $this->getBuilder();
$clone = $builder->clone();

$builder->select('*')->from('users')->whereBitOr('type', $type);
$this->assertEquals('select * from "users" where type | ? = ?', $builder->toSql());
$builder->select('*')->from('users')->orWhereBitOr('flags', $flags);
$this->assertEquals('select * from "users" where type | ? = ? or flags | ? = ?', $builder->toSql());

$clone->select('*')->from('users')->whereBitOrNot('type', $type);
$this->assertEquals('select * from "users" where type | ? != ?', $clone->toSql());
$clone->select('*')->from('users')->orWhereBitOrNot('flags', $flags);
$this->assertEquals('select * from "users" where type | ? != ? or flags | ? != ?', $clone->toSql());
}

public function testBitWheresXor()
{
$type = 16;
$flags = 32;
$builder = $this->getBuilder();
$clone = $builder->clone();

$builder->select('*')->from('users')->whereBitXor('type', $type);
$this->assertEquals('select * from "users" where type ^ ? = ?', $builder->toSql());
$builder->select('*')->from('users')->orWhereBitXor('flags', $flags);
$this->assertEquals('select * from "users" where type ^ ? = ? or flags ^ ? = ?', $builder->toSql());

$clone->select('*')->from('users')->whereBitXorNot('type', $type);
$this->assertEquals('select * from "users" where type ^ ? != ?', $clone->toSql());
$clone->select('*')->from('users')->orWhereBitXorNot('flags', $flags);
$this->assertEquals('select * from "users" where type ^ ? != ? or flags ^ ? != ?', $clone->toSql());
}

public function testClone()
{
$builder = $this->getBuilder();
Expand Down

0 comments on commit 0e1d0fa

Please sign in to comment.