query and graph
This commit is contained in:
+2
-1
@@ -19,7 +19,8 @@
|
|||||||
"symfony/yaml": "^7.0"
|
"symfony/yaml": "^7.0"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"phpstan/phpstan": "^1.8"
|
"phpstan/phpstan": "^1.8",
|
||||||
|
"laravel/framework": "^10.10"
|
||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
"psr-4": {
|
"psr-4": {
|
||||||
|
|||||||
Generated
+3819
-473
File diff suppressed because it is too large
Load Diff
@@ -18,7 +18,7 @@ return new class extends Migration {
|
|||||||
$table->string('status');
|
$table->string('status');
|
||||||
$table->jsonb('data');
|
$table->jsonb('data');
|
||||||
$table->jsonb('_sys');
|
$table->jsonb('_sys');
|
||||||
$table->jsonb('_file');
|
$table->jsonb('_file')->nullable();
|
||||||
|
|
||||||
$table->index(['schema', 'status']);
|
$table->index(['schema', 'status']);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ namespace Lucent\Edge;
|
|||||||
use Lucent\LucentException;
|
use Lucent\LucentException;
|
||||||
use Lucent\Validator\Validator as LucentValidator;
|
use Lucent\Validator\Validator as LucentValidator;
|
||||||
use PhpOption\Option;
|
use PhpOption\Option;
|
||||||
|
use stdClass;
|
||||||
|
|
||||||
final class Edge
|
final class Edge
|
||||||
{
|
{
|
||||||
@@ -63,4 +64,20 @@ final class Edge
|
|||||||
depth: data_get($data, 'depth', 0),
|
depth: data_get($data, 'depth', 0),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function fromDB(stdClass $data): Edge
|
||||||
|
{
|
||||||
|
|
||||||
|
return new Edge(
|
||||||
|
|
||||||
|
source: data_get($data, 'source'),
|
||||||
|
target: data_get($data, 'target'),
|
||||||
|
sourceSchema: data_get($data, 'sourceSchema'),
|
||||||
|
targetSchema: data_get($data, 'targetSchema'),
|
||||||
|
field: data_get($data, 'field'),
|
||||||
|
data: Option::fromValue(data_get($data,"data")),
|
||||||
|
rank: data_get($data, 'rank'),
|
||||||
|
depth: data_get($data, 'depth', 0),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,10 +5,11 @@ namespace Lucent\File;
|
|||||||
use Illuminate\Http\UploadedFile;
|
use Illuminate\Http\UploadedFile;
|
||||||
use Lucent\Channel\ChannelService;
|
use Lucent\Channel\ChannelService;
|
||||||
use Lucent\LucentException;
|
use Lucent\LucentException;
|
||||||
use Lucent\Record\File;
|
use Lucent\Record\FileInfo;
|
||||||
use Lucent\Record\QueryRecord;
|
use Lucent\Record\QueryRecord;
|
||||||
use Lucent\Schema\Schema\Schema;
|
use Lucent\Schema\Schema\Schema;
|
||||||
use Lucent\Schema\Schema\Type;
|
use Lucent\Schema\Schema\Type;
|
||||||
|
use Lucent\Support\Result\Result;
|
||||||
|
|
||||||
class FileService
|
class FileService
|
||||||
{
|
{
|
||||||
@@ -24,6 +25,15 @@ class FileService
|
|||||||
return $this->channelService->channel->url. "/storage/".$file->_file->path;
|
return $this->channelService->channel->url. "/storage/".$file->_file->path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Schema $schema
|
||||||
|
* @param string $uploadFromUrl
|
||||||
|
* @return Result<FileInfo|string>
|
||||||
|
*/
|
||||||
|
public function createFromUrl(Schema $schema, string $uploadFromUrl): Result{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @throws LucentException
|
* @throws LucentException
|
||||||
*/
|
*/
|
||||||
@@ -48,7 +58,7 @@ class FileService
|
|||||||
}
|
}
|
||||||
|
|
||||||
return new FileUploadResult(
|
return new FileUploadResult(
|
||||||
recordFile: File::fromArray($file), duplicateId: "", isDuplicate: false
|
recordFile: FileInfo::fromArray($file), duplicateId: "", isDuplicate: false
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,15 +2,15 @@
|
|||||||
|
|
||||||
namespace Lucent\File;
|
namespace Lucent\File;
|
||||||
|
|
||||||
use Lucent\Record\File;
|
use Lucent\Record\FileInfo;
|
||||||
|
|
||||||
class FileUploadResult
|
class FileUploadResult
|
||||||
{
|
{
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
public ?File $recordFile,
|
public ?FileInfo $recordFile,
|
||||||
public string $duplicateId,
|
public string $duplicateId,
|
||||||
public bool $isDuplicate,
|
public bool $isDuplicate,
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ use Illuminate\Support\Facades\Storage;
|
|||||||
use Illuminate\Support\Str;
|
use Illuminate\Support\Str;
|
||||||
use Intervention\Image\ImageManagerStatic;
|
use Intervention\Image\ImageManagerStatic;
|
||||||
use Lucent\LucentException;
|
use Lucent\LucentException;
|
||||||
use Lucent\Record\File as RecordFile;
|
use Lucent\Record\FileInfo as RecordFile;
|
||||||
use Lucent\Schema\Schema\Schema;
|
use Lucent\Schema\Schema\Schema;
|
||||||
use Spatie\ImageOptimizer\OptimizerChainFactory;
|
use Spatie\ImageOptimizer\OptimizerChainFactory;
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
<?php namespace Lucent\Http;
|
||||||
|
|
||||||
|
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
|
||||||
|
use Illuminate\Foundation\Validation\ValidatesRequests;
|
||||||
|
use Illuminate\Routing\Controller as BaseController;
|
||||||
|
|
||||||
|
class Controller extends BaseController
|
||||||
|
{
|
||||||
|
use AuthorizesRequests, ValidatesRequests;
|
||||||
|
}
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
namespace Lucent\Http\Controller;
|
namespace Lucent\Http\Controller;
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
use Lucent\Http\Controller;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Lucent\Account\AuthService;
|
use Lucent\Account\AuthService;
|
||||||
use Lucent\Svelte\Svelte;
|
use Lucent\Svelte\Svelte;
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
namespace Lucent\Http\Controller\Api;
|
namespace Lucent\Http\Controller\Api;
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
use Lucent\Http\Controller;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Http\Response;
|
use Illuminate\Http\Response;
|
||||||
use Lucent\Edge\EdgeService;
|
use Lucent\Edge\EdgeService;
|
||||||
@@ -12,26 +12,26 @@ use function Lucent\Response\ok;
|
|||||||
|
|
||||||
class EdgeController extends Controller
|
class EdgeController extends Controller
|
||||||
{
|
{
|
||||||
|
//
|
||||||
public function create(Request $request): Response
|
// public function create(Request $request): Response
|
||||||
{
|
// {
|
||||||
try {
|
// try {
|
||||||
$edge = EdgeService::create(
|
// $edge = EdgeService::create(
|
||||||
source: $request->input("source"),
|
// source: $request->input("source"),
|
||||||
target: $request->input("target"),
|
// target: $request->input("target"),
|
||||||
sourceSchema: $request->input("sourceSchema"),
|
// sourceSchema: $request->input("sourceSchema"),
|
||||||
targetSchema: $request->input("targetSchema"),
|
// targetSchema: $request->input("targetSchema"),
|
||||||
field: $request->input("field"),
|
// field: $request->input("field"),
|
||||||
rank: $request->input("rank") ?? "",
|
// rank: $request->input("rank") ?? "",
|
||||||
);
|
// );
|
||||||
} catch (LucentException $th) {
|
// } catch (LucentException $th) {
|
||||||
return fail($th);
|
// return fail($th);
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
|
//
|
||||||
return ok([
|
// return ok([
|
||||||
"edge" => $edge,
|
// "edge" => $edge,
|
||||||
]);
|
// ]);
|
||||||
}
|
// }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,13 +2,11 @@
|
|||||||
|
|
||||||
namespace Lucent\Http\Controller\Api;
|
namespace Lucent\Http\Controller\Api;
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
use Lucent\Http\Controller;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Facades\Validator;
|
use Illuminate\Support\Facades\Validator;
|
||||||
use Lucent\Account\AuthService;
|
use Lucent\Account\AuthService;
|
||||||
use Lucent\Channel\ChannelRepo;
|
|
||||||
use Lucent\File\FileUploadResult;
|
use Lucent\File\FileUploadResult;
|
||||||
use Lucent\Query\Query;
|
|
||||||
use Lucent\Record\RecordService;
|
use Lucent\Record\RecordService;
|
||||||
use function Lucent\File\uploadFile;
|
use function Lucent\File\uploadFile;
|
||||||
use function Lucent\Response\fail;
|
use function Lucent\Response\fail;
|
||||||
@@ -16,47 +14,46 @@ use function Lucent\Response\ok;
|
|||||||
|
|
||||||
class FileController extends Controller
|
class FileController extends Controller
|
||||||
{
|
{
|
||||||
public function __construct(
|
// public function __construct(
|
||||||
private readonly RecordService $recordService,
|
// private readonly RecordService $recordService,
|
||||||
private readonly Query $query
|
// )
|
||||||
)
|
// {
|
||||||
{
|
// }
|
||||||
}
|
//
|
||||||
|
// public function upload(Request $request)
|
||||||
public function upload(Request $request)
|
// {
|
||||||
{
|
// $validator = Validator::make(request()->all(), [
|
||||||
$validator = Validator::make(request()->all(), [
|
// 'files.*' => 'required|file|max:100000',
|
||||||
'files.*' => 'required|file|max:100000',
|
// ]);
|
||||||
]);
|
//
|
||||||
|
// if ($validator->fails()) {
|
||||||
if ($validator->fails()) {
|
// return fail($validator->errors()->first());
|
||||||
return fail($validator->errors()->first());
|
// }
|
||||||
}
|
// $channel = ChannelRepo::current();
|
||||||
$channel = ChannelRepo::current();
|
// $schema = $channel->schemas->firstWhere("name", $request->input("schema"));
|
||||||
$schema = $channel->schemas->firstWhere("name", $request->input("schema"));
|
// $files = request()->file('files');
|
||||||
$files = request()->file('files');
|
//
|
||||||
|
//
|
||||||
|
// $uploadResults = collect($files)->map(fn($file) => uploadFile($schema, $file))->toArray();
|
||||||
$uploadResults = collect($files)->map(fn($file) => uploadFile($schema, $file))->toArray();
|
// $insertedIds = collect($uploadResults)
|
||||||
$insertedIds = collect($uploadResults)
|
// ->filter(fn(FileUploadResult $res) => !$res->isDuplicate)
|
||||||
->filter(fn(FileUploadResult $res) => !$res->isDuplicate)
|
// ->values()
|
||||||
->values()
|
// ->map(function (FileUploadResult $uploadResult) use ($schema, $request) {
|
||||||
->map(function (FileUploadResult $uploadResult) use ($schema, $request) {
|
//
|
||||||
|
//
|
||||||
|
// return $this->recordService->create(
|
||||||
return $this->recordService->create(
|
// userId: AuthService::currentUserId($request),
|
||||||
userId: AuthService::currentUserId($request),
|
// schemaName: $schema->name,
|
||||||
schemaName: $schema->name,
|
// data: [],
|
||||||
data: [],
|
// file: (array)$uploadResult->recordFile,
|
||||||
file: (array)$uploadResult->recordFile,
|
// edges: [],
|
||||||
edges: [],
|
// status: $request->input("status") ?? "published",
|
||||||
status: $request->input("status") ?? "published",
|
// uploadFromUrl: ""
|
||||||
uploadFromUrl: ""
|
// );
|
||||||
);
|
//
|
||||||
|
// })->toArray();
|
||||||
})->toArray();
|
//
|
||||||
|
//
|
||||||
|
// return ok($insertedIds);
|
||||||
return ok($insertedIds);
|
// }
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
namespace Lucent\Http\Controller\Api;
|
namespace Lucent\Http\Controller\Api;
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
use Lucent\Http\Controller;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Lucent\Channel\ChannelRepo;
|
use Lucent\Channel\ChannelRepo;
|
||||||
use Lucent\LucentException;
|
use Lucent\LucentException;
|
||||||
@@ -15,93 +15,93 @@ use function Lucent\Response\ok;
|
|||||||
|
|
||||||
class RecordController extends Controller
|
class RecordController extends Controller
|
||||||
{
|
{
|
||||||
public function __construct(
|
// public function __construct(
|
||||||
private readonly RecordService $recordService,
|
// private readonly RecordService $recordService,
|
||||||
private readonly Query $query
|
// private readonly Query $query
|
||||||
)
|
// )
|
||||||
{
|
// {
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
public function records(Request $request)
|
// public function records(Request $request)
|
||||||
{
|
// {
|
||||||
$channel = ChannelRepo::current();
|
// $channel = ChannelRepo::current();
|
||||||
$urlParams = $request->all();
|
// $urlParams = $request->all();
|
||||||
$sort = data_get($urlParams, "sort") ?? "-_sys.updatedAt";
|
// $sort = data_get($urlParams, "sort") ?? "-_sys.updatedAt";
|
||||||
$filter = data_get($urlParams, "filter") ?? [];
|
// $filter = data_get($urlParams, "filter") ?? [];
|
||||||
$arguments = array_merge([
|
// $arguments = array_merge([
|
||||||
|
//
|
||||||
], $filter);
|
// ], $filter);
|
||||||
|
//
|
||||||
$skip = data_get($urlParams, "skip") ?? 0;
|
// $skip = data_get($urlParams, "skip") ?? 0;
|
||||||
$limit = data_get($urlParams, "limit") ?? 15;
|
// $limit = data_get($urlParams, "limit") ?? 15;
|
||||||
$queryResult = $this->query
|
// $queryResult = $this->query
|
||||||
->filter($arguments)
|
// ->filter($arguments)
|
||||||
->limit($limit)
|
// ->limit($limit)
|
||||||
->skip($skip)
|
// ->skip($skip)
|
||||||
->sort($sort)
|
// ->sort($sort)
|
||||||
->childrenDepth($request->input("childrenDepth") ?? 1)
|
// ->childrenDepth($request->input("childrenDepth") ?? 1)
|
||||||
->parentsDepth($request->input("parentsDepth") ?? 0)
|
// ->parentsDepth($request->input("parentsDepth") ?? 0)
|
||||||
->runWithCount();
|
// ->runWithCount();
|
||||||
|
//
|
||||||
$graph = $queryResult->getQueryRecords($channel->schemas);
|
// $graph = $queryResult->getQueryRecords($channel->schemas);
|
||||||
$total = $queryResult->getTotal();
|
// $total = $queryResult->getTotal();
|
||||||
|
//
|
||||||
return ok([
|
// return ok([
|
||||||
"graph" => $graph->toArray(),
|
// "graph" => $graph->toArray(),
|
||||||
"sort" => $sort,
|
// "sort" => $sort,
|
||||||
"limit" => $limit,
|
// "limit" => $limit,
|
||||||
"skip" => $skip,
|
// "skip" => $skip,
|
||||||
"total" => $total,
|
// "total" => $total,
|
||||||
]);
|
// ]);
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
public function create(Request $request)
|
// public function create(Request $request)
|
||||||
{
|
// {
|
||||||
|
//
|
||||||
try {
|
// try {
|
||||||
|
//
|
||||||
$recordId = $this->recordService->create(
|
// $recordId = $this->recordService->create(
|
||||||
userId: $request->input("userId"),
|
// userId: $request->input("userId"),
|
||||||
schemaName: $request->input("schema"),
|
// schemaName: $request->input("schema"),
|
||||||
data: $request->input("data") ?? [],
|
// data: $request->input("data") ?? [],
|
||||||
file: $request->input("file") ?? [],
|
// file: $request->input("file") ?? [],
|
||||||
edges: $request->input("edges") ?? [],
|
// edges: $request->input("edges") ?? [],
|
||||||
status: $request->input("status") ?? "draft",
|
// status: $request->input("status") ?? "draft",
|
||||||
uploadFromUrl: $request->input("uploadFromUrl") ?? ""
|
// uploadFromUrl: $request->input("uploadFromUrl") ?? ""
|
||||||
);
|
// );
|
||||||
|
//
|
||||||
} catch (ValidatorException $th) {
|
// } catch (ValidatorException $th) {
|
||||||
return fail($th->getValidatorErrors());
|
// return fail($th->getValidatorErrors());
|
||||||
} catch (LucentException $th) {
|
// } catch (LucentException $th) {
|
||||||
return fail($th);
|
// return fail($th);
|
||||||
}
|
// }
|
||||||
return ok(["id" => $recordId]);
|
// return ok(["id" => $recordId]);
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
public function update(Request $request)
|
// public function update(Request $request)
|
||||||
{
|
// {
|
||||||
|
//
|
||||||
try {
|
// try {
|
||||||
$this->recordService->update(
|
// $this->recordService->update(
|
||||||
userId: $request->input("userId"),
|
// userId: $request->input("userId"),
|
||||||
id: $request->route("id"),
|
// id: $request->route("id"),
|
||||||
data: $request->input("data"),
|
// data: $request->input("data"),
|
||||||
status: $request->input("status"),
|
// status: $request->input("status"),
|
||||||
edges: $request->input("edges") ?? [],
|
// edges: $request->input("edges") ?? [],
|
||||||
updateEdges: false,
|
// updateEdges: false,
|
||||||
);
|
// );
|
||||||
} catch (ValidatorException $th) {
|
// } catch (ValidatorException $th) {
|
||||||
return fail($th->getValidatorErrors());
|
// return fail($th->getValidatorErrors());
|
||||||
} catch (LucentException $th) {
|
// } catch (LucentException $th) {
|
||||||
return fail($th);
|
// return fail($th);
|
||||||
} catch (Throwable $th) {
|
// } catch (Throwable $th) {
|
||||||
if ($th->getCode() == 11000) {
|
// if ($th->getCode() == 11000) {
|
||||||
return fail("ID has to be unique in the channel");
|
// return fail("ID has to be unique in the channel");
|
||||||
}
|
// }
|
||||||
return fail($th);
|
// return fail($th);
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
return ok();
|
// return ok();
|
||||||
}
|
// }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
namespace Lucent\Http\Controller\Api;
|
namespace Lucent\Http\Controller\Api;
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
use Lucent\Http\Controller;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Lucent\Schema\SchemaService;
|
use Lucent\Schema\SchemaService;
|
||||||
use function Lucent\Response\fail;
|
use function Lucent\Response\fail;
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
namespace Lucent\Http\Controller;
|
namespace Lucent\Http\Controller;
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
use Lucent\Http\Controller;
|
||||||
use Illuminate\Contracts\Session\Session;
|
use Illuminate\Contracts\Session\Session;
|
||||||
use Illuminate\Contracts\View\View;
|
use Illuminate\Contracts\View\View;
|
||||||
use Illuminate\Http\RedirectResponse;
|
use Illuminate\Http\RedirectResponse;
|
||||||
|
|||||||
@@ -2,14 +2,10 @@
|
|||||||
|
|
||||||
namespace Lucent\Http\Controller;
|
namespace Lucent\Http\Controller;
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
use Lucent\Http\Controller;
|
||||||
use Illuminate\Contracts\View\View;
|
use Illuminate\Contracts\View\View;
|
||||||
use Illuminate\Http\Request;
|
|
||||||
use Illuminate\Http\Response;
|
|
||||||
use Illuminate\Support\Facades\Artisan;
|
|
||||||
use Lucent\Channel\ChannelService;
|
use Lucent\Channel\ChannelService;
|
||||||
use Lucent\Svelte\Svelte;
|
use Lucent\Svelte\Svelte;
|
||||||
use function Lucent\Response\ok;
|
|
||||||
|
|
||||||
class BuildController extends Controller
|
class BuildController extends Controller
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
namespace Lucent\Http\Controller;
|
namespace Lucent\Http\Controller;
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
use Lucent\Http\Controller;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Facades\Validator;
|
use Illuminate\Support\Facades\Validator;
|
||||||
use Lucent\Channel\ChannelService;
|
use Lucent\Channel\ChannelService;
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
namespace Lucent\Http\Controller;
|
namespace Lucent\Http\Controller;
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
use Lucent\Http\Controller;
|
||||||
use Illuminate\Contracts\View\View;
|
use Illuminate\Contracts\View\View;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Http\Response;
|
use Illuminate\Http\Response;
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
namespace Lucent\Http\Controller;
|
namespace Lucent\Http\Controller;
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
use Lucent\Http\Controller;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Lucent\Account\AccountService;
|
use Lucent\Account\AccountService;
|
||||||
use Lucent\Account\AuthService;
|
use Lucent\Account\AuthService;
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
namespace Lucent\Http\Controller;
|
namespace Lucent\Http\Controller;
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
use Lucent\Http\Controller;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Lucent\Account\AccountService;
|
use Lucent\Account\AccountService;
|
||||||
use Lucent\Account\AuthService;
|
use Lucent\Account\AuthService;
|
||||||
@@ -203,7 +203,6 @@ class RecordController extends Controller
|
|||||||
{
|
{
|
||||||
$rid = $request->route("rid");
|
$rid = $request->route("rid");
|
||||||
|
|
||||||
|
|
||||||
$graph = $this->query
|
$graph = $this->query
|
||||||
->filter(["id" => $rid])
|
->filter(["id" => $rid])
|
||||||
->limit(1)
|
->limit(1)
|
||||||
@@ -214,6 +213,7 @@ class RecordController extends Controller
|
|||||||
->parentsLimit(200)
|
->parentsLimit(200)
|
||||||
->run();
|
->run();
|
||||||
|
|
||||||
|
|
||||||
if ($graph->records->isEmpty()) {
|
if ($graph->records->isEmpty()) {
|
||||||
return $this->svelte->render(
|
return $this->svelte->render(
|
||||||
layout: "channel",
|
layout: "channel",
|
||||||
|
|||||||
@@ -2,12 +2,9 @@
|
|||||||
|
|
||||||
namespace Lucent\Http\Controller;
|
namespace Lucent\Http\Controller;
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
use Lucent\Http\Controller;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Lucent\Record\RecordRepo;
|
|
||||||
use Lucent\Revision\RevisionRepo;
|
|
||||||
use Lucent\Revision\RevisionService;
|
use Lucent\Revision\RevisionService;
|
||||||
use function Lucent\Response\fail;
|
|
||||||
use function Lucent\Response\ok;
|
use function Lucent\Response\ok;
|
||||||
|
|
||||||
class RevisionController extends Controller
|
class RevisionController extends Controller
|
||||||
|
|||||||
@@ -2,13 +2,21 @@
|
|||||||
|
|
||||||
namespace Lucent\Query\DatabaseGraph;
|
namespace Lucent\Query\DatabaseGraph;
|
||||||
|
|
||||||
|
use Lucent\Edge\Edge;
|
||||||
use Lucent\Query\QueryOptions;
|
use Lucent\Query\QueryOptions;
|
||||||
|
use Lucent\Support\Collection;
|
||||||
|
|
||||||
interface DatabaseGraph
|
interface DatabaseGraph
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @param array<string> $ids
|
* @param array<string> $ids
|
||||||
|
* @return Collection<Edge>
|
||||||
*/
|
*/
|
||||||
public function getChildren(array $ids, QueryOptions $options): array;
|
public function getChildren(array $ids, QueryOptions $options): Collection;
|
||||||
public function getParents(array $ids, QueryOptions $options): array;
|
|
||||||
|
/**
|
||||||
|
* @param array<string> $ids
|
||||||
|
* @return Collection<Edge>
|
||||||
|
*/
|
||||||
|
public function getParents(array $ids, QueryOptions $options): Collection;
|
||||||
}
|
}
|
||||||
@@ -3,15 +3,18 @@
|
|||||||
namespace Lucent\Query\DatabaseGraph;
|
namespace Lucent\Query\DatabaseGraph;
|
||||||
|
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use Lucent\Edge\Edge;
|
||||||
use Lucent\Query\QueryOptions;
|
use Lucent\Query\QueryOptions;
|
||||||
|
use Lucent\Support\Collection;
|
||||||
|
|
||||||
class PgsqlDatabaseGraph implements DatabaseGraph
|
class PgsqlDatabaseGraph implements DatabaseGraph
|
||||||
{
|
{
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param array<string> $ids
|
* @param array<string> $ids
|
||||||
|
* @return Collection<Edge>
|
||||||
*/
|
*/
|
||||||
public function getChildren(array $ids, QueryOptions $options): array
|
public function getChildren(array $ids, QueryOptions $options): Collection
|
||||||
{
|
{
|
||||||
$subquery = DB::table('edges AS g')
|
$subquery = DB::table('edges AS g')
|
||||||
->select(DB::raw('g.source,g.target,g.rank,"g"."sourceSchema","g"."targetSchema",g.field, 1 as depth '))
|
->select(DB::raw('g.source,g.target,g.rank,"g"."sourceSchema","g"."targetSchema",g.field, 1 as depth '))
|
||||||
@@ -30,16 +33,17 @@ class PgsqlDatabaseGraph implements DatabaseGraph
|
|||||||
->orderBy("rank")
|
->orderBy("rank")
|
||||||
);
|
);
|
||||||
|
|
||||||
return DB::table('search_graph')
|
return new Collection(DB::table('search_graph')
|
||||||
// ->select(DB::raw("*, 1 as depth "))
|
// ->select(DB::raw("*, 1 as depth "))
|
||||||
->withRecursiveExpression('search_graph', $subquery)
|
->withRecursiveExpression('search_graph', $subquery)
|
||||||
->get()->toArray();
|
->get()->map([Edge::class, 'fromDB']));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param array<string> $ids
|
* @param array<string> $ids
|
||||||
|
* @return Collection<Edge>
|
||||||
*/
|
*/
|
||||||
public function getParents(array $ids, QueryOptions $options): array
|
public function getParents(array $ids, QueryOptions $options): Collection
|
||||||
{
|
{
|
||||||
$subquery = DB::table('edges AS g')
|
$subquery = DB::table('edges AS g')
|
||||||
->select(DB::raw('g.source,g.target,g.rank,"g"."sourceSchema","g"."targetSchema",g.field, 1 as depth '))
|
->select(DB::raw('g.source,g.target,g.rank,"g"."sourceSchema","g"."targetSchema",g.field, 1 as depth '))
|
||||||
@@ -59,9 +63,9 @@ class PgsqlDatabaseGraph implements DatabaseGraph
|
|||||||
->orderBy("rank")
|
->orderBy("rank")
|
||||||
);
|
);
|
||||||
|
|
||||||
return DB::table('search_graph')
|
return new Collection(DB::table('search_graph')
|
||||||
// ->select(DB::raw('sg.source,sg.target,sg.rank,sg."sourceSchema",sg."targetSchema",sg.field,sg.depth'))
|
// ->select(DB::raw('sg.source,sg.target,sg.rank,sg."sourceSchema",sg."targetSchema",sg.field,sg.depth'))
|
||||||
->withRecursiveExpression('search_graph', $subquery)
|
->withRecursiveExpression('search_graph', $subquery)
|
||||||
->get()->toArray();
|
->get()->map([Edge::class, 'fromDB']));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3,14 +3,17 @@
|
|||||||
namespace Lucent\Query\DatabaseGraph;
|
namespace Lucent\Query\DatabaseGraph;
|
||||||
|
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use Lucent\Edge\Edge;
|
||||||
use Lucent\Query\QueryOptions;
|
use Lucent\Query\QueryOptions;
|
||||||
|
use Lucent\Support\Collection;
|
||||||
|
|
||||||
class SqliteDatabaseGraph implements DatabaseGraph
|
class SqliteDatabaseGraph implements DatabaseGraph
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @param array<string> $ids
|
* @param array<string> $ids
|
||||||
|
* @return Collection<Edge>
|
||||||
*/
|
*/
|
||||||
public function getChildren(array $ids, QueryOptions $options): array
|
public function getChildren(array $ids, QueryOptions $options): Collection
|
||||||
{
|
{
|
||||||
$subquery = DB::table('edges AS g')
|
$subquery = DB::table('edges AS g')
|
||||||
->select(DB::raw('g.source,g.target,g.rank,g.sourceSchema,g.targetSchema,g.field, 1 as depth '))
|
->select(DB::raw('g.source,g.target,g.rank,g.sourceSchema,g.targetSchema,g.field, 1 as depth '))
|
||||||
@@ -29,16 +32,17 @@ class SqliteDatabaseGraph implements DatabaseGraph
|
|||||||
->orderBy("rank")
|
->orderBy("rank")
|
||||||
);
|
);
|
||||||
|
|
||||||
return DB::table('search_graph')
|
return new Collection(DB::table('search_graph')
|
||||||
// ->select(DB::raw("*, 1 as depth "))
|
// ->select(DB::raw("*, 1 as depth "))
|
||||||
->withRecursiveExpression('search_graph', $subquery)
|
->withRecursiveExpression('search_graph', $subquery)
|
||||||
->get()->toArray();
|
->get()->map([Edge::class, 'fromDB']));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param array<string> $ids
|
* @param array<string> $ids
|
||||||
|
* @return Collection<Edge>
|
||||||
*/
|
*/
|
||||||
public function getParents(array $ids, QueryOptions $options): array
|
public function getParents(array $ids, QueryOptions $options): Collection
|
||||||
{
|
{
|
||||||
$subquery = DB::table('edges AS g')
|
$subquery = DB::table('edges AS g')
|
||||||
->select(DB::raw('g.source,g.target,g.rank,"g"."sourceSchema","g"."targetSchema",g.field, 1 as depth '))
|
->select(DB::raw('g.source,g.target,g.rank,"g"."sourceSchema","g"."targetSchema",g.field, 1 as depth '))
|
||||||
@@ -58,9 +62,9 @@ class SqliteDatabaseGraph implements DatabaseGraph
|
|||||||
->orderBy("rank")
|
->orderBy("rank")
|
||||||
);
|
);
|
||||||
|
|
||||||
return DB::table('search_graph')
|
return new Collection(DB::table('search_graph')
|
||||||
// ->select(DB::raw('sg.source,sg.target,sg.rank,sg."sourceSchema",sg."targetSchema",sg.field,sg.depth'))
|
// ->select(DB::raw('sg.source,sg.target,sg.rank,sg."sourceSchema",sg."targetSchema",sg.field,sg.depth'))
|
||||||
->withRecursiveExpression('search_graph', $subquery)
|
->withRecursiveExpression('search_graph', $subquery)
|
||||||
->get()->toArray();
|
->get()->map([Edge::class, 'fromDB']));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+50
-47
@@ -4,23 +4,29 @@ namespace Lucent\Query;
|
|||||||
|
|
||||||
use Lucent\Edge\Edge;
|
use Lucent\Edge\Edge;
|
||||||
use Lucent\Record\QueryRecord;
|
use Lucent\Record\QueryRecord;
|
||||||
|
use Lucent\Record\Record;
|
||||||
use Lucent\Support\Collection;
|
use Lucent\Support\Collection;
|
||||||
|
use PhpOption\Option;
|
||||||
|
|
||||||
final class Graph
|
final class Graph
|
||||||
{
|
{
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Collection<QueryRecord> $records
|
* @param Collection<Record> $rootRecords
|
||||||
|
* @param Collection<Record> $records
|
||||||
* @param Collection<Edge> $edges
|
* @param Collection<Edge> $edges
|
||||||
* */
|
* */
|
||||||
public function __construct(
|
public function __construct(
|
||||||
public Collection $records,
|
public Collection $rootRecords,
|
||||||
public Collection $edges,
|
public Collection $records,
|
||||||
public Collection $parentEdges,
|
public Collection $edges,
|
||||||
|
public Collection $parentEdges,
|
||||||
public QueryOptions $queryOptions,
|
public QueryOptions $queryOptions,
|
||||||
public ?int $total = null,
|
public ?int $total = null,
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
$this->edges->sortBy("rank")->values();
|
||||||
|
$this->parentEdges->sortBy("rank")->values();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -39,7 +45,8 @@ final class Graph
|
|||||||
|
|
||||||
public function tree(): Collection
|
public function tree(): Collection
|
||||||
{
|
{
|
||||||
return $this->getRootRecords()
|
return $this->rootRecords
|
||||||
|
->map([QueryRecord::class, 'fromRecord'])
|
||||||
->map(fn($r) => $this->findParents($r))
|
->map(fn($r) => $this->findParents($r))
|
||||||
->map(fn($r) => $this->findChildren($r));
|
->map(fn($r) => $this->findChildren($r));
|
||||||
|
|
||||||
@@ -47,61 +54,57 @@ final class Graph
|
|||||||
|
|
||||||
public function findChildren(QueryRecord $record, int $depth = 1): QueryRecord
|
public function findChildren(QueryRecord $record, int $depth = 1): QueryRecord
|
||||||
{
|
{
|
||||||
if($this->queryOptions->childrenDepth < $depth){
|
if ($this->queryOptions->childrenDepth < $depth) {
|
||||||
return $record;
|
return $record;
|
||||||
}
|
}
|
||||||
$recordEdges = $this->edges
|
$record->_children = $this->edges
|
||||||
->filter(fn(Edge $ed) => $ed->source === $record->id )
|
->filter(fn(Edge $ed) => $ed->source === $record->record->id)
|
||||||
->unique(fn(Edge $ed) => $ed->targetSchema . $ed->field . $ed->target . $ed->source)
|
->unique(fn(Edge $ed) => $ed->targetSchema . $ed->field . $ed->target . $ed->source)
|
||||||
->sort(fn($a, $b) => $a->rank <=> $b->rank)->values();
|
->sort(fn($a, $b) => $a->rank <=> $b->rank)
|
||||||
$groupRecordEdges = [];
|
->values()
|
||||||
foreach ($recordEdges as $element) {
|
->map(function (Edge $edge): Option {
|
||||||
$groupRecordEdges[$element->field][] = $element;
|
$records = $this->records->filter(fn(Record $rec) => $rec->id == $edge->target)->values();
|
||||||
}
|
if ($records->isEmpty()) {
|
||||||
$children = [];
|
return none();
|
||||||
foreach ($groupRecordEdges as $field => $edges) {
|
|
||||||
|
|
||||||
$children[$field] = [];
|
|
||||||
foreach ($edges as $anEdge) {
|
|
||||||
$aRecord = $this->records->filter(fn(QueryRecord $rec) => $rec->id == $anEdge->target)->values();
|
|
||||||
if (empty($aRecord[0])) {
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
$queryRecord = QueryRecord::fromRecord($records->first());
|
||||||
|
$queryRecord->edge = some($edge);
|
||||||
|
return some($queryRecord);
|
||||||
|
})
|
||||||
|
->filter(fn(Option $o) => $o->isDefined())
|
||||||
|
->values()
|
||||||
|
->map(fn(Option $o) => $this->findChildren($o->get(), $depth + 1))
|
||||||
|
->groupBy(fn(QueryRecord $qr) => $qr->edge->get()->field);
|
||||||
|
|
||||||
$children[$field][] = $this->findChildren($aRecord[0], $depth + 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$record->_children = $children;
|
|
||||||
return $record;
|
return $record;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public function findParents(QueryRecord $record, int $depth = 1): QueryRecord
|
public function findParents(QueryRecord $record, int $depth = 1): QueryRecord
|
||||||
{
|
{
|
||||||
if($this->queryOptions->parentsDepth < $depth){
|
|
||||||
|
if ($this->queryOptions->parentsDepth < $depth) {
|
||||||
return $record;
|
return $record;
|
||||||
}
|
}
|
||||||
$recordEdges = $this->parentEdges->filter(fn(Edge $ed) => $ed->target === $record->id)->where("depth", $depth)->values()->sort(fn($a, $b) => $a->rank <=> $b->rank)->values();
|
$record->_parents = $this->parentEdges
|
||||||
|
->filter(fn(Edge $ed) => $ed->target === $record->record->id)
|
||||||
$groupRecordEdges = [];
|
->where("depth", $depth)
|
||||||
foreach ($recordEdges as $element) {
|
->values()
|
||||||
$groupRecordEdges[$element->field][] = $element;
|
->sort(fn($a, $b) => $a->rank <=> $b->rank)
|
||||||
}
|
->values()
|
||||||
$parents = [];
|
->map(function (Edge $edge): Option {
|
||||||
foreach ($groupRecordEdges as $field => $edges) {
|
$records = $this->records->filter(fn(Record $rec) => $rec->id == $edge->source)->values();
|
||||||
|
if ($records->isEmpty()) {
|
||||||
$parents[$field] = [];
|
return none();
|
||||||
foreach ($edges as $anEdge) {
|
|
||||||
$aRecord = $this->records->filter(fn(QueryRecord $rec) => $rec->id == $anEdge->source)->values();
|
|
||||||
if (empty($aRecord[0])) {
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
$queryRecord = QueryRecord::fromRecord($records->first());
|
||||||
|
$queryRecord->edge = some($edge);
|
||||||
|
return some($queryRecord);
|
||||||
|
})
|
||||||
|
->filter(fn(Option $o) => $o->isDefined())
|
||||||
|
->values()
|
||||||
|
->map(fn(Option $o) => $this->findParents($o->get(), $depth + 1))
|
||||||
|
->groupBy(fn(QueryRecord $qr) => $qr->edge->get()->field);
|
||||||
|
|
||||||
$parents[$field][] = $this->findParents($aRecord[0], $depth + 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$record->_parents = $parents;
|
|
||||||
return $record;
|
return $record;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+29
-80
@@ -4,12 +4,11 @@ namespace Lucent\Query;
|
|||||||
|
|
||||||
use Illuminate\Database\Query\Builder;
|
use Illuminate\Database\Query\Builder;
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
use Lucent\Edge\Edge;
|
|
||||||
use Lucent\Query\DatabaseGraph\DatabaseGraph;
|
use Lucent\Query\DatabaseGraph\DatabaseGraph;
|
||||||
use Lucent\Query\Filter\AndFilter;
|
use Lucent\Query\Filter\AndFilter;
|
||||||
use Lucent\Query\Filter\OrFilter;
|
use Lucent\Query\Filter\OrFilter;
|
||||||
use Lucent\Record\InputFormatter;
|
use Lucent\Record\InputFormatter;
|
||||||
use Lucent\Record\QueryRecord;
|
use Lucent\Record\Mapper;
|
||||||
use Lucent\Record\Record;
|
use Lucent\Record\Record;
|
||||||
use Lucent\Support\Collection;
|
use Lucent\Support\Collection;
|
||||||
|
|
||||||
@@ -26,6 +25,7 @@ final class Query
|
|||||||
public readonly FilterParser $filterParser,
|
public readonly FilterParser $filterParser,
|
||||||
public readonly InputFormatter $inputFormatter,
|
public readonly InputFormatter $inputFormatter,
|
||||||
public readonly DatabaseGraph $databaseGraph,
|
public readonly DatabaseGraph $databaseGraph,
|
||||||
|
public readonly Mapper $recordMapper,
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
$this->options = new QueryOptions();
|
$this->options = new QueryOptions();
|
||||||
@@ -46,91 +46,54 @@ final class Query
|
|||||||
|
|
||||||
public function run(): Graph
|
public function run(): Graph
|
||||||
{
|
{
|
||||||
$resultsRecords = $this->mainQuery();
|
$rootRecords = $this->mainQuery();
|
||||||
$ids = array_map(function ($rec) {
|
$ids = $rootRecords->pluck("id");
|
||||||
return $rec->id;
|
|
||||||
}, $resultsRecords);
|
|
||||||
|
|
||||||
$resultChildrenEdgesTargetIds = [];
|
$resultChildrenEdgesTargetIds = [];
|
||||||
$resultChildrenEdges = [];
|
$resultChildrenEdges = new Collection();
|
||||||
if ($this->options->childrenDepth > 0 && !empty($ids)) {
|
if ($this->options->childrenDepth > 0 && $ids->isNotEmpty()) {
|
||||||
$resultChildrenEdges = $this->getChildren($ids);
|
$resultChildrenEdges = $this->databaseGraph->getChildren($ids->toArray(), $this->options);
|
||||||
$resultChildrenEdgesTargetIds = array_map(fn($e) => $e->target, $resultChildrenEdges);
|
$resultChildrenEdgesTargetIds = $resultChildrenEdges->pluck("target");
|
||||||
}
|
}
|
||||||
$resultParentSourceTargetIds = [];
|
$resultParentSourceTargetIds = [];
|
||||||
$resultParentEdges = [];
|
$resultParentEdges = new Collection();
|
||||||
if ($this->options->parentsDepth > 0 && !empty($ids)) {
|
if ($this->options->parentsDepth > 0 && $ids->isNotEmpty()) {
|
||||||
$resultParentEdges = $this->getParents($ids);
|
$resultParentEdges = $this->databaseGraph->getParents($ids->toArray(), $this->options);
|
||||||
$resultParentSourceTargetIds = array_map(fn($e) => $e->source, $resultParentEdges);
|
$resultParentSourceTargetIds = $resultParentEdges->pluck("source");
|
||||||
}
|
}
|
||||||
|
|
||||||
$edgesIds = collect($resultParentSourceTargetIds)->merge($resultChildrenEdgesTargetIds)->unique()->values()->toArray();
|
$edgesIds = collect($resultParentSourceTargetIds)->merge($resultChildrenEdgesTargetIds)->unique()->values()->toArray();
|
||||||
$edgeRecords = [];
|
$edgeRecords = new Collection();
|
||||||
if (!empty($edgesIds)) {
|
if (!empty($edgesIds)) {
|
||||||
$edgeRecords = DB::table('records')
|
$edgeRecords = new Collection(DB::table('records')
|
||||||
->whereIn("id", $edgesIds)
|
->whereIn("id", $edgesIds)
|
||||||
->whereIn("status", $this->options->status)
|
->whereIn("status", $this->options->status)
|
||||||
->get()->toArray();
|
->get()->map([$this->recordMapper, 'fromDB']));
|
||||||
}
|
}
|
||||||
$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();
|
|
||||||
|
|
||||||
$formattedRecords = $this->formatRecords($resultsRecordsUnique, $resultChildrenEdges, $resultParentEdges);
|
$graph = new Graph(
|
||||||
|
$rootRecords,
|
||||||
|
$edgeRecords,
|
||||||
|
$resultChildrenEdges,
|
||||||
|
$resultParentEdges,
|
||||||
|
$this->options
|
||||||
|
);
|
||||||
$this->reset();
|
$this->reset();
|
||||||
return $formattedRecords;
|
return $graph;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private function reset()
|
private function reset(): void
|
||||||
{
|
{
|
||||||
$this->options = new QueryOptions();
|
$this->options = new QueryOptions();
|
||||||
$this->filters = [];
|
$this->filters = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
private function formatRecords(array $records, array $edges, array $parentEdges): Graph
|
|
||||||
{
|
|
||||||
$queryRecords = collect($records)->map(function ($recordData) {
|
|
||||||
|
|
||||||
$record = Record::fromDB($recordData);
|
|
||||||
$record->data = $this->inputFormatter->fill($record->schema, $record->data);
|
|
||||||
$queryRecord = QueryRecord::fromRecord($record);
|
|
||||||
$queryRecord->isRoot = data_get($recordData, "isRoot") === true;
|
|
||||||
return $queryRecord;
|
|
||||||
})->toArray();
|
|
||||||
|
|
||||||
|
|
||||||
$queryEdges = collect($edges)->map(function ($edgeData) {
|
|
||||||
|
|
||||||
return Edge::fromArray((array)$edgeData);
|
|
||||||
|
|
||||||
})->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),
|
|
||||||
$this->options,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public function tree(): Collection
|
public function tree(): Collection
|
||||||
{
|
{
|
||||||
return $this->run()->tree();
|
return $this->run()->tree();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private function parseFilters(Builder $query): Builder
|
private function parseFilters(Builder $query): Builder
|
||||||
{
|
{
|
||||||
foreach ($this->filters as $filter) {
|
foreach ($this->filters as $filter) {
|
||||||
@@ -140,8 +103,10 @@ final class Query
|
|||||||
return $query;
|
return $query;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
private function mainQuery(): array
|
* @return Collection<Record>
|
||||||
|
*/
|
||||||
|
private function mainQuery(): Collection
|
||||||
{
|
{
|
||||||
$query = DB::table("records");
|
$query = DB::table("records");
|
||||||
$query = $this->parseFilters($query);
|
$query = $this->parseFilters($query);
|
||||||
@@ -149,24 +114,8 @@ final class Query
|
|||||||
$query->limit($this->options->limit);
|
$query->limit($this->options->limit);
|
||||||
$query->offset($this->options->skip);
|
$query->offset($this->options->skip);
|
||||||
}
|
}
|
||||||
|
|
||||||
$query = $this->orderByQuery($query);
|
$query = $this->orderByQuery($query);
|
||||||
|
return new Collection($query->get()->map([$this->recordMapper, 'fromDB']));
|
||||||
return $query->get()->map(function ($r) {
|
|
||||||
$r->isRoot = true;
|
|
||||||
return $r;
|
|
||||||
})->toArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
private
|
|
||||||
function getChildren(array $ids): array
|
|
||||||
{
|
|
||||||
return $this->databaseGraph->getChildren($ids, $this->options);
|
|
||||||
}
|
|
||||||
|
|
||||||
private function getParents(array $ids): array
|
|
||||||
{
|
|
||||||
return $this->databaseGraph->getParents($ids, $this->options);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,59 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Lucent\Record;
|
||||||
|
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
use stdClass;
|
||||||
|
|
||||||
|
class Document implements Record
|
||||||
|
{
|
||||||
|
|
||||||
|
function __construct(
|
||||||
|
public string $id,
|
||||||
|
public string $schema,
|
||||||
|
public Status $status,
|
||||||
|
public System $_sys,
|
||||||
|
public RecordData $data,
|
||||||
|
)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private function indexValues(array $arrObject): string
|
||||||
|
{
|
||||||
|
|
||||||
|
return trim(Str::lower(collect($arrObject)
|
||||||
|
->map(function ($value) {
|
||||||
|
if (is_array($value)) {
|
||||||
|
return $this->indexValues($value ?? []);
|
||||||
|
}
|
||||||
|
return str_replace(array("\r", "\n"), '', strip_tags((string)$value));
|
||||||
|
})
|
||||||
|
->values()->join(" ")));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function toDB(): array
|
||||||
|
{
|
||||||
|
$searchIndex = $this->indexValues($this->data->toArray());
|
||||||
|
return [
|
||||||
|
"id" => $this->id,
|
||||||
|
"status" => $this->status->value,
|
||||||
|
"schema" => $this->schema,
|
||||||
|
"_sys" => json_encode($this->_sys),
|
||||||
|
"_file" => null,
|
||||||
|
"data" => json_encode($this->data),
|
||||||
|
"search" => $searchIndex,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function fromDB(stdClass $data): Document
|
||||||
|
{
|
||||||
|
return new Document(
|
||||||
|
id: $data->id,
|
||||||
|
schema: $data->schema,
|
||||||
|
status: Status::from($data->status),
|
||||||
|
_sys: System::fromArray(json_decode($data->_sys, true)),
|
||||||
|
data: new RecordData(json_decode($data->data, true)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
+45
-22
@@ -2,37 +2,60 @@
|
|||||||
|
|
||||||
namespace Lucent\Record;
|
namespace Lucent\Record;
|
||||||
|
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
use stdClass;
|
||||||
|
|
||||||
class File
|
class File implements Record
|
||||||
{
|
{
|
||||||
|
|
||||||
function __construct(
|
function __construct(
|
||||||
public readonly string $originalName,
|
public string $id,
|
||||||
public readonly string $mime,
|
public string $schema,
|
||||||
public readonly string $path,
|
public Status $status,
|
||||||
public readonly int $size,
|
public System $_sys,
|
||||||
public readonly int $width,
|
public RecordData $data,
|
||||||
public readonly int $height,
|
public FileInfo $_file,
|
||||||
public readonly string $checksum,
|
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function fromArray(array $data): File
|
|
||||||
{
|
private function indexValues(array $arrObject){
|
||||||
return new File(
|
|
||||||
originalName: data_get($data, "originalName"),
|
return trim(Str::lower(collect($arrObject)
|
||||||
mime: data_get($data, "mime"),
|
->map(function($value){
|
||||||
path: data_get($data, "path"),
|
if(is_array($value)){
|
||||||
size: data_get($data, "size"),
|
return $this->indexValues($value ?? []);
|
||||||
width: data_get($data, "width"),
|
}
|
||||||
height: data_get($data, "height"),
|
return str_replace(array("\r", "\n"), '', strip_tags((string)$value));
|
||||||
checksum: data_get($data, "checksum"),
|
})
|
||||||
);
|
->values()->join(" ")." ". $this->_file->originalName));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function toArray(): array
|
public function toDB(): array
|
||||||
{
|
{
|
||||||
return \json_decode(\json_encode($this), true);
|
$searchIndex = $this->indexValues($this->data->toArray());
|
||||||
|
return [
|
||||||
|
"id" => $this->id,
|
||||||
|
"status" => $this->status->value,
|
||||||
|
"schema" => $this->schema,
|
||||||
|
"_sys" => json_encode($this->_sys),
|
||||||
|
"_file" => json_encode($this->_file),
|
||||||
|
"data" => json_encode($this->data),
|
||||||
|
"search" => $searchIndex,
|
||||||
|
];
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
public static function fromDB(stdClass $data): File
|
||||||
|
{
|
||||||
|
|
||||||
|
return new File(
|
||||||
|
id: $data->id,
|
||||||
|
schema: $data->schema,
|
||||||
|
status: Status::from($data->status),
|
||||||
|
_sys: System::fromArray(json_decode($data->_sys, true)),
|
||||||
|
data: new RecordData(json_decode($data->data, true)),
|
||||||
|
_file: FileInfo::fromJSON($data->_file),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Lucent\Record;
|
||||||
|
|
||||||
|
|
||||||
|
readonly class FileInfo
|
||||||
|
{
|
||||||
|
|
||||||
|
function __construct(
|
||||||
|
public string $originalName,
|
||||||
|
public string $mime,
|
||||||
|
public string $path,
|
||||||
|
public int $size,
|
||||||
|
public int $width,
|
||||||
|
public int $height,
|
||||||
|
public string $checksum,
|
||||||
|
)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function fromArray(array $data): FileInfo
|
||||||
|
{
|
||||||
|
return new FileInfo(
|
||||||
|
originalName: data_get($data, "originalName"),
|
||||||
|
mime: data_get($data, "mime"),
|
||||||
|
path: data_get($data, "path"),
|
||||||
|
size: data_get($data, "size"),
|
||||||
|
width: data_get($data, "width"),
|
||||||
|
height: data_get($data, "height"),
|
||||||
|
checksum: data_get($data, "checksum"),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function toArray(): array
|
||||||
|
{
|
||||||
|
return \json_decode(\json_encode($this), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function fromJSON(string $json): self
|
||||||
|
{
|
||||||
|
$file = json_decode($json, true);
|
||||||
|
return self::fromArray($file);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Lucent\Record;
|
||||||
|
|
||||||
|
use stdClass;
|
||||||
|
|
||||||
|
class Mapper
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
public InputFormatter $inputFormatter
|
||||||
|
)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public function fromDB(stdClass $data): Record
|
||||||
|
{
|
||||||
|
$record = match (true) {
|
||||||
|
!empty($data->_file) => File::fromDB($data),
|
||||||
|
default => Document::fromDB($data),
|
||||||
|
};
|
||||||
|
|
||||||
|
$record->data = $this->inputFormatter->fill($record->schema, $record->data);
|
||||||
|
return $record;
|
||||||
|
}
|
||||||
|
}
|
||||||
+15
-18
@@ -2,21 +2,23 @@
|
|||||||
|
|
||||||
namespace Lucent\Record;
|
namespace Lucent\Record;
|
||||||
|
|
||||||
use Lucent\LucentException;
|
use Lucent\Edge\Edge;
|
||||||
|
use Lucent\Support\Collection;
|
||||||
|
use PhpOption\Option;
|
||||||
|
|
||||||
class QueryRecord
|
class QueryRecord
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* @param Record $record
|
||||||
|
* @param Option<Edge> $edge
|
||||||
|
* @param Collection<QueryRecord> $_children
|
||||||
|
* @param Collection<QueryRecord> $_parents
|
||||||
|
*/
|
||||||
function __construct(
|
function __construct(
|
||||||
public string $id,
|
public Record $record,
|
||||||
public string $schema,
|
public Option $edge,
|
||||||
public Status $status,
|
public Collection $_children = new Collection(),
|
||||||
public System $_sys,
|
public Collection $_parents = new Collection(),
|
||||||
public RecordData $data,
|
|
||||||
public bool $isRoot,
|
|
||||||
public ?File $_file = null,
|
|
||||||
public array $_children = [],
|
|
||||||
public array $_parents = [],
|
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@@ -24,13 +26,8 @@ class QueryRecord
|
|||||||
public static function fromRecord(Record $record): QueryRecord
|
public static function fromRecord(Record $record): QueryRecord
|
||||||
{
|
{
|
||||||
return new QueryRecord(
|
return new QueryRecord(
|
||||||
id: $record->id,
|
record: $record,
|
||||||
schema: $record->schema,
|
edge: none(),
|
||||||
status: $record->status,
|
|
||||||
_sys: $record->_sys,
|
|
||||||
data: $record->data,
|
|
||||||
isRoot: false,
|
|
||||||
_file: $record->_file,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-67
@@ -2,78 +2,15 @@
|
|||||||
|
|
||||||
namespace Lucent\Record;
|
namespace Lucent\Record;
|
||||||
|
|
||||||
|
use Illuminate\Support\Str;
|
||||||
use JsonSerializable;
|
use JsonSerializable;
|
||||||
use stdClass;
|
use stdClass;
|
||||||
use Illuminate\Support\Str;
|
|
||||||
|
|
||||||
class Record implements JsonSerializable
|
interface Record
|
||||||
{
|
{
|
||||||
|
|
||||||
|
static function fromDB(stdClass $data): Record;
|
||||||
function __construct(
|
public function toDB(): array;
|
||||||
public string $id,
|
|
||||||
public string $schema,
|
|
||||||
public Status $status,
|
|
||||||
public System $_sys,
|
|
||||||
public RecordData $data,
|
|
||||||
public ?File $_file = null,
|
|
||||||
)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private function indexValues(array $arrObject){
|
|
||||||
|
|
||||||
return trim(Str::lower(collect($arrObject)
|
|
||||||
->map(function($value){
|
|
||||||
if(is_array($value)){
|
|
||||||
return $this->indexValues($value ?? []);
|
|
||||||
}
|
|
||||||
return str_replace(array("\r", "\n"), '', strip_tags((string)$value));
|
|
||||||
})
|
|
||||||
->values()->join(" ")." ". $this->_file?->originalName ?? ""));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function toDB(): array
|
|
||||||
{
|
|
||||||
$searchIndex = $this->indexValues($this->data->toArray());
|
|
||||||
return [
|
|
||||||
"id" => $this->id,
|
|
||||||
"status" => $this->status->value,
|
|
||||||
"schema" => $this->schema,
|
|
||||||
"_sys" => json_encode($this->_sys),
|
|
||||||
"_file" => json_encode($this->_file),
|
|
||||||
"data" => json_encode($this->data),
|
|
||||||
"search" => $searchIndex,
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function fromDB(stdClass $data): Record
|
|
||||||
{
|
|
||||||
|
|
||||||
$file = json_decode($data->_file, true);
|
|
||||||
if (!empty($file)) {
|
|
||||||
|
|
||||||
$file = new File(...$file);
|
|
||||||
} else {
|
|
||||||
$file = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return new Record(
|
|
||||||
id: $data->id,
|
|
||||||
schema: $data->schema,
|
|
||||||
status: Status::from($data->status),
|
|
||||||
_sys: System::fromArray(json_decode($data->_sys, true)),
|
|
||||||
data: new RecordData(json_decode($data->data, true)),
|
|
||||||
_file: $file,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public function jsonSerialize(): static
|
|
||||||
{
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ namespace Lucent\Revision;
|
|||||||
|
|
||||||
use Illuminate\Support\Str;
|
use Illuminate\Support\Str;
|
||||||
use Lucent\Edge\EdgeCollection;
|
use Lucent\Edge\EdgeCollection;
|
||||||
use Lucent\Record\File;
|
use Lucent\Record\FileInfo;
|
||||||
use Lucent\Record\Record;
|
use Lucent\Record\Record;
|
||||||
use Lucent\Record\RecordData;
|
use Lucent\Record\RecordData;
|
||||||
use Lucent\Record\System;
|
use Lucent\Record\System;
|
||||||
@@ -19,7 +19,7 @@ readonly class Revision
|
|||||||
public System $_sys,
|
public System $_sys,
|
||||||
public RecordData $data,
|
public RecordData $data,
|
||||||
public EdgeCollection $_edges,
|
public EdgeCollection $_edges,
|
||||||
public ?File $_file = null,
|
public ?FileInfo $_file = null,
|
||||||
|
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ namespace Lucent\Revision;
|
|||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
use Lucent\Edge\Edge;
|
use Lucent\Edge\Edge;
|
||||||
use Lucent\Edge\EdgeCollection;
|
use Lucent\Edge\EdgeCollection;
|
||||||
use Lucent\Record\File;
|
use Lucent\Record\FileInfo;
|
||||||
use Lucent\Record\RecordData;
|
use Lucent\Record\RecordData;
|
||||||
use Lucent\Record\System;
|
use Lucent\Record\System;
|
||||||
use Lucent\Support\Collection;
|
use Lucent\Support\Collection;
|
||||||
@@ -91,7 +91,7 @@ class RevisionRepo
|
|||||||
$file = json_decode($data->_file, true);
|
$file = json_decode($data->_file, true);
|
||||||
if (!empty($file)) {
|
if (!empty($file)) {
|
||||||
|
|
||||||
$file = new File(...$file);
|
$file = new FileInfo(...$file);
|
||||||
} else {
|
} else {
|
||||||
$file = null;
|
$file = null;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user