This commit is contained in:
2023-10-13 21:06:23 +03:00
parent 129e3af471
commit 9e37a7f730
34 changed files with 845 additions and 780 deletions
+61 -62
View File
@@ -4,9 +4,10 @@ namespace Lucent\Query;
use Illuminate\Database\Query\Builder;
use Illuminate\Support\Facades\DB;
use Lucent\Channel\ChannelService;
use Lucent\Edge\Edge;
use Lucent\Primitive\Collection;
use Lucent\Query\Filter\AndFilter;
use Lucent\Query\Filter\OrFilter;
use Lucent\Record\InputFormatter;
use Lucent\Record\QueryRecord;
use Lucent\Record\Record;
@@ -14,11 +15,14 @@ use Lucent\Record\Record;
final class Query
{
public Filter $filter;
/**
* @var array<AndFilter> $filters
*/
public array $filters;
public QueryOptions $options;
public function __construct(
public readonly ChannelService $channelService,
public readonly FilterParser $filterParser,
public readonly InputFormatter $inputFormatter,
)
{
@@ -27,7 +31,13 @@ final class Query
public function filter(array $filterArguments): Query
{
$this->filter = new Filter($filterArguments);
$this->filters[] = new AndFilter($filterArguments);
return $this;
}
public function orFilter(array $filterArguments): Query
{
$this->filters[] = new OrFilter($filterArguments);
return $this;
}
@@ -62,16 +72,22 @@ final class Query
->get()->toArray();
}
$resultsRecordsUnique = collect(array_merge($resultsRecords, $edgeRecords))->unique("id")->values()->toArray();
$resultEdges = collect(array_merge($resultChildrenEdges, $resultParentEdges))
->unique(fn($edge) => $edge->source . $edge->target . $edge->field)
->toArray();
// $resultEdges = collect(array_merge($resultChildrenEdges, $resultParentEdges))
// ->unique(fn($edge) => $edge->source . $edge->target . $edge->field)
// ->toArray();
return $this->formatRecords($resultsRecordsUnique, $resultEdges);
$this->reset();
return $this->formatRecords($resultsRecordsUnique, $resultChildrenEdges, $resultParentEdges);
}
private function formatRecords(array $records, array $edges): Graph
private function reset()
{
$this->options = new QueryOptions();
$this->filters = [];
}
private function formatRecords(array $records, array $edges, array $parentEdges): Graph
{
$queryRecords = collect($records)->map(function ($recordData) {
@@ -89,10 +105,17 @@ final class Query
})->sortBy("rank")->values()->toArray();
$queryParentEdges = collect($parentEdges)->map(function ($edgeData) {
return Edge::fromArray((array)$edgeData);
})->sortBy("rank")->values()->toArray();
return new Graph(
new Collection($queryRecords),
new Collection($queryEdges),
new Collection($queryParentEdges),
);
}
@@ -103,61 +126,21 @@ final class Query
}
private function parseFilters(Builder $query): Builder
{
$filters = $this->filter->run(new Query($this->channelService, $this->inputFormatter));
$ignoredFilters = [];
foreach ($filters as $filter) {
if (in_array($filter["field"], $ignoredFilters)) {
continue;
} else if ($filter["operator"] == "in") {
$query->whereIn($filter["field"], $filter["value"]);
} else if ($filter["operator"] == "nin") {
$query->whereNotIn($filter["field"], $filter["value"]);
} elseif ($filter["operator"] == "eqobject") {
$object = $filter["value"];
// unset related filters used here
$addToIgnored = collect($filters)
->filter(fn($f) => str_starts_with($f["field"], $object))
->values()
->map(fn($f) => $f["field"])
->toArray();
$ignoredFilters = array_merge($ignoredFilters, $addToIgnored);
$objectFilters = collect($filters)
->filter(fn($f) => str_starts_with($f["field"], $object))
->values()
->reduce(function ($c, $f) use ($object) {
$field = str_replace($object . "->", "", $f["field"]);
$c[$field] = $f["value"];
return $c;
});
// target result
// filter[data.previousNames_object]=previousNames&filter[previousNames.name_eq]=alpha&filter[previousNames.id_eqnum]=24
// $query->whereJsonContains("data->previousNames", [["name" => "alpha", "id" => 24]]);
// $query->whereJsonContains($filter["field"], [$objectFilters]);
} else {
$query->where($filter["field"], $filter["operator"], $filter["value"]);
}
foreach ($this->filters as $filter) {
$query = $this->filterParser->parse($query, $filter);
}
$query->whereIn("status", $this->options->status);
return $query;
}
/**
* @throws SubqueryNoResultException
*/
private function mainQuery(): array
{
$query = DB::table("records");
$query = $this->parseFilters($query);
if($this->options->limit > 0){
if ($this->options->limit > 0) {
$query->limit($this->options->limit);
$query->offset($this->options->skip);
}
@@ -174,14 +157,19 @@ final class Query
function getChildren(array $ids): array
{
$subquery = DB::table('edges AS g')
->select(DB::raw('g.source,g.target,g.rank,"g"."sourceSchema","g"."targetSchema",g.field, 0 as depth '))
->whereIn('source', $ids)
->limit($this->options->childrenLimit)
->select(DB::raw('g.source,g.target,g.rank,g.sourceSchema,g.targetSchema,g.field, 1 as depth '))
->whereIn('source', $ids);
if (!empty($this->options->childrenFields)) {
$subquery->whereIn('field', $this->options->childrenFields);
}
$subquery->limit($this->options->childrenLimit)
->unionAll(
DB::table(DB::raw("edges AS g, search_graph AS sg "))
->selectRaw('g.source,g.target,g.rank,"g"."sourceSchema","g"."targetSchema",g.field,sg.depth + 1 as depth')
->whereRaw("g.source = sg.target")
->where("sg.depth", "<=", $this->options->childrenDepth)
->where("depth", "<", $this->options->childrenDepth)
->orderBy("rank")
);
@@ -191,18 +179,17 @@ final class Query
->get()->toArray();
}
private
function getParents(array $ids): array
private function getParents(array $ids): array
{
$subquery = DB::table('edges AS g')
->select(DB::raw('g.source,g.target,g.rank,"g"."sourceSchema","g"."targetSchema",g.field, 0 as depth '))
->select(DB::raw('g.source,g.target,g.rank,"g"."sourceSchema","g"."targetSchema",g.field, 1 as depth '))
->limit($this->options->parentsLimit)
->whereIn('g.target', $ids)
->unionAll(
DB::table(DB::raw("edges AS g, search_graph AS sg "))
->selectRaw('g.source,g.target,g.rank,"g"."sourceSchema","g"."targetSchema",g.field,sg.depth + 1 as depth')
->whereRaw("g.target = sg.source")
->where("sg.depth", "<=", $this->options->parentsDepth)
->where("depth", "<", $this->options->parentsDepth)
->orderBy("rank")
);
@@ -251,6 +238,18 @@ final class Query
return $this;
}
public function childrenFields(array $fields): Query
{
$this->options->childrenFields = $fields;
return $this;
}
public function parentFields(array $fields): Query
{
$this->options->parentFields = $fields;
return $this;
}
public function parentsDepth(int $depth): Query
{
$this->options->parentsDepth = $depth;