Prosím o otestování Nette Database 4.0 RC

David Grudl
Nette Core | 8218
+
+6
-

Prosím o otestování nové velké verze Nette Database 4.0 RC

composer require nette/database:^4.0.0-dev

Nová verze představuje především velkou architektonickou změnu. Není už pevně spojená s PDO. A je možné doplnit drivery pro další databázové rozšíření v PHP. Například mysqli, které přinese možnost spouštět dotazy paralelně, což může být hodně zajímavé.

Další novinkou je spojení tříd Nette\Database\Connection a Explorer do jedné. Ono to tak kdysi v NDB bylo a myslím, že je dobré se k tomuto konceptu vrátit. Názvy těchto tříd jsou nyní aliasy.

Novinkou je možnost konfigurovat, jak se převádí hodnoty načtené z databáze, a to pomocí

database:
	dsn: ...
	options:
		convertBoolean: true   # MySQL tinyint(1) / BIT v SQLServer převádí na boolean
		convertDateTime: true  # zda převádět data na objekty DateTime
		convertDecimal: true   # zda převádet na int/float nebo ponechat string
		newDateTime: true      # používá Nette\Database\DateTime místo Nette\Utils\DateTime

Všechny tyto volby jsou zapnuté by default, stejně jako volba newDateTime.

Změny:

  • Metoda getInsertId() nyní vrací integery místo řetězců
  • Metoda DriverException::getCode() vrací číselný driver-specific kód místo řetězce SQLstate
  • Z kódu jsem dal pryč rozhraní IRow a IRowContainer, které imho k ničemu užitečnému nebyly
  • Deprecated jsou metody poplatné čistě PDO: Connection::getPdo()getDsn()

Mám připravených pár bombastických novinek, které vyžadují novou architekturu Nette Database 4.0

A ačkoliv je nová verze pod kapotou kompletně předělaná, snažil jsem se, aby nezpůsobovala žádné nekompatibility. Na svých projektech jsem nepotřeboval cokoliv upravovat. Tak prosím ověřte, jestli na nějaké nekompatibility nenarazíte, ať je můžeme vychytat.

Je to někdo, kdo si vytvářel pro NDB vlastní databázový driver?

kminekmatej
Generous Backer | 38
+
0
-

Ahoj,
já mám ve svém projektu definován přístup ke dvěma databázím a po přepnutí na DB4 mi nejde vybuildit container. Error log: https://cloud.kminet.eu/…9TmJDBpRMKjD . Config db vypadá takto:

database:
    default:
        dsn: 'mysql:host=localhost;dbname=admin.boost.space'
        user: dbuser
        password: 'dbpwd'
    b:
        dsn: 'mysql:host=localhost;dbname=boost.space'
        user: dbuser
        password: 'dbpwd'
        reflection: conventional

nightfish
Člen | 516
+
+3
-

@kminekmatej Podle kódu NDB verze 3.2 to vypadá, že reflection: bylo v průběhu času nahrazeno za conventions: a drženo jen z důvodu zpětné kompatibility – viz kód.
Pokud čtu kód správně, mohlo by stačit nahradit reflection: conventional za conventions: Static.

ViPEr*CZ*
Člen | 817
+
0
-

Zkousim na jedne mensi appce.

Dostavam se na

Argument #1 ($dateTime) must be of type Nette\Utils\DateTime, Nette\Database\DateTime

Coz jsem teda vyresil asi na dvou mistech. Asi muze byt opruz kdyz to je na vice mistech.
Ale melo by to jit resit strojove.

Jen jsem to chtel rovnou checknout na PHP 8.4 a koukam, ze mame za-lockovano
nette/routing v3.1.0 requires php 8.1 – 8.3 → your php version (8.4.0beta4) does not satisfy that requirement

Na 8.3.11 to frci :-)

smuuf
Člen | 1
+
+1
-

DB driver

My vlastní DB driver používáme – vypadá nějak takto:

<?php

declare(strict_types=1);

namespace App\Infra\Database\Drivers;

use Nette\Database\Driver;
use Nette\Database\Connection;
use Nette\Database\Drivers\MySqlDriver;

final class AcmeMysqlDbDriver extends MySqlDriver {

	/** @var bool Does this driver support setting isolation level for transaction? */
	public const SUPPORTS_ISOLATION_LEVEL = true;

	/** @var int Max execution time for each query (in seconds) within a DB connection. */
	private const MAX_STATEMENT_TIME = 60 * 10;

	/**
	 * @param array{
	 *     charset?: string,
	 *     sqlmode?: string,
	 *     supportBooleans?: bool,
	 *   } $options
	 */
	public function initialize(Connection $connection, array $options): void {

		parent::initialize($connection, $options);
		$connection->query(sprintf(
			'SET SESSION max_statement_time=%d;',
			self::MAX_STATEMENT_TIME,
		));

		// https://jira.mariadb.org/browse/MDEV-20083
		// https://mariadb.com/kb/en/conversion-of-big-in-predicates-into-subqueries/
		// Disable this "optimization", because our queries are MUCH faster (in
		// another words: they finish and do not hang.)
		$connection->query('SET SESSION in_predicate_conversion_threshold=0;');

		// NOTE: Cannot use PHP8,1 first-class callable syntax as we sometimes
		// need to serialize DB connection - e.g. in tests - where PHP
		// would complain about serializing a closure.
		$connection->setRowNormalizer(
			[BothWaysDbRowKeysNormalizer::class, 'normalizeRow'],
		);

	}

	public function isSupported(string $item): bool {

		return in_array($item, [
			Driver::SupportSelectUngroupedColumns,
			Driver::SupportMultiColumnAsOrCond,
			Driver::SupportSubselect,
		], true);

	}

}

Jak je vidět, využíváme inicializaci driveru pro nastavení potřebných věcí pro dané spojení – doufám, že tahle možnost bude v 4.0 zachovaná. V https://github.com/…Explorer.php#L35 vidím možný list $onConnect callbacků, kam by se toto dalo strčit, ale jelikož není zřejmé, jak (kdy přesně) se v rámci Nette DI bude připojení ve finále inicializovat, tak netuším, zda budu mít možnost nějaké $onConnect[] = ... udělat ještě před tím, než se zavolá connect() – snad ano.

Row normalizer

Pokud koukám správně, tak v aktuálním masteru také vidím, že je „row normalized“ deprecated: [...] is deprecated, configure 'convert*' options instead., viz https://github.com/…Explorer.php#L202

Row normalizer používáme ke modifikování dat array (slovníku) daného řádku – v našem případě hodnotu pod klíčem (sloupcem) this_is_some_column chceme mít k dispozici i pod klíčem thisIsSomeColumn, takže potřebujeme duplikovat klíče se změněným case (což bychom btw. nemuseli duplikovat, kdyby se kdysi nezavrhly věci typu https://github.com/…se/issues/90). Čili jelikož potřebujeme modifikovat celý array, tak nějaké:


class Explorer
{
	...
	private const TypeConverterOptions = ['convertBoolean', 'convertDateTime', 'convertDecimal', 'newDateTime'];
	...
}

… je nám docela k ničemu. Bylo by fajn udržet možnost si připravit data řádku tak, jak my potřebujeme. Pokud se možnost toto dělat někde v 4.0 schovává, tak jsem to nebyl schopen rozpoznat – a kdyby to nešlo, tak to bude upgrade na Nette Database 4.0 silně blokovat.

Zmizelé getDsn()

V naší appce databázi shardujeme – máme hlavní DB + zcela separátně jiné, menší databáze. Pro spojení k tomuhle všemu používáme Nette Database/Explorer a kvůli tomu musíme v kódu managovat vytváření instancí spojení a Explorerů pro každý shard.

K tomu se nám náramně hodí getDsn(), které je aktuálně k dispozici (např. jako klíč pro kešování zmiňovaných instancí, ale i další věci, které jsou složitější k vysvětlení). Hlasoval bych pro zachování možnosti získat z PDO driveru zpět DSN – které tam, jestli koukám správně, stejně bude moct být: https://github.com/…O/Driver.php#L24

Editoval smuuf (9. 10. 10:13)

mystik
Člen | 308
+
+1
-

Taky jsem pro zachovani getDsn. My vyuzivame shardovani v testech a potrebujem ziskavat DSN kvuli oddeleni cache a lockovani konkurentnixh testu nad stejnym sharden DB.

kminekmatej
Generous Backer | 38
+
+2
-

Jo, getDsn() bych rovněž potřeboval