Skip to content

Commit 5fe3cbd

Browse files
committed
Added Native Mysqli QUery builder support
1 parent 15266e8 commit 5fe3cbd

File tree

1 file changed

+155
-161
lines changed

1 file changed

+155
-161
lines changed

src/MySQLi/DB.php

Lines changed: 155 additions & 161 deletions
Original file line numberDiff line numberDiff line change
@@ -3,169 +3,163 @@
33
namespace Rcalicdan\FiberAsync\MySQLi;
44

55
use Rcalicdan\FiberAsync\Api\AsyncMySQLi;
6-
use Rcalicdan\FiberAsync\Config\ConfigLoader;
6+
use Rcalicdan\FiberAsync\Config\MysqliConfigLoader;
77
use Rcalicdan\FiberAsync\Promise\Interfaces\PromiseInterface;
8-
use Rcalicdan\FiberAsync\QueryBuilder\PDOQueryBuilder;
8+
use Rcalicdan\FiberAsync\QueryBuilder\MySQLiQueryBuilder;
99

1010
/**
11-
* DB API - Main entry point for auto-configured async database operations using AsyncMySQLi under the hood
12-
* with asynchonous query builder support.
13-
*
14-
* This API automatically loads configuration from .env and config/database.php
15-
* the first time it is used, providing a zero-setup experience for the developer.
16-
*/
11+
* DB API - Main entry point for auto-configured async database operations using AsyncMySQLi under the hood
12+
* with asynchronous query builder support.
13+
*
14+
* This API automatically loads configuration from .env and config/mysqli/config.php
15+
* the first time it is used, providing a zero-setup experience for the developer.
16+
*/
1717
class DB
1818
{
19-
private static bool $isInitialized = false;
20-
private static bool $hasValidationError = false;
21-
22-
/**
23-
* The core of the new design: A private, self-configuring initializer.
24-
* This method is called by every public method to ensure the system is ready.
25-
* Validates only once if successful, but re-validates if there were previous errors.
26-
*/
27-
private static function initializeIfNeeded(): void
28-
{
29-
if (self::$isInitialized && ! self::$hasValidationError) {
30-
return;
31-
}
32-
33-
self::$hasValidationError = false;
34-
35-
try {
36-
$configLoader = ConfigLoader::getInstance();
37-
$dbConfigAll = $configLoader->get('database');
38-
39-
if (! is_array($dbConfigAll)) {
40-
throw new \RuntimeException("Database configuration not found. Ensure 'config/database.php' exists in your project root.");
41-
}
42-
43-
$defaultConnection = $dbConfigAll['default'] ?? null;
44-
if (! is_string($defaultConnection)) {
45-
throw new \RuntimeException('Default connection name must be a string in your database config.');
46-
}
47-
48-
$connections = $dbConfigAll['connections'] ?? null;
49-
if (! is_array($connections)) {
50-
throw new \RuntimeException('Database connections configuration must be an array.');
51-
}
52-
53-
if (! isset($connections[$defaultConnection]) || ! is_array($connections[$defaultConnection])) {
54-
throw new \RuntimeException("Default database connection '{$defaultConnection}' not defined in your database config.");
55-
}
56-
57-
$connectionConfig = $connections[$defaultConnection];
58-
59-
/** @var array<string, mixed> $validatedConfig */
60-
$validatedConfig = [];
61-
foreach ($connectionConfig as $key => $value) {
62-
if (! is_string($key)) {
63-
throw new \RuntimeException('Database connection configuration must have string keys only.');
64-
}
65-
$validatedConfig[$key] = $value;
66-
}
67-
68-
$poolSize = 10;
69-
if (isset($dbConfigAll['pool_size'])) {
70-
if (! is_int($dbConfigAll['pool_size']) || $dbConfigAll['pool_size'] < 1) {
71-
throw new \RuntimeException('Database pool size must be a positive integer.');
72-
}
73-
$poolSize = $dbConfigAll['pool_size'];
74-
}
75-
76-
AsyncMySQLi::init($validatedConfig, $poolSize);
77-
self::$isInitialized = true;
78-
79-
} catch (\Exception $e) {
80-
self::$hasValidationError = true;
81-
self::$isInitialized = false;
82-
83-
throw $e;
84-
}
85-
}
86-
87-
/**
88-
* Resets the entire database system. Crucial for isolated testing.
89-
*/
90-
public static function reset(): void
91-
{
92-
AsyncMySQLi::reset();
93-
ConfigLoader::reset();
94-
self::$isInitialized = false;
95-
self::$hasValidationError = false;
96-
}
97-
98-
/**
99-
* Start a new query builder instance for the given table.
100-
*/
101-
public static function table(string $table): PDOQueryBuilder
102-
{
103-
self::initializeIfNeeded();
104-
105-
return new PDOQueryBuilder($table);
106-
}
107-
108-
/**
109-
* Execute a raw query.
110-
*
111-
* @param array<string, mixed> $bindings
112-
* @return PromiseInterface<array<int, array<string, mixed>>>
113-
*/
114-
public static function raw(string $sql, array $bindings = []): PromiseInterface
115-
{
116-
self::initializeIfNeeded();
117-
118-
return AsyncMySQLi::query($sql, $bindings);
119-
}
120-
121-
/**
122-
* Execute a raw query and return the first result.
123-
*
124-
* @param array<string, mixed> $bindings
125-
* @return PromiseInterface<array<string, mixed>|false>
126-
*/
127-
public static function rawFirst(string $sql, array $bindings = []): PromiseInterface
128-
{
129-
self::initializeIfNeeded();
130-
131-
return AsyncMySQLi::fetchOne($sql, $bindings);
132-
}
133-
134-
/**
135-
* Execute a raw query and return a single scalar value.
136-
*
137-
* @param array<string, mixed> $bindings
138-
* @return PromiseInterface<mixed>
139-
*/
140-
public static function rawValue(string $sql, array $bindings = []): PromiseInterface
141-
{
142-
self::initializeIfNeeded();
143-
144-
return AsyncMySQLi::fetchValue($sql, $bindings);
145-
}
146-
147-
/**
148-
* Execute a raw statement (INSERT, UPDATE, DELETE).
149-
*
150-
* @param array<string, mixed> $bindings
151-
* @return PromiseInterface<int>
152-
*/
153-
public static function rawExecute(string $sql, array $bindings = []): PromiseInterface
154-
{
155-
self::initializeIfNeeded();
156-
157-
return AsyncMySQLi::execute($sql, $bindings);
158-
}
159-
160-
/**
161-
* Run a database transaction.
162-
*
163-
* @return PromiseInterface<mixed>
164-
*/
165-
public static function transaction(callable $callback): PromiseInterface
166-
{
167-
self::initializeIfNeeded();
168-
169-
return AsyncMySQLi::transaction($callback);
170-
}
171-
}
19+
private static bool $isInitialized = false;
20+
private static bool $hasValidationError = false;
21+
22+
/**
23+
* The core of the new design: A private, self-configuring initializer.
24+
* This method is called by every public method to ensure the system is ready.
25+
* Validates only once if successful, but re-validates if there were previous errors.
26+
*/
27+
private static function initializeIfNeeded(): void
28+
{
29+
if (self::$isInitialized && !self::$hasValidationError) {
30+
return;
31+
}
32+
33+
self::$hasValidationError = false;
34+
35+
try {
36+
$configLoader = MysqliConfigLoader::getInstance();
37+
$dbConfig = $configLoader->get('config');
38+
39+
if (!is_array($dbConfig)) {
40+
throw new \RuntimeException("MySQLi configuration not found. Ensure 'config/mysqli/config.php' exists in your project root.");
41+
}
42+
43+
$connectionConfig = $dbConfig['connection'] ?? null;
44+
if (!is_array($connectionConfig)) {
45+
throw new \RuntimeException('MySQLi connection configuration must be an array.');
46+
}
47+
48+
// Validate required connection parameters
49+
$required = ['host', 'database', 'username'];
50+
foreach ($required as $key) {
51+
if (!isset($connectionConfig[$key])) {
52+
throw new \RuntimeException("Missing required MySQLi connection parameter: {$key}");
53+
}
54+
}
55+
56+
/** @var array<string, mixed> $validatedConfig */
57+
$validatedConfig = [];
58+
foreach ($connectionConfig as $key => $value) {
59+
if (!is_string($key)) {
60+
throw new \RuntimeException('MySQLi connection configuration must have string keys only.');
61+
}
62+
$validatedConfig[$key] = $value;
63+
}
64+
65+
$poolSize = $dbConfig['pool_size'] ?? 10;
66+
if (!is_int($poolSize) || $poolSize < 1) {
67+
throw new \RuntimeException('MySQLi pool size must be a positive integer.');
68+
}
69+
70+
AsyncMySQLi::init($validatedConfig, $poolSize);
71+
self::$isInitialized = true;
72+
73+
} catch (\Exception $e) {
74+
self::$hasValidationError = true;
75+
self::$isInitialized = false;
76+
77+
throw $e;
78+
}
79+
}
80+
81+
/**
82+
* Resets the entire database system. Crucial for isolated testing.
83+
*/
84+
public static function reset(): void
85+
{
86+
AsyncMySQLi::reset();
87+
MysqliConfigLoader::reset();
88+
self::$isInitialized = false;
89+
self::$hasValidationError = false;
90+
}
91+
92+
/**
93+
* Start a new query builder instance for the given table.
94+
*/
95+
public static function table(string $table): MySQLiQueryBuilder
96+
{
97+
self::initializeIfNeeded();
98+
99+
return new MySQLiQueryBuilder($table);
100+
}
101+
102+
/**
103+
* Execute a raw query.
104+
*
105+
* @param array<string, mixed> $bindings
106+
* @return PromiseInterface<array<int, array<string, mixed>>>
107+
*/
108+
public static function raw(string $sql, array $bindings = []): PromiseInterface
109+
{
110+
self::initializeIfNeeded();
111+
112+
return AsyncMySQLi::query($sql, $bindings);
113+
}
114+
115+
/**
116+
* Execute a raw query and return the first result.
117+
*
118+
* @param array<string, mixed> $bindings
119+
* @return PromiseInterface<array<string, mixed>|false>
120+
*/
121+
public static function rawFirst(string $sql, array $bindings = []): PromiseInterface
122+
{
123+
self::initializeIfNeeded();
124+
125+
return AsyncMySQLi::fetchOne($sql, $bindings);
126+
}
127+
128+
/**
129+
* Execute a raw query and return a single scalar value.
130+
*
131+
* @param array<string, mixed> $bindings
132+
* @return PromiseInterface<mixed>
133+
*/
134+
public static function rawValue(string $sql, array $bindings = []): PromiseInterface
135+
{
136+
self::initializeIfNeeded();
137+
138+
return AsyncMySQLi::fetchValue($sql, $bindings);
139+
}
140+
141+
/**
142+
* Execute a raw statement (INSERT, UPDATE, DELETE).
143+
*
144+
* @param array<string, mixed> $bindings
145+
* @return PromiseInterface<int>
146+
*/
147+
public static function rawExecute(string $sql, array $bindings = []): PromiseInterface
148+
{
149+
self::initializeIfNeeded();
150+
151+
return AsyncMySQLi::execute($sql, $bindings);
152+
}
153+
154+
/**
155+
* Run a database transaction.
156+
*
157+
* @return PromiseInterface<mixed>
158+
*/
159+
public static function transaction(callable $callback): PromiseInterface
160+
{
161+
self::initializeIfNeeded();
162+
163+
return AsyncMySQLi::transaction($callback);
164+
}
165+
}

0 commit comments

Comments
 (0)