rosavox/source/helpers/storage-sqlitetable.php

311 lines
5.2 KiB
PHP

<?php
namespace rosavox\helpers\storage;
require_once('helpers/list.php');
require_once('helpers/sqlite.php');
require_once('helpers/storage-interface.php');
/**
*/
class class_sqlitetable implements interface_/*<int,list<any>>*/
{
/**
*/
public static function field_name(
array $field
) : string
{
return \rosavox\helpers\string_\coin(
'field_{{name}}',
[
'name' => $field['name'],
]
);
}
/**
*/
private string $path;
/**
*/
private string $name;
/**
* @param $fields {
* list<
* record<
* name:string,
* type:string,
* nullable:boolean,
* >
* >
* }
*/
private array $fields;
/**
*/
public function __construct(
string $path,
string $name,
array $fields
)
{
$this->path = $path;
$this->name = $name;
$this->fields = $fields;
}
/**
*/
public function setup() : void
{
$result = \rosavox\helpers\sqlite\query(
$this->path,
\rosavox\helpers\string_\coin(
'CREATE TABLE IF NOT EXISTS {{name}}(id INTEGER PRIMARY KEY AUTOINCREMENT, {{fields}});',
[
'name' => $this->name,
'fields' => \implode(
', ',
\array_map(
fn ($field) => \rosavox\helpers\string_\coin(
'{{name}} {{type}}{{macro_nullable}}',
[
'name' => self::field_name($field),
'type' => \rosavox\helpers\sqlite\map_type($field['type']),
'macro_nullable' => ($field['nullable'] ? '' : ' NOT NULL'),
]
),
$this->fields
)
),
]
),
[
]
);
}
/**
*/
public function list_() : array
{
$result = \rosavox\helpers\sqlite\query(
$this->path,
\rosavox\helpers\string_\coin(
'SELECT id,{{fields}} FROM {{name}}',
[
'fields' => \implode(
', ',
\rosavox\helpers\list_\map(
$this->fields,
fn ($field) => self::field_name($field)
)
),
'name' => $this->name,
]
),
[
]
);
$entries = [];
while (true)
{
$row = $result['result']->fetchArray(\SQLITE3_NUM);
if ($row !== false)
{
\array_push(
$entries,
[
'id' => $row[0],
'value' => \array_slice($row, 1),
]
);
}
else
{
break;
}
}
return $entries;
}
/**
*/
public function read($id)
{
$result = \rosavox\helpers\sqlite\query(
$this->path,
\rosavox\helpers\string_\coin(
'SELECT {{fields}} FROM {{name}} WHERE (id = {{id}});',
[
'fields' => \implode(
', ',
\rosavox\helpers\list_\map(
$this->fields,
fn ($field) => self::field_name($field)
)
),
'name' => $this->name,
'id' => \rosavox\helpers\sqlite\placeholder('id'),
]
),
[
'id' => $id,
]
);
$rows = [];
while (true)
{
$row = $result['result']->fetchArray(\SQLITE3_NUM);
if ($row !== false)
{
\array_push($rows, $row);
}
else
{
break;
}
}
$count = \count($rows);
if ($count === 0)
{
throw (new \Exception('not found'));
}
else
{
if ($count > 1)
{
throw (new \Exception('ambiguous'));
}
else
{
return $rows[0];
}
}
}
/**
*/
public function create($row)
{
$result = \rosavox\helpers\sqlite\query(
$this->path,
\rosavox\helpers\string_\coin(
'INSERT INTO {{name}}({{schema}}) VALUES ({{values}});',
[
'name' => $this->name,
'schema' => \implode(
', ',
\array_map(
fn ($field) => self::field_name($field),
$this->fields
)
),
'values' => \implode(
', ',
\array_map(
fn ($field) => \rosavox\helpers\sqlite\placeholder(
self::field_name($field)
),
$this->fields
)
),
]
),
\rosavox\helpers\list_\to_map(
\rosavox\helpers\list_\map(
\rosavox\helpers\list_\sequence(
\count($this->fields)
),
fn ($index) => [
'key' => self::field_name($this->fields[$index]),
'value' => $row[$index],
]
)
)
);
return $result['last_insert_id'];
}
/**
*/
public function update($id, $row) : void
{
$result = \rosavox\helpers\sqlite\query(
$this->path,
\rosavox\helpers\string_\coin(
'UPDATE {{name}} SET {{sets}} WHERE (id = :id);',
[
'name' => $this->name,
'sets' => \implode(
', ',
\array_map(
fn ($field) => \rosavox\helpers\string_\coin(
'{{name}} = {{placeholder}}',
[
'name' => self::field_name($field),
'placeholder' => \rosavox\helpers\sqlite\placeholder(self::field_name($field)),
]
),
$this->fields
)
),
]
),
\array_merge(
[
'id' => $id,
],
\rosavox\helpers\list_\to_map(
\rosavox\helpers\list_\map(
\rosavox\helpers\list_\sequence(
\count($this->fields)
),
fn ($index) => [
'key' => self::field_name($this->fields[$index]),
'value' => $row[$index],
]
)
)
)
);
}
/**
*/
public function delete($id) : void
{
$result = \rosavox\helpers\sqlite\query(
$this->path,
\rosavox\helpers\string_\coin(
'DELETE * FROM {{name}} WHERE (id = {{id}});',
[
'name' => $this->name,
'id' => \rosavox\helpers\sqlite\placeholder('id'),
]
),
[
'id' => $id,
]
);
}
}
?>