Skip to content

Commit

Permalink
Enable database transactions feature
Browse files Browse the repository at this point in the history
  • Loading branch information
richan-fongdasen committed Apr 22, 2024
1 parent d3cf794 commit 0f6196e
Show file tree
Hide file tree
Showing 5 changed files with 145 additions and 30 deletions.
7 changes: 0 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,6 @@ This package provides a Turso database driver for Laravel, allowing you to use T

You can find a demo application that uses this Turso database driver in the [richan-fongdasen/pingcrm](https://github.com/richan-fongdasen/pingcrm) repository.

## Unsupported Features

Some features are not yet supported by this package:

- Creating and dropping database
- [Database Transactions](https://turso.tech/blog/bring-your-own-sdk-with-tursos-http-api-ff4ccbed)

## Requirements

- PHP 8.2 or higher
Expand Down
26 changes: 20 additions & 6 deletions src/Database/TursoPDO.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
namespace RichanFongdasen\Turso\Database;

use PDO;
use RichanFongdasen\Turso\Exceptions\FeatureNotSupportedException;

/**
* Turso PDO Database Connection.
Expand All @@ -14,9 +13,14 @@
* that is used by the Turso database driver.
*
* see: https://www.php.net/manual/en/class.pdo.php
*
* Turso database transactions & interactive queries reference:
* https://docs.turso.tech/sdk/http/reference#interactive-query
*/
class TursoPDO extends PDO
{
protected bool $inTransaction = false;

protected array $lastInsertIds = [];

public function __construct(
Expand All @@ -30,25 +34,31 @@ public function __construct(

public function beginTransaction(): bool
{
throw new FeatureNotSupportedException('Database transaction is not supported by the current Turso database driver.');
$this->inTransaction = $this->prepare('BEGIN')->execute();

return $this->inTransaction;
}

public function commit(): bool
{
throw new FeatureNotSupportedException('Database transaction is not supported by the current Turso database driver.');
$result = $this->prepare('COMMIT')->execute();

$this->inTransaction = false;

return $result;
}

public function exec(string $queryStatement): int
{
$statement = $this->prepare($queryStatement);
$statement->execute();

return $statement->getAffectedRows();
return $statement->rowCount();
}

public function inTransaction(): bool
{
return false;
return $this->inTransaction;
}

public function lastInsertId(?string $name = null): string|false
Expand All @@ -69,7 +79,11 @@ public function prepare(string $query, array $options = []): TursoPDOStatement

public function rollBack(): bool
{
throw new FeatureNotSupportedException('Database transaction is not supported by the current Turso database driver.');
$result = $this->prepare('ROLLBACK')->execute();

$this->inTransaction = false;

return $result;
}

public function setLastInsertId(?string $name = null, ?int $value = null): void
Expand Down
89 changes: 89 additions & 0 deletions tests/Feature/DatabaseTransactionsTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
<?php

use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
use RichanFongdasen\Turso\Tests\Fixtures\Models\User;

beforeEach(function () {
migrateTables('users', 'posts');

$this->user = User::factory()->create();
});

afterEach(function () {
Schema::dropAllTables();
});

test('it can rollback the transaction', function () {
$this->user->name = 'John Doe';
$this->user->save();

expect(User::count())->toBe(1);

DB::transaction(function () {
$this->user->name = 'Jane Doe';
$this->user->save();

expect(User::first()->name)->toBe('Jane Doe');

DB::rollBack();
});

expect(User::count())->toBe(1);
expect(User::first()->name)->toBe('John Doe');
})->group('DatabaseTransactionsTest', 'FeatureTest');

test('it can rollback the transaction by manually using the transactions', function () {
$this->user->name = 'John Doe';
$this->user->save();

expect(User::count())->toBe(1);

DB::beginTransaction();

$this->user->name = 'Jane Doe';
$this->user->save();

expect(User::first()->name)->toBe('Jane Doe');

DB::rollBack();

expect(User::count())->toBe(1);
expect(User::first()->name)->toBe('John Doe');
})->group('DatabaseTransactionsTest', 'FeatureTest');

test('it can commit the transaction', function () {
$this->user->name = 'John Doe';
$this->user->save();

expect(User::count())->toBe(1);

DB::transaction(function () {
$this->user->name = 'Jane Doe';
$this->user->save();

expect(User::first()->name)->toBe('Jane Doe');
});

expect(User::count())->toBe(1);
expect(User::first()->name)->toBe('Jane Doe');
})->group('DatabaseTransactionsTest', 'FeatureTest');

test('it can commit the transaction by manually using the transactions', function () {
$this->user->name = 'John Doe';
$this->user->save();

expect(User::count())->toBe(1);

DB::beginTransaction();

$this->user->name = 'Jane Doe';
$this->user->save();

expect(User::first()->name)->toBe('Jane Doe');

DB::commit();

expect(User::count())->toBe(1);
expect(User::first()->name)->toBe('Jane Doe');
})->group('DatabaseTransactionsTest', 'FeatureTest');
36 changes: 36 additions & 0 deletions tests/Feature/TursoPDOTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,44 @@

beforeEach(function () {
$this->pdo = DB::connection()->getPdo();

$this->pdo->exec('CREATE TABLE "projects" ("id" INTEGER PRIMARY KEY, "name" TEXT);');
});

afterEach(function () {
$this->pdo->exec('DROP TABLE IF EXISTS "projects";');
});

test('it can execute SQL command', function () {
expect($this->pdo->exec('PRAGMA foreign_keys = ON;'))->toBe(0);
})->group('TursoPDOTest', 'FeatureTest');

test('it can begin the database transaction, and rollback the changes.', function () {
$this->pdo->beginTransaction();

$this->pdo->exec('INSERT INTO "projects" ("name") VALUES (\'Project 1\');');
$this->pdo->exec('INSERT INTO "projects" ("name") VALUES (\'Project 2\');');

expect($this->pdo->inTransaction())->toBeTrue()
->and($this->pdo->exec('SELECT * FROM "projects";'))->toBe(2);

$this->pdo->rollBack();

expect($this->pdo->inTransaction())->toBeFalse()
->and($this->pdo->exec('SELECT * FROM "projects";'))->toBe(0);
})->group('TursoPDOTest', 'FeatureTest');

test('it can begin the database transaction, and commit the changes.', function () {
$this->pdo->beginTransaction();

$this->pdo->exec('INSERT INTO "projects" ("name") VALUES (\'Project 1\');');
$this->pdo->exec('INSERT INTO "projects" ("name") VALUES (\'Project 2\');');

expect($this->pdo->inTransaction())->toBeTrue()
->and($this->pdo->exec('SELECT * FROM "projects";'))->toBe(2);

$this->pdo->commit();

expect($this->pdo->inTransaction())->toBeFalse()
->and($this->pdo->exec('SELECT * FROM "projects";'))->toBe(2);
})->group('TursoPDOTest', 'FeatureTest');
17 changes: 0 additions & 17 deletions tests/Unit/Database/TursoPDOTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

use Illuminate\Support\Facades\DB;
use RichanFongdasen\Turso\Database\TursoPDO;
use RichanFongdasen\Turso\Exceptions\FeatureNotSupportedException;

beforeEach(function () {
$this->pdo = DB::connection()->getPdo();
Expand All @@ -12,22 +11,6 @@
expect($this->pdo)->toBeInstanceOf(TursoPDO::class);
})->group('TursoPDOTest', 'UnitTest');

test('it raises exception on beginning a database transaction', function () {
$this->pdo->beginTransaction();
})->throws(FeatureNotSupportedException::class)->group('TursoPDOTest', 'UnitTest');

test('it raises exception on committing a database transaction', function () {
$this->pdo->commit();
})->throws(FeatureNotSupportedException::class)->group('TursoPDOTest', 'UnitTest');

test('it raises exception on rolling back a database transaction', function () {
$this->pdo->rollBack();
})->throws(FeatureNotSupportedException::class)->group('TursoPDOTest', 'UnitTest');

test('database transaction status should always be false', function () {
expect($this->pdo->inTransaction())->toBeFalse();
})->group('TursoPDOTest', 'UnitTest');

test('it can manage the last insert id value', function () {
$this->pdo->setLastInsertId(value: 123);

Expand Down

0 comments on commit 0f6196e

Please sign in to comment.