311 lines
5.2 KiB
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,
|
|
]
|
|
);
|
|
}
|
|
|
|
}
|
|
|
|
?>
|