Skip to content

Commit 5c65c36

Browse files
committed
Added Mysqli Specific query builder support.
1 parent 71572a1 commit 5c65c36

File tree

10 files changed

+458
-53
lines changed

10 files changed

+458
-53
lines changed

src/Api/DB.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
use Rcalicdan\FiberAsync\Config\ConfigLoader;
66
use Rcalicdan\FiberAsync\Promise\Interfaces\PromiseInterface;
7-
use Rcalicdan\FiberAsync\QueryBuilder\AsyncQueryBuilder;
7+
use Rcalicdan\FiberAsync\QueryBuilder\PDOQueryBuilder;
88

99
/**
1010
* DB API - Main entry point for auto-configured async database operations using AsyncPDO under the hood
@@ -97,11 +97,11 @@ public static function reset(): void
9797
/**
9898
* Start a new query builder instance for the given table.
9999
*/
100-
public static function table(string $table): AsyncQueryBuilder
100+
public static function table(string $table): PDOQueryBuilder
101101
{
102102
self::initializeIfNeeded();
103103

104-
return new AsyncQueryBuilder($table);
104+
return new PDOQueryBuilder($table);
105105
}
106106

107107
/**

src/Helpers/async_helper.php

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
<?php
22

33
use Rcalicdan\FiberAsync\Api\Async;
4-
use Rcalicdan\FiberAsync\Api\Promise;
54
use Rcalicdan\FiberAsync\Api\Timer;
65
use Rcalicdan\FiberAsync\Promise\Interfaces\CancellablePromiseInterface;
76
use Rcalicdan\FiberAsync\Promise\Interfaces\PromiseInterface;
7+
use Rcalicdan\FiberAsync\Promise\Promise;
88

99
if (! function_exists('in_fiber')) {
1010
/**
@@ -172,7 +172,7 @@ function timeout(callable|PromiseInterface|array $promises, float $seconds): Can
172172
}
173173
}
174174

175-
if (! function_exists('resolve')) {
175+
if (! function_exists('resolved')) {
176176
/**
177177
* Create a promise that is already resolved with the given value.
178178
*
@@ -188,13 +188,13 @@ function timeout(callable|PromiseInterface|array $promises, float $seconds): Can
188188
* $promise = resolve('Hello World');
189189
* $result = await($promise); // 'Hello World'
190190
*/
191-
function resolve(mixed $value): PromiseInterface
191+
function resolved(mixed $value): PromiseInterface
192192
{
193-
return Promise::resolve($value);
193+
return Promise::resolved($value);
194194
}
195195
}
196196

197-
if (! function_exists('reject')) {
197+
if (! function_exists('rejected')) {
198198
/**
199199
* Create a promise that is already rejected with the given reason.
200200
*
@@ -207,9 +207,9 @@ function resolve(mixed $value): PromiseInterface
207207
* @example
208208
* $promise = reject(new Exception('Something went wrong'));
209209
*/
210-
function reject(mixed $reason): PromiseInterface
210+
function rejected(mixed $reason): PromiseInterface
211211
{
212-
return Promise::reject($reason);
212+
return Promise::rejected($reason);
213213
}
214214
}
215215

src/MySQLi/DB.php

Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
<?php
2+
3+
namespace Rcalicdan\FiberAsync\MySQLi;
4+
5+
use Rcalicdan\FiberAsync\Api\AsyncMySQLi;
6+
use Rcalicdan\FiberAsync\Config\ConfigLoader;
7+
use Rcalicdan\FiberAsync\Promise\Interfaces\PromiseInterface;
8+
use Rcalicdan\FiberAsync\QueryBuilder\PDOQueryBuilder;
9+
10+
/**
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+
*/
17+
class DB
18+
{
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+
}

0 commit comments

Comments
 (0)