Compare commits

...

6 Commits

4 changed files with 125 additions and 70 deletions

View File

@ -66,4 +66,4 @@ if ($database->write($record)) {
## Used by ## Used by
- My site-article about how i was kidnapped by PMC Wagner operatives [mirzaev/repression](https://git.svoboda.works/mirzaev/repression) - My site-article about how i was kidnapped by PMC Wagner operatives [mirzaev/repression](https://git.svoboda.works/mirzaev/repression)
- My decentralized P2P blockchain chats project [mirzaev/notchat](https://git.svoboda.works/mirzaev/notchat) - My decentralized P2P blockchain chats project [mirzaev/notchat](https://git.svoboda.works/mirzaev/notchat)
- Svoboda Telegram chat-robot [svoboda/negotiator](https://git.svoboda.works/svoboda/negotiator) - Svoboda Telegram chat-robot negotiator [svoboda/negotiator](https://git.svoboda.works/svoboda/negotiator)

View File

@ -259,42 +259,42 @@ class database
*/ */
public function unpack(array $binaries): record public function unpack(array $binaries): record
{ {
// Declaring the buffer of unpacked values // Declaring the buffer of unpacked values
$unpacked = []; $unpacked = [];
foreach ($this->columns as $index => $column) { foreach ($this->columns as $index => $column) {
// Iterating over columns // Iterating over columns
// Initializing link to the binary value
$binary = $binaries[$index] ?? null;
if ($column->type === type::string) { // Initializing link to the binary value
// String $binary = $binaries[$index] ?? null;
// Unpacking the value if ($column->type === type::string) {
$value = unpack($column->type->value . $column->length, $binary ?? str_repeat("\0", $column->length))[1]; // String
// Deleting NULL-characters // Unpacking the value
$unnulled = str_replace("\0", '', $value); $value = unpack($column->type->value . $column->length, $binary ?? str_repeat("\0", $column->length))[1];
// Encoding the unpacked value // Deleting NULL-characters
$encoded = mb_convert_encoding($unnulled, $this->encoding->value); $unnulled = str_replace("\0", '', $value);
// Writing into the buffer of readed values // Encoding the unpacked value
$unpacked[] = $encoded; $encoded = mb_convert_encoding($unnulled, $this->encoding->value);
} else {
// Other types
// Writing into the buffer of readed values // Writing into the buffer of readed values
$unpacked[] = unpack($column->type->value, $binary ?? "\0")[1]; $unpacked[] = $encoded;
} } else {
// Other types
// Writing into the buffer of readed values
$unpacked[] = unpack($column->type->value, $binary ?? "\0")[1];
} }
}
// Implementing the record // Implementing the record
$record = $this->record(...$unpacked); $record = $this->record(...$unpacked);
// Exit (success) // Exit (success)
return $record; return $record;
} }
/** /**
@ -368,8 +368,13 @@ class database
* *
* @return array|null Readed records * @return array|null Readed records
*/ */
public function read(?callable $filter = null, ?callable $update = null, bool $delete = false, int $amount = 1, int $offset = 0): ?array public function read(
{ ?callable $filter = null,
?callable $update = null,
bool $delete = false,
int $amount = 1,
int $offset = 0
): ?array {
// Opening the database file // Opening the database file
$file = fopen($this->database, 'c+b'); $file = fopen($this->database, 'c+b');
@ -414,58 +419,60 @@ class database
// Unpacking the record // Unpacking the record
$record = $this->unpack($binaries); $record = $this->unpack($binaries);
if ((bool) array_filter($record->values())) { if ((bool) array_filter($record->values())) {
// The record contains at least one non-empty value // The record contains at least one non-empty value
if (is_null($filter) || $filter($record, $records)) { if (is_null($filter) || $filter($record, $records)) {
// Passed the filter // Passed the filter
if ($offset-- <= 0) { if ($offset-- <= 0) {
// Offsetted // Offsetted
if ($delete) { if ($delete) {
// Requested deleting // Requested deleting
// Moving to the beginning of the row // Moving to the beginning of the row
fseek($file, -$this->length, SEEK_CUR); fseek($file, -$this->length, SEEK_CUR);
// Writing NUL-characters instead of the record to the database file // Writing NUL-characters instead of the record to the database file
fwrite($file, str_repeat("\0", $this->length)); fwrite($file, str_repeat("\0", $this->length));
// Moving to the end of the row // Moving to the end of the row
fseek($file, $this->length, SEEK_CUR); fseek($file, $this->length, SEEK_CUR);
} else if ($update) { } else if ($update) {
// Requested updating // Requested updating
// Updating the record // Updating the record
$update($record); $update($record);
// Packing the updated record // Packing the updated record
$packed = $this->pack($record); $packed = $this->pack($record);
// Moving to the beginning of the row // Moving to the beginning of the row
fseek($file, -$this->length, SEEK_CUR); fseek($file, -$this->length, SEEK_CUR);
// Writing to the database file // Writing to the database file
fwrite($file, $packed); fwrite($file, $packed);
// Moving to the end of the row // Moving to the end of the row
fseek($file, $this->length, SEEK_CUR); fseek($file, $this->length, SEEK_CUR);
}
// Writing into the buffer of records
$records[] = $record;
// Decreasing the amount iterator
--$amount;
} }
// Writing into the buffer of records
$records[] = $record;
// Decreasing the amount iterator
--$amount;
} }
} else {
// The record contains only empty values
} }
} else { } catch (exception_logic | exception_invalid_argument | exception_domain $exception) {
// The record contains only empty values
}
} catch (exception_logic | exception_invalid_argument $exception) {
// Writing into the buffer of failed to reading records // Writing into the buffer of failed to reading records
/* $failed[] = $record; */
// Exit (fail)
throw new exception_runtime('Failed to processing the record', previous: $exception);
} }
} }
@ -483,6 +490,25 @@ class database
return null; return null;
} }
/**
* Count
*
* @throws exception_runtime If the database is corrupted (counting result is float)
*
* @return int Amount of records
*/
public function count(): int
{
// Deleting the database file cache
clearstatcache(true, $this->database);
// Counting
$amount = $this->length > 0 && file_exists($this->database) ? filesize($this->database) / $this->length : 0;
// Exit (success/fail)
return is_int($amount) ? $amount : throw new exception_runtime('The database is corrupted');
}
/** /**
* Backups * Backups
* *

View File

@ -4,6 +4,9 @@ declare(strict_types=1);
namespace mirzaev\baza; namespace mirzaev\baza;
// Built-in libraries
use DomainException as exception_domain;
/** /**
* Record * Record
* *
@ -63,12 +66,23 @@ class record
* @param string $name Name of the parameter * @param string $name Name of the parameter
* @param mixed $value Content of the parameter * @param mixed $value Content of the parameter
* *
* @throws exception_domain if not found the parameter
*
* @return void * @return void
*/ */
public function __set(string $name, mixed $value = null): void public function __set(string $name, mixed $value = null): void
{ {
// Writing the value and exit if (isset($this->values[$name])) {
$this->values[$name] = $value; // Initialized the parameter
// Writing the value and exit
$this->values[$name] = $value;
} else {
// Not initialized the parameter
// Exit (fail)
throw new exception_domain("Not found the parameter: $name");
}
} }
/** /**

View File

@ -1,5 +1,7 @@
<?php <?php
declare(strict_types=1);
use mirzaev\baza\database, use mirzaev\baza\database,
mirzaev\baza\record, mirzaev\baza\record,
mirzaev\baza\column, mirzaev\baza\column,
@ -7,11 +9,24 @@ use mirzaev\baza\database,
mirzaev\baza\enumerations\type; mirzaev\baza\enumerations\type;
// Initializing path to the composer loader file (main project) // Initializing path to the composer loader file (main project)
$autoload = __DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'vendor' . DIRECTORY_SEPARATOR . 'autoload.php'; $autoload =
__DIR__ . DIRECTORY_SEPARATOR .
'..' . DIRECTORY_SEPARATOR .
'..' . DIRECTORY_SEPARATOR .
'..' . DIRECTORY_SEPARATOR .
'vendor' . DIRECTORY_SEPARATOR .
'autoload.php';
// Reinitializing path to the composer loaded file (depencendy project) // Reinitializing path to the composer loaded file (depencendy project)
if (!file_exists($autoload)) if (!file_exists($autoload))
$autoload = __DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'autoload.php'; $autoload =
__DIR__ . DIRECTORY_SEPARATOR .
'..' . DIRECTORY_SEPARATOR .
'..' . DIRECTORY_SEPARATOR .
'..' . DIRECTORY_SEPARATOR .
'..' . DIRECTORY_SEPARATOR .
'..' . DIRECTORY_SEPARATOR .
'autoload.php';
// Importing files of thr project and dependencies // Importing files of thr project and dependencies
require($autoload); require($autoload);