Dragon-Knight/database.php

72 lines
2.0 KiB
PHP

<?php
/**
* An extension to the SQLite3 class to add our own logging and binding semantics!
*/
class Database extends SQLite3
{
public int $count = 0;
public array $log = [];
public float $query_time = 0;
public function __construct(string $db_path)
{
parent::__construct($db_path);
parent::exec('PRAGMA cache_size = 32000');
parent::exec('PRAGMA journal_mode = WAL');
parent::exec('PRAGMA temp_store = MEMORY');
}
public function query(string $query, array $params = []): SQLite3Result|false
{
$p = strpos($query, '?') !== false;
$stmt = $this->prepare($query);
foreach ($params ?? [] as $k => $v) $stmt->bindValue($p ? $k + 1 : $k, $v, $this->getSQLiteType($v));
$start = microtime(true);
$r = $stmt->execute();
$this->log($query, microtime(true) - $start);
return $r;
}
public function exec(string $query): bool
{
$start = microtime(true);
$r = parent::exec($query);
$this->log($query, microtime(true) - $start);
return $r;
}
public function exists(string $table, string $column, mixed $value, bool $case_insensitive = true): bool
{
if ($case_insensitive) {
$query = "SELECT 1 FROM $table WHERE $column = :v COLLATE NOCASE LIMIT 1";
} else {
$query = "SELECT 1 FROM $table WHERE $column = :v LIMIT 1";
}
$result = $this->query($query, [':v' => $value]);
return $result->fetchArray(SQLITE3_NUM) !== false;
}
private function log(string $query, float $time_taken): void
{
$this->count++;
$this->query_time += $time_taken;
$this->log[] = [$query, $time_taken];
}
private function getSQLiteType(mixed $value): int
{
return match (true) {
is_int($value) => SQLITE3_INTEGER,
is_float($value) => SQLITE3_FLOAT,
is_null($value) => SQLITE3_NULL,
default => SQLITE3_TEXT
};
}
}