This commit is contained in:
James Cole 2023-12-03 07:02:23 +01:00
parent a5c370c70e
commit 3136bccb24
No known key found for this signature in database
GPG Key ID: B49A324B7EAD6D80
7 changed files with 170 additions and 6 deletions

View File

@ -917,6 +917,7 @@ trait MetaCollection
$list = $tags->pluck('tag')->toArray();
$filter = static function (array $object) use ($list): bool {
foreach ($object['transactions'] as $transaction) {
app('log')->debug(sprintf('Transaction has %d tag(s)', count($transaction['tags'])));
foreach ($transaction['tags'] as $tag) {
if (in_array($tag['name'], $list, true)) {
return false;

View File

@ -515,7 +515,6 @@ class GroupCollector implements GroupCollectorInterface
// add to query:
$this->query->orWhereIn('transaction_journals.transaction_group_id', $groupIds);
}
$result = $this->query->get($this->fields);
// now to parse this into an array.
@ -823,10 +822,15 @@ class GroupCollector implements GroupCollectorInterface
private function postFilterCollection(Collection $collection): Collection
{
$currentCollection = $collection;
app('log')->debug(sprintf('GroupCollector: postFilterCollection has %d filter(s) and %d transaction(s).', count($this->postFilters), count($currentCollection)));
/**
* @var Closure $function
*/
foreach ($this->postFilters as $function) {
app('log')->debug('Applying filter...');
$nextCollection = new Collection();
// loop everything in the current collection
// and save it (or not) in the new collection.
@ -843,6 +847,7 @@ class GroupCollector implements GroupCollectorInterface
$nextCollection->push($item);
}
$currentCollection = $nextCollection;
app('log')->debug(sprintf('GroupCollector: postFilterCollection has %d transaction(s) left.', count($currentCollection)));
}
return $currentCollection;
}

View File

@ -87,7 +87,7 @@ class TagRepository implements TagRepositoryInterface
*/
public function get(): Collection
{
return $this->user->tags()->orderBy('tag', 'ASC')->get();
return $this->user->tags()->orderBy('tag', 'ASC')->get(['tags.*']);
}
/**
@ -454,4 +454,24 @@ class TagRepository implements TagRepositoryInterface
/** @var Location|null */
return $tag->locations()->first();
}
/**
* @inheritDoc
*/
public function tagStartsWith(string $query): Collection
{
$search = sprintf('%s%%', $query);
return $this->user->tags()->where('tag', 'LIKE', $search)->get(['tags.*']);
}
/**
* @inheritDoc
*/
public function tagEndsWith(string $query): Collection
{
$search = sprintf('%%%s', $query);
return $this->user->tags()->where('tag', 'LIKE', $search)->get(['tags.*']);
}
}

View File

@ -153,6 +153,24 @@ interface TagRepositoryInterface
*/
public function searchTag(string $query): Collection;
/**
* Find one or more tags that start with the string in the query
*
* @param string $query
*
* @return Collection
*/
public function tagStartsWith(string $query): Collection;
/**
* Find one or more tags that start with the string in the query
*
* @param string $query
*
* @return Collection
*/
public function tagEndsWith(string $query): Collection;
/**
* Search the users tags.
*

View File

@ -57,7 +57,6 @@ use Gdbots\QueryParser\QueryParser;
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Support\Collection;
use LogicException;
use PragmaRX\Random\Generators\StringGenerator;
use TypeError;
/**
@ -82,6 +81,9 @@ class OperatorQuerySearch implements SearchInterface
private array $validOperators;
private array $words;
private array $excludeTags;
private array $includeTags;
/**
* OperatorQuerySearch constructor.
*
@ -93,6 +95,8 @@ class OperatorQuerySearch implements SearchInterface
$this->operators = new Collection();
$this->page = 1;
$this->words = [];
$this->excludeTags = [];
$this->includeTags = [];
$this->prohibitedWords = [];
$this->invalidOperators = [];
$this->limit = 25;
@ -167,6 +171,8 @@ class OperatorQuerySearch implements SearchInterface
foreach ($query1->getNodes() as $searchNode) {
$this->handleSearchNode($searchNode);
}
$this->parseTagInstructions();
$this->collector->setSearchWords($this->words);
$this->collector->excludeSearchWords($this->prohibitedWords);
@ -868,7 +874,8 @@ class OperatorQuerySearch implements SearchInterface
case 'tag_is':
$result = $this->tagRepository->findByTag($value);
if (null !== $result) {
$this->collector->setTags(new Collection([$result]));
$this->includeTags[] = $result->id;
$this->includeTags = array_unique($this->includeTags);
}
// no tags found means search must result in nothing.
if (null === $result) {
@ -876,11 +883,79 @@ class OperatorQuerySearch implements SearchInterface
$this->collector->findNothing();
}
break;
case 'tag_contains':
$tags = $this->tagRepository->searchTag($value);
if (0 === $tags->count()) {
app('log')->info(sprintf('No valid tags in "%s"-operator, so search will not return ANY results.', $operator));
$this->collector->findNothing();
}
if ($tags->count() > 0) {
$ids = array_values($tags->pluck('id')->toArray());
$this->includeTags = array_unique(array_merge($this->includeTags, $ids));
}
break;
case 'tag_starts':
$tags = $this->tagRepository->tagStartsWith($value);
if (0 === $tags->count()) {
app('log')->info(sprintf('No valid tags in "%s"-operator, so search will not return ANY results.', $operator));
$this->collector->findNothing();
}
if ($tags->count() > 0) {
$ids = array_values($tags->pluck('id')->toArray());
$this->includeTags = array_unique(array_merge($this->includeTags, $ids));
}
break;
case '-tag_starts':
$tags = $this->tagRepository->tagStartsWith($value);
if (0 === $tags->count()) {
app('log')->info(sprintf('No valid tags in "%s"-operator, so search will not return ANY results.', $operator));
$this->collector->findNothing();
}
if ($tags->count() > 0) {
$ids = array_values($tags->pluck('id')->toArray());
$this->excludeTags = array_unique(array_merge($this->includeTags, $ids));
}
break;
case 'tag_ends':
$tags = $this->tagRepository->tagEndsWith($value);
if (0 === $tags->count()) {
app('log')->info(sprintf('No valid tags in "%s"-operator, so search will not return ANY results.', $operator));
$this->collector->findNothing();
}
if ($tags->count() > 0) {
$ids = array_values($tags->pluck('id')->toArray());
$this->includeTags = array_unique(array_merge($this->includeTags, $ids));
}
break;
case '-tag_ends':
$tags = $this->tagRepository->tagEndsWith($value);
if (0 === $tags->count()) {
app('log')->info(sprintf('No valid tags in "%s"-operator, so search will not return ANY results.', $operator));
$this->collector->findNothing();
}
if ($tags->count() > 0) {
$ids = array_values($tags->pluck('id')->toArray());
$this->excludeTags = array_unique(array_merge($this->includeTags, $ids));
}
break;
case '-tag_contains':
$tags = $this->tagRepository->searchTag($value)->keyBy('id');
if (0 === $tags->count()) {
app('log')->info(sprintf('No valid tags in "%s"-operator, so search will not return ANY results.', $operator));
$this->collector->findNothing();
}
if ($tags->count() > 0) {
$ids = array_values($tags->pluck('id')->toArray());
$this->excludeTags = array_unique(array_merge($this->excludeTags, $ids));
}
break;
case '-tag_is':
case 'tag_is_not':
$result = $this->tagRepository->searchTag($value);
if ($result->count() > 0) {
$this->collector->setWithoutSpecificTags($result);
$this->excludeTags[] = $result->id;
$this->excludeTags = array_unique($this->excludeTags);
}
break;
//
@ -2160,4 +2235,42 @@ class OperatorQuerySearch implements SearchInterface
$this->limit = $limit;
$this->collector->setLimit($this->limit);
}
/**
* @return void
* @throws \Psr\Container\ContainerExceptionInterface
* @throws \Psr\Container\NotFoundExceptionInterface
*/
private function parseTagInstructions(): void
{
app('log')->debug('Now in parseTagInstructions()');
// if exclude tags, remove excluded tags.
if (count($this->excludeTags) > 0) {
app('log')->debug(sprintf('%d exclude tag(s)', count($this->excludeTags)));
$collection = new Collection;
foreach ($this->excludeTags as $tagId) {
$tag = $this->tagRepository->find($tagId);
if (null !== $tag) {
app('log')->debug(sprintf('Exclude tag "%s"', $tag->tag));
$collection->push($tag);
}
}
app('log')->debug(sprintf('Selecting all tags except %d excluded tag(s).', $collection->count()));
$this->collector->setWithoutSpecificTags($collection);
}
// if include tags, include them:
if (count($this->includeTags) > 0) {
app('log')->debug(sprintf('%d include tag(s)', count($this->includeTags)));
$collection = new Collection;
foreach ($this->includeTags as $tagId) {
$tag = $this->tagRepository->find($tagId);
if (null !== $tag) {
app('log')->debug(sprintf('Include tag "%s"', $tag->tag));
$collection->push($tag);
}
}
$this->collector->setTags($collection);
}
}
}

View File

@ -34,6 +34,9 @@ return [
'tag_is' => ['alias' => false, 'needs_context' => true,],
'tag_is_not' => ['alias' => false, 'needs_context' => true,],
'tag' => ['alias' => true, 'alias_for' => 'tag_is', 'needs_context' => true,],
'tag_contains' => ['alias' => false, 'needs_context' => true,],
'tag_ends' => ['alias' => false, 'needs_context' => true,],
'tag_starts' => ['alias' => false, 'needs_context' => true,],
'description_is' => ['alias' => false, 'needs_context' => true,],
'description' => ['alias' => true, 'alias_for' => 'description_is', 'needs_context' => true,],
'description_contains' => ['alias' => false, 'needs_context' => true,],

View File

@ -449,6 +449,10 @@ return [
'search_modifier_transaction_type' => 'Transaction type is ":value"',
'search_modifier_not_transaction_type' => 'Transaction type is not ":value"',
'search_modifier_tag_is' => 'Tag is ":value"',
'search_modifier_tag_contains' => 'Tag contains ":value"',
'search_modifier_not_tag_contains' => 'Tag does not contain ":value"',
'search_modifier_tag_ends' => 'Tag ends with ":value"',
'search_modifier_tag_starts' => 'Tag starts with ":value"',
'search_modifier_not_tag_is' => 'No tag is ":value"',
'search_modifier_date_on_year' => 'Transaction is in year ":value"',
'search_modifier_not_date_on_year' => 'Transaction is not in year ":value"',