>" in a relational * database, one would create a core table for the primitive record fields (foo) and separate tables for all * non-primitive fields (bar), which are linked to the core table * * @template type_value * @template type_element * @author Christian Fraß */ class struct_sqltablecluster_tight_supplement { /** * @var struct_sqltable */ public $target_table; /** * @var string */ public $core_id_column; /** * @var boolean */ public $include_own_id; /** * @var boolean */ public $exclude_core_id; /** */ public function __construct( struct_sqltable $target_table, string $core_id_column, bool $include_own_id, bool $exclude_core_id ) { $this->target_table = $target_table; $this->core_id_column = $core_id_column; $this->include_own_id = $include_own_id; $this->exclude_core_id = $exclude_core_id; } } /** * exemplary structure: * »CREATE TABLE core(id);« * »CREATE TABLE target(id);« * »CREATE TABLE edge(core_id,target_id);« * * typical use case: domain B depends on domain A; elements of A can exist in ignorance of B * * * @template type_value * @template type_thing * @author Christian Fraß */ class struct_sqltablecluster_loose_supplement { /** * @var struct_sqltable * * will only be used to add a deletion hook */ public $target_table; /** * @var struct_sqltable */ public $edge_table; /** * @var string * * name of the column in the edge table, which references the id in the core table */ public $core_id_column; /** * @var string * * name of the column in the edge table, which references the id in the target table */ public $target_id_column; /** */ public function __construct( struct_sqltable $target_table, struct_sqltable $edge_table, string $core_id_column, string $target_id_column ) { $this->target_table = $target_table; $this->edge_table = $edge_table; $this->core_id_column = $core_id_column; $this->target_id_column = $target_id_column; } } /** * @author Christian Fraß */ class struct_sqltablecluster { /** * @var struct_sqltable */ public $core; /** * @var array {map>} */ public $tight_supplements; /** * @var array {map>} */ public $loose_supplements; /** * @var \Closure { * function< * record< * core_row:map, * tight_supplement_values:map>, * loose_supplement_values:map> * >, * type_value * > * } */ public $assemble; /** * @var \Closure { * function< * type_value, * record< * core_row:map, * tight_supplement_values:map>, * loose_supplement_values:map> * > * > * } */ public $disperse; /** * @var \alveolata\observer\class_observer */ public $observer_delete; /** */ public function __construct( struct_sqltable $core, array $tight_supplements, array $loose_supplements, \Closure $assemble, \Closure $disperse ) { $this->core = $core; $this->tight_supplements = $tight_supplements; $this->loose_supplements = $loose_supplements; $this->assemble = $assemble; $this->disperse = $disperse; $this->observer_delete = \alveolata\observer\class_observer::make(); } } /** * @author Christian Fraß */ function sqltablecluster_make( struct_sqltable $core, array $tight_supplements, array $loose_supplements, \Closure $assemble, \Closure $disperse ) : struct_sqltablecluster { $subject = ( new struct_sqltablecluster( $core, $tight_supplements, $loose_supplements, $assemble, $disperse ) ); // hooks { // remove corresponding edges, when a supplemental dataset is deleted { foreach ($subject->loose_supplements as $loose_supplement_name => $loose_supplement) { sqltable_hook_delete( $loose_supplement->target_table, function ($target_id) use ($loose_supplement) : void { $loose_supplement_ids = sqltable_search( $loose_supplement->edge_table, [$loose_supplement->target_id_column => $target_id] ); \alveolata\list_\map/**/( $loose_supplement_ids, function (int $loose_supplement_id) use ($loose_supplement) : void { sqltable_delete($loose_supplement->edge_table, $loose_supplement_id); } ); } ); } } } return $subject; } /** * @author Christian Fraß */ function sqltablecluster_hook_delete( struct_sqltable $subject, \Closure $procedure ) : string { return $subject->observer_delete->register($procedure); } /** * @author Christian Fraß */ function sqltablecluster_create( struct_sqltablecluster $subject, /*map */$value )/* : int*/ { $dispersal = ($subject->disperse)($value); $core_row = $dispersal['core_row']; // core { $core_id = sqltable_create($subject->core, $core_row); } // tight supplements { $tight_supplement_ids = \alveolata\map\map/**/( $subject->tight_supplements, function ($tight_supplement, $tight_supplement_name) use ($dispersal, $core_id) { return \alveolata\list_\map( $dispersal['tight_supplement_values'][$tight_supplement_name], function ($tight_supplement_row) use ($core_id, $tight_supplement) { $tight_supplement_row[$tight_supplement->core_id_column] = $core_id; return sqltable_create($tight_supplement->target_table, $tight_supplement_row); } ); } ); } // loose supplements { $loose_supplement_ids = \alveolata\map\map/**/( $subject->loose_supplements, function ($loose_supplement, $loose_supplement_name) use ($dispersal, $core_id) { return \alveolata\list_\map( $dispersal['loose_supplement_values'][$loose_supplement_name], function (int $target_id) use ($core_id, $loose_supplement) { $loose_supplement_row = [ $loose_supplement->core_id_column => $core_id, $loose_supplement->target_id_column => $target_id, ]; return sqltable_create($loose_supplement->edge_table, $loose_supplement_row); } ); } ); } $key = $core_id; return $key; } /** * @author Christian Fraß * @todo improve update of satellites */ function sqltablecluster_update( struct_sqltablecluster $subject, /*int */$key, /*map */$value ) : void { $core_id = $key; $dispersal = ($subject->disperse)($value); $core_row = $dispersal['core_row']; // core { sqltale_update($subject->core, $core_id, $core_row); } // tight supplements { \alveolata\map\map( $subject->tight_supplements, function ($tight_supplement, $tight_supplement_name) use ($core_id, $value, $dispersal) { // remove old { $tight_supplement_ids_old = sqltable_search($tight_supplement->target_table, [$tight_supplement->core_id_column => $core_id]); \alveolata\list_\map/**/( $tight_supplement_ids_old, function (int $tight_supplement_id_old) use ($tight_supplement) : void { sqltable_delete($tight_supplement->target_table, $tight_supplement_id_old); } ); } // insert new { $tight_supplement_ids_new = \alveolata\list_\map( $dispersal['tight_supplement_values'][$tight_supplement_name], function ($tight_supplement_row) use ($core_id, $tight_supplement) { $tight_supplement_row[$tight_supplement->core_id_column] = $core_id; return sqltable_create($tight_supplement->target_table, $tight_supplement_row); } ); } } ); } // loose supplements { \alveolata\map\map( $subject->loose_supplements, function ($loose_supplement, $loose_supplement_name) use ($core_id, $value, $dispersal) { // remove old { $loose_supplement_ids_old = sqltable_search($loose_supplement->edge_table, [$loose_supplement->core_id_column => $core_id]); \alveolata\list_\map/**/( $loose_supplement_ids_old, function (int $loose_supplement_id_old) use ($loose_supplement) : void { sqltable_delete($loose_supplement->edge_table, $loose_supplement_id_old); } ); } // insert new { $loose_supplement_ids_new = \alveolata\list_\map( $dispersal['loose_supplement_values'][$loose_supplement_name], function (int $target_id) use ($core_id, $loose_supplement) { $loose_supplement_row = [ $loose_supplement->core_id_column => $core_id, $loose_supplement->target_id_column => $target_id, ]; return sqltable_create($loose_supplement->edge_table, $loose_supplement_row); } ); } } ); } } /** * @author Christian Fraß */ function sqltablecluster_delete( struct_sqltablecluster $subject, /*int */$key ) : void { // delete depedent data { $observation = $subject->observer_delete->notify($key); } $core_id = $key; $core_row = sqltable_read($subject->core, $core_id); // loose_supplements { \alveolata\map\map( $subject->loose_supplements, function (struct_sqltablecluster_loose_supplement $loose_supplement) use ($core_id) { $loose_supplement_ids = sqltable_search($loose_supplement->edge_table, [$loose_supplement->core_id_column => $core_id]); return \alveolata\list_\map/**/( $loose_supplement_ids, function (int $loose_supplement_id) use ($loose_supplement) : void { sqltable_delete($loose_supplement->edge_table, $loose_supplement_id); } ); } ); } // tight_supplements { \alveolata\map\map( $subject->tight_supplements, function (struct_sqltablecluster_tight_supplement $tight_supplement) use ($core_id) { $tight_supplement_ids = sqltable_search($tight_supplement->target_table, [$tight_supplement->core_id_column => $core_id]); return \alveolata\list_\map/**/( $tight_supplement_ids, function (int $tight_supplement_id) use ($tight_supplement) : void { sqltable_delete($tight_supplement->target_table, $tight_supplement_id); } ); } ); } // core { sqltable_delete($subject->core, $core_id); } } /** * @author Christian Fraß */ function sqltablecluster_read( struct_sqltablecluster $subject, /*int */$key )/* : map*/ { $core_id = $key; // core { $core_row = sqltable_read($subject->core, $core_id); } // tight supplements { $tight_supplement_values = \alveolata\map\map( $subject->tight_supplements, function (struct_sqltablecluster_tight_supplement $tight_supplement) use ($core_id) { $tight_supplement_ids = sqltable_search($tight_supplement->target_table, [$tight_supplement->core_id_column => $core_id]); sort($tight_supplement_ids); $value = \alveolata\list_\map/**/( $tight_supplement_ids, function (int $tight_supplement_id) use ($tight_supplement) { $tight_supplement_row = sqltable_read($tight_supplement->target_table, $tight_supplement_id); if ($tight_supplement->include_own_id) { $tight_supplement_row['id'] = $tight_supplement_id; } if ($tight_supplement->exclude_core_id) { unset($tight_supplement_row[$tight_supplement->core_id_column]); } return $tight_supplement_row; } ); return $value; } ); } // loose supplements { $loose_supplement_values = \alveolata\map\map( $subject->loose_supplements, function (struct_sqltablecluster_loose_supplement $loose_supplement) use ($core_id) { $loose_supplement_ids = sqltable_search($loose_supplement->edge_table, [$loose_supplement->core_id_column => $core_id]); sort($loose_supplement_ids); $value = \alveolata\list_\map/**/( $loose_supplement_ids, function (int $loose_supplement_id) use ($loose_supplement) { $loose_supplement_row = sqltable_read($loose_supplement->edge_table, $loose_supplement_id); $target_id = $loose_supplement_row[$loose_supplement->target_id_column]; return $target_id; } ); return $value; } ); } $stuff = [ 'core_row' => $core_row, 'tight_supplement_values' => $tight_supplement_values, 'loose_supplement_values' => $loose_supplement_values, ]; $value = ($subject->assemble)($stuff); return $value; } /** * @author Christian Fraß * @todo search in satellites */ function sqltablecluster_search( struct_sqltablecluster $subject, array $parameters = [] ) : array { return sqltable_search($subject->core, $parameters); } ?>