Nette\Database, PostgreSQL, testy
- Milo
- Nette Core | 1283
Začínám si osahávat Nette\Database abych se něčemu přiučil. A dělám to na PostgreSQL. Po pár pokusech jsem dospěl k tomu, že dokud nerozběhám všechny testy, nemá to cenu :)
Chtěl bych tady probrat postup úpravy testů, než začnu posílat nějaké commity. Zkoušel jsem je tak zběžně pro PostgreSQL upravit a viděl bych to takhle:
- Implementovat
NotImplemented
pro postgre driver (nemám problém) - Rozlišení, pro jakou databázi test běží
- zavrhnul jsem možnost pojmenovat test jako
Table.aggregation.MySQL.phpt
aTable.aggregation.PgSQL.phpt
. Přijde mi to jako zbytečná duplikace. Možná u jednoho, dvou testů… - zavést přepínač
--db pgsql
, výchozí bude mysql nebo none, tj. testy se budou přeskakovat
- zavrhnul jsem možnost pojmenovat test jako
nette_test.sql
přejmenovat nanette_test_mysql.sql
,nette_test_pgsql.sql
atd…- Testy rozdílné pro různé databáze řešit následovně. U třech čtvrtin to nebude potřeba.
switch ($db) {
case 'mysql':
... assertion ...
break;
case 'pgsq':
... assertion ...
break;
default:
... skip test: Test not implemented for $db ...
}
Narazil jsem už na jednu vlastnost/chybu. Při grupování dovoluje MySQL vybrat sloupce, které nejsou součástí GROUP BY. Postgres bohužel ne.
SELECT id, name FROM tabulka GROUP BY id; -- MySQL OK, PostgreSQL ne
SELECT id, name FROM tabulka GROUP BY id, name; -- PostgreSQL OK
Zatím jsem nezkoumal jak to upravit, to jen tak do pléna…
- hrach
- Člen | 1838
Super, konečně někdo, kdo má zkušenost s postgre :) a je ochotne to vytunit.
- jasný :)
- detekci bych nedelal podle prepinace, ale upravil bych skript ktery ridi pripojeni:
$connectionList = array(
function() { return new Database\Connection('mysql:host=localhost', 'root'); },
function() { return new Database\Connection('pgsql:host=localhost', 'root'); },
);
foreach ($connectionList as $i => $connectionItem) {
try {
$connection = $connectionItem();
} catch (PDOException $e) {
if ($i === count($connectionList))
TestHelpers::skip('Requires corretly configured mysql connection and "nette_test" database.');
continue;
}
break;
}
3. alternativni soubory s testy bych nedelal, resil bych to az na
konkretnich mistech
4. na konkretnich mistech bych to resil podminkami zalozenymi na
$driverName = $this->connection->getAttribute(PDO::ATTR_DRIVER_NAME);
if ($driverName == ...) ...
Ohledne posledni polozky s group by – to je zalezitost uzivatele? Ale
urcite to nejak vyresime! :)
Jeste jednou diky.
Editoval hrach (26. 2. 2012 16:06)
- Milo
- Nette Core | 1283
hrach napsal(a):
- detekci bych nedelal podle prepinace, ale upravil bych skript ktery ridi pripojeni:
$connectionList = array( function() { return new Database\Connection('mysql:host=localhost', 'root'); }, function() { return new Database\Connection('pgsql:host=localhost', 'root'); }, ); foreach ($connectionList as $i => $connectionItem) { try { $connection = $connectionItem(); } catch (PDOException $e) { if ($i === count($connectionList)) // tuhle podmínku nechápu :) TestHelpers::skip('Requires corretly configured mysql connection and "nette_test" database.'); continue; } break; }
Teď se každý test (.phpt soubor) spouští jednou. Pokud tedy nebude jedna
databáze dostupná, vyhodnotí se jako skipped ikdyž pro jinou databázi
projde. Možná nějak anotací zajistit vícenásobné spuštění testu.
Třeba @variants databases
a někde definovat
$databases = array('mysql', 'pgsql');
nebo přímo
@variants mysql, pgsql
.
3. alternativni soubory s testy bych nedelal, resil bych to az na konkretnich mistech
Tímhle bodem jsem myslel inicializační SQL skript. Ten bude muset být per databáze.
4. na konkretnich mistech bych to resil podminkami zalozenymi na
$driverName = $this->connection->getAttribute(PDO::ATTR_DRIVER_NAME); if ($driverName == ...) ...
To je fakt.
Ohledne posledni polozky s group by – to je zalezitost uzivatele? Ale urcite to nejak vyresime! :)
Jeste jednou diky.
Zatím to nechám než se dá dohromady postup spouštění testů.
- hrach
- Člen | 1838
Zkus implementovat svuj navrh, ti to pak ohodnotim :P treba to David prijme, treba to jeste dopilujeme.
Ohledne klicu: tak ted nevim co mas presne na mysli. Obecne nette\table\selection nepodporuje vicesloupcovy klice.
Viceloupcove cizi klice slysim poprve v zivote. Urcite to neni cilena podpora. Implementaci bych ani neplanoval, vzhledem k omezene podpore. NDB se prave snazi jit co nejjednodussi cestou, aby tyto jednodocuhe dotazy byli vsemozne spustitelne :)
Kdyztak me kontaktuj na jabberu, muzeme to probrat.
Editoval hrach (26. 2. 2012 20:31)
- Milo
- Nette Core | 1283
Něco vyvořim.
Vícesloupcové cizí klíče… snad to nekomolim.
-- Jednosloupcový: t2.parent_id => t1.id
t2 JOIN t1 ON t2.parent_id = t1.id
-- Vícesloupcový: t2.(parent_id1, parent_id2) => t1.(id1, id2)
t2 JOIN t1 ON t2.parent_id1 = t1.id1 AND t2.parent_id2 = t1.id2
Málokdy a málokdo to používá. Někdy se ale hodí. V PostgreSQL se vytváří jako
CONSTRAINT "t2_fk" FOREIGN KEY ("parent_id1", "parent_id2") REFERENCES "public"."t1"("id1", "id2")
Editoval Milo (26. 2. 2012 21:23)
- Milo
- Nette Core | 1283
Narazil jsem na nějaké chyby v testech, které budou chtít upravit/opravit selection.
Table.aggregation.phpt (35)
===========================
Assert::same(2, count($authors));
Grouping error: 7 ERROR: column "author.name" must appear in the GROUP BY clause or be used in an aggregate function
Obdobná chyba i v testech:
Table.backjoin.phpt, Table.join.phpt
Table.discoveredReflection.phpt (33)
====================================
Failed asserting that array(4) is identical to expected array(4) on line 50.
Chybí tu nějaké tagy.
Actual: array(
'1001 tipu a triku pro PHP' => array(
'author' => 'Jakub Vrana',
'tags' => array(
'MySQL',
),
),
'JUSH' => array(
'author' => 'Jakub Vrana',
'tags' => array(
'JavaScript',
),
),
'Nette' => array(
'author' => 'David Grudl',
'tags' => array(
'PHP',
),
),
'Dibi' => array(
'author' => 'David Grudl',
'tags' => array(
'MySQL',
),
),
)
Table.insert().phpt
===================
Error: Invalid argument supplied for foreach() in D:\Web\lib\Nette\Nette\Database\Table\Selection.php:714
Table.insert().multi.phpt funguje
Stejná chyba v Table.update().phpt
Reflection.MySQL.phpt
=====================
Tady nechápu, proč se očekávají dva indexy. Na tabulce je přeci jen jeden, primární přes dva sloupce. book_tag_tag nevím kde se bere, to by měl být cizí klíč.
- Milo
- Nette Core | 1283
Konečně se mi povedlo rozběhat všechny testy pro PostgreSQL. Ten způsob spouštění varianty pro MySQL, PgSQL ještě přepíšu. Kouknul bys (byste někdo) na commity ohledně změn v Selection a spol a zhodnotil je?
Pak bych ty commity nějak přerozdělil a poslal pull request.
Editoval Milo (29. 2. 2012 11:26)
- hrach
- Člen | 1838
Vypadá to dost dobře :)
- detekci sekvence bych přesunul do driveru
- https://github.com/…c5349f0a36d7#… bych se nebál uvozovek misto apostrofu :) nemam rad escapovani
- https://github.com/…ca8f797d9d69#… to execute sem nepochopil. mrknu na to az v patek, az budu doma u pc.
- ve vysledku posquashovat ty veci do takovych 5 commitu :) bude to krasny :D
diky moc!
- Milo
- Nette Core | 1283
hrach napsal(a):
Vypadá to dost dobře :)
To je fajn :)
- detekci sekvence bych přesunul do driveru
- https://github.com/…c5349f0a36d7#… bych se nebál uvozovek misto apostrofu :) nemam rad escapovani
Kosmetika ještě proběhne.
- https://github.com/…ca8f797d9d69#… to execute sem nepochopil. mrknu na to az v patek, az budu doma u pc.
execute()
asi nebude nutný. Měl jsem to tam jako hotfix.
Některé testy chybovaly, protože $this->rows
bylo NULL. Teď
když to zakomentuju, proběhnou. Zjistím, co to zapříčinilo.
- ve vysledku posquashovat ty veci do takovych 5 commitu :) bude to krasny :D
diky moc!
Taky díky. Ještě k tomu dopíšu nějaké testy, zejména na reflexi. Dostanu se k tomu ale nejdřív přes víkend.
Potýkám se ještě s problémem ORDER
. Na Linuxu mi to řadí
čísla na konec, na Windows na začátek. Je to asi záležitost konfigurace pg
clusteru a locales, ale to se nesnadno mění a každý to může mít jinak.
Nejsnazší by bylo 1001 tipů vyhodit :)
- Milo
- Nette Core | 1283
Dotáhnul jsem to na tenhle pull request. Testy prochází na PostgreSQL 8.3 a MySQL 5.5 na windows. Na Linuxu některé PostgreSQL neprojdou kvůli jinému řazení čísel a písmen.