Nette\Database + PostgresSQL a klauzule RETURNING

Upozornění: Tohle vlákno je hodně staré a informace nemusí být platné pro současné Nette.
Barvoj
Člen | 60
+
0
-

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)