NullDb\NullDbBackend::class, 'mariadb' => MariaDB\MariaDBBackend::class, 'mysql' => MariaDB\MariaDBBackend::class, 'sqlite' => SQLite\SQLiteBackend::class, 'sqlite3' => SQLite\SQLiteBackend::class, ]; public static function create(string $dsn): IDbConnection { static $backends = []; $uri = parse_url($dsn); if($uri === false) throw new InvalidArgumentException('$dsn is not a valid uri.'); $scheme = $uri['scheme']; if(in_array($scheme, $backends)) $backend = $backends[$scheme]; else { $backend = null; if(array_key_exists($scheme, self::DB_PROTOS)) $name = self::DB_PROTOS[$scheme]; else $name = str_replace('-', '\\', $scheme); if(class_exists($name) && is_subclass_of($name, IDbBackend::class)) { $backend = new $name; $name = get_class($backend); } if($backend === null) throw new DataException('No implementation is available for the specified scheme.'); if(!$backend->isAvailable()) throw new DataException('Requested database backend is not available, likely due to missing dependencies.'); $backends[$name] = $backend; } return $backend->createConnection( $backend->parseDsn($uri) ); } /** * Transaction wrapper. * * Takes a database connection with transaction support and a callable that may return a boolean based on the success of the actions. * If the callable returns nothing, nothing will happen. * If the callable returns true, commit will be called. * If the callable returns false, rollback will be called. * * @param IDbTransactions $connection A database connection with transaction support. * @param callable $callable A callable that handles the transaction, may return a bool. */ public static function transaction(IDbTransactions $connection, callable $callable): void { $connection->beginTransaction(); $result = $callable($connection) ?? null; if(is_bool($result)) { if($result) $connection->commit(); else $connection->rollback(); } } /** * Detects the DbType of the passed argument. Should be used for DbType::AUTO. * * @param mixed $value A value of unknown type. * @return int DbType of the value passed in the argument. */ public static function detectType(mixed $value): int { if(is_null($value)) return DbType::NULL; if(is_float($value)) return DbType::FLOAT; if(is_int($value)) return DbType::INTEGER; // ┌ should probably also check for Stringable, length should also be taken into consideration // ↓ though maybe with that it's better to assume that when an object is passed it'll always be Massive if(is_string($value)) return DbType::STRING; return DbType::BLOB; } }