Skip to content

Commit 4e89741

Browse files
author
Ben Thomson
committed
Add unit tests for upsert() query builder method.
Based off implementation done in laravel/framework#34698 and laravel/framework#34712.
1 parent a49a954 commit 4e89741

File tree

2 files changed

+260
-4
lines changed

2 files changed

+260
-4
lines changed

composer.json

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -88,10 +88,7 @@
8888
"autoload-dev": {
8989
"classmap": [
9090
"tests/TestCase.php"
91-
],
92-
"psr-4": {
93-
"October\\Rain\\Tests\\": "tests/"
94-
}
91+
]
9592
},
9693
"scripts": {
9794
"test": [

tests/Database/QueryBuilderTest.php

Lines changed: 259 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,259 @@
1+
<?php
2+
3+
use Illuminate\Database\ConnectionInterface;
4+
use Illuminate\Database\Query\Grammars\Grammar;
5+
use Illuminate\Database\Query\Processors\Processor;
6+
use October\Rain\Database\Query\Grammars\MySqlGrammar;
7+
use October\Rain\Database\Query\Grammars\PostgresGrammar;
8+
use October\Rain\Database\Query\Grammars\SQLiteGrammar;
9+
use October\Rain\Database\Query\Grammars\SqlServerGrammar;
10+
use October\Rain\Database\QueryBuilder;
11+
12+
class QueryBuilderTest extends TestCase
13+
{
14+
public function testSelectConcat()
15+
{
16+
// MySQL
17+
$query = $this->getMySqlBuilder()
18+
->select(['id'])
19+
->selectConcat(['field', ' ', 'cast'], 'full_cast')
20+
->selectConcat(['field2', ' ', 'cast2'], 'full_cast2');
21+
22+
$this->assertEquals(
23+
'select `id`, concat(`field`, \' \', `cast`) as `full_cast`, concat(`field2`, \' \', `cast2`) as `full_cast2`',
24+
$query->toSql()
25+
);
26+
27+
$query = $this->getMySqlBuilder()
28+
->select(['id'])
29+
->selectConcat(['"field"', ' ', 'cast'], 'full_cast');
30+
31+
$this->assertEquals(
32+
'select `id`, concat(\'field\', \' \', `cast`) as `full_cast`',
33+
$query->toSql()
34+
);
35+
36+
// SQLite
37+
$query = $this->getSQLiteBuilder()
38+
->select(['id'])
39+
->selectConcat(['field', ' ', 'cast'], 'full_cast')
40+
->selectConcat(['field2', ' ', 'cast2'], 'full_cast2');
41+
42+
$this->assertEquals(
43+
'select "id", "field" || \' \' || "cast" as "full_cast", "field2" || \' \' || "cast2" as "full_cast2"',
44+
$query->toSql()
45+
);
46+
47+
$query = $this->getSQLiteBuilder()
48+
->select(['id'])
49+
->selectConcat(['"field"', ' ', 'cast'], 'full_cast');
50+
51+
$this->assertEquals(
52+
'select "id", \'field\' || \' \' || "cast" as "full_cast"',
53+
$query->toSql()
54+
);
55+
56+
// PostgreSQL
57+
$query = $this->getPostgresBuilder()
58+
->select(['id'])
59+
->selectConcat(['field', ' ', 'cast'], 'full_cast')
60+
->selectConcat(['field2', ' ', 'cast2'], 'full_cast2');
61+
62+
$this->assertEquals(
63+
'select "id", concat("field", \' \', "cast") as "full_cast", concat("field2", \' \', "cast2") as "full_cast2"',
64+
$query->toSql()
65+
);
66+
67+
$query = $this->getPostgresBuilder()
68+
->select(['id'])
69+
->selectConcat(['"field"', ' ', 'cast'], 'full_cast');
70+
71+
$this->assertEquals(
72+
'select "id", concat(\'field\', \' \', "cast") as "full_cast"',
73+
$query->toSql()
74+
);
75+
76+
// SQL Server
77+
$query = $this->getSqlServerBuilder()
78+
->select(['id'])
79+
->selectConcat(['field', ' ', 'cast'], 'full_cast')
80+
->selectConcat(['field2', ' ', 'cast2'], 'full_cast2');
81+
82+
$this->assertEquals(
83+
'select [id], concat([field], \' \', [cast]) as [full_cast], concat([field2], \' \', [cast2]) as [full_cast2]',
84+
$query->toSql()
85+
);
86+
87+
$query = $this->getSqlServerBuilder()
88+
->select(['id'])
89+
->selectConcat(['"field"', ' ', 'cast'], 'full_cast');
90+
91+
$this->assertEquals(
92+
'select [id], concat(\'field\', \' \', [cast]) as [full_cast]',
93+
$query->toSql()
94+
);
95+
}
96+
97+
public function testUpsert()
98+
{
99+
// MySQL
100+
$builder = $this->getMySqlBuilder();
101+
$builder->getConnection()
102+
->expects($this->once())
103+
->method('affectingStatement')
104+
->with('insert into `users` (`email`, `name`) values (?, ?), (?, ?) on duplicate key update `email` = values(`email`), `name` = values(`name`)', ['foo', 'bar', 'foo2', 'bar2'])
105+
->willReturn(2);
106+
$result = $builder->from('users')->upsert([['email' => 'foo', 'name' => 'bar'], ['name' => 'bar2', 'email' => 'foo2']], 'email');
107+
$this->assertEquals(2, $result);
108+
109+
// PostgreSQL
110+
$builder = $this->getPostgresBuilder();
111+
$builder->getConnection()
112+
->expects($this->once())
113+
->method('affectingStatement')
114+
->with('insert into "users" ("email", "name") values (?, ?), (?, ?) on conflict ("email") do update set "email" = "excluded"."email", "name" = "excluded"."name"', ['foo', 'bar', 'foo2', 'bar2'])
115+
->willReturn(2);
116+
$result = $builder->from('users')->upsert([['email' => 'foo', 'name' => 'bar'], ['name' => 'bar2', 'email' => 'foo2']], 'email');
117+
$this->assertEquals(2, $result);
118+
119+
// SQLite
120+
$builder = $this->getSQLiteBuilder();
121+
$builder->getConnection()
122+
->expects($this->once())
123+
->method('affectingStatement')
124+
->with('insert into "users" ("email", "name") values (?, ?), (?, ?) on conflict ("email") do update set "email" = "excluded"."email", "name" = "excluded"."name"', ['foo', 'bar', 'foo2', 'bar2'])
125+
->willReturn(2);
126+
$result = $builder->from('users')->upsert([['email' => 'foo', 'name' => 'bar'], ['name' => 'bar2', 'email' => 'foo2']], 'email');
127+
$this->assertEquals(2, $result);
128+
129+
// SQL Server
130+
$builder = $this->getSqlServerBuilder();
131+
$builder->getConnection()
132+
->expects($this->once())
133+
->method('affectingStatement')
134+
->with('merge [users] using (values (?, ?), (?, ?)) [laravel_source] ([email], [name]) on [laravel_source].[email] = [users].[email] when matched then update set [email] = [laravel_source].[email], [name] = [laravel_source].[name] when not matched then insert ([email], [name]) values ([email], [name])', ['foo', 'bar', 'foo2', 'bar2'])
135+
->willReturn(2);
136+
$result = $builder->from('users')->upsert([['email' => 'foo', 'name' => 'bar'], ['name' => 'bar2', 'email' => 'foo2']], 'email');
137+
$this->assertEquals(2, $result);
138+
}
139+
140+
public function testUpsertWithUpdateColumns()
141+
{
142+
// MySQL
143+
$builder = $this->getMySqlBuilder();
144+
$builder->getConnection()
145+
->expects($this->once())
146+
->method('affectingStatement')
147+
->with('insert into `users` (`email`, `name`) values (?, ?), (?, ?) on duplicate key update `name` = values(`name`)', ['foo', 'bar', 'foo2', 'bar2'])
148+
->willReturn(2);
149+
$result = $builder->from('users')->upsert([['email' => 'foo', 'name' => 'bar'], ['name' => 'bar2', 'email' => 'foo2']], 'email', ['name']);
150+
$this->assertEquals(2, $result);
151+
152+
// PostgreSQL
153+
$builder = $this->getPostgresBuilder();
154+
$builder->getConnection()
155+
->expects($this->once())
156+
->method('affectingStatement')
157+
->with('insert into "users" ("email", "name") values (?, ?), (?, ?) on conflict ("email") do update set "name" = "excluded"."name"', ['foo', 'bar', 'foo2', 'bar2'])
158+
->willReturn(2);
159+
$result = $builder->from('users')->upsert([['email' => 'foo', 'name' => 'bar'], ['name' => 'bar2', 'email' => 'foo2']], 'email', ['name']);
160+
$this->assertEquals(2, $result);
161+
162+
// SQLite
163+
$builder = $this->getSQLiteBuilder();
164+
$builder->getConnection()
165+
->expects($this->once())
166+
->method('affectingStatement')
167+
->with('insert into "users" ("email", "name") values (?, ?), (?, ?) on conflict ("email") do update set "name" = "excluded"."name"', ['foo', 'bar', 'foo2', 'bar2'])
168+
->willReturn(2);
169+
$result = $builder->from('users')->upsert([['email' => 'foo', 'name' => 'bar'], ['name' => 'bar2', 'email' => 'foo2']], 'email', ['name']);
170+
$this->assertEquals(2, $result);
171+
172+
// SQL Server
173+
$builder = $this->getSqlServerBuilder();
174+
$builder->getConnection()
175+
->expects($this->once())
176+
->method('affectingStatement')
177+
->with('merge [users] using (values (?, ?), (?, ?)) [laravel_source] ([email], [name]) on [laravel_source].[email] = [users].[email] when matched then update set [name] = [laravel_source].[name] when not matched then insert ([email], [name]) values ([email], [name])', ['foo', 'bar', 'foo2', 'bar2'])
178+
->willReturn(2);
179+
$result = $builder->from('users')->upsert([['email' => 'foo', 'name' => 'bar'], ['name' => 'bar2', 'email' => 'foo2']], 'email', ['name']);
180+
$this->assertEquals(2, $result);
181+
}
182+
183+
protected function getConnection()
184+
{
185+
$connection = $this->getMockBuilder(ConnectionInterface::class)
186+
->disableOriginalConstructor()
187+
->disableOriginalClone()
188+
->disableArgumentCloning()
189+
->disallowMockingUnknownTypes()
190+
->setMethods([
191+
'table',
192+
'raw',
193+
'selectOne',
194+
'select',
195+
'cursor',
196+
'insert',
197+
'update',
198+
'delete',
199+
'statement',
200+
'affectingStatement',
201+
'unprepared',
202+
'prepareBindings',
203+
'transaction',
204+
'beginTransaction',
205+
'commit',
206+
'rollBack',
207+
'transactionLevel',
208+
'pretend',
209+
])
210+
->addMethods([
211+
'getDatabaseName',
212+
])
213+
->getMock();
214+
215+
$connection->method('getDatabaseName')->willReturn('database');
216+
217+
return $connection;
218+
}
219+
220+
protected function getBuilder()
221+
{
222+
$grammar = new Grammar;
223+
$processor = $this->createMock(Processor::class);
224+
225+
return new QueryBuilder($this->getConnection(), $grammar, $processor);
226+
}
227+
228+
protected function getMySqlBuilder()
229+
{
230+
$grammar = new MySqlGrammar;
231+
$processor = $this->createMock(Processor::class);
232+
233+
return new QueryBuilder($this->getConnection(), $grammar, $processor);
234+
}
235+
236+
protected function getPostgresBuilder()
237+
{
238+
$grammar = new PostgresGrammar;
239+
$processor = $this->createMock(Processor::class);
240+
241+
return new QueryBuilder($this->getConnection(), $grammar, $processor);
242+
}
243+
244+
protected function getSQLiteBuilder()
245+
{
246+
$grammar = new SQLiteGrammar;
247+
$processor = $this->createMock(Processor::class);
248+
249+
return new QueryBuilder($this->getConnection(), $grammar, $processor);
250+
}
251+
252+
protected function getSqlServerBuilder()
253+
{
254+
$grammar = new SqlServerGrammar;
255+
$processor = $this->createMock(Processor::class);
256+
257+
return new QueryBuilder($this->getConnection(), $grammar, $processor);
258+
}
259+
}

0 commit comments

Comments
 (0)