Skip to content

Commit

Permalink
Add support for upsert
Browse files Browse the repository at this point in the history
  • Loading branch information
imanghafoori1 committed Jun 7, 2023
1 parent 00b3855 commit c753c0f
Show file tree
Hide file tree
Showing 5 changed files with 106 additions and 21 deletions.
33 changes: 17 additions & 16 deletions src/FakeConnection.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,11 @@ public function statement($query, $bindings = [])
return parent::statement($query);
}

return $this->run($query['sql'], $bindings, function () use ($query) {
$pretending = true;

return $this->run($query['sql'], $bindings, function () use ($query, $pretending) {
if ($this->pretending()) {
return true;
return $pretending;
}

return (bool) FakeDB::insertGetId($query['value'], $query['builder']->from);
Expand All @@ -52,13 +54,8 @@ public function statement($query, $bindings = [])
public function select($query, $bindings = [], $useReadPdo = true)
{
$query = $query->data;
return $this->run($query['sql'], $bindings, function () use ($query) {
if ($this->pretending()) {
return [];
}

return FakeDb::exec($query);
});
return $this->runFake($query, $bindings, []);
}

public function affectingStatement($query, $bindings = [])
Expand All @@ -72,15 +69,19 @@ public function affectingStatement($query, $bindings = [])
return Arr::isAssoc($query['value']) ? 1 : count($query['value']);
}

if (in_array($type, ['update', 'delete', 'truncate'])) {
return $this->select($queryObj, $bindings);
if (in_array($type, ['update', 'delete', 'truncate', 'upsert'])) {
return $this->runFake($query, $bindings, 0);
}
}

if (is_array($query) && isset($query['uniqueBy'])) {
$sql = $query['sql'];
$query = $query['builder'];
$values = $query['values'];
$uniqueBy = $query['uniqueBy'];
}
protected function runFake($sql, $bindings, $pretend)
{
return $this->run($sql['sql'], $bindings, function () use ($sql, $pretend) {
if ($this->pretending()) {
return $pretend;
}

return FakeDb::exec($sql);
});
}
}
37 changes: 34 additions & 3 deletions src/FakeDB.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
use Illuminate\Database\ConnectionResolver;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Query\Expression;
use Illuminate\Database\Query\Grammars\SQLiteGrammar;
use Illuminate\Support\Arr;
use Illuminate\Support\Collection;
use Illuminate\Support\Str;
Expand Down Expand Up @@ -525,6 +524,38 @@ public static function update($query): int
return FakeDB::syncTable($collection, $builder->from);
}

public static function upsert($query)
{
$values = $query['values'];
$uniqueBy = $query['uniqueBy'];
$query = $query['builder'];
$from = $query->from;

foreach ($values as $value) {
$shouldInsert = true;
$i = 0;
foreach (self::$fakeRows[$from] ?? [] as $i => $_row) {
$allMatch = true;
foreach ($uniqueBy as $uniqueCol) {
if ($_row[$from][$uniqueCol] !== $value[$uniqueCol]) {
$allMatch = false;
break;
}
}
if ($allMatch) {
$shouldInsert = false;
break;
}
}

if ($shouldInsert) {
self::addRow($from, $value);
} else {
self::$fakeRows[$from][$i][$from] = $value;
}
}
}

public static function exec($query)
{
$type = $query['type'];
Expand All @@ -546,8 +577,8 @@ public static function select($query)
$builder = $query['builder'];

if ($aggregate = $builder->aggregate) {
$function = $aggregate["function"];
$columns = $aggregate["columns"];
$function = $aggregate['function'];
$columns = $aggregate['columns'];

return self::aggregate($columns, $builder, $function);
}
Expand Down
3 changes: 2 additions & 1 deletion src/FakeGrammar.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use Illuminate\Database\Query\Builder;
use Illuminate\Database\Query\Grammars\Grammar;
use Illuminate\Database\Query\Grammars\MySqlGrammar;

class FakeGrammar extends Grammar
{
Expand Down Expand Up @@ -72,7 +73,7 @@ public function compileUpsert(Builder $query, array $values, array $uniqueBy, ar
'builder' => $query,
'values' => $values,
'uniqueBy' => $uniqueBy,
'sql' => parent::compileUpsert($query, $values, $uniqueBy, $update)
'sql' => (new MySqlGrammar)->compileUpsert($query, $values, $uniqueBy, $update)
]);
}

Expand Down
4 changes: 3 additions & 1 deletion src/FakeQueryBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@ public function crossJoin($table, $first = null, $operator = null, $second = nul

public function truncate()
{
$this->applyBeforeQueryCallbacks();
if (method_exists($this, 'applyBeforeQueryCallbacks')) {
$this->applyBeforeQueryCallbacks();
}

$this->connection->affectingStatement($this->grammar->compileTruncate($this));
}
Expand Down
50 changes: 50 additions & 0 deletions tests/UpsertTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?php

namespace Imanghafoori\EloquentMockery\Tests;

use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Imanghafoori\EloquentMockery\FakeDB;
use PHPUnit\Framework\TestCase;

class UpsertModel extends Model
{
protected $fillable = ['name'];

protected $table = 'upserty';
}

class UpsertTest extends TestCase
{
public function test_upsert()
{
if (! method_exists(Builder::class, 'upsert')) {
$this->markTestSkipped();
}
FakeDB::mockQueryBuilder();

UpsertModel::query()->upsert([
'name' => 'a1',
'age' => 12,
], ['name']);
UpsertModel::query()->upsert([
'name' => 'a',
'age' => 10,
], ['name']);
UpsertModel::query()->upsert([
'name' => 'a',
'age' => 11,
], ['name']);
UpsertModel::query()->upsert([
'name' => 'a',
'age' => 11,
], ['name', 'age']);

$this->assertEquals(2, UpsertModel::query()->count());
$upsert = UpsertModel::query()->get();
$this->assertEquals(12, $upsert[0]->age);
$this->assertEquals(11, $upsert[1]->age);

FakeDB::dontMockQueryBuilder();
}
}

0 comments on commit c753c0f

Please sign in to comment.