Nette\Database + PostgresSQL a klauzule RETURNING
- Barvoj
- Člen | 60
Ahoj,
na projektu používám PostgreSQL a Nette\Database.
Snažím se napsat metodu insertOrUpdate, která by vložila nový záznam nebo aktualizovala již existující a vrátila mi ID záznamu.
V PostgreSQL jsem za tímto účelem chtěl použít
INSERT .. ON CONFLICT ... UPDATE ... RETURNING ID
a napsal si na to
repository, která vypadá přibližně takto:
use Nette\Database\Context;
use Nette\Object;
class UserRepository extends Object
{
/** @var Context */
protected $database;
/**
* @param Context $database
*/
public function __construct(Context $database)
{
$this->database = $database;
}
/**
* @param array $data
* @return int Id
*/
public function insertOrUpdate($data)
{
$result = $this->database->query("INSERT INTO user ? ON CONFLICT (username) DO UPDATE SET ? RETURNING id", $data, $data);
...
}
}
Problém je v tom, že Nette\Database tento dotaz nezpracuje správně. Správný dotaz by měl být cca takový:
INSERT INTO user ("id", "username", "name") VALUES ('1', 'pepa', 'Pepa Novák') ON CONFLICT (username) DO UPDATE SET "id"='1', "username"='pepa', "name"='Pepa Novák' RETURNING id
ve skutečnosti se ale provede tento
INSERT INTO user ("id", "username", "name") VALUES ('1', 'pepa', 'Pepa Novák') ON CONFLICT (username) DO UPDATE SET ("id", "username", "name") VALUES ('1', 'pepa', 'Pepa Novák') RETURNING id
což skončí výjimkou.
Jak je vidět, špatně se doplní hodnoty do části
UPDATE SET ?
.
Trochu jsem to debugoval a dostal jsem se k třídě SqlPreprocessor ve které se SQL zpracovává nějakým regulárním výrazem.
Experimentálně jsem ověřil že problémová část je
RETURNING id
. Bez ní se dotaz provede správně.
Tomu regulárnímu výrazu moc nerozumím ale zřejmě se z toho SQL
získávají některá klíčová slova jako
INSERT,SET atp. a následně se podle nich
správně nahradí ty otazníky. A právě klíčové slovo
SET ten regulární výraz nenajde, pokud je na konci to
RETURNING id
.
Přemýšlím, že ve volné chvíli ten regulár prozkoumám a pokud budu schopen ho upravit, tak zkusím vymyslet nějaký PR. Ale nejprve bych se chtěl zeptat, jestli něco nepřehlížím a jestli má vůbec smysl se v tom reguláru šťourat, když se jedná o specialitku PostgreSQL.
Budu taky vděčný za jiné nápady, jak toto řešit :)
Editoval Barvoj (4. 5. 2016 16:43)