>*/ { /** */ 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, ] ); } } ?>