feat: implement date range filter and epoch time stamps
Signed-off-by: Sebastian Krupinski <krupinski01@gmail.com>
This commit is contained in:
@@ -9,13 +9,16 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace KTXM\ProviderLocalChrono\Store\Personal;
|
namespace KTXM\ProviderLocalChrono\Store\Personal;
|
||||||
|
|
||||||
|
use DateTimeImmutable;
|
||||||
use KTXC\Db\DataStore;
|
use KTXC\Db\DataStore;
|
||||||
|
use KTXF\Chrono\Entity\EventRangeMetadata;
|
||||||
use KTXF\Resource\Filter\Filter;
|
use KTXF\Resource\Filter\Filter;
|
||||||
use KTXF\Resource\Filter\FilterComparisonOperator;
|
use KTXF\Resource\Filter\FilterComparisonOperator;
|
||||||
use KTXF\Resource\Filter\FilterConjunctionOperator;
|
use KTXF\Resource\Filter\FilterConjunctionOperator;
|
||||||
use KTXF\Resource\Range\Range;
|
use KTXF\Resource\Range\Range;
|
||||||
use KTXF\Resource\Range\RangeType;
|
use KTXF\Resource\Range\RangeType;
|
||||||
use KTXF\Resource\Sort\Sort;
|
use KTXF\Resource\Sort\Sort;
|
||||||
|
use KTXF\Utile\Timestamp;
|
||||||
use KTXF\Utile\UUID;
|
use KTXF\Utile\UUID;
|
||||||
use KTXM\ProviderLocalChrono\Providers\Personal\CollectionResource;
|
use KTXM\ProviderLocalChrono\Providers\Personal\CollectionResource;
|
||||||
use KTXM\ProviderLocalChrono\Providers\Personal\EntityResource;
|
use KTXM\ProviderLocalChrono\Providers\Personal\EntityResource;
|
||||||
@@ -97,6 +100,37 @@ class Store {
|
|||||||
return $mongoFilter;
|
return $mongoFilter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* construct query conditions and find options from a range
|
||||||
|
*
|
||||||
|
* @param Range $range range options
|
||||||
|
*
|
||||||
|
* @return array{0: array, 1: array} query conditions and find options
|
||||||
|
*/
|
||||||
|
protected function constructRange(Range $range): array {
|
||||||
|
$conditions = [];
|
||||||
|
$options = [];
|
||||||
|
|
||||||
|
if ($range->type() === RangeType::TALLY) {
|
||||||
|
// For TALLY ranges, use position (skip) and tally (limit)
|
||||||
|
/** @var \KTXF\Resource\Range\IRangeTally $range */
|
||||||
|
$options['skip'] = $range->getPosition();
|
||||||
|
$options['limit'] = $range->getTally();
|
||||||
|
} elseif ($range->type() === RangeType::DATE) {
|
||||||
|
// Select entities whose calculated bounds overlap the half-open interval [start, end).
|
||||||
|
/** @var \KTXF\Resource\Range\IRangeDate $range */
|
||||||
|
$conditions['startsOn'] = [
|
||||||
|
'$lt' => $range->getEnd(),
|
||||||
|
];
|
||||||
|
$conditions['$or'] = [
|
||||||
|
['endsOn' => ['$gt' => $range->getStart()]],
|
||||||
|
['endsOn' => null],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return [$conditions, $options];
|
||||||
|
}
|
||||||
|
|
||||||
protected function constructSort(array $map, Sort $sort): array {
|
protected function constructSort(array $map, Sort $sort): array {
|
||||||
$mongoSort = [];
|
$mongoSort = [];
|
||||||
|
|
||||||
@@ -222,8 +256,8 @@ class Store {
|
|||||||
$data['uid'] = $userId;
|
$data['uid'] = $userId;
|
||||||
$data['cid'] = UUID::v4();
|
$data['cid'] = UUID::v4();
|
||||||
$data['signature'] = isset($data['signature']) && is_numeric($data['signature']) ? (int)$data['signature'] : 0;
|
$data['signature'] = isset($data['signature']) && is_numeric($data['signature']) ? (int)$data['signature'] : 0;
|
||||||
$data['createdOn'] = date('c');
|
$data['createdOn'] = Timestamp::now();
|
||||||
$data['modifiedOn'] = $data['createdOn'];
|
$data['modifiedOn'] = Timestamp::now();
|
||||||
// create entry
|
// create entry
|
||||||
$result = $this->_store->selectCollection($this->_CollectionTable)->insertOne($data);
|
$result = $this->_store->selectCollection($this->_CollectionTable)->insertOne($data);
|
||||||
if ($result->getInsertedCount() === 1) {
|
if ($result->getInsertedCount() === 1) {
|
||||||
@@ -250,7 +284,7 @@ class Store {
|
|||||||
if ($cid === null) {
|
if ($cid === null) {
|
||||||
throw new \InvalidArgumentException('Collection identifier is required for modification');
|
throw new \InvalidArgumentException('Collection identifier is required for modification');
|
||||||
}
|
}
|
||||||
$data['modifiedOn'] = date('c');
|
$data['modifiedOn'] = Timestamp::now();
|
||||||
unset($data['_id'], $data['tid'], $data['uid'], $data['cid']);
|
unset($data['_id'], $data['tid'], $data['uid'], $data['cid']);
|
||||||
// modify entry
|
// modify entry
|
||||||
$this->_store->selectCollection($this->_CollectionTable)->updateOne(
|
$this->_store->selectCollection($this->_CollectionTable)->updateOne(
|
||||||
@@ -328,21 +362,11 @@ class Store {
|
|||||||
|
|
||||||
// Apply range/pagination if provided
|
// Apply range/pagination if provided
|
||||||
if ($range !== null) {
|
if ($range !== null) {
|
||||||
if ($range->type() === RangeType::TALLY) {
|
[$rangeConditions, $rangeOptions] = $this->constructRange($range);
|
||||||
// For TALLY ranges, use position (skip) and tally (limit)
|
if ($rangeConditions !== []) {
|
||||||
/** @var \KTXF\Resource\Range\IRangeTally $rangeTally */
|
$query = ['$and' => [$query, $rangeConditions]];
|
||||||
$rangeTally = $range;
|
|
||||||
$findOptions['skip'] = $rangeTally->getPosition();
|
|
||||||
$findOptions['limit'] = $rangeTally->getTally();
|
|
||||||
} elseif ($range->type() === RangeType::DATE) {
|
|
||||||
// For DATE ranges, filter by date fields
|
|
||||||
/** @var \KTXF\Resource\Range\IRangeDate $rangeDate */
|
|
||||||
$rangeDate = $range;
|
|
||||||
$query['data.startsOn'] = [
|
|
||||||
'\$gte' => $rangeDate->getStart()->format('c'),
|
|
||||||
'\$lte' => $rangeDate->getEnd()->format('c')
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
|
$findOptions = array_merge($findOptions, $rangeOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
$cursor = $this->_store->selectCollection($this->_EntityTable)->find($query, $findOptions);
|
$cursor = $this->_store->selectCollection($this->_EntityTable)->find($query, $findOptions);
|
||||||
@@ -450,15 +474,16 @@ class Store {
|
|||||||
public function entityCreate(string $tenantId, string $userId, string $collectionId, EntityResource $entity): EntityResource {
|
public function entityCreate(string $tenantId, string $userId, string $collectionId, EntityResource $entity): EntityResource {
|
||||||
// convert entity to store format
|
// convert entity to store format
|
||||||
$data = $entity->toStore();
|
$data = $entity->toStore();
|
||||||
|
$data = array_merge($data, EventRangeMetadata::fromStoreDocument($data));
|
||||||
// assign identifiers and timestamps
|
// assign identifiers and timestamps
|
||||||
$data['tid'] = $tenantId;
|
$data['tid'] = $tenantId;
|
||||||
$data['uid'] = $userId;
|
$data['uid'] = $userId;
|
||||||
$data['cid'] = $collectionId;
|
$data['cid'] = $collectionId;
|
||||||
$data['eid'] = UUID::v4();
|
$data['eid'] = UUID::v4();
|
||||||
$data['createdOn'] = date('c');
|
$data['createdOn'] = Timestamp::now();
|
||||||
$data['createdBy'] = $userId;
|
$data['createdBy'] = $userId;
|
||||||
$data['modifiedOn'] = $data['createdOn'];
|
$data['modifiedOn'] = Timestamp::now();
|
||||||
$data['modifiedBy'] = $data['createdBy'];
|
$data['modifiedBy'] = $userId;
|
||||||
|
|
||||||
$result = $this->_store->selectCollection($this->_EntityTable)->insertOne($data);
|
$result = $this->_store->selectCollection($this->_EntityTable)->insertOne($data);
|
||||||
|
|
||||||
@@ -487,7 +512,9 @@ class Store {
|
|||||||
public function entityModify(string $tenantId, string $userId, string $collectionId, string $identifier, EntityResource $entity): EntityResource {
|
public function entityModify(string $tenantId, string $userId, string $collectionId, string $identifier, EntityResource $entity): EntityResource {
|
||||||
// convert entity to store format
|
// convert entity to store format
|
||||||
$data = $entity->toStore();
|
$data = $entity->toStore();
|
||||||
$data['modifiedOn'] = date('c');
|
$data = array_merge($data, EventRangeMetadata::fromStoreDocument($data));
|
||||||
|
// assign identifiers and timestamps
|
||||||
|
$data['modifiedOn'] = Timestamp::now();
|
||||||
$data['modifiedBy'] = $userId;
|
$data['modifiedBy'] = $userId;
|
||||||
// Remove identifiers from update data (they shouldn't change)
|
// Remove identifiers from update data (they shouldn't change)
|
||||||
unset($data['_id'], $data['tid'], $data['uid'], $data['cid'], $data['eid']);
|
unset($data['_id'], $data['tid'], $data['uid'], $data['cid'], $data['eid']);
|
||||||
@@ -599,7 +626,7 @@ class Store {
|
|||||||
'eid' => $eid,
|
'eid' => $eid,
|
||||||
'operation' => $operation,
|
'operation' => $operation,
|
||||||
'signature' => $signature,
|
'signature' => $signature,
|
||||||
'mutatedOn' => time(),
|
'mutatedOn' => Timestamp::now(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// update signature as normalized numeric value
|
// update signature as normalized numeric value
|
||||||
|
|||||||
Reference in New Issue
Block a user