Skip to content

Commit

Permalink
Fix whereJsonContains and whereJsonDoesntContain methods with a s…
Browse files Browse the repository at this point in the history
…ingle column name (#143)
  • Loading branch information
msmakouz authored Nov 23, 2023
1 parent 2e04ba4 commit 406928e
Show file tree
Hide file tree
Showing 9 changed files with 153 additions and 4 deletions.
6 changes: 5 additions & 1 deletion src/Driver/Postgres/Injection/CompileJsonContains.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,11 @@ protected function compile(string $statement): string
{
$path = $this->getPath($statement);
$field = $this->getField($statement);
$attribute = $this->getAttribute($statement);
$attribute = $this->findAttribute($statement);

if (empty($attribute)) {
return \sprintf('(%s)::jsonb @> ?', $field);
}

if (!empty($path)) {
return \sprintf('(%s->%s->%s)::jsonb @> ?', $field, $path, $attribute);
Expand Down
19 changes: 18 additions & 1 deletion src/Driver/Postgres/Injection/PostgresJsonExpression.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,27 @@ protected function getPath(string $statement, string $quote = "'"): string
* @return int|non-empty-string
*/
protected function getAttribute(string $statement): string|int
{
$attribute = $this->findAttribute($statement);
if ($attribute === null) {
throw new DriverException('Invalid statement. Unable to extract attribute.');
}

return $attribute;
}

/**
* Returns the attribute (last part of the full path). Returns null if the attribute is not found.
*
* @param non-empty-string $statement
*
* @return int|non-empty-string|null
*/
protected function findAttribute(string $statement): string|int|null
{
$path = $this->getPathArray($statement);
if ($path === []) {
throw new DriverException('Invalid statement. Unable to extract attribute.');
return null;
}

$attribute = \array_pop($path);
Expand Down
20 changes: 20 additions & 0 deletions tests/Database/Functional/Driver/MySQL/Query/DeleteQueryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,16 @@ public function testDeleteWithWhereJsonContainsNested(): void
$this->assertSameParameters([json_encode('+1234567890')], $select);
}

public function testDeleteWithWhereJsonContainsSinglePath(): void
{
$select = $this->database
->delete('table')
->whereJsonContains('settings', []);

$this->assertSameQuery('DELETE FROM {table} WHERE json_contains({settings}, ?)', $select);
$this->assertSameParameters([json_encode([])], $select);
}

public function testDeleteWithWhereJsonContainsArray(): void
{
$select = $this->database
Expand Down Expand Up @@ -190,6 +200,16 @@ public function testDeleteWithWhereJsonDoesntContainNested(): void
$this->assertSameParameters([json_encode('+1234567890')], $select);
}

public function testDeleteWithWhereJsonDoesntContainSinglePath(): void
{
$select = $this->database
->delete('table')
->whereJsonDoesntContain('settings', []);

$this->assertSameQuery('DELETE FROM {table} WHERE NOT json_contains({settings}, ?)', $select);
$this->assertSameParameters([json_encode([])], $select);
}

public function testDeleteWithWhereJsonDoesntContainArray(): void
{
$select = $this->database
Expand Down
22 changes: 22 additions & 0 deletions tests/Database/Functional/Driver/MySQL/Query/SelectQueryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,17 @@ public function testSelectWithWhereJsonContainsNested(): void
$this->assertSameParameters([json_encode('+1234567890')], $select);
}

public function testSelectWithWhereJsonContainsSinglePath(): void
{
$select = $this->database
->select()
->from('table')
->whereJsonContains('settings', []);

$this->assertSameQuery('SELECT * FROM {table} WHERE json_contains({settings}, ?)', $select);
$this->assertSameParameters([json_encode([])], $select);
}

public function testSelectWithWhereJsonContainsArray(): void
{
$select = $this->database
Expand Down Expand Up @@ -212,6 +223,17 @@ public function testSelectWithWhereJsonDoesntContainNested(): void
$this->assertSameParameters([json_encode('+1234567890')], $select);
}

public function testSelectWithWhereJsonDoesntContainSinglePath(): void
{
$select = $this->database
->select()
->from('table')
->whereJsonDoesntContain('settings', []);

$this->assertSameQuery('SELECT * FROM {table} WHERE NOT json_contains({settings}, ?)', $select);
$this->assertSameParameters([json_encode([])], $select);
}

public function testSelectWithWhereJsonDoesntContainArray(): void
{
$select = $this->database
Expand Down
22 changes: 22 additions & 0 deletions tests/Database/Functional/Driver/MySQL/Query/UpdateQueryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,17 @@ public function testUpdateWithWhereJsonContainsNested(): void
$this->assertSameParameters(['value', json_encode('+1234567890')], $select);
}

public function testUpdateWithWhereJsonContainsSinglePath(): void
{
$select = $this->database
->update('table')
->values(['some' => 'value'])
->whereJsonContains('settings', []);

$this->assertSameQuery('UPDATE {table} SET {some} = ? WHERE json_contains({settings}, ?)', $select);
$this->assertSameParameters(['value', json_encode([])], $select);
}

public function testUpdateWithWhereJsonContainsArray(): void
{
$select = $this->database
Expand Down Expand Up @@ -200,6 +211,17 @@ public function testUpdateWithWhereJsonDoesntContainNested(): void
$this->assertSameParameters(['value', json_encode('+1234567890')], $select);
}

public function testUpdateWithWhereJsonDoesntContainSinglePath(): void
{
$select = $this->database
->update('table')
->values(['some' => 'value'])
->whereJsonDoesntContain('settings', []);

$this->assertSameQuery('UPDATE {table} SET {some} = ? WHERE NOT json_contains({settings}, ?)', $select);
$this->assertSameParameters(['value', json_encode([])], $select);
}

public function testUpdateWithWhereJsonDoesntContainArray(): void
{
$select = $this->database
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,16 @@ public function testDeleteWithWhereJsonContainsNested(): void
$this->assertSameParameters([json_encode('+1234567890')], $select);
}

public function testDeleteWithWhereJsonContainsSinglePath(): void
{
$select = $this->database
->delete('table')
->whereJsonContains('settings', []);

$this->assertSameQuery('DELETE FROM {table} WHERE ({settings})::jsonb @> ?', $select);
$this->assertSameParameters([json_encode([])], $select);
}

public function testDeleteWithWhereJsonContainsArray(): void
{
$select = $this->database
Expand Down Expand Up @@ -178,6 +188,16 @@ public function testDeleteWithWhereJsonDoesntContainNested(): void
$this->assertSameParameters([json_encode('+1234567890')], $select);
}

public function testDeleteWithWhereJsonDoesntContainSinglePath(): void
{
$select = $this->database
->delete('table')
->whereJsonDoesntContain('settings', []);

$this->assertSameQuery('DELETE FROM {table} WHERE NOT ({settings})::jsonb @> ?', $select);
$this->assertSameParameters([json_encode([])], $select);
}

public function testDeleteWithWhereJsonDoesntContainArray(): void
{
$select = $this->database
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,17 @@ public function testSelectWithWhereJsonContainsNested(): void
$this->assertSameParameters([json_encode('+1234567890')], $select);
}

public function testSelectWithWhereJsonContainsSinglePath(): void
{
$select = $this->database
->select()
->from('table')
->whereJsonContains('settings', []);

$this->assertSameQuery('SELECT * FROM {table} WHERE ({settings})::jsonb @> ?', $select);
$this->assertSameParameters([json_encode([])], $select);
}

public function testSelectWithWhereJsonContainsArray(): void
{
$select = $this->database
Expand Down Expand Up @@ -185,6 +196,17 @@ public function testSelectWithWhereJsonDoesntContainNested(): void
$this->assertSameParameters([json_encode('+1234567890')], $select);
}

public function testSelectWithWhereJsonDoesntContainSinglePath(): void
{
$select = $this->database
->select()
->from('table')
->whereJsonDoesntContain('settings', []);

$this->assertSameQuery('SELECT * FROM {table} WHERE NOT ({settings})::jsonb @> ?', $select);
$this->assertSameParameters([json_encode([])], $select);
}

public function testSelectWithWhereJsonDoesntContainArray(): void
{
$select = $this->database
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,12 +116,23 @@ public function testUpdateWithWhereJsonContainsNested(): void
->whereJsonContains('settings->phones->work', '+1234567890');

$this->assertSameQuery(
"UPDATE {table} SET {some} = ? WHERE({settings}->'phones'->'work')::jsonb @> ?",
"UPDATE {table} SET {some} = ? WHERE ({settings}->'phones'->'work')::jsonb @> ?",
$select
);
$this->assertSameParameters(['value', json_encode('+1234567890')], $select);
}

public function testUpdateWithWhereJsonContainsSinglePath(): void
{
$select = $this->database
->update('table')
->values(['some' => 'value'])
->whereJsonContains('settings', []);

$this->assertSameQuery('UPDATE {table} SET {some} = ? WHERE ({settings})::jsonb @> ?', $select);
$this->assertSameParameters(['value', json_encode([])], $select);
}

public function testUpdateWithWhereJsonContainsArray(): void
{
$select = $this->database
Expand Down Expand Up @@ -194,6 +205,17 @@ public function testUpdateWithWhereJsonDoesntContainNested(): void
$this->assertSameParameters(['value', json_encode('+1234567890')], $select);
}

public function testUpdateWithWhereJsonDoesntContainSinglePath(): void
{
$select = $this->database
->update('table')
->values(['some' => 'value'])
->whereJsonDoesntContain('settings', []);

$this->assertSameQuery('UPDATE {table} SET {some} = ? WHERE NOT ({settings})::jsonb @> ?', $select);
$this->assertSameParameters(['value', json_encode([])], $select);
}

public function testUpdateWithWhereJsonDoesntContainArray(): void
{
$select = $this->database
Expand Down
2 changes: 1 addition & 1 deletion tests/Database/Unit/Driver/JsonerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ public function __toString(): string
// JsonSerializable object will be converted to JSON string correctly if 'encode' is set to 'true'
yield [
new class () implements \JsonSerializable {
public function jsonSerialize()
public function jsonSerialize(): array
{
return ['foo' => 'bar'];
}
Expand Down

0 comments on commit 406928e

Please sign in to comment.