2024-07-11 17:21:33 -05:00
|
|
|
<?php
|
|
|
|
|
|
|
|
/*
|
|
|
|
SQLite database wrapper class.
|
|
|
|
|
|
|
|
By default, foreign keys are enabled and the database is in WAL mode. In general
|
|
|
|
these defaults should be perfect for most use cases.
|
|
|
|
*/
|
|
|
|
|
|
|
|
class Database
|
|
|
|
{
|
|
|
|
private PDO $c;
|
|
|
|
private int $queries = 0;
|
|
|
|
private array $log = [];
|
|
|
|
private float $time = 0;
|
2024-07-17 22:11:45 -05:00
|
|
|
private string $path = '';
|
2024-07-11 17:21:33 -05:00
|
|
|
|
|
|
|
public function __construct(string $path, array $opts = [])
|
|
|
|
{
|
|
|
|
$opts = !empty($opts) ? $opts : [
|
|
|
|
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
|
|
|
|
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
|
|
|
|
];
|
|
|
|
|
|
|
|
try {
|
|
|
|
$this->c = new PDO("sqlite:$path", null, null, $opts);
|
|
|
|
$this->c->exec('PRAGMA foreign_keys = ON;'); // Enable foreign keys
|
|
|
|
$this->c->exec('PRAGMA journal_mode = WAL;'); // Enable WAL
|
2024-07-17 22:11:45 -05:00
|
|
|
$this->path = $path;
|
2024-07-11 17:21:33 -05:00
|
|
|
} catch (PDOException $e) {
|
|
|
|
throw $e;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public function do(string $query, array $params = []): PDOStatement|false
|
|
|
|
{
|
|
|
|
$start = microtime(true);
|
|
|
|
|
|
|
|
try {
|
|
|
|
$stmt = $this->c->prepare($query);
|
|
|
|
$stmt->execute($params);
|
|
|
|
$this->record($query, $start);
|
|
|
|
return $stmt;
|
|
|
|
} catch (PDOException $e) {
|
2024-07-12 23:24:59 -05:00
|
|
|
print_r($query);
|
|
|
|
throw $e;
|
2024-07-11 17:21:33 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public function q(string $query): PDOStatement|false
|
|
|
|
{
|
|
|
|
$start = microtime(true);
|
|
|
|
|
|
|
|
try {
|
|
|
|
$stmt = $this->c->query($query);
|
|
|
|
$this->record($query, $start);
|
|
|
|
return $stmt;
|
|
|
|
} catch (PDOException $e) {
|
2024-07-12 23:24:59 -05:00
|
|
|
print_r($query);
|
|
|
|
throw $e;
|
2024-07-11 17:21:33 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private function record(string $query, float $start): void
|
|
|
|
{
|
|
|
|
$time = microtime(true) - $start;
|
|
|
|
$this->queries++;
|
|
|
|
$this->log[] = [$query, $time];
|
|
|
|
$this->time += $time;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function queries(): int
|
|
|
|
{
|
|
|
|
return $this->queries;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function log(): array
|
|
|
|
{
|
|
|
|
return $this->log;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function time(): float
|
|
|
|
{
|
|
|
|
return $this->time;
|
|
|
|
}
|
2024-07-12 23:24:59 -05:00
|
|
|
|
2024-07-17 22:11:45 -05:00
|
|
|
public function path(): string
|
|
|
|
{
|
|
|
|
return $this->path;
|
|
|
|
}
|
|
|
|
|
2024-07-13 23:15:25 -05:00
|
|
|
public function lastInsertID(): int
|
|
|
|
{
|
|
|
|
return $this->c->lastInsertId();
|
|
|
|
}
|
|
|
|
|
2024-07-12 23:24:59 -05:00
|
|
|
public function insertFromCSV(string $table, string $path): PDOStatement|false
|
|
|
|
{
|
|
|
|
// open the file
|
|
|
|
$handle = fopen($path, 'r');
|
|
|
|
if ($handle === false) return false;
|
|
|
|
|
|
|
|
// reduce the column names to lower case with underscores
|
|
|
|
$columns = array_map(function ($column) {
|
|
|
|
return strtolower(str_replace(' ', '_', $column));
|
|
|
|
}, fgetcsv($handle));
|
|
|
|
|
|
|
|
// set up the query
|
|
|
|
$query = "INSERT INTO $table (" . implode(',', $columns) . ') VALUES ';
|
|
|
|
|
|
|
|
// read the rows and add them to the query
|
|
|
|
while (($row = fgetcsv($handle)) !== false) {
|
|
|
|
// go through the row and put strings into single quotes
|
|
|
|
$row = array_map(function ($column) {
|
|
|
|
if (is_numeric($column)) return $column;
|
2024-07-13 22:37:40 -05:00
|
|
|
return "'" . str_replace("'", "''", $column) . "'";
|
2024-07-12 23:24:59 -05:00
|
|
|
}, $row);
|
|
|
|
|
|
|
|
// add the row to the query
|
|
|
|
$query .= '(' . implode(',', $row) . '),';
|
|
|
|
}
|
|
|
|
|
|
|
|
// remove the trailing comma
|
|
|
|
$query = rtrim($query, ',') . ';';
|
|
|
|
|
|
|
|
// execute the insert
|
|
|
|
return $this->q($query);
|
|
|
|
}
|
2024-07-11 17:21:33 -05:00
|
|
|
}
|