418 lines
7.9 KiB
PHP
418 lines
7.9 KiB
PHP
<?php
|
|
|
|
namespace alveolata\storage;
|
|
|
|
// require_once(DIR_ALVEOLATA . '/definitions.php');
|
|
require_once(DIR_ALVEOLATA . '/string/functions.php');
|
|
require_once(DIR_ALVEOLATA . '/list/functions.php');
|
|
require_once(DIR_ALVEOLATA . '/sql/functions.php');
|
|
require_once(DIR_ALVEOLATA . '/report/functions.php');
|
|
require_once(DIR_ALVEOLATA . '/observer/wrapper-class.php');
|
|
require_once(DIR_ALVEOLATA . '/database/abstract/interface.php');
|
|
|
|
|
|
/**
|
|
* @author Christian Fraß <frass@greenscale.de>
|
|
*/
|
|
class struct_sqltable
|
|
{
|
|
|
|
/**
|
|
* @var \alveolata\database\interface_database
|
|
* @author Christian Fraß <frass@greenscale.de>
|
|
*/
|
|
public $database;
|
|
|
|
|
|
/**
|
|
* @var string
|
|
* @author Christian Fraß <frass@greenscale.de>
|
|
*/
|
|
public $name;
|
|
|
|
|
|
/**
|
|
* @var list<record<name:string,type:string,null_allowed:boolean,default:any>>
|
|
* @author Christian Fraß <frass@greenscale.de>
|
|
*/
|
|
public $fields;
|
|
|
|
|
|
/**
|
|
* @var \alveolata\observer\class_observer
|
|
*/
|
|
public $observer_teardown;
|
|
|
|
|
|
/**
|
|
* @var \alveolata\observer\class_observer
|
|
*/
|
|
public $observer_delete;
|
|
|
|
|
|
/**
|
|
* @author Christian Fraß <frass@greenscale.de>
|
|
*/
|
|
public function __construct(
|
|
\alveolata\database\interface_database $database,
|
|
string $name,
|
|
array $fields
|
|
)
|
|
{
|
|
$this->database = $database;
|
|
$this->name = $name;
|
|
$this->fields = $fields;
|
|
|
|
$this->observer_teardown = \alveolata\observer\class_observer::make();
|
|
$this->observer_delete = \alveolata\observer\class_observer::make();
|
|
}
|
|
|
|
}
|
|
|
|
|
|
/**
|
|
* @author Christian Fraß <frass@greenscale.de>
|
|
*/
|
|
function sqltable_make(
|
|
\alveolata\database\interface_database $database,
|
|
string $name,
|
|
array $fields = UNSET_ARRAY
|
|
) : struct_sqltable
|
|
{
|
|
return (
|
|
new struct_sqltable(
|
|
$database,
|
|
$name,
|
|
$fields
|
|
)
|
|
);
|
|
}
|
|
|
|
|
|
/**
|
|
* @author Christian Fraß <frass@greenscale.de>
|
|
*/
|
|
function sqltable_hook_delete(
|
|
struct_sqltable $subject,
|
|
\Closure $procedure
|
|
) : string
|
|
{
|
|
return $subject->observer_delete->register($procedure);
|
|
}
|
|
|
|
|
|
/**
|
|
* @author Christian Fraß <frass@greenscale.de>
|
|
*/
|
|
function sqltable_teardown(
|
|
struct_sqltable $subject
|
|
) : void
|
|
{
|
|
$subject->observer_teardown->notify(null);
|
|
$template = \alveolata\string\coin(
|
|
'DROP TABLE IF EXISTS `{{tablename}}`',
|
|
[
|
|
'tablename' => $subject->name,
|
|
]
|
|
);
|
|
$subject->database->query(
|
|
$template
|
|
);
|
|
}
|
|
|
|
|
|
/**
|
|
* @author Christian Fraß <frass@greenscale.de>
|
|
*/
|
|
function sqltable_setup(
|
|
struct_sqltable $subject
|
|
) : void
|
|
{
|
|
if ($subject->fields === UNSET_ARRAY) {
|
|
$report = \alveolata\report\make(
|
|
'SQL table setup not possible since fields have not been specified',
|
|
[
|
|
'tablename' => $subject->name,
|
|
]
|
|
);
|
|
throw (\alveolata\report\as_exception($report));
|
|
}
|
|
else {
|
|
$arguments = [];
|
|
$fielddescriptions = [];
|
|
// id
|
|
{
|
|
$fielddescription = \alveolata\string\coin(
|
|
'`id` {{definition}}',
|
|
[
|
|
'definition' => $subject->database->boilerplate_field_definition_for_integer_primary_key_with_auto_increment(),
|
|
]
|
|
);
|
|
array_push($fielddescriptions, $fielddescription);
|
|
}
|
|
// regular fields
|
|
{
|
|
}
|
|
foreach ($subject->fields as $field) {
|
|
$key = \alveolata\string\coin(
|
|
'defaultvalue_{{columnname}}',
|
|
[
|
|
'columnname' => $field['name'],
|
|
]
|
|
);
|
|
$fielddescription = \alveolata\string\coin(
|
|
'`{{columnname}}` {{type}} {{nullability}} DEFAULT {{defaultvalue}}',
|
|
[
|
|
'columnname' => $field['name'],
|
|
'type' => $field['type'],
|
|
'nullability' => ($field['null_allowed'] ? 'NULL' : 'NOT NULL'),
|
|
// 'defaultvalue' => $field['default'],
|
|
'defaultvalue' => sprintf(':%s', $key),
|
|
]
|
|
);
|
|
array_push($fielddescriptions, $fielddescription);
|
|
$value = ($field['default'] ?? 'NULL');
|
|
$arguments[$key] = $value;
|
|
}
|
|
$template = \alveolata\string\coin(
|
|
'CREATE TABLE IF NOT EXISTS `{{tablename}}`({{fields}});',
|
|
[
|
|
'tablename' => $subject->name,
|
|
'fields' => implode(', ', $fielddescriptions),
|
|
]
|
|
);
|
|
$subject->database->query(
|
|
$template,
|
|
$arguments
|
|
);
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* @author Christian Fraß <frass@greenscale.de>
|
|
*/
|
|
function sqltable_create(
|
|
struct_sqltable $subject,
|
|
/*map<string,any> */$value
|
|
)/* : int*/
|
|
{
|
|
$fields = array_keys($value);
|
|
$template = \alveolata\string\coin(
|
|
'INSERT INTO `{{tablename}}`({{fields}}) VALUES ({{values}})',
|
|
[
|
|
'tablename' => $subject->name,
|
|
'fields' => implode(
|
|
',',
|
|
\alveolata\list_\map(
|
|
$fields,
|
|
function ($field) {
|
|
return \alveolata\string\coin('`{{field}}`', ['field' => $field]);
|
|
}
|
|
)
|
|
),
|
|
'values' => implode(
|
|
',',
|
|
\alveolata\list_\map(
|
|
$fields,
|
|
function ($field) {
|
|
return \alveolata\string\coin(':{{field}}', ['field' => $field]);
|
|
}
|
|
)
|
|
),
|
|
]
|
|
);
|
|
$arguments = $value;
|
|
$result = $subject->database->query(
|
|
$template,
|
|
$arguments
|
|
);
|
|
return $result['id'];
|
|
}
|
|
|
|
|
|
/**
|
|
* @author Christian Fraß <frass@greenscale.de>
|
|
*/
|
|
function sqltable_update(
|
|
struct_sqltable $subject,
|
|
/*int */$key,
|
|
/*map<string,any> */$value
|
|
) : void
|
|
{
|
|
$fields = array_keys($value);
|
|
if (empty($fields)) {
|
|
}
|
|
else {
|
|
$template = \alveolata\string\coin(
|
|
'UPDATE `{{tablename}}` SET {{sets}} WHERE (`id` = :id)',
|
|
[
|
|
'tablename' => $subject->name,
|
|
'sets' => implode(
|
|
',',
|
|
\alveolata\list_\map(
|
|
$fields,
|
|
function ($field) {
|
|
return \alveolata\string\coin('`{{field}}` = :{{field}}', ['field' => $field]);
|
|
}
|
|
)
|
|
),
|
|
]
|
|
);
|
|
$arguments = array_merge(
|
|
[
|
|
'id' => $key,
|
|
],
|
|
$value,
|
|
);
|
|
$result = $subject->database->query(
|
|
$template,
|
|
$arguments
|
|
);
|
|
/*
|
|
if (! ($result['affected'] === 1)) {
|
|
$report = \alveolata\report\make(
|
|
'could not update dataset',
|
|
[
|
|
'tablename' => $subject->name,
|
|
'key' => $key
|
|
]
|
|
);
|
|
throw (\alveolata\report\as_exception($report));
|
|
}
|
|
else {
|
|
// do nothing
|
|
}
|
|
*/
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* @author Christian Fraß <frass@greenscale.de>
|
|
*/
|
|
function sqltable_delete(
|
|
struct_sqltable $subject,
|
|
/*int */$key
|
|
) : void
|
|
{
|
|
$subject->observer_delete->notify($key);
|
|
$template = \alveolata\string\coin(
|
|
'DELETE FROM `{{tablename}}` WHERE (`id` = :id)',
|
|
[
|
|
'tablename' => $subject->name,
|
|
]
|
|
);
|
|
$arguments = [
|
|
'id' => $key,
|
|
];
|
|
$result = $subject->database->query(
|
|
$template,
|
|
$arguments
|
|
);
|
|
if (! ($result['affected'] === 1)) {
|
|
$report = \alveolata\report\make(
|
|
'could not delete dataset',
|
|
[
|
|
'tablename' => $subject->name,
|
|
'key' => $key
|
|
]
|
|
);
|
|
throw (\alveolata\report\as_exception($report));
|
|
}
|
|
else {
|
|
// do nothing
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* @author Christian Fraß <frass@greenscale.de>
|
|
*/
|
|
function sqltable_read(
|
|
struct_sqltable $subject,
|
|
/*int */$key
|
|
)/* : map<string,any>*/
|
|
{
|
|
$template = \alveolata\string\coin(
|
|
'SELECT * FROM `{{tablename}}` WHERE (`id` = :id)',
|
|
[
|
|
'tablename' => $subject->name,
|
|
]
|
|
);
|
|
$result = $subject->database->query(
|
|
$template,
|
|
[
|
|
'id' => $key
|
|
]
|
|
);
|
|
if (count($result['rows']) !== 1) {
|
|
$report = \alveolata\report\make(
|
|
'none or ambiguous result on read',
|
|
[
|
|
'tablename' => $subject->name,
|
|
'id' => $key,
|
|
]
|
|
);
|
|
throw (\alveolata\report\as_exception($report));
|
|
}
|
|
else {
|
|
$row = $result['rows'][0];
|
|
unset($row['id']);
|
|
return $row;
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* @author Christian Fraß <frass@greenscale.de>
|
|
*/
|
|
function sqltable_search(
|
|
struct_sqltable $subject,
|
|
array $parameters = []
|
|
) : array
|
|
{
|
|
$condition = (
|
|
(count($parameters) === 0)
|
|
// ? 'TRUE'
|
|
? '(0 = 0)'
|
|
: \alveolata\string\coin(
|
|
'({{clauses}})',
|
|
[
|
|
'clauses' => \alveolata\sql\conjunction(
|
|
\alveolata\list_\map(
|
|
array_keys($parameters),
|
|
function ($key) {
|
|
return \alveolata\string\coin(
|
|
'`{{key}}` = :{{key}}',
|
|
[
|
|
'key' => $key,
|
|
]
|
|
);
|
|
}
|
|
)
|
|
),
|
|
]
|
|
)
|
|
);
|
|
$template = \alveolata\string\coin(
|
|
'SELECT `id` FROM `{{tablename}}` WHERE {{condition}}',
|
|
[
|
|
'tablename' => $subject->name,
|
|
'condition' => $condition,
|
|
]
|
|
);
|
|
$arguments = $parameters;
|
|
$result = $subject->database->query(
|
|
$template,
|
|
$arguments
|
|
);
|
|
return \alveolata\list_\map(
|
|
$result['rows'],
|
|
function ($row) {
|
|
return $row['id'];
|
|
}
|
|
);
|
|
}
|
|
|
|
?>
|