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
8 changes: 7 additions & 1 deletion src/LitebaseClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,12 @@ public function exec(array $input): ?QueryResult
$parameters = [];

foreach ($input['parameters'] ?? [] as $param) {
// Base64 encode BLOB values for HTTP transport (JSON serialization)
// The binary streaming transport handles raw binary data
if ($param['type'] === 'BLOB' && $this->transport instanceof HttpTransport) {
$param['value'] = base64_encode((string) $param['value']);
}

$parameters[] = new StatementParameter($param);
}

Expand Down Expand Up @@ -235,7 +241,7 @@ public function withTransport(string $transportType): LitebaseClient
$this->transport = new HttpStreamingTransport($this->configuration);
break;
default:
throw new Exception('Invalid transport type: '.$transportType);
throw new Exception('Invalid transport type: ' . $transportType);
}

return $this;
Expand Down
41 changes: 22 additions & 19 deletions src/LitebaseStatement.php
Original file line number Diff line number Diff line change
Expand Up @@ -60,29 +60,29 @@ public function bindParam(
*/
public function bindValue(int|string $parameter, mixed $value, int $data_type = PDO::PARAM_STR): bool
{
$type = 'NULL';
$type = ColumnType::TEXT->name;

switch ($data_type) {
case PDO::PARAM_BOOL:
case PDO::PARAM_INT:
$type = 'INTEGER';
$type = ColumnType::INTEGER->name;
break;
case PDO::PARAM_STR:
$type = 'TEXT';
// Auto-detect float type when PDO::PARAM_STR is passed
if (is_float($value)) {
$type = ColumnType::FLOAT->name;
} else {
$type = ColumnType::TEXT->name;
}
break;
case PDO::PARAM_NULL:
$type = 'NULL';
$type = ColumnType::NULL->name;
break;
// TODO: Test BLOB type
case PDO::PARAM_LOB:
$type = 'BLOB';
$type = ColumnType::BLOB->name;
break;
// TODO: Add a case for float type
// case PDO::PARAM_FLOAT:
// $type = "REAL";
// break;
default:
$type = 'TEXT'; // Default to TEXT if no match
$type = ColumnType::TEXT->name; // Default to TEXT if no match
break;
}

Expand Down Expand Up @@ -164,11 +164,11 @@ public function execute(?array $params = null): bool
foreach ($params as $key => $value) {
// Determine the type based on the value
$type = match (true) {
$value === null => 'NULL',
is_int($value) => 'INTEGER',
is_float($value) => 'REAL',
is_bool($value) => 'INTEGER',
default => 'TEXT',
$value === null => ColumnType::NULL->name,
is_int($value) => ColumnType::INTEGER->name,
is_float($value) => ColumnType::FLOAT->name,
is_bool($value) => ColumnType::INTEGER->name,
default => ColumnType::TEXT->name,
};

$transformedParams[$key] = [
Expand Down Expand Up @@ -212,14 +212,14 @@ public function execute(?array $params = null): bool
$columns = $this->columns ?? [];

return array_combine(
array_map(fn ($col) => $col['name'], $columns),
array_map(fn($col) => $col['name'], $columns),
$row
);
}, $this->result->rows);
}

if (isset($this->result->rowCount)) {
$this->rowCount = $this->result->rowCount;
if (isset($this->result->changes)) {
$this->rowCount = $this->result->changes;
}

return true;
Expand Down Expand Up @@ -282,6 +282,9 @@ public function fetchColumn($columnIndex = 0): mixed
return $value !== false ? $row[$value] : null;
}

/**
* {@inheritDoc}
*/
public function rowCount(): int
{
return $this->rowCount;
Expand Down
90 changes: 89 additions & 1 deletion tests/Integration/LitebasePDOTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
'name' => 'test',
]));
} catch (\Exception $e) {
throw new \RuntimeException('Failed to connect to Litebase server for integration tests: '.$e->getMessage());
throw new \RuntimeException('Failed to connect to Litebase server for integration tests: ' . $e->getMessage());
}
});

Expand Down Expand Up @@ -140,4 +140,92 @@
expect($user['name'])->toBe('Alice');
expect($user['email'])->toBe('[email protected]');
});

test('can handle all column data types', function () {
$client = new LitebaseClient(
Configuration::create([
'host' => 'localhost',
'port' => '8888',
'username' => 'root',
'password' => 'password',
'database' => 'test/main',
])
);

$pdo = new LitebasePDO($client);

// Create table with all supported column types
$pdo->exec('CREATE TABLE IF NOT EXISTS type_test (
id INTEGER PRIMARY KEY AUTOINCREMENT,
int_col INTEGER,
float_col REAL,
text_col TEXT,
blob_col BLOB,
null_col TEXT
)');

// Insert data with different types using execute with params
$statement = $pdo->prepare('INSERT INTO type_test (int_col, float_col, text_col, blob_col, null_col) VALUES (?, ?, ?, ?, ?)');

$blobData = hex2bin('48656c6c6f20576f726c64'); // "Hello World" as binary

$statement->execute([
42, // INTEGER
3.14159, // FLOAT
'Hello World', // TEXT
$blobData, // BLOB
null, // NULL
]);

expect($statement->rowCount())->toBe(1);

// Now test bindValue for a second insert
$statement2 = $pdo->prepare('INSERT INTO type_test (int_col, float_col, text_col, blob_col, null_col) VALUES (?, ?, ?, ?, ?)');

$blobData2 = hex2bin('776f726c6420686921'); // "world hi!" as binary

$statement2->bindValue(1, 99, PDO::PARAM_INT);
$statement2->bindValue(2, 2.71828, PDO::PARAM_STR);
$statement2->bindValue(3, 'Test String', PDO::PARAM_STR);
$statement2->bindValue(4, $blobData2, PDO::PARAM_LOB);
$statement2->bindValue(5, null, PDO::PARAM_NULL);

$statement2->execute();

expect($statement2->rowCount())->toBe(1);

// Retrieve and verify the first row
$statement = $pdo->prepare('SELECT * FROM type_test WHERE int_col = ?');
$statement->execute([42]);

/** @var array<string, mixed> $row */
$row = $statement->fetch(PDO::FETCH_ASSOC);
/** @var float $floatValue */
$floatValue = $row['float_col'];
/** @var string $blobValue */
$blobValue = $row['blob_col'];

expect($row)->not->toBeNull();
expect($row['int_col'])->toBe(42);
expect($row['float_col'])->toBeFloat();
expect(abs($floatValue - 3.14159))->toBeLessThan(0.00001);
expect($row['text_col'])->toBe('Hello World');
expect($row['blob_col'])->toBe($blobData);
expect(bin2hex($blobValue))->toBe('48656c6c6f20576f726c64');
expect($row['null_col'])->toBeNull();

// Retrieve and verify the second row
$statement = $pdo->prepare('SELECT * FROM type_test WHERE int_col = ?');
$statement->execute([99]);

/** @var array<string, mixed> $row2 */
$row2 = $statement->fetch(PDO::FETCH_ASSOC);

expect($row2)->not->toBeNull();
expect($row2['int_col'])->toBe(99);
expect($row2['float_col'])->toBeFloat();
expect($row2['text_col'])->toBe('Test String');
expect($row2['blob_col'])->toBe($blobData2);
expect($row2['null_col'])->toBeNull();
});
});