Skip to content

Commit

Permalink
Add some test cases related to supported database column types, and e…
Browse files Browse the repository at this point in the history
…loquent attribute castings.
  • Loading branch information
richan-fongdasen committed Apr 23, 2024
1 parent 420bf40 commit 746fd61
Show file tree
Hide file tree
Showing 24 changed files with 1,785 additions and 41 deletions.
49 changes: 8 additions & 41 deletions src/Database/TursoPDOStatement.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
use PDO;
use PDOException;
use PDOStatement;
use RichanFongdasen\Turso\Enums\PdoParam;
use RichanFongdasen\Turso\Enums\TursoType;
use RichanFongdasen\Turso\Facades\Turso;
use RichanFongdasen\Turso\Http\QueryResponse;

Expand Down Expand Up @@ -41,38 +43,11 @@ public function setFetchMode(int $mode, mixed ...$args): bool
return true;
}

public function bindValue(string|int $param, mixed $value, $type = PDO::PARAM_STR): bool
public function bindValue(string|int $param, mixed $value, int $type = PDO::PARAM_STR): bool
{
if ($value === null) {
$type = PDO::PARAM_NULL;
}

if ($type === PDO::PARAM_STR && (! ctype_print($value) || ! mb_check_encoding($value, 'UTF-8'))) {
$type = PDO::PARAM_LOB;
}
$type = TursoType::fromValue($value);

$this->bindings[$param] = match ($type) {
PDO::PARAM_LOB => [
'type' => 'blob',
'base64' => base64_encode(base64_encode($value)),
],
PDO::PARAM_BOOL => [
'type' => 'boolean',
'value' => (string) ((int) $value),
],
PDO::PARAM_INT => [
'type' => 'integer',
'value' => (string) $value,
],
PDO::PARAM_NULL => [
'type' => 'null',
'value' => 'null',
],
default => [
'type' => 'text',
'value' => (string) $value,
],
};
$this->bindings[$param] = $type->bind($value);

return true;
}
Expand All @@ -81,15 +56,9 @@ public function execute(?array $params = null): bool
{
collect((array) $params)
->each(function (mixed $value, int $key) {
$type = match (gettype($value)) {
'boolean' => PDO::PARAM_BOOL,
'double', 'integer' => PDO::PARAM_INT,
'resource' => PDO::PARAM_LOB,
'NULL' => PDO::PARAM_NULL,
default => PDO::PARAM_STR,
};

$this->bindValue($key, $value, $type);
$type = PdoParam::fromValue($value);

$this->bindValue($key, $value, $type->value);
});

$this->response = Turso::query($this->query, array_values($this->bindings));
Expand Down Expand Up @@ -156,8 +125,6 @@ public function fetchAll(int $mode = PDO::FETCH_DEFAULT, ...$args): array
default => throw new PDOException('Unsupported fetch mode.'),
};

// $this->responses = new Collection();

return $response;
}

Expand Down
27 changes: 27 additions & 0 deletions src/Enums/PdoParam.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php

declare(strict_types=1);

namespace RichanFongdasen\Turso\Enums;

use PDO;

enum PdoParam: int
{
case NULL = PDO::PARAM_NULL;
case BOOL = PDO::PARAM_BOOL;
case INT = PDO::PARAM_INT;
case STR = PDO::PARAM_STR;
case LOB = PDO::PARAM_LOB;

public static function fromValue(mixed $value): static
{
return match (gettype($value)) {
'boolean' => self::BOOL,
'double', 'integer' => self::INT,
'resource' => self::LOB,
'NULL' => self::NULL,
default => self::STR,
};
}
}
66 changes: 66 additions & 0 deletions src/Enums/TursoType.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
<?php

declare(strict_types=1);

namespace RichanFongdasen\Turso\Enums;

/**
* Turso data type enumeration.
* Ref: https://github.com/tursodatabase/libsql/blob/main/docs/HRANA_3_SPEC.md#values.
*/
enum TursoType: string
{
case NULL = 'null';
case INTEGER = 'integer';
case FLOAT = 'float';
case TEXT = 'text';
case BLOB = 'blob';

public static function fromValue(mixed $value): static
{
$result = match (gettype($value)) {
'NULL' => self::NULL,
'boolean', 'integer' => self::INTEGER,
'double', 'float' => self::FLOAT,
'string' => self::fromString($value),

default => null,
};

return ($result !== null)
? $result
: self::TEXT;
}

public static function fromString(string $value): self
{
if (! ctype_print($value) || ! mb_check_encoding($value, 'UTF-8')) {
return self::BLOB;
}

return self::TEXT;
}

public function bind(mixed $value): array
{
return match ($this) {
self::NULL => [
'type' => $this->value,
'value' => 'null',
],
self::FLOAT => [
'type' => $this->value,
'value' => $value,
],
self::BLOB => [
'type' => $this->value,
'base64' => base64_encode(base64_encode($value)),
],

default => [
'type' => $this->value,
'value' => (string) $value,
],
};
}
}
56 changes: 56 additions & 0 deletions tests/Feature/DataTypes/BooleanDataTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<?php

use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;

beforeEach(function () {
Schema::create('boolean_table', function ($table) {
$table->id();
$table->boolean('confirmed');
});
});

afterEach(function () {
Schema::dropIfExists('boolean_table');
});

test('it can insert a new boolean data, and the value will be saved as an integer', function () {
$result = DB::table('boolean_table')->insert([
'confirmed' => true,
]);

$newData = DB::table('boolean_table')->first();

expect($result)->toBeTrue()
->and(DB::table('boolean_table')->count())->toBe(1)
->and($newData->confirmed)->toBe(1);
})->group('BooleanDataTest', 'DataTypes', 'FeatureTest');

test('it can update an existing boolean data, and the retrieved value will be an integer', function () {
DB::table('boolean_table')->insert([
'confirmed' => true,
]);

$result = DB::table('boolean_table')->update([
'confirmed' => false,
]);

$updatedData = DB::table('boolean_table')->first();

expect($result)->toBe(1)
->and($updatedData->confirmed)->toBe(0);
})->group('BooleanDataTest', 'DataTypes', 'FeatureTest');

test('it can find the saved record', function () {
DB::table('boolean_table')->insert([
'confirmed' => true,
]);
DB::table('boolean_table')->insert([
'confirmed' => false,
]);

$found = DB::table('boolean_table')->where('confirmed', false)->first();

expect($found->id)->toBe(2)
->and($found->confirmed)->toBe(0);
})->group('BooleanDataTest', 'DataTypes', 'FeatureTest');
64 changes: 64 additions & 0 deletions tests/Feature/DataTypes/DateDataTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
<?php

use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;

beforeEach(function () {
Schema::create('date_table', function ($table) {
$table->id();
$table->date('started_at');
});
});

afterEach(function () {
Schema::dropIfExists('date_table');
});

test('it can insert a new date data', function () {
$date = '2021-01-01';

$result = DB::table('date_table')->insert([
'started_at' => $date,
]);

$newData = DB::table('date_table')->first();

expect($result)->toBeTrue()
->and(DB::table('date_table')->count())->toBe(1)
->and($newData->started_at)->toBe($date);
})->group('DateDataTest', 'DataTypes', 'FeatureTest');

test('it can update an existing date data', function () {
$date = '2021-01-01';

DB::table('date_table')->insert([
'started_at' => $date,
]);

$newDate = '2021-02-01';

$result = DB::table('date_table')->update([
'started_at' => $newDate,
]);

$updatedData = DB::table('date_table')->first();

expect($result)->toBe(1)
->and($updatedData->started_at)->toBe($newDate);
})->group('DateDataTest', 'DataTypes', 'FeatureTest');

test('it can find the saved record', function () {
$date = '2021-01-01';

DB::table('date_table')->insert([
'started_at' => '2021-02-01',
]);
DB::table('date_table')->insert([
'started_at' => $date,
]);

$found = DB::table('date_table')->where('started_at', $date)->first();

expect($found->id)->toBe(2)
->and($found->started_at)->toBe($date);
})->group('DateDataTest', 'DataTypes', 'FeatureTest');
65 changes: 65 additions & 0 deletions tests/Feature/DataTypes/DateTimeDataTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
<?php

use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;

beforeEach(function () {
Schema::create('datetime_table', function ($table) {
$table->id();
$table->dateTime('published_at');
$table->timestamps();
});
});

afterEach(function () {
Schema::dropIfExists('datetime_table');
});

test('it can insert a new datetime data', function () {
$publishedAt = now();

$result = DB::table('datetime_table')->insert([
'published_at' => $publishedAt,
]);

$newData = DB::table('datetime_table')->first();

expect($result)->toBeTrue()
->and(DB::table('datetime_table')->count())->toBe(1)
->and($newData->published_at)->toBe($publishedAt->format('Y-m-d H:i:s'));
})->group('DateTimeDataTest', 'DataTypes', 'FeatureTest');

test('it can update an existing datetime data', function () {
$publishedAt = now();

DB::table('datetime_table')->insert([
'published_at' => $publishedAt,
]);

$newPublishedAt = now()->subDay();

$result = DB::table('datetime_table')->update([
'published_at' => $newPublishedAt,
]);

$updatedData = DB::table('datetime_table')->first();

expect($result)->toBe(1)
->and($updatedData->published_at)->toBe($newPublishedAt->format('Y-m-d H:i:s'));
})->group('DateTimeDataTest', 'DataTypes', 'FeatureTest');

test('it can find the saved record', function () {
$publishedAt = now();

DB::table('datetime_table')->insert([
'published_at' => now()->subDay(),
]);
DB::table('datetime_table')->insert([
'published_at' => $publishedAt,
]);

$found = DB::table('datetime_table')->where('published_at', '>=', $publishedAt->format('Y-m-d H:i:s'))->first();

expect($found->id)->toBe(2)
->and($found->published_at)->toBe($publishedAt->format('Y-m-d H:i:s'));
})->group('DateTimeDataTest', 'DataTypes', 'FeatureTest');
Loading

0 comments on commit 746fd61

Please sign in to comment.