579 lines
15 KiB
PHP
579 lines
15 KiB
PHP
<?php
|
|
|
|
namespace SleekDB;
|
|
|
|
use Closure;
|
|
use SleekDB\Exceptions\InvalidArgumentException;
|
|
use SleekDB\Exceptions\IdNotAllowedException;
|
|
use SleekDB\Exceptions\InvalidConfigurationException;
|
|
use SleekDB\Exceptions\IOException;
|
|
use SleekDB\Exceptions\JsonException;
|
|
|
|
if(false === class_exists("\Composer\Autoload\ClassLoader")){
|
|
require_once __DIR__.'/Store.php';
|
|
}
|
|
|
|
/**
|
|
* Class SleekDB
|
|
* @package SleekDB
|
|
* @deprecated since version 2.0, use SleekDB\Store instead.
|
|
*/
|
|
class SleekDB
|
|
{
|
|
|
|
/**
|
|
* @var QueryBuilder
|
|
*/
|
|
protected $queryBuilder;
|
|
|
|
/**
|
|
* @var Store
|
|
*/
|
|
protected $store;
|
|
|
|
private $shouldKeepConditions = false;
|
|
|
|
/**
|
|
* SleekDB constructor.
|
|
* @param string $storeName
|
|
* @param string $dataDir
|
|
* @param array $configuration
|
|
* @throws InvalidArgumentException
|
|
* @throws IOException
|
|
* @throws InvalidConfigurationException
|
|
*/
|
|
public function __construct(string $storeName, string $dataDir, array $configuration = []){
|
|
$this->init($storeName, $dataDir, $configuration);
|
|
}
|
|
|
|
/**
|
|
* Initialize the SleekDB instance.
|
|
* @param string $storeName
|
|
* @param string $dataDir
|
|
* @param array $conf
|
|
* @throws InvalidArgumentException
|
|
* @throws IOException
|
|
* @throws InvalidConfigurationException
|
|
*/
|
|
public function init(string $storeName, string $dataDir, array $conf = []){
|
|
$this->setStore(new Store($storeName, $dataDir, $conf));
|
|
$this->setQueryBuilder($this->getStore()->createQueryBuilder());
|
|
}
|
|
|
|
/**
|
|
* Initialize the store.
|
|
* @param string $storeName
|
|
* @param string $dataDir
|
|
* @param array $configuration
|
|
* @return SleekDB
|
|
* @throws InvalidArgumentException
|
|
* @throws IOException
|
|
* @throws InvalidConfigurationException
|
|
*/
|
|
public static function store(string $storeName, string $dataDir, array $configuration = []): SleekDB
|
|
{
|
|
return new SleekDB($storeName, $dataDir, $configuration);
|
|
}
|
|
|
|
/**
|
|
* Execute Query and get Results
|
|
* @return array
|
|
* @throws InvalidArgumentException
|
|
* @throws IOException
|
|
*/
|
|
public function fetch(): array
|
|
{
|
|
return $this->getQuery()->fetch();
|
|
}
|
|
|
|
/**
|
|
* Check if data is found
|
|
* @return bool
|
|
* @throws InvalidArgumentException
|
|
* @throws IOException
|
|
*/
|
|
public function exists(): bool
|
|
{
|
|
return $this->getQuery()->exists();
|
|
}
|
|
|
|
/**
|
|
* Return the first document.
|
|
* @return array
|
|
* @throws InvalidArgumentException
|
|
* @throws IOException
|
|
*/
|
|
public function first(): array
|
|
{
|
|
return $this->getQuery()->first();
|
|
}
|
|
|
|
/**
|
|
* Creates a new object in the store.
|
|
* It is stored as a plaintext JSON document.
|
|
* @param array $storeData
|
|
* @return array
|
|
* @throws IOException
|
|
* @throws IdNotAllowedException
|
|
* @throws InvalidArgumentException
|
|
* @throws JsonException
|
|
*/
|
|
public function insert(array $storeData): array
|
|
{
|
|
return $this->getStore()->insert($storeData);
|
|
}
|
|
|
|
/**
|
|
* Creates multiple objects in the store.
|
|
* @param array $storeData
|
|
* @return array
|
|
* @throws IOException
|
|
* @throws IdNotAllowedException
|
|
* @throws InvalidArgumentException
|
|
* @throws JsonException
|
|
*/
|
|
public function insertMany(array $storeData): array
|
|
{
|
|
return $this->getStore()->insertMany($storeData);
|
|
}
|
|
|
|
/**
|
|
* Update one or multiple documents, based on current query
|
|
* @param array $updatable
|
|
* @return bool
|
|
* @throws InvalidArgumentException
|
|
* @throws IOException
|
|
*/
|
|
public function update(array $updatable): bool
|
|
{
|
|
return $this->getQuery()->update($updatable);
|
|
}
|
|
|
|
/**
|
|
* Deletes matched store objects.
|
|
* @param int $returnOption
|
|
* @return bool|array|int
|
|
* @throws InvalidArgumentException
|
|
* @throws IOException
|
|
*/
|
|
public function delete(int $returnOption = Query::DELETE_RETURN_BOOL){
|
|
return $this->getQuery()->delete($returnOption);
|
|
}
|
|
|
|
/**
|
|
* Deletes a store and wipes all the data and cache it contains.
|
|
* @return bool
|
|
* @throws IOException
|
|
*/
|
|
public function deleteStore(): bool
|
|
{
|
|
return $this->getStore()->deleteStore();
|
|
}
|
|
|
|
/**
|
|
* This method would make a unique token for the current query.
|
|
* We would use this hash token as the id/name of the cache file.
|
|
* @return string
|
|
*/
|
|
public function getCacheToken(): string
|
|
{
|
|
return $this->getQueryBuilder()->getQuery()->getCache()->getToken();
|
|
}
|
|
|
|
/**
|
|
* Select specific fields
|
|
* @param string[] $fieldNames
|
|
* @return SleekDB
|
|
*/
|
|
public function select(array $fieldNames): SleekDB
|
|
{
|
|
$this->setQueryBuilder($this->getQueryBuilder()->select($fieldNames));
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Exclude specific fields
|
|
* @param string[] $fieldNames
|
|
* @return SleekDB
|
|
* @throws InvalidArgumentException
|
|
*/
|
|
public function except(array $fieldNames): SleekDB
|
|
{
|
|
$this->setQueryBuilder($this->getQueryBuilder()->except($fieldNames));
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Add conditions to filter data.
|
|
* @param string|array|mixed ...$conditions (string fieldName, string condition, mixed value) OR (array(array(string fieldName, string condition, mixed value)[, array(...)]))
|
|
* @return SleekDB
|
|
* @throws InvalidArgumentException
|
|
*/
|
|
public function where(...$conditions): SleekDB
|
|
{
|
|
foreach ($conditions as $key => $arg) {
|
|
if ($key > 0) {
|
|
throw new InvalidArgumentException("Allowed: (string fieldName, string condition, mixed value) OR (array(array(string fieldName, string condition, mixed value)[, array(...)]))");
|
|
}
|
|
if (is_array($arg)) {
|
|
// parameters given as arrays for multiple "where" with "and" between each condition
|
|
$this->setQueryBuilder($this->getQueryBuilder()->where($arg));
|
|
break;
|
|
}
|
|
if (count($conditions) === 3) {
|
|
// parameters given as (string fieldName, string condition, mixed value) for a single "where"
|
|
$this->setQueryBuilder($this->getQueryBuilder()->where($conditions));
|
|
break;
|
|
}
|
|
}
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Add "in" condition to filter data.
|
|
* @param string $fieldName
|
|
* @param array $values
|
|
* @return SleekDB
|
|
* @throws InvalidArgumentException
|
|
*/
|
|
public function in(string $fieldName, array $values = []): SleekDB
|
|
{
|
|
$this->setQueryBuilder($this->getQueryBuilder()->in($fieldName, $values));
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Add "not in" condition to filter data.
|
|
* @param string $fieldName
|
|
* @param array $values
|
|
* @return SleekDB
|
|
* @throws InvalidArgumentException
|
|
*/
|
|
public function notIn(string $fieldName, array $values = []): SleekDB
|
|
{
|
|
$this->setQueryBuilder($this->getQueryBuilder()->notIn($fieldName, $values));
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Add or-where conditions to filter data.
|
|
* @param string|array|mixed ...$conditions (string fieldName, string condition, mixed value) OR array(array(string fieldName, string condition, mixed value) [, array(...)])
|
|
* @return SleekDB
|
|
* @throws InvalidArgumentException
|
|
*/
|
|
public function orWhere(...$conditions): SleekDB
|
|
{
|
|
foreach ($conditions as $key => $arg) {
|
|
if ($key > 0) {
|
|
throw new InvalidArgumentException("Allowed: (string fieldName, string condition, mixed value) OR array(array(string fieldName, string condition, mixed value) [, array(...)])");
|
|
}
|
|
if (is_array($arg)) {
|
|
// parameters given as arrays for an "or where" with "and" between each condition
|
|
$this->setQueryBuilder($this->getQueryBuilder()->orWhere($arg));
|
|
break;
|
|
}
|
|
if (count($conditions) === 3) {
|
|
// parameters given as (string fieldName, string condition, mixed value) for a single "or where"
|
|
$this->setQueryBuilder($this->getQueryBuilder()->orWhere($conditions));
|
|
break;
|
|
}
|
|
}
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Set the amount of data record to skip.
|
|
* @param int $skip
|
|
* @return SleekDB
|
|
* @throws InvalidArgumentException
|
|
*/
|
|
public function skip(int $skip = 0): SleekDB
|
|
{
|
|
$this->setQueryBuilder($this->getQueryBuilder()->skip($skip));
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Set the amount of data record to limit.
|
|
* @param int $limit
|
|
* @return SleekDB
|
|
* @throws InvalidArgumentException
|
|
*/
|
|
public function limit(int $limit = 0): SleekDB
|
|
{
|
|
$this->setQueryBuilder($this->getQueryBuilder()->limit($limit));
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Set the sort order.
|
|
* @param string $order "asc" or "desc"
|
|
* @param string $orderBy
|
|
* @return SleekDB
|
|
* @throws InvalidArgumentException
|
|
*/
|
|
public function orderBy(string $order, string $orderBy = '_id'): SleekDB
|
|
{
|
|
$this->setQueryBuilder($this->getQueryBuilder()->orderBy([$orderBy => $order]));
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Do a fulltext like search against more than one field.
|
|
* @param string|array $field one fieldName or multiple fieldNames as an array
|
|
* @param string $keyword
|
|
* @return SleekDB
|
|
* @throws InvalidArgumentException
|
|
*/
|
|
public function search($field, string $keyword): SleekDB
|
|
{
|
|
$this->setQueryBuilder($this->getQueryBuilder()->search($field, $keyword));
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* @param Closure $joinedStore
|
|
* @param string $dataPropertyName
|
|
* @return SleekDB
|
|
*/
|
|
public function join(Closure $joinedStore, string $dataPropertyName): SleekDB
|
|
{
|
|
$this->setQueryBuilder($this->getQueryBuilder()->join($joinedStore, $dataPropertyName));
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Re-generate the cache for the query.
|
|
* @return SleekDB
|
|
*/
|
|
public function makeCache(): SleekDB
|
|
{
|
|
$this->setQueryBuilder($this->getQueryBuilder()->regenerateCache());
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Disable cache for the query.
|
|
* @return SleekDB
|
|
*/
|
|
public function disableCache(): SleekDB
|
|
{
|
|
$this->setQueryBuilder($this->getQueryBuilder()->disableCache());
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Use caching for current query
|
|
* @param int|null $lifetime time to live as int in seconds or null to regenerate cache on every insert, update and delete
|
|
* @return SleekDB
|
|
* @throws InvalidArgumentException
|
|
*/
|
|
public function useCache(int $lifetime = null): SleekDB
|
|
{
|
|
$this->setQueryBuilder($this->getQueryBuilder()->useCache($lifetime));
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Delete cache file/s for current query.
|
|
* @return SleekDB
|
|
*/
|
|
public function deleteCache(): SleekDB
|
|
{
|
|
$this->getQueryBuilder()->getQuery()->getCache()->delete();
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Delete all cache files for current store.
|
|
* @return SleekDB
|
|
*/
|
|
public function deleteAllCache(): SleekDB
|
|
{
|
|
$this->getQueryBuilder()->getQuery()->getCache()->deleteAll();
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Keep the active query conditions.
|
|
* @return SleekDB
|
|
*/
|
|
public function keepConditions(): SleekDB
|
|
{
|
|
$this->shouldKeepConditions = true;
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Return distinct values.
|
|
* @param array|string $fields
|
|
* @return SleekDB
|
|
* @throws InvalidArgumentException
|
|
*/
|
|
public function distinct($fields = []): SleekDB
|
|
{
|
|
$this->setQueryBuilder($this->getQueryBuilder()->distinct($fields));
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* @return QueryBuilder
|
|
*/
|
|
public function getQueryBuilder(): QueryBuilder
|
|
{
|
|
return $this->queryBuilder;
|
|
}
|
|
|
|
/**
|
|
* @param QueryBuilder $queryBuilder
|
|
*/
|
|
private function setQueryBuilder(QueryBuilder $queryBuilder){
|
|
$this->queryBuilder = $queryBuilder;
|
|
}
|
|
|
|
/**
|
|
* @return Query
|
|
*/
|
|
public function getQuery(): Query
|
|
{
|
|
$query = $this->getQueryBuilder()->getQuery();
|
|
$this->resetQueryBuilder();
|
|
return $query;
|
|
}
|
|
|
|
/**
|
|
* @return Cache
|
|
*/
|
|
public function getCache(): Cache
|
|
{
|
|
// we do not want to reset the QueryBuilder
|
|
return $this->getQueryBuilder()->getQuery()->getCache();
|
|
}
|
|
|
|
|
|
/**
|
|
* @param Store $store
|
|
*/
|
|
private function setStore(Store $store){
|
|
$this->store = $store;
|
|
}
|
|
|
|
/**
|
|
* @return Store
|
|
*/
|
|
public function getStore(): Store
|
|
{
|
|
return $this->store;
|
|
}
|
|
|
|
/**
|
|
* Handle shouldKeepConditions and reset queryBuilder accordingly
|
|
*/
|
|
private function resetQueryBuilder(){
|
|
if($this->shouldKeepConditions === true) {
|
|
return;
|
|
}
|
|
$this->setQueryBuilder($this->getStore()->createQueryBuilder());
|
|
}
|
|
|
|
|
|
/**
|
|
* Retrieve all documents.
|
|
* @return array
|
|
* @throws IOException
|
|
* @throws InvalidArgumentException
|
|
*/
|
|
public function findAll(): array
|
|
{
|
|
return $this->getStore()->findAll();
|
|
}
|
|
|
|
/**
|
|
* Retrieve one document by its _id. Very fast because it finds the document by its file path.
|
|
* @param int $id
|
|
* @return array|null
|
|
* @throws InvalidArgumentException
|
|
*/
|
|
public function findById(int $id){
|
|
return $this->getStore()->findById($id);
|
|
}
|
|
|
|
/**
|
|
* Retrieve one or multiple documents.
|
|
* @param array $criteria
|
|
* @param array $orderBy
|
|
* @param int $limit
|
|
* @param int $offset
|
|
* @return array
|
|
* @throws IOException
|
|
* @throws InvalidArgumentException
|
|
*/
|
|
public function findBy(array $criteria, array $orderBy = null, int $limit = null, int $offset = null): array
|
|
{
|
|
return $this->getStore()->findBy($criteria, $orderBy, $limit, $offset);
|
|
}
|
|
|
|
/**
|
|
* Retrieve one document.
|
|
* @param array $criteria
|
|
* @return array|null single document or NULL if no document can be found
|
|
* @throws IOException
|
|
* @throws InvalidArgumentException
|
|
*/
|
|
public function findOneBy(array $criteria)
|
|
{
|
|
return $this->getStore()->findOneBy($criteria);
|
|
}
|
|
|
|
/**
|
|
* Update one or multiple documents.
|
|
* @param array $updatable true if all documents could be updated and false if one document did not exist
|
|
* @return bool
|
|
* @throws IOException
|
|
* @throws InvalidArgumentException
|
|
*/
|
|
public function updateBy(array $updatable): bool
|
|
{
|
|
return $this->getStore()->update($updatable);
|
|
}
|
|
|
|
/**
|
|
* Delete one or multiple documents.
|
|
* @param $criteria
|
|
* @param int $returnOption
|
|
* @return array|bool|int
|
|
* @throws IOException
|
|
* @throws InvalidArgumentException
|
|
*/
|
|
public function deleteBy($criteria, $returnOption = Query::DELETE_RETURN_BOOL){
|
|
return $this->getStore()->deleteBy($criteria, $returnOption);
|
|
}
|
|
|
|
/**
|
|
* Delete one document by its _id. Very fast because it deletes the document by its file path.
|
|
* @param $id
|
|
* @return bool true if document does not exist or deletion was successful, false otherwise
|
|
* @throws IOException
|
|
*/
|
|
public function deleteById($id): bool
|
|
{
|
|
return $this->getStore()->deleteById($id);
|
|
}
|
|
|
|
/**
|
|
* Add a where statement that is nested. ( $x or ($y and $z) )
|
|
* @param array $conditions
|
|
* @return $this
|
|
* @throws InvalidArgumentException
|
|
* @deprecated since version 2.3, use where and orWhere instead.
|
|
*/
|
|
public function nestedWhere(array $conditions): SleekDB
|
|
{
|
|
$this->setQueryBuilder($this->getQueryBuilder()->nestedWhere($conditions));
|
|
return $this;
|
|
}
|
|
|
|
}
|