Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit acaba1a

Browse files
authored
PHPORM-114 Implement Builder::upsert (#3053)
1 parent a62d4b9 commit acaba1a

File tree

4 files changed

+112
-2
lines changed

4 files changed

+112
-2
lines changed

‎CHANGELOG.md‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,11 @@ All notable changes to this project will be documented in this file.
33

44
## [4.7.0] - coming soon
55

6+
* Add `Query\Builder::upsert()` method by @GromNaN in [#3052](https://github.com/mongodb/laravel-mongodb/pull/3052)
67
* Add `Connection::getServerVersion()` by @GromNaN in [#3043](https://github.com/mongodb/laravel-mongodb/pull/3043)
78
* Add `Schema\Builder::getTables()` and `getTableListing()` by @GromNaN in [#3044](https://github.com/mongodb/laravel-mongodb/pull/3044)
89
* Add `Schema\Builder::getColumns()` and `getIndexes()` by @GromNaN in [#3045](https://github.com/mongodb/laravel-mongodb/pull/3045)
9-
* Add `Schema\Builder::hasColumn` and `hasColumns` method by @Alex-Belyi in [#3002](https://github.com/mongodb/laravel-mongodb/pull/3001)
10+
* Add `Schema\Builder::hasColumn` and `hasColumns` method by @Alex-Belyi in [#3001](https://github.com/mongodb/laravel-mongodb/pull/3001)
1011

1112
## [4.6.0] - 2024年07月09日
1213

‎src/Query/Builder.php‎

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -725,6 +725,47 @@ public function update(array $values, array $options = [])
725725
return $this->performUpdate($values, $options);
726726
}
727727

728+
/** @inheritdoc */
729+
public function upsert(array $values, $uniqueBy, $update = null): int
730+
{
731+
if ($values === []) {
732+
return 0;
733+
}
734+
735+
$this->applyBeforeQueryCallbacks();
736+
737+
$options = $this->inheritConnectionOptions();
738+
$uniqueBy = array_fill_keys((array) $uniqueBy, 1);
739+
740+
// If no update fields are specified, all fields are updated
741+
if ($update !== null) {
742+
$update = array_fill_keys((array) $update, 1);
743+
}
744+
745+
$bulk = [];
746+
747+
foreach ($values as $value) {
748+
$filter = $operation = [];
749+
foreach ($value as $key => $val) {
750+
if (isset($uniqueBy[$key])) {
751+
$filter[$key] = $val;
752+
}
753+
754+
if ($update === null || array_key_exists($key, $update)) {
755+
$operation['$set'][$key] = $val;
756+
} else {
757+
$operation['$setOnInsert'][$key] = $val;
758+
}
759+
}
760+
761+
$bulk[] = ['updateOne' => [$filter, $operation, ['upsert' => true]]];
762+
}
763+
764+
$result = $this->collection->bulkWrite($bulk, $options);
765+
766+
return $result->getInsertedCount() + $result->getUpsertedCount() + $result->getModifiedCount();
767+
}
768+
728769
/** @inheritdoc */
729770
public function increment($column, $amount = 1, array $extra = [], array $options = [])
730771
{

‎tests/ModelTest.php‎

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,40 @@ public function testUpdate(): void
143143
$this->assertEquals('Hans Thomas', $check->fullname);
144144
}
145145

146+
public function testUpsert()
147+
{
148+
$result = User::upsert([
149+
['email' => 'foo', 'name' => 'bar'],
150+
['name' => 'bar2', 'email' => 'foo2'],
151+
], ['email']);
152+
153+
$this->assertSame(2, $result);
154+
155+
$this->assertSame(2, $result);
156+
$this->assertSame(2, User::count());
157+
$this->assertSame('bar', User::where('email', 'foo')->first()->name);
158+
159+
// Update 1 document
160+
$result = User::upsert([
161+
['email' => 'foo', 'name' => 'bar2'],
162+
['name' => 'bar2', 'email' => 'foo2'],
163+
], 'email', ['name']);
164+
165+
// Even if the same value is set for the 2nd document, the "updated_at" field is updated
166+
$this->assertSame(2, $result);
167+
$this->assertSame(2, User::count());
168+
$this->assertSame('bar2', User::where('email', 'foo')->first()->name);
169+
170+
// If no update fields are specified, all fields are updated
171+
$result = User::upsert([
172+
['email' => 'foo', 'name' => 'bar3'],
173+
], 'email');
174+
175+
$this->assertSame(1, $result);
176+
$this->assertSame(2, User::count());
177+
$this->assertSame('bar3', User::where('email', 'foo')->first()->name);
178+
}
179+
146180
public function testManualStringId(): void
147181
{
148182
$user = new User();

‎tests/QueryBuilderTest.php‎

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
use Illuminate\Support\LazyCollection;
1212
use Illuminate\Support\Str;
1313
use Illuminate\Testing\Assert;
14+
use Illuminate\Tests\Database\DatabaseQueryBuilderTest;
1415
use InvalidArgumentException;
1516
use MongoDB\BSON\ObjectId;
1617
use MongoDB\BSON\Regex;
@@ -588,7 +589,7 @@ public function testSubdocumentArrayAggregate()
588589
$this->assertEquals(12, DB::collection('items')->avg('amount.*.hidden'));
589590
}
590591

591-
public function testUpsert()
592+
public function testUpdateWithUpsert()
592593
{
593594
DB::collection('items')->where('name', 'knife')
594595
->update(
@@ -607,6 +608,39 @@ public function testUpsert()
607608
$this->assertEquals(2, DB::collection('items')->count());
608609
}
609610

611+
public function testUpsert()
612+
{
613+
/** @see DatabaseQueryBuilderTest::testUpsertMethod() */
614+
// Insert 2 documents
615+
$result = DB::collection('users')->upsert([
616+
['email' => 'foo', 'name' => 'bar'],
617+
['name' => 'bar2', 'email' => 'foo2'],
618+
], 'email', 'name');
619+
620+
$this->assertSame(2, $result);
621+
$this->assertSame(2, DB::collection('users')->count());
622+
$this->assertSame('bar', DB::collection('users')->where('email', 'foo')->first()['name']);
623+
624+
// Update 1 document
625+
$result = DB::collection('users')->upsert([
626+
['email' => 'foo', 'name' => 'bar2'],
627+
['name' => 'bar2', 'email' => 'foo2'],
628+
], 'email', 'name');
629+
630+
$this->assertSame(1, $result);
631+
$this->assertSame(2, DB::collection('users')->count());
632+
$this->assertSame('bar2', DB::collection('users')->where('email', 'foo')->first()['name']);
633+
634+
// If no update fields are specified, all fields are updated
635+
$result = DB::collection('users')->upsert([
636+
['email' => 'foo', 'name' => 'bar3'],
637+
], 'email');
638+
639+
$this->assertSame(1, $result);
640+
$this->assertSame(2, DB::collection('users')->count());
641+
$this->assertSame('bar3', DB::collection('users')->where('email', 'foo')->first()['name']);
642+
}
643+
610644
public function testUnset()
611645
{
612646
$id1 = DB::collection('users')->insertGetId(['name' => 'John Doe', 'note1' => 'ABC', 'note2' => 'DEF']);

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /