Skip to content

Commit 1b0be87

Browse files
committed
:octocat: +postgres INSERT ... ON CONFLICT
1 parent 97a5281 commit 1b0be87

File tree

7 files changed

+66
-23
lines changed

7 files changed

+66
-23
lines changed

src/Dialects/Dialect.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,10 +70,11 @@ public function selectCount(array $from, string $where = null, bool $distinct =
7070
* @param string $table
7171
* @param array $fields
7272
* @param string|null $onConflict
73+
* @param string|null $conflictTarget
7374
*
7475
* @return array
7576
*/
76-
public function insert(string $table, array $fields, string $onConflict = null):array;
77+
public function insert(string $table, array $fields, string $onConflict = null, string $conflictTarget = null):array;
7778

7879
/**
7980
* @param string $table

src/Dialects/DialectAbstract.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ public function select(array $cols, array $from, string $where = null, $limit =
8282
}
8383

8484
/** @inheritdoc */
85-
public function insert(string $table, array $fields, string $onConflict = null):array{
85+
public function insert(string $table, array $fields, string $onConflict = null, string $conflictTarget = null):array{
8686
$sql = ['INSERT INTO'];
8787
$sql[] = $this->quote($table);
8888
$sql[] = '('.$this->quotes[0].implode($this->quotes[1].', '.$this->quotes[0], $fields).$this->quotes[1].')';

src/Dialects/MySQL.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ class MySQL extends DialectAbstract{
1818
protected $charset = 'utf8mb4_bin';
1919

2020
/** @inheritdoc */
21-
public function insert(string $table, array $fields, string $onConflict = null):array{
21+
public function insert(string $table, array $fields, string $onConflict = null, string $conflictTarget = null):array{
2222
$onConflict = strtoupper($onConflict);
2323

2424
switch($onConflict){

src/Dialects/Postgres.php

Lines changed: 47 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212

1313
namespace chillerlan\Database\Dialects;
1414

15+
use chillerlan\Database\Query\QueryException;
16+
1517
class Postgres extends DialectAbstract{
1618

1719
protected $quotes = ['"', '"'];
@@ -53,6 +55,51 @@ public function select(array $cols, array $from, string $where = null, $limit =
5355
return $sql;
5456
}
5557

58+
/**
59+
* @link https://www.postgresql.org/docs/9.5/static/sql-insert.html#SQL-ON-CONFLICT
60+
*
61+
* @inheritdoc
62+
*/
63+
public function insert(string $table, array $fields, string $onConflict = null, string $conflictTarget = null):array{
64+
$sql = parent::insert($table, $fields);
65+
66+
if(in_array($onConflict, ['IGNORE', 'REPLACE'], true)){
67+
68+
if(empty($conflictTarget)){
69+
throw new QueryException('postgres insert on conflict: no conflict target given');
70+
}
71+
72+
$sql[] = 'ON CONFLICT ('.$this->quote($conflictTarget).') DO';
73+
74+
switch($onConflict){
75+
case 'IGNORE':
76+
$sql[] = 'NOTHING';
77+
break;
78+
case 'REPLACE':
79+
$sql[] = $this->onConflictUpdate($fields);
80+
break;
81+
}
82+
83+
}
84+
85+
return $sql;
86+
}
87+
88+
/**
89+
* @param array $fields
90+
*
91+
* @return string
92+
*/
93+
protected function onConflictUpdate(array $fields):string {
94+
$onConflictUpdate = [];
95+
96+
foreach($fields as $f){
97+
$onConflictUpdate[] = $this->quote($f).' = EXCLUDED.'.$this->quote($f);
98+
}
99+
100+
return 'UPDATE SET '.implode(', ', $onConflictUpdate);
101+
}
102+
56103
/** @inheritdoc */
57104
public function createDatabase(string $dbname, bool $ifNotExists = null, string $collate = null):array{
58105
$sql = ['CREATE DATABASE'];
@@ -295,20 +342,3 @@ public function showCreateTable(string $table):array{
295342
}
296343

297344
}
298-
299-
300-
/*
301-
create table querytest
302-
(
303-
id INTEGER
304-
primary key,
305-
hash VARCHAR(32),
306-
data TEXT,
307-
value DECIMAL(9,6),
308-
active BOOLEAN,
309-
created TIMESTAMP default 'CURRENT_TIMESTAMP'
310-
)
311-
;
312-
313-
314-
*/

src/Query/Insert.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,11 @@ interface Insert extends Statement{
3030
/**
3131
* @param string $table
3232
* @param string|null $on_conflict
33+
* @param string|null $conflict_target
3334
*
3435
* @return \chillerlan\Database\Query\Insert
3536
*/
36-
public function into(string $table, string $on_conflict = null);
37+
public function into(string $table, string $on_conflict = null, string $conflict_target = null);
3738

3839
/**
3940
* @param iterable $values

src/Query/OnConflictTrait.php

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,16 +24,23 @@ trait OnConflictTrait{
2424
*/
2525
protected $on_conflict;
2626

27+
/**
28+
* @var string
29+
*/
30+
protected $conflict_target;
31+
2732
/**
2833
* @param string $name
2934
* @param string|null $on_conflict
35+
* @param string|null $conflict_target
3036
*
3137
* @return $this
3238
* @throws \chillerlan\Database\Query\QueryException
3339
*/
34-
public function name(string $name, string $on_conflict = null){
40+
public function name(string $name, string $on_conflict = null, string $conflict_target = null){
3541
$this->name = trim($name);
3642
$on_conflict = trim(strtoupper($on_conflict));
43+
$on_conflict = trim(strtoupper($conflict_target));
3744

3845
if(empty($this->name)){
3946
throw new QueryException('no name specified');
@@ -43,6 +50,10 @@ public function name(string $name, string $on_conflict = null){
4350
$this->on_conflict = $on_conflict;
4451
}
4552

53+
if(!empty($conflict_target)){
54+
$this->conflict_target = $conflict_target;
55+
}
56+
4657
return $this;
4758
}
4859

src/Query/QueryBuilder.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -276,7 +276,7 @@ protected function getSQL():array{
276276
throw new QueryException('no values given');
277277
}
278278

279-
return $this->dialect->insert($this->name, array_keys($this->multi ? $this->bindValues[0] : $this->bindValues), $this->on_conflict);
279+
return $this->dialect->insert($this->name, array_keys($this->multi ? $this->bindValues[0] : $this->bindValues), $this->on_conflict, $this->conflict_target);
280280
}
281281

282282
/** @inheritdoc */

0 commit comments

Comments
 (0)