Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 0 additions & 27 deletions src/Database/Concerns/Query/HasDriver.php

This file was deleted.

3 changes: 2 additions & 1 deletion src/Database/Concerns/Query/HasTransaction.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
namespace Phenix\Database\Concerns\Query;

use Amp\Sql\SqlConnection;
use Amp\Sql\SqlResult;
use Amp\Sql\SqlTransaction;
use Closure;
use Phenix\Database\TransactionContext;
Expand Down Expand Up @@ -85,7 +86,7 @@ public function setTransaction(SqlTransaction $transaction): self
return $this;
}

protected function exec(string $dml, array $params = []): mixed
protected function exec(string $dml, array $params = []): SqlResult
{
return $this->getExecutor()->prepare($dml)->execute($params);
}
Expand Down
13 changes: 12 additions & 1 deletion src/Database/Dialects/Postgres/Compilers/Insert.php
Original file line number Diff line number Diff line change
Expand Up @@ -61,16 +61,27 @@ public function compile(QueryAst $ast): CompiledClause

$parts[] = 'ON CONFLICT DO NOTHING';

if (! empty($ast->returning)) {
$parts[] = 'RETURNING';
$parts[] = Arr::implodeDeeply($ast->returning, ', ');
}

$sql = Arr::implodeDeeply($parts);
$sql = $this->convertPlaceholders($sql);

return new CompiledClause($sql, $ast->params);
}

$result = parent::compile($ast);
$parts = [$result->sql];

if (! empty($ast->returning)) {
$parts[] = 'RETURNING';
$parts[] = Arr::implodeDeeply($ast->returning, ', ');
}

return new CompiledClause(
$this->convertPlaceholders($result->sql),
$this->convertPlaceholders(Arr::implodeDeeply($parts)),
$result->params
);
}
Expand Down
17 changes: 17 additions & 0 deletions src/Database/Dialects/Sqlite/Compilers/Insert.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

namespace Phenix\Database\Dialects\Sqlite\Compilers;

use Phenix\Database\Dialects\CompiledClause;
use Phenix\Database\Dialects\Compilers\InsertCompiler;
use Phenix\Database\QueryAst;
use Phenix\Util\Arr;
Expand Down Expand Up @@ -40,4 +41,20 @@ protected function compileUpsert(QueryAst $ast): string
Arr::implodeDeeply($updateColumns, ', ')
);
}

public function compile(QueryAst $ast): CompiledClause
{
$result = parent::compile($ast);
$parts = [$result->sql];

if (! empty($ast->returning)) {
$parts[] = 'RETURNING';
$parts[] = Arr::implodeDeeply($ast->returning, ', ');
}

return new CompiledClause(
Arr::implodeDeeply($parts),
$result->params
);
}
}
35 changes: 35 additions & 0 deletions src/Database/Grammar.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,12 @@

namespace Phenix\Database;

use Amp\Mysql\MysqlConnectionPool;
use Amp\Postgres\PostgresConnectionPool;
use Amp\Sql\SqlConnection;
use Phenix\Database\Constants\Driver;
use Phenix\Facades\Config;
use Phenix\Sqlite\SqliteConnection;

abstract class Grammar
{
Expand All @@ -21,4 +26,34 @@ public function getDriver(): Driver
{
return $this->driver;
}

protected function resolveDriver(SqlConnection $connection): void
{
$driver = $this->resolveDriverFromConnection($connection);
$driver ??= $this->resolveDriverFromConfig();

$this->driver = $driver;
}

protected function resolveDriverFromConfig(): Driver
{
$default = Config::get('database.default');

return Driver::tryFrom($default) ?? Driver::MYSQL;
}

protected function resolveDriverFromConnection(SqlConnection $connection): Driver|null
{
$driver = null;

if ($connection instanceof MysqlConnectionPool) {
$driver = Driver::MYSQL;
} elseif ($connection instanceof PostgresConnectionPool) {
$driver = Driver::POSTGRESQL;
} elseif ($connection instanceof SqliteConnection) {
$driver = Driver::SQLITE;
}

return $driver;
}
}
10 changes: 9 additions & 1 deletion src/Database/Models/DatabaseModel.php
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,13 @@ public function getModelKeyName(): string
return $this->modelKey->getName();
}

public function getModelKeyColumnName(): string
{
$this->modelKey ??= $this->findModelKey();

return $this->modelKey->getColumnName();
}

public function setConnection(SqlConnection|string $connection): void
{
$this->modelConnection = $connection;
Expand Down Expand Up @@ -167,7 +174,8 @@ public function save(TransactionManager|null $transactionManager = null): bool
->update($data);
}

$result = $queryBuilder->insertRow($data);
$result = $queryBuilder
->insertGetId($data, $this->getModelKeyColumnName());

if ($result) {
if (! $this->keyIsInitialized()) {
Expand Down
5 changes: 2 additions & 3 deletions src/Database/Models/QueryBuilders/DatabaseQueryBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ public function __construct()
$this->relationships = [];
$this->connection = App::make(Connection::default());

$this->resolveDriverFromConnection($this->connection);
$this->resolveDriver($this->connection);
}

public function __clone(): void
Expand Down Expand Up @@ -204,8 +204,7 @@ public function create(array $attributes): DatabaseModel

$queryBuilder = clone $this;
$queryBuilder->setModel($model);

$result = $queryBuilder->insertRow($data);
$result = $queryBuilder->insertGetId($data, $model->getModelKeyColumnName());

if ($result) {
$modelKeyName = $model->getModelKeyName();
Expand Down
2 changes: 0 additions & 2 deletions src/Database/QueryBase.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@

use Closure;
use Phenix\Database\Concerns\Query\BuildsQuery;
use Phenix\Database\Concerns\Query\HasDriver;
use Phenix\Database\Concerns\Query\HasJoinClause;
use Phenix\Database\Concerns\Query\HasLock;
use Phenix\Database\Constants\Action;
Expand All @@ -17,7 +16,6 @@

abstract class QueryBase extends Clause implements QueryBuilder, Builder
{
use HasDriver;
use BuildsQuery;
use HasLock;
use HasJoinClause;
Expand Down
21 changes: 14 additions & 7 deletions src/Database/QueryBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

namespace Phenix\Database;

use Amp\Mysql\Internal\MysqlPooledResult;
use Amp\Sql\SqlConnection;
use Amp\Sql\SqlQueryError;
use Amp\Sql\SqlResult;
Expand All @@ -17,6 +16,7 @@
use Phenix\Database\Concerns\Query\HasTransaction;
use Phenix\Database\Constants\Action;
use Phenix\Database\Constants\Connection;
use Phenix\Database\Constants\Driver;

use function is_string;

Expand All @@ -32,7 +32,7 @@ public function __construct()

$this->connection = App::make(Connection::default());

$this->resolveDriverFromConnection($this->connection);
$this->resolveDriver($this->connection);
}

public function __clone(): void
Expand All @@ -56,7 +56,7 @@ public function connection(SqlConnection|string $connection): self

$this->connection = $connection;

$this->resolveDriverFromConnection($this->connection);
$this->resolveDriver($this->connection);

return $this;
}
Expand Down Expand Up @@ -169,15 +169,22 @@ public function insertFrom(Closure $subquery, array $columns, bool $ignore = fal
}
}

public function insertRow(array $data): int|string|bool
public function insertGetId(array $data, string $columns = 'id'): int|string|false|null
{
[$dml, $params] = parent::insert($data);
$this->returning((array) $columns);

try {
/** @var MysqlPooledResult $result */
[$dml, $params] = parent::insert($data);
$result = $this->exec($dml, $params);

return $result->getLastInsertId();
if (method_exists($result, 'getLastInsertId') && $this->driver !== Driver::POSTGRESQL) {
return $result->getLastInsertId();
}

$row = $result->fetchRow();
$row ??= [];

return array_values($row)[0] ?? null;
} catch (SqlQueryError|SqlTransactionError $e) {
report($e);

Expand Down
72 changes: 72 additions & 0 deletions tests/Feature/Database/Models/Postgres/DatabaseModelTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
<?php

declare(strict_types=1);

use Phenix\Database\Constants\Connection;
use Phenix\Database\Constants\Driver;
use Phenix\Database\Models\QueryBuilders\DatabaseQueryBuilder;
use Phenix\Facades\Config;
use Tests\Feature\Database\Models\User;
use Tests\Mocks\Database\PostgresqlConnectionPool;
use Tests\Mocks\Database\Result;
use Tests\Mocks\Database\Statement;

use function Pest\Faker\faker;

it('saves a new model on postgresql using its mapped key column', function (): void {
Config::set('database.default', Driver::POSTGRESQL->value);

$capturedSql = '';
$connection = $this->getMockBuilder(PostgresqlConnectionPool::class)->getMock();

$connection->expects($this->once())
->method('prepare')
->willReturnCallback(function (string $sql) use (&$capturedSql): Statement {
$capturedSql = $sql;

$result = new Result([['user_id' => 77]]);
$result->setLastInsertedId(77);

return new Statement($result);
});

$this->app->swap(Connection::name(Driver::POSTGRESQL->value), $connection);

$model = new User();
$model->setConnection(Driver::POSTGRESQL->value);
$model->name = 'John Doe';
$model->email = faker()->email();

expect($model->save())->toBeTrue();
expect($model->id)->toBe(77);
expect($model->isExisting())->toBeTrue();
expect($capturedSql)->toContain('RETURNING id');
});

it('creates a new model on postgresql using its mapped key column', function (): void {
Config::set('database.default', Driver::POSTGRESQL->value);

$capturedSql = '';
$connection = $this->getMockBuilder(PostgresqlConnectionPool::class)->getMock();

$connection->expects($this->once())
->method('prepare')
->willReturnCallback(function (string $sql) use (&$capturedSql): Statement {
$capturedSql = $sql;

return new Statement(new Result([['user_id' => 88]]));
});

$queryBuilder = new DatabaseQueryBuilder();
$queryBuilder->connection($connection);
$queryBuilder->setModel(new User());

$model = $queryBuilder->create([
'name' => 'Jane Doe',
'email' => faker()->email(),
]);

expect($model->id)->toBe(88);
expect($model->isExisting())->toBeTrue();
expect($capturedSql)->toContain('RETURNING id');
});
Loading
Loading