*/ class struct_sqltable { /** * @var \alveolata\database\interface_database * @author Christian Fraß */ public $database; /** * @var string * @author Christian Fraß */ public $name; /** * @var list> * @author Christian Fraß */ public $fields; /** * @var \alveolata\observer\class_observer */ public $observer_teardown; /** * @var \alveolata\observer\class_observer */ public $observer_delete; /** * @author Christian Fraß */ 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ß */ 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ß */ function sqltable_hook_delete( struct_sqltable $subject, \Closure $procedure ) : string { return $subject->observer_delete->register($procedure); } /** * @author Christian Fraß */ 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ß */ 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ß */ function sqltable_create( struct_sqltable $subject, /*map */$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ß */ function sqltable_update( struct_sqltable $subject, /*int */$key, /*map */$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ß */ 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ß */ function sqltable_read( struct_sqltable $subject, /*int */$key )/* : map*/ { $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ß */ 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']; } ); } ?>