Nette\Database, PostgreSQL, testy

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

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:

  1. Implementovat NotImplemented pro postgre driver (nemám problém)
  2. Rozlišení, pro jakou databázi test běží
    • zavrhnul jsem možnost pojmenovat test jako Table.aggregation.MySQL.phpt a Table.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
  3. nette_test.sql přejmenovat na nette_test_mysql.sql, nette_test_pgsql.sql atd…
  4. 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
+
0
-

Super, konečně někdo, kdo má zkušenost s postgre :) a je ochotne to vytunit.

  1. jasný :)
  2. 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
+
0
-

hrach napsal(a):

  1. 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ů.

Milo
Nette Core | 1283
+
0
-

Podporuje Nette\Database vícesloupcové cizí klíče? U SQLite driveru se zdá že jo, u MySQL že ne :) Tak abych věděl jak pro PostgreSQL.

hrach
Člen | 1838
+
0
-

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
+
0
-

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
+
0
-

Zatím takhle, nejjednodušší varianta. Samotné testy budu teprv přepisovat.

Ideální se mi jeví použití anotace @variants, ale to až v druhém kole :)

Editoval Milo (27. 2. 2012 14:34)

Milo
Nette Core | 1283
+
0
-

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
+
0
-

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
+
0
-

Vypadá to dost dobře :)

diky moc!

Milo
Nette Core | 1283
+
0
-

hrach napsal(a):

Vypadá to dost dobře :)

To je fajn :)

Kosmetika ještě proběhne.

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
+
0
-

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.