diff --git a/front/js/svelte/common/OffCanvas.svelte b/front/js/svelte/common/OffCanvas.svelte index 035210e..61a1db9 100644 --- a/front/js/svelte/common/OffCanvas.svelte +++ b/front/js/svelte/common/OffCanvas.svelte @@ -3,25 +3,25 @@ import {onDestroy, onMount} from "svelte"; import offcanvas from "bootstrap/js/src/offcanvas.js"; export let title = ""; - let offcanvasEl; - let offcanvasInstance; + let offCanvasEl; + let offCanvasInstance; export function show() { - offcanvasInstance.show(); + if(!offCanvasInstance){ + offCanvasInstance = new offcanvas(offCanvasEl); + } + offCanvasInstance.show(); } onMount(()=>{ - offcanvasInstance = new offcanvas(offcanvasEl); + offCanvasInstance = new offcanvas(offCanvasEl); }); - - - export function hide(e) { - e.preventDefault(); - offcanvasInstance.hide(); + export function hide() { + offCanvasInstance.hide(); } -
{title}
diff --git a/front/js/svelte/content/Index.svelte b/front/js/svelte/content/Index.svelte index 04fce41..111b350 100644 --- a/front/js/svelte/content/Index.svelte +++ b/front/js/svelte/content/Index.svelte @@ -5,6 +5,7 @@ import Table from "./Table.svelte"; import {getContext} from "svelte"; import Grid from "./Grid.svelte"; + import Tools from "./tools/Tools.svelte"; const axios = getContext("axios"); export let schema; @@ -53,20 +54,19 @@ {#if selected.length > 0 && !inModal && isWritable} {:else} - - - - - - - - - - - - - - + {/if} {#if schema.type === "collection"} diff --git a/front/js/svelte/content/tools/AppliedFilter.svelte b/front/js/svelte/content/tools/AppliedFilter.svelte index 00e12f4..499eade 100644 --- a/front/js/svelte/content/tools/AppliedFilter.svelte +++ b/front/js/svelte/content/tools/AppliedFilter.svelte @@ -10,7 +10,7 @@ export let value; export let inModal; export let modalUrl; - export let graph; + export let records let filter = { label: "", @@ -51,13 +51,13 @@ } - const filterRecord = extractFilterRecord(graph, value); + const filterRecord = extractFilterRecord(records, value); - function extractFilterRecord(graph, value) { + function extractFilterRecord(records, value) { if (!filter.isReference) { return null; } - return graph.records.find(r => r.id === value); + return records.find(r => r.id === value); } function removeFilter(k) { diff --git a/front/js/svelte/content/tools/Tools.svelte b/front/js/svelte/content/tools/Tools.svelte index 4456185..12c2afc 100644 --- a/front/js/svelte/content/tools/Tools.svelte +++ b/front/js/svelte/content/tools/Tools.svelte @@ -18,7 +18,6 @@ export let modalUrl; export let isWritable; export let records; - export let graph; export let systemFields = []; // export let visibleFields = []; @@ -37,7 +36,7 @@ if (inModal) { dispatch("refresh", url); } else { - window.location = url; + window.location.href = url; } } @@ -152,7 +151,7 @@ value={v} {inModal} {modalUrl} - {graph} + {records} on:refresh /> {/each} diff --git a/front/js/svelte/records/Edit.svelte b/front/js/svelte/records/Edit.svelte index ff0377e..ec505ae 100644 --- a/front/js/svelte/records/Edit.svelte +++ b/front/js/svelte/records/Edit.svelte @@ -15,6 +15,7 @@ // export let isWritable = false; // export let users; $: validationErrors = null; + $: errorMessage = null; let form; @@ -90,6 +91,8 @@ {schema} {record} {isCreateMode} + {errorMessage} + {validationErrors} on:save={save} /> diff --git a/front/js/svelte/records/EditHeader.svelte b/front/js/svelte/records/EditHeader.svelte index e06f2a9..d75cf0f 100644 --- a/front/js/svelte/records/EditHeader.svelte +++ b/front/js/svelte/records/EditHeader.svelte @@ -20,7 +20,7 @@ } -

+

- + {/if}
r.edge))), + edges: JSON.parse(JSON.stringify(graph?.map(r => r.edge.target+r.edge.field) ?? [])), }; hasUnsavedData = checkUnsavedData(); @@ -49,7 +46,6 @@ setOriginalData() }) - afterUpdate(() => { hasUnsavedData = checkUnsavedData(); }); @@ -79,11 +75,9 @@ return !isEqual(originalContent, { data: data, status: status, - edges: graph.map(r => r.edge), + edges: graph?.map(r => r.edge.target+r.edge.field) ?? [], }); } - - diff --git a/front/js/svelte/records/form/references/EdgeData.svelte b/front/js/svelte/records/form/references/EdgeData.svelte index b49b096..999288a 100644 --- a/front/js/svelte/records/form/references/EdgeData.svelte +++ b/front/js/svelte/records/form/references/EdgeData.svelte @@ -3,13 +3,16 @@ import {getContext} from "svelte"; import Form from "../Form.svelte"; import OffCanvas from "../../../common/OffCanvas.svelte"; - import Preview from "../../../newPreview/Preview.svelte"; + import PreviewCard from "../../PreviewCard.svelte"; + import axios from "axios"; export let field; + export let record; export let edge; let form; let offCanvas; - + $: validationErrors = null; + $: errorMessage = null; const channel = getContext("channel"); let schema = channel.schemas.find(s => s.name === field.data); @@ -17,20 +20,56 @@ offCanvas.show(); } - - function save(e){ e.preventDefault(); - console.log("yo") + console.log("SAVE: Attempt"); + validationErrors = null; + return new Promise(function (resolve, reject) { + axios + .put(channel.lucentUrl + "/edges", edge) + .then(function (response) { + console.log("SAVE: SAVED"); + edge = response.data; + form.setOriginalData(); + resolve(null); + offCanvas.hide(); + }) + .catch(function (error) { + // setOriginalContent(); + if (error.response) { + if (typeof error.response.data.error === "string") { + errorMessage = error.response.data.error; + } else { + validationErrors = error.response.data.error; + console.log(validationErrors) + } + } + resolve(null); + + }); + }); + } +
+ +
+
diff --git a/front/js/svelte/records/form/references/Reference.svelte b/front/js/svelte/records/form/references/Reference.svelte index 90b4f47..b415034 100644 --- a/front/js/svelte/records/form/references/Reference.svelte +++ b/front/js/svelte/records/form/references/Reference.svelte @@ -88,7 +88,7 @@ hasDelete={true} editable={!!field?.data} {field} - edge={reference.edge} + bind:edge={reference.edge} on:remove={removeReference} />
diff --git a/front/js/svelte/records/form/references/reference.js b/front/js/svelte/records/form/references/reference.js index 524500d..e124266 100644 --- a/front/js/svelte/records/form/references/reference.js +++ b/front/js/svelte/records/form/references/reference.js @@ -10,6 +10,7 @@ export function insertEdges(existingRecords, sourceRecord, targetRecords, fieldN sourceSchema: sourceRecord.schema, targetSchema: r.schema, field: fieldName, + data: {}, rank: "" } diff --git a/src/Commands/RemoveOrphanEdges.php b/src/Commands/RemoveOrphanEdges.php index 55c33eb..fcf86d9 100644 --- a/src/Commands/RemoveOrphanEdges.php +++ b/src/Commands/RemoveOrphanEdges.php @@ -3,7 +3,7 @@ namespace Lucent\Commands; use Illuminate\Console\Command; -use Lucent\Edge\EdgeService; +use Lucent\Graph\Edge\EdgeService; use Lucent\Query\Query; class RemoveOrphanEdges extends Command diff --git a/src/Database/migrations/04_revisions.php b/src/Database/migrations/04_revisions.php index 392ae4b..30a428d 100644 --- a/src/Database/migrations/04_revisions.php +++ b/src/Database/migrations/04_revisions.php @@ -21,6 +21,7 @@ return new class extends Migration { $table->jsonb('_file'); $table->jsonb('_edges'); }); + } /** diff --git a/src/Database/migrations/08_EdgeRevisions.php b/src/Database/migrations/08_EdgeRevisions.php new file mode 100644 index 0000000..9f7ce49 --- /dev/null +++ b/src/Database/migrations/08_EdgeRevisions.php @@ -0,0 +1,33 @@ +dropColumn("schema"); + $table->dropColumn("_file"); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('revisions', function (Blueprint $table) { + $table->string('schema'); + $table->jsonb('_file'); + }); + } +}; diff --git a/src/Edge/EdgeData.php b/src/Edge/EdgeData.php deleted file mode 100644 index 839a2e1..0000000 --- a/src/Edge/EdgeData.php +++ /dev/null @@ -1,50 +0,0 @@ -data = array_merge($this->data, $data->toArray()); - return $this; - } - - public function get(string $key, mixed $default = null): mixed - { - return $this->data[$key] ?? $default; - } - - public function set(string $key, mixed $value): EdgeData - { - $this->data[$key] = $value; - return $this; - } - - public function isEmpty(string $key): bool - { - return empty($this->get($key)); - } - - public function isDefined(string $key): bool - { - return !empty($this->get($key)); - } - - - public function toArray(): array - { - return $this->data; - } - - public function jsonSerialize(): array - { - return $this->data; - } - - -} diff --git a/src/Edge/EdgeRepo.php b/src/Edge/EdgeRepo.php deleted file mode 100644 index 9cbc95f..0000000 --- a/src/Edge/EdgeRepo.php +++ /dev/null @@ -1,85 +0,0 @@ -insert($edge->toDB()); - } catch (PDOException $e) { - if ($e->getCode() == 23505) { - throw new LucentException("Edge already exists"); - } - throw $e; - } - - } - - /** - * @param string $from - * @param EdgeCollection $edges - * @return void - */ - public function update(string $from, EdgeCollection $edges): void - { - DB::table("edges")->where("source", $from)->delete(); - if($edges->isEmpty()){ - return; - } - - $edgesDB = collect($edges)->map(fn(Edge $e) => $e->toDB())->toArray(); - DB::table("edges")->insert($edgesDB); - } - - - public function findAll(): EdgeCollection - { - $edges = DB::table("edges")->get(); - return new EdgeCollection(...$edges->map([$this, 'mapEdge'])->toArray()); - } - - public function mapEdge(stdClass $edge): Edge - { - if (empty($edge->data)) { - $data = none(); - } else { - $data = some(new EdgeData(json_decode($edge->data))); - } - - - return new Edge( - source: $edge->source, - target: $edge->target, - sourceSchema: $edge->sourceSchema, - targetSchema: $edge->targetSchema, - field: $edge->field, - data: $data, - rank: $edge->rank, - depth: $edge->depth ?? 0 - ); - - } - - public function remove(Edge $edge): void - { - DB::table("edges") - ->where("source", $edge->source) - ->where("target", $edge->target) - ->where("sourceSchema", $edge->sourceSchema) - ->where("targetSchema", $edge->targetSchema) - ->where("field", $edge->field) - ->delete(); - } - -} diff --git a/src/Edge/EdgeService.php b/src/Edge/EdgeService.php deleted file mode 100644 index 0386a37..0000000 --- a/src/Edge/EdgeService.php +++ /dev/null @@ -1,59 +0,0 @@ -edgeRepo->insert($edge); - return $edge; - } - - /** - * @param string $from - * @param EdgeCollection $edges - * @return void - */ - public function update(string $from, EdgeCollection $edges): void - { - $this->edgeRepo->update($from, $edges); - } - - public function findAll(): EdgeCollection - { - return $this->edgeRepo->findAll(); - } - - public function remove(Edge $edge): void - { - $this->edgeRepo->remove($edge); - } - -} diff --git a/src/File/FileService.php b/src/File/FileService.php index af41f5f..6192102 100644 --- a/src/File/FileService.php +++ b/src/File/FileService.php @@ -4,9 +4,9 @@ namespace Lucent\File; use Illuminate\Http\UploadedFile; use Lucent\Channel\ChannelService; +use Lucent\Graph\Record\FileInfo; +use Lucent\Graph\Record\QueryRecord; use Lucent\LucentException; -use Lucent\Record\FileInfo; -use Lucent\Record\QueryRecord; use Lucent\Schema\Schema\Schema; use Lucent\Schema\Schema\Type; use Lucent\Support\Result\Result; diff --git a/src/File/FileUploadResult.php b/src/File/FileUploadResult.php index 38d1d1c..3e81590 100644 --- a/src/File/FileUploadResult.php +++ b/src/File/FileUploadResult.php @@ -2,7 +2,7 @@ namespace Lucent\File; -use Lucent\Record\FileInfo; +use Lucent\Graph\Record\FileInfo; class FileUploadResult { diff --git a/src/File/ImageService.php b/src/File/ImageService.php index bcc95f9..8b5b41f 100644 --- a/src/File/ImageService.php +++ b/src/File/ImageService.php @@ -6,7 +6,7 @@ use Exception; use Illuminate\Log\Logger; use Intervention\Image\ImageManager; use Lucent\Channel\ChannelService; -use Lucent\Record\QueryRecord; +use Lucent\Graph\Record\QueryRecord; class ImageService { diff --git a/src/File/Uploader.php b/src/File/Uploader.php index 334d997..0d6792a 100644 --- a/src/File/Uploader.php +++ b/src/File/Uploader.php @@ -9,8 +9,8 @@ use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Storage; use Illuminate\Support\Str; use Intervention\Image\ImageManagerStatic; +use Lucent\Graph\Record\FileInfo as RecordFile; use Lucent\LucentException; -use Lucent\Record\FileInfo as RecordFile; use Lucent\Schema\Schema\Schema; use Spatie\ImageOptimizer\OptimizerChainFactory; diff --git a/src/Record/RecordData.php b/src/Graph/Data/FieldData.php similarity index 63% rename from src/Record/RecordData.php rename to src/Graph/Data/FieldData.php index 784147f..dc2ab2b 100644 --- a/src/Record/RecordData.php +++ b/src/Graph/Data/FieldData.php @@ -1,14 +1,14 @@ data = array_merge($this->data, $data->toArray()); @@ -20,7 +20,7 @@ class RecordData extends ArrayContainer return $this->data[$key] ?? $default; } - public function set(string $key, mixed $value): RecordData + public function set(string $key, mixed $value): FieldData { $this->data[$key] = $value; return $this; @@ -47,5 +47,13 @@ class RecordData extends ArrayContainer return $this->data; } + public static function fromArray(array $data):self{ + return new self($data); + } + + public static function fromJson(string $data):self{ + return self::fromArray(json_decode($data,true)); + } + } diff --git a/src/Record/InputFormatter.php b/src/Graph/Data/InputFormatter.php similarity index 66% rename from src/Record/InputFormatter.php rename to src/Graph/Data/InputFormatter.php index 4085273..d5df614 100644 --- a/src/Record/InputFormatter.php +++ b/src/Graph/Data/InputFormatter.php @@ -1,6 +1,6 @@ channelService->getSchema($schemaName)->get(); + return $schema->fields ->filter(fn(FieldInterface $field)=> $field instanceof FieldDataInterface) - ->reduce(fn(RecordData $carry, FieldDataInterface $field) => $field->format($input, $carry), new RecordData([])); + ->reduce(fn(FieldData $carry, FieldDataInterface $field) => $field->format($input, $carry), new FieldData([])); } diff --git a/src/Graph/Edge/Contracts/EdgeData.php b/src/Graph/Edge/Contracts/EdgeData.php new file mode 100644 index 0000000..0cfdf6a --- /dev/null +++ b/src/Graph/Edge/Contracts/EdgeData.php @@ -0,0 +1,18 @@ + $data - */ + public function __construct( - public string $source, - public string $target, - public string $sourceSchema, - public string $targetSchema, - public string $field, - public Option $data, - public string $rank = "a", - public int $depth = 0, + public string $source, + public string $target, + public string $sourceSchema, + public string $targetSchema, + public string $field, + public FieldData $data, + public string $rank = "a", + public int $depth = 0, ) { } public function equal(Edge $edge): bool { - return $this->targetSchema === $edge->targetSchema && $this->field === $edge->field && $this->target === $edge->target && $this->source === $edge->source; + return $this->field === $edge->field && $this->target === $edge->target && $this->source === $edge->source; } public function toArray(): array @@ -46,14 +42,13 @@ final class Edge public static function fromArray(array $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")), + data: FieldData::fromArray(data_get($data, "data", [])), rank: data_get($data, 'rank'), depth: data_get($data, 'depth', 0), ); @@ -69,9 +64,11 @@ final class Edge sourceSchema: data_get($data, 'sourceSchema'), targetSchema: data_get($data, 'targetSchema'), field: data_get($data, 'field'), - data: Option::fromValue(data_get($data,"data")), + data: FieldData::fromJson($data->data ?? "{}"), rank: data_get($data, 'rank'), depth: data_get($data, 'depth', 0), ); } + + } diff --git a/src/Edge/EdgeCollection.php b/src/Graph/Edge/EdgeCollection.php similarity index 57% rename from src/Edge/EdgeCollection.php rename to src/Graph/Edge/EdgeCollection.php index a57db42..e9cd7e2 100644 --- a/src/Edge/EdgeCollection.php +++ b/src/Graph/Edge/EdgeCollection.php @@ -1,16 +1,16 @@ + * @extends Collection */ final class EdgeCollection extends Collection { - public function __construct( + private function __construct( Edge ...$array ) { @@ -25,10 +25,24 @@ final class EdgeCollection extends Collection return collect($this)->values()->toArray(); } + public function toDB(): array + { + return collect($this)->map(fn(Edge $edge) => $edge->toDB())->toArray(); + } + + /** + * @param array $data + * @return EdgeCollection + */ public static function fromArray(array $data): EdgeCollection { $edges = collect($data) - ->map([Edge::class, 'fromArray']) + ->map(function (mixed $edge) { + if ($edge instanceof Edge) { + return $edge; + } + return Edge::fromArray($edge); + }) ->unique(fn(Edge $e) => $e->field . $e->source . $e->target); return new EdgeCollection(...$edges); } diff --git a/src/Graph/Edge/EdgeRepo.php b/src/Graph/Edge/EdgeRepo.php new file mode 100644 index 0000000..0e13ab1 --- /dev/null +++ b/src/Graph/Edge/EdgeRepo.php @@ -0,0 +1,89 @@ +where("source", $sourceId)->delete(); + DB::table("edges")->insert($edgeCollection->toDB()); + }); + } + + public function insert(Edge $edge): void + { + try { + DB::table("edges")->insert($edge->toDB()); + } catch (PDOException $e) { + if ($e->getCode() == 23505) { + throw new LucentException("Edge already exists"); + } + throw $e; + } + + } + + public function update(Edge $edge): void + { + DB::table("edges") + ->where("source", $edge->source) + ->where("target", $edge->target) + ->where("field", $edge->field) + ->update([ + "data" => json_encode($edge->data), + "rank" => $edge->rank, + ]); + } + + +// public function findAll(): EdgeCollection +// { +// $edges = DB::table("edges")->get(); +// return new EdgeCollection(...$edges->map([$this, 'mapEdge'])->toArray()); +// } +// +// public function mapEdge(stdClass $edge): Edge +// { +// if (empty($edge->data)) { +// $data = none(); +// } else { +// $data = some(new FieldData(json_decode($edge->data))); +// } +// +// +// return new Edge( +// source: $edge->source, +// target: $edge->target, +// sourceSchema: $edge->sourceSchema, +// targetSchema: $edge->targetSchema, +// field: $edge->field, +// data: $data, +// rank: $edge->rank, +// depth: $edge->depth ?? 0 +// ); +// +// } +// +// public function remove(Edge $edge): void +// { +// DB::table("edges") +// ->where("source", $edge->source) +// ->where("target", $edge->target) +// ->where("sourceSchema", $edge->sourceSchema) +// ->where("targetSchema", $edge->targetSchema) +// ->where("field", $edge->field) +// ->delete(); +// } + +} diff --git a/src/Graph/Edge/EdgeService.php b/src/Graph/Edge/EdgeService.php new file mode 100644 index 0000000..7453070 --- /dev/null +++ b/src/Graph/Edge/EdgeService.php @@ -0,0 +1,95 @@ + $edges + * @return EdgeCollection + */ + public function replaceEdgesForRecord(Record $record, Collection $edges): EdgeCollection + { + $edgeCollection = $this->getUniqueRecordEdges($edges, $record); + $this->edgeRepo->replaceBySourceId($record->id, $edgeCollection); + return $edgeCollection; + + } + + public function update(EdgeData $data) :Result{ + + $edge = $this->mapper->fromArray(toArray($data)); + $this->edgeRepo->update($edge); + return Success::create($edge); + } +// +// /** +// * @throws LucentException +// */ +// public function create( +// string $source, +// string $target, +// string $sourceSchema, +// string $targetSchema, +// string $field, +// string $rank, +// ): Edge +// { +// +// +// $edge = new Edge( +// +// source: $source, +// target: $target, +// sourceSchema: $sourceSchema, +// targetSchema: $targetSchema, +// field: $field, +// rank: $rank, +// ); +// $this->edgeRepo->insert($edge); +// return $edge; +// } +// +// /** +// * @param string $from +// * @param EdgeCollection $edges +// * @return void +// */ +// public function update(string $from, EdgeCollection $edges): void +// { +// $this->edgeRepo->update($from, $edges); +// } +// +// public function findAll(): EdgeCollection +// { +// return $this->edgeRepo->findAll(); +// } +// +// public function remove(Edge $edge): void +// { +// $this->edgeRepo->remove($edge); +// } + + private function getUniqueRecordEdges(Collection $edges, Record $record): EdgeCollection + { + $edges = $edges + ->map(fn(RecordEdgeData $edge, $index) => $edge->toEdge($record, $index)); + return EdgeCollection::fromArray($edges->toArray()); + } +} diff --git a/src/Graph/Edge/Mapper.php b/src/Graph/Edge/Mapper.php new file mode 100644 index 0000000..05bc5fe --- /dev/null +++ b/src/Graph/Edge/Mapper.php @@ -0,0 +1,45 @@ +getEdgeDataSchema($edge); + if(!empty($edgeSchema)){ + $edge->data = $this->inputFormatter->fill($edgeSchema, $edge->data); + } + + + return $edge; + } + + public function fromArray(array $data): Edge + { + $edge = Edge::fromArray($data); + $edgeSchema = $this->getEdgeDataSchema($edge); + if(!empty($edgeSchema)){ + $edge->data = $this->inputFormatter->fill($edgeSchema, $edge->data); + } + return $edge; + } + + private function getEdgeDataSchema(Edge $edge): string + { + + return $this->channelService->getSchema($edge->sourceSchema)->get()->fields->where("name", $edge->field)->first()->data; + } +} \ No newline at end of file diff --git a/src/Record/Contracts/EditorTree.php b/src/Graph/Record/Contracts/EditorTree.php similarity index 81% rename from src/Record/Contracts/EditorTree.php rename to src/Graph/Record/Contracts/EditorTree.php index 637ab0b..7bfafa7 100644 --- a/src/Record/Contracts/EditorTree.php +++ b/src/Graph/Record/Contracts/EditorTree.php @@ -1,8 +1,8 @@ schema, targetSchema: $this->targetSchema, field: $this->field, - data: $this->data, + data: $this->data->map([FieldData::class,'fromArray'])->getOrElse(new FieldData([])), rank: $index, ); } diff --git a/src/Record/Contracts/UpdateRecordData.php b/src/Graph/Record/Contracts/UpdateRecordData.php similarity index 86% rename from src/Record/Contracts/UpdateRecordData.php rename to src/Graph/Record/Contracts/UpdateRecordData.php index 76c421c..8496b6f 100644 --- a/src/Record/Contracts/UpdateRecordData.php +++ b/src/Graph/Record/Contracts/UpdateRecordData.php @@ -1,8 +1,8 @@ schema, status: Status::from($data->status), _sys: System::fromArray(json_decode($data->_sys, true)), - data: new RecordData(json_decode($data->data, true)), + data: new FieldData(json_decode($data->data, true)), ); } } \ No newline at end of file diff --git a/src/Record/File.php b/src/Graph/Record/File.php similarity index 82% rename from src/Record/File.php rename to src/Graph/Record/File.php index f896612..8265b94 100644 --- a/src/Record/File.php +++ b/src/Graph/Record/File.php @@ -1,19 +1,20 @@ schema, status: Status::from($data->status), _sys: System::fromArray(json_decode($data->_sys, true)), - data: new RecordData(json_decode($data->data, true)), + data: new FieldData(json_decode($data->data, true)), _file: FileInfo::fromJSON($data->_file), ); } diff --git a/src/Record/FileInfo.php b/src/Graph/Record/FileInfo.php similarity index 96% rename from src/Record/FileInfo.php rename to src/Graph/Record/FileInfo.php index 05529e9..edf6550 100644 --- a/src/Record/FileInfo.php +++ b/src/Graph/Record/FileInfo.php @@ -1,6 +1,6 @@ query - ->filter(["id_in" => $this->getIdsExcept($ignoreId)]) - ->limit(7) - ->run(); - - + $graph = $this->query->run( + fn($builder) => $builder->filter(["id_in" => $this->getIdsExcept($ignoreId)]) + ->limit(7) + ); return $this->order($graph->records->toArray()); } } diff --git a/src/Record/Mapper.php b/src/Graph/Record/Mapper.php similarity index 86% rename from src/Record/Mapper.php rename to src/Graph/Record/Mapper.php index 86cf8a1..d78056b 100644 --- a/src/Record/Mapper.php +++ b/src/Graph/Record/Mapper.php @@ -1,7 +1,8 @@ toDB(); @@ -21,14 +21,14 @@ class RecordRepo /** * @param array $ids */ - public static function updateStatusBulk(Status $status, array $ids): void + public function updateStatusBulk(Status $status, array $ids): void { DB::table("records")->whereIn("id", $ids)->update([ 'status' => $status->value ]); } - public static function update(Record $record): void + public function update(Record $record): void { $recordToDB = $record->toDB(); diff --git a/src/Record/RecordService.php b/src/Graph/Record/RecordService.php similarity index 85% rename from src/Record/RecordService.php rename to src/Graph/Record/RecordService.php index 685e707..4470107 100644 --- a/src/Record/RecordService.php +++ b/src/Graph/Record/RecordService.php @@ -1,20 +1,21 @@ channelService->getSchema($data->schemaName)->get(); - $formattedData = $this->inputFormatter->fill($data->schemaName, new RecordData($data->data)); + $formattedData = $this->inputFormatter->fill($data->schemaName, new FieldData($data->data)); $newRecordId = $data->id->getOrElse(Id::new()); $record = new Document( @@ -61,32 +61,58 @@ readonly class RecordService data: $formattedData, ); - $uniqueEdges = $this->getUniqueEdges($data->edges, $record); - if ($data->status === Status::PUBLISHED) { $errors = $this->recordValidator->check($data->schemaName, $record->data); if ($errors->isNotEmpty()) { return Error::create($errors); } } - RecordRepo::create($record); - $this->edgeService->update($record->id, $uniqueEdges); - $this->revisionService->create($record, $uniqueEdges); + + $this->recordRepo->create($record); + $edgeCollection = $this->edgeService->replaceEdgesForRecord($record,$data->edges); + $this->revisionService->create($record, $edgeCollection); return Success::create($record->id); } /** - * @param Collection $edges - * @param Record $record - * @return EdgeCollection + * @param UpdateRecordData $data + * @return Result> */ - private function getUniqueEdges(Collection $edges, Record $record): EdgeCollection + public function update(UpdateRecordData $data): Result { - $edges = $edges - ->map(fn(RecordEdgeData $edge, $index) => $edge->toEdge($record, $index)); - return new EdgeCollection(...$edges->toArray()); + $record = $this->query->filter(["id" => $data->id])->run()->rootRecords->first(); + + if (empty($record)) { + return Error::create("Record id is missing"); + } + $formattedData = $this->inputFormatter->fill($record->schema, new FieldData($data->data)); + + if ($data->status === Status::PUBLISHED) { + $errors = $this->recordValidator->check($record->schema, $record->data); + if ($errors->isNotEmpty()) { + return Error::create($errors); + } + } + + $newRecord = new Document( + id: $record->id, + schema: $record->schema, + status: $data->status, + _sys: $record->_sys->update($this->authService->currentUserId()), + data: $record->data->merge($formattedData), + ); + + $this->recordRepo->update($newRecord); + + $edgeCollection = EdgeCollection::fromArray([]); + if ($data->updateEdges) { + $edgeCollection = $this->edgeService->replaceEdgesForRecord($record,$data->edges); + } + $this->revisionService->create($newRecord, $edgeCollection); + return Success::create($record->id); } + /** * @throws LucentException * @throws ValidatorException @@ -104,7 +130,7 @@ readonly class RecordService { $schema = $this->channelService->getSchema($schemaName)->get(); - $formattedData = $this->inputFormatter->fill($schemaName, new RecordData($data)); + $formattedData = $this->inputFormatter->fill($schemaName, new FieldData($data)); if (empty($formattedData["id"])) { $formattedData["id"] = Id::new(); } @@ -151,45 +177,7 @@ readonly class RecordService } - /** - * @param UpdateRecordData $data - * @return Result> - */ - public function update(UpdateRecordData $data): Result - { - $record = $this->query->filter(["id" => $data->id])->run()->rootRecords->first(); - if (empty($record)) { - return Error::create("Record id is missing"); - } - $formattedData = $this->inputFormatter->fill($record->schema, new RecordData($data->data)); - - $uniqueEdges = new EdgeCollection(); - if ($data->updateEdges) { - $uniqueEdges = $this->getUniqueEdges($data->edges, $record); - } - if ($data->status === Status::PUBLISHED) { - $errors = $this->recordValidator->check($record->schema, $record->data); - if ($errors->isNotEmpty()) { - return Error::create($errors); - } - } - - $newRecord = new Document( - id: $record->id, - schema: $record->schema, - status: $data->status, - _sys: $record->_sys->update($this->authService->currentUserId()), - data: $record->data->merge($formattedData), - ); - - RecordRepo::update($newRecord); - if ($data->updateEdges) { - $this->edgeService->update($newRecord->id, $uniqueEdges); - } - $this->revisionService->create($newRecord, $uniqueEdges); - return Success::create($record->id); - } /** */ @@ -290,7 +278,7 @@ readonly class RecordService return $carry; }, []); - $formattedData = $this->inputFormatter->fill($schema->name, new RecordData($defaultValues)); + $formattedData = $this->inputFormatter->fill($schema->name, new FieldData($defaultValues)); return new Document( id: Id::new(), schema: $schema->name, diff --git a/src/Record/Status.php b/src/Graph/Record/Status.php similarity index 79% rename from src/Record/Status.php rename to src/Graph/Record/Status.php index bad0d46..8da5b07 100644 --- a/src/Record/Status.php +++ b/src/Graph/Record/Status.php @@ -1,6 +1,6 @@ edgeService->update(new EdgeData( + source: $request->input("source"), + target: $request->input("target"), + sourceSchema: $request->input("sourceSchema"), + targetSchema: $request->input("targetSchema"), + field: $request->input("field"), + data: $request->input("data"), + rank: $request->input("rank"), + )); + return result($res); + } + + +} diff --git a/src/Http/Controller/FileController.php b/src/Http/Controller/FileController.php index 35497e6..e4836d5 100644 --- a/src/Http/Controller/FileController.php +++ b/src/Http/Controller/FileController.php @@ -2,13 +2,13 @@ namespace Lucent\Http\Controller; -use Lucent\Http\Controller; use Illuminate\Http\Request; use Illuminate\Support\Facades\Validator; use Lucent\Channel\ChannelService; use Lucent\File\FileUploadResult; +use Lucent\Graph\Record\RecordService; +use Lucent\Http\Controller; use Lucent\Query\Query; -use Lucent\Record\RecordService; use function Lucent\File\loadDisk; use function Lucent\File\uploadFile; use function Lucent\Response\fail; diff --git a/src/Http/Controller/RecordController.php b/src/Http/Controller/RecordController.php index 526a3ad..99efcda 100644 --- a/src/Http/Controller/RecordController.php +++ b/src/Http/Controller/RecordController.php @@ -2,27 +2,28 @@ namespace Lucent\Http\Controller; -use Lucent\Http\Controller; use Illuminate\Http\Request; use Lucent\Account\AccountService; use Lucent\Channel\ChannelService; +use Lucent\Graph\Record\Contracts\EditorTree; +use Lucent\Graph\Record\Contracts\NewDocumentData; +use Lucent\Graph\Record\Contracts\RecordEdgeData; +use Lucent\Graph\Record\Contracts\UpdateRecordData; +use Lucent\Graph\Record\Manager; +use Lucent\Graph\Record\QueryRecord; +use Lucent\Graph\Record\RecordService; +use Lucent\Graph\Record\Status; +use Lucent\Http\Controller; use Lucent\LucentException; +use Lucent\Query\Builder; use Lucent\Query\Operator; use Lucent\Query\Query; -use Lucent\Record\Contracts\EditorTree; -use Lucent\Record\Contracts\NewDocumentData; -use Lucent\Record\Contracts\RecordEdgeData; -use Lucent\Record\Contracts\UpdateRecordData; -use Lucent\Record\Manager; -use Lucent\Record\QueryRecord; -use Lucent\Record\RecordService; -use Lucent\Record\Status; use Lucent\Schema\Schema\System; use Lucent\Schema\Validator\ValidatorException; use Lucent\Support\Collection; use Lucent\Support\Result\Success; use Lucent\Svelte\Svelte; -use PhpOption\Option; +use Lucent\Support\Option\Option; use function Lucent\Response\fail; use function Lucent\Response\ok; use function Lucent\Response\result; @@ -36,7 +37,7 @@ class RecordController extends Controller private readonly Svelte $svelte, private readonly Query $query, private readonly Manager $recordManager, - private readonly EditorTree $editorTree + private readonly EditorTree $editorTree ) { } @@ -64,19 +65,17 @@ class RecordController extends Controller "status_in" => "draft,published", ], $filter); - $skip = data_get($urlParams, "skip") ?? 0; $limit = 30; - $graph = $this->query - ->filter($arguments) + $graph = $this->query->run(fn(Builder $builder) => $builder->filter($arguments) ->limit($limit) ->status(explode(",", $arguments["status_in"])) ->skip($skip) ->sort($sort) ->childrenFields($schema?->visible ?? []) ->childrenDepth(1) - ->parentsDepth(0) - ->runWithCount(); + ->withCount() + ); $data = [ "schemas" => $this->channelService->channel->schemas, @@ -102,6 +101,7 @@ class RecordController extends Controller } return $data; } + $data["inModal"] = false; return $this->svelte->render( layout: "channel", @@ -204,15 +204,14 @@ class RecordController extends Controller { $rid = $request->route("rid"); - $graph = $this->query - ->filter(["id" => $rid]) + $graph = $this->query->run(fn(Builder $builder) => $builder->filter(["id" => $rid]) ->limit(1) ->skip(0) - ->childrenDepth(2) - ->childrenLimit(200) + ->childrenDepth(1) + ->childrenLimit(500) ->parentsDepth(1) - ->parentsLimit(200) - ->run(); + ); + if ($graph->rootRecords->isEmpty()) { return $this->svelte->render( @@ -316,9 +315,9 @@ class RecordController extends Controller $recordEdgeData = (new Collection($request->input("edges")))->map(fn($item) => new RecordEdgeData( target: $item["target"], - targetSchema:$item["targetSchema"], + targetSchema: $item["targetSchema"], field: $item["field"], - data: Option::fromValue(data_get($item,"data")), + data: Option::fromValue(data_get($item, "data")), )); $res = match ($request->input("isCreateMode")) { diff --git a/src/Http/web.php b/src/Http/web.php index a49c95f..31e6af1 100644 --- a/src/Http/web.php +++ b/src/Http/web.php @@ -4,6 +4,7 @@ use Illuminate\Support\Facades\Route; use Lucent\Http\Controller\AccountController; use Lucent\Http\Controller\AuthController; use Lucent\Http\Controller\BuildController; +use Lucent\Http\Controller\EdgeController; use Lucent\Http\Controller\FileController; use Lucent\Http\Controller\HomeController; use Lucent\Http\Controller\MemberController; @@ -60,6 +61,11 @@ Route::group([ Route::post('/{rid}/rollback/{version}', [RecordController::class, 'rollback']); }); + Route::middleware(["lucent.auth"])->prefix("/edges")->group(function () { + + Route::put('/', [EdgeController::class, 'update']); + }); + Route::middleware(["lucent.auth"])->group(function () { Route::get('/records/{rid}/revisions', [RevisionController::class, 'index']); @@ -82,6 +88,5 @@ Route::group([ }); - }); diff --git a/src/Lexorank/Lexorank.php b/src/Lexorank/Lexorank.php index b81ad29..3c47ba1 100644 --- a/src/Lexorank/Lexorank.php +++ b/src/Lexorank/Lexorank.php @@ -10,7 +10,6 @@ use function ord; use function strcmp; use function substr; -/** @psalm-immutable */ final class Lexorank { diff --git a/src/LucentServiceProvider.php b/src/LucentServiceProvider.php index 42a3b80..7f9fe08 100644 --- a/src/LucentServiceProvider.php +++ b/src/LucentServiceProvider.php @@ -16,6 +16,7 @@ use Lucent\JsonSchema\Command\GenerateJsonSchema; use Lucent\Query\DatabaseGraph\DatabaseGraph; use Lucent\Query\DatabaseGraph\PgsqlDatabaseGraph; use Lucent\Query\DatabaseGraph\SqliteDatabaseGraph; +use Lucent\Query\Query; use Lucent\Schema\Commands\CompileSchemas; class LucentServiceProvider extends ServiceProvider @@ -33,6 +34,8 @@ class LucentServiceProvider extends ServiceProvider return new ImageManager(['driver' => 'imagick']); }); + + $this->app->bind(DatabaseGraph::class, function () { return match (config("lucent.database")) { "sqlite" => new SqliteDatabaseGraph(), @@ -61,17 +64,17 @@ class LucentServiceProvider extends ServiceProvider $this->loadViewsFrom(__DIR__ . '/Views', 'lucent'); $this->loadRoutesFrom(__DIR__ . '/Http/web.php'); - $this->loadRoutesFrom(__DIR__ . '/Http/api.php'); +// $this->loadRoutesFrom(__DIR__ . '/Http/api.php'); $this->loadMigrationsFrom(__DIR__ . '/Database/migrations'); if ($this->app->runningInConsole()) { $this->commands([ - CompileSchemas::class, - RebuildThumbnails::class, - LiveLink::class, - RemoveOrphanEdges::class, - GenerateJsonSchema::class, +// CompileSchemas::class, +// RebuildThumbnails::class, +// LiveLink::class, +// RemoveOrphanEdges::class, +// GenerateJsonSchema::class, ]); } diff --git a/src/Query/Builder.php b/src/Query/Builder.php new file mode 100644 index 0000000..ae57e0f --- /dev/null +++ b/src/Query/Builder.php @@ -0,0 +1,237 @@ + $filters + */ + public function __construct( + public array $filters = [], + public int $limit = 20, + public int $skip = 0, + public int $childrenDepth = -1, + public int $parentsDepth = -1, + public int $childrenLimit = -1, + public int $parentsLimit = -1, + public array $childrenFields = [], + public array $parentFields = [], + public array $sort = [], + public array $status = ["published", "draft"], + public bool $withCount = false + ) + { + + } + + + public function filter(array $filterArguments): Builder + { + $this->filters[] = new AndFilter($filterArguments); + return $this; + } + + public function orFilter(array $filterArguments): Builder + { + $this->filters[] = new OrFilter($filterArguments); + return $this; + } + + public function limit(int $limit): Builder + { + $this->limit = $limit; + return $this; + } + + public function skip(int $skip): Builder + { + $this->skip = $skip; + return $this; + } + + public function childrenDepth(int $depth): Builder + { + $this->childrenDepth = $depth; + return $this; + } + + public function childrenLimit(int $limit): Builder + { + $this->childrenLimit = $limit; + return $this; + } + + public function childrenFields(array $fields): Builder + { + $this->childrenFields = $fields; + return $this; + } + + public function parentFields(array $fields): Builder + { + $this->parentFields = $fields; + return $this; + } + + public function parentsDepth(int $depth): Builder + { + $this->parentsDepth = $depth; + return $this; + } + + public function parentsLimit(int $limit): Builder + { + $this->parentsLimit = $limit; + return $this; + } + + + public function sort(string $sort): Builder + { + $this->sort[] = $sort; + return $this; + } + + public function status(array $status): Builder + { + $this->status = $status; + return $this; + } + + public function withCount(): Builder + { + + $this->withCount = true; + return $this; + } + + + + public function resolveRecordFilters(LaravelBuilder $laravelBuilder): LaravelBuilder + { + foreach ($this->filters as $filter) { + $groupFilters = $this->groupFilters($filter); + $filterParser = new FilterParser(); + $arguments = $filterParser->formatArguments($groupFilters->record); + $laravelBuilder = match (get_class($filter)) { + AndFilter::class => $this->parseAnd($laravelBuilder, $arguments), + OrFilter::class => $this->parseOr($laravelBuilder, $arguments), + }; + } + return $laravelBuilder; + } + + public function resolveReferenceFilters(LaravelBuilder $laravelBuilder): LaravelBuilder + { + foreach ($this->filters as $filter) { + $groupFilters = $this->groupFilters($filter); + $filterParser = new FilterParser(); + if(empty($groupFilters->reference)){ + break; + } + $arguments[] = $filterParser->formatReferencesArguments($groupFilters->reference); + $laravelBuilder = match (get_class($filter)) { + AndFilter::class => $this->parseAnd($laravelBuilder, $arguments), + OrFilter::class => $this->parseOr($laravelBuilder, $arguments), + }; + } + return $laravelBuilder; + } + + public function resolveEdgeFilters(LaravelBuilder $laravelBuilder): LaravelBuilder + { + foreach ($this->filters as $filter) { + $groupFilters = $this->groupFilters($filter); + if(empty($groupFilters->edge)){ + break; + } + $filterParser = new FilterParser(); + $arguments[] = $filterParser->formatEdgesArguments($groupFilters->edge); + $laravelBuilder = match (get_class($filter)) { + AndFilter::class => $this->parseAnd($laravelBuilder, $arguments), + OrFilter::class => $this->parseOr($laravelBuilder, $arguments), + }; + } + return $laravelBuilder; + } + + private function groupFilters(Filter $arguments): FilterGroup + { + return collect($arguments->toArray())->reduce(function ($c, $v, $k) { + + if (str_starts_with($k, "children.")) { + $c->reference[$k] = $v; + return $c; + } + if (str_starts_with($k, "edges.")) { + $c->edge[$k] = $v; + return $c; + } + $c->record[$k] = $v; + return $c; + }, new FilterGroup()); + } + + + /** + * @param array $arguments + */ + private function parseAnd(LaravelBuilder $builder, array $arguments): LaravelBuilder + { + foreach ($arguments as $argument) { + if ($argument->operator == "in") { + $builder->whereIn($argument->field, $argument->value); + } else if ($argument->operator == "nin") { + $builder->whereNotIn($argument->field, $argument->value); + } else if ($argument->operator == "exists") { + $builder->where($argument->field, "!=", ""); + $builder->where($argument->field, "!=", null); + } elseif ($argument->operator == "filter") { + $builder->whereJsonContains($argument->field, [$argument->value]); + // 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 { + $builder->where($argument->field, $argument->operator, $argument->value); + } + } + + return $builder; + } + + /** + * @param array $arguments + */ + private function parseOr(LaravelBuilder $builder, array $arguments): LaravelBuilder + { + $builder->where(function (LaravelBuilder $orBuilder) use ($arguments) { + foreach ($arguments as $argument) { + if ($argument->operator == "in") { + $orBuilder->orWhereIn($argument->field, $argument->value); + } else if ($argument->operator == "nin") { + $orBuilder->orWhereNotIn($argument->field, $argument->value); + } else if ($argument->operator == "exists") { + $orBuilder->where($argument->field, "!=", ""); + $orBuilder->where($argument->field, "!=", null); + } elseif ($argument->operator == "filter") { + $orBuilder->whereJsonContains($argument->field, [$argument->value]); + // 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 { + $orBuilder->orWhere($argument->field, $argument->operator, $argument->value); + } + } + }); + return $builder; + } +} \ No newline at end of file diff --git a/src/Query/Filter/AndFilter.php b/src/Query/Data/AndFilter.php similarity index 87% rename from src/Query/Filter/AndFilter.php rename to src/Query/Data/AndFilter.php index 6e9c36b..adb74b2 100644 --- a/src/Query/Filter/AndFilter.php +++ b/src/Query/Data/AndFilter.php @@ -1,6 +1,6 @@ $ids - * @return Collection + * @return Collection */ - public function getChildren(array $ids, QueryOptions $options): Collection; + public function getChildren(array $ids, Builder $options): Collection; /** * @param array $ids - * @return Collection + * @return Collection */ - public function getParents(array $ids, QueryOptions $options): Collection; + public function getParents(array $ids, Builder $options): Collection; } \ No newline at end of file diff --git a/src/Query/DatabaseGraph/PgsqlDatabaseGraph.php b/src/Query/DatabaseGraph/PgsqlDatabaseGraph.php index a126d97..1b09370 100644 --- a/src/Query/DatabaseGraph/PgsqlDatabaseGraph.php +++ b/src/Query/DatabaseGraph/PgsqlDatabaseGraph.php @@ -3,23 +3,24 @@ namespace Lucent\Query\DatabaseGraph; use Illuminate\Support\Facades\DB; -use Lucent\Edge\Edge; -use Lucent\Query\QueryOptions; +use Lucent\Query\Builder; use Lucent\Support\Collection; +use stdClass; class PgsqlDatabaseGraph implements DatabaseGraph { - /** * @param array $ids - * @return Collection + * @return Collection */ - public function getChildren(array $ids, QueryOptions $options): Collection + public function getChildren(array $ids, Builder $options): Collection { $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,g.data, 1 as depth ')) ->whereIn('source', $ids); + $subquery = $options->resolveEdgeFilters($subquery); + if (!empty($options->childrenFields)) { $subquery->whereIn('field', $options->childrenFields); } @@ -27,7 +28,7 @@ class PgsqlDatabaseGraph implements DatabaseGraph $subquery->limit($options->childrenLimit) ->union( 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') + ->selectRaw('g.source,g.target,g.rank,"g"."sourceSchema","g"."targetSchema",g.field,g.data,sg.depth + 1 as depth') ->whereRaw("g.source = sg.target") ->where("depth", "<", $options->childrenDepth) ->orderBy("rank") @@ -36,19 +37,21 @@ class PgsqlDatabaseGraph implements DatabaseGraph return new Collection(DB::table('search_graph') // ->select(DB::raw("*, 1 as depth ")) ->withRecursiveExpression('search_graph', $subquery) - ->get()->map([Edge::class, 'fromDB'])); + ->get()); } /** * @param array $ids - * @return Collection + * @return Collection */ - public function getParents(array $ids, QueryOptions $options): Collection + public function getParents(array $ids, Builder $options): Collection { $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,g.data, 1 as depth ')) ->whereIn('g.target', $ids); + $subquery = $options->resolveEdgeFilters($subquery); + if (!empty($options->parentFields)) { $subquery->whereIn('field', $options->parentFields); } @@ -57,7 +60,7 @@ class PgsqlDatabaseGraph implements DatabaseGraph ->limit($options->parentsLimit) ->union( 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') + ->selectRaw('g.source,g.target,g.rank,"g"."sourceSchema","g"."targetSchema",g.field,g.data,sg.depth + 1 as depth') ->whereRaw("g.target = sg.source") ->where("depth", "<", $options->parentsDepth) ->orderBy("rank") @@ -66,6 +69,6 @@ class PgsqlDatabaseGraph implements DatabaseGraph return new Collection(DB::table('search_graph') // ->select(DB::raw('sg.source,sg.target,sg.rank,sg."sourceSchema",sg."targetSchema",sg.field,sg.depth')) ->withRecursiveExpression('search_graph', $subquery) - ->get()->map([Edge::class, 'fromDB'])); + ->get()); } } \ No newline at end of file diff --git a/src/Query/DatabaseGraph/SqliteDatabaseGraph.php b/src/Query/DatabaseGraph/SqliteDatabaseGraph.php index 9342bd3..e050701 100644 --- a/src/Query/DatabaseGraph/SqliteDatabaseGraph.php +++ b/src/Query/DatabaseGraph/SqliteDatabaseGraph.php @@ -3,22 +3,26 @@ namespace Lucent\Query\DatabaseGraph; use Illuminate\Support\Facades\DB; -use Lucent\Edge\Edge; -use Lucent\Query\QueryOptions; +use Lucent\Query\Builder; + use Lucent\Support\Collection; +use stdClass; class SqliteDatabaseGraph implements DatabaseGraph { + /** * @param array $ids - * @return Collection + * @return Collection */ - public function getChildren(array $ids, QueryOptions $options): Collection + public function getChildren(array $ids, Builder $options):Collection { $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,g.data, 1 as depth ')) ->whereIn('source', $ids); + $subquery = $options->resolveEdgeFilters($subquery); + if (!empty($options->childrenFields)) { $subquery->whereIn('field', $options->childrenFields); } @@ -26,7 +30,7 @@ class SqliteDatabaseGraph implements DatabaseGraph $subquery->limit($options->childrenLimit) ->union( 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') + ->selectRaw('g.source,g.target,g.rank,"g"."sourceSchema","g"."targetSchema",g.field,g.data,sg.depth + 1 as depth') ->whereRaw("g.source = sg.target") ->where("depth", "<", $options->childrenDepth) ->orderBy("rank") @@ -35,19 +39,20 @@ class SqliteDatabaseGraph implements DatabaseGraph return new Collection(DB::table('search_graph') // ->select(DB::raw("*, 1 as depth ")) ->withRecursiveExpression('search_graph', $subquery) - ->get()->map([Edge::class, 'fromDB'])); + ->get()); } /** * @param array $ids - * @return Collection + * @return Collection */ - public function getParents(array $ids, QueryOptions $options): Collection + public function getParents(array $ids, Builder $options):Collection { $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,g.data, 1 as depth ')) ->whereIn('g.target', $ids); + $subquery = $options->resolveEdgeFilters($subquery); if (!empty($options->parentFields)) { $subquery->whereIn('field', $options->parentFields); } @@ -56,7 +61,7 @@ class SqliteDatabaseGraph implements DatabaseGraph ->limit($options->parentsLimit) ->union( 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') + ->selectRaw('g.source,g.target,g.rank,"g"."sourceSchema","g"."targetSchema",g.field,g.data,sg.depth + 1 as depth') ->whereRaw("g.target = sg.source") ->where("depth", "<", $options->parentsDepth) ->orderBy("rank") @@ -65,6 +70,6 @@ class SqliteDatabaseGraph implements DatabaseGraph return new Collection(DB::table('search_graph') // ->select(DB::raw('sg.source,sg.target,sg.rank,sg."sourceSchema",sg."targetSchema",sg.field,sg.depth')) ->withRecursiveExpression('search_graph', $subquery) - ->get()->map([Edge::class, 'fromDB'])); + ->get()); } } \ No newline at end of file diff --git a/src/Query/FilterParser.php b/src/Query/FilterParser.php index cbcaa41..abb4e66 100644 --- a/src/Query/FilterParser.php +++ b/src/Query/FilterParser.php @@ -2,29 +2,24 @@ namespace Lucent\Query; -use Illuminate\Contracts\Foundation\Application; -use Illuminate\Database\Query\Builder; use Illuminate\Support\Facades\DB; -use Lucent\Query\Filter\AndFilter; -use Lucent\Query\Filter\Argument; -use Lucent\Query\Filter\Filter; -use Lucent\Query\Filter\OrFilter; +use Lucent\Query\Data\Argument; final class FilterParser { - public function __construct(public Application $app) + public function __construct() { } - /** * @param array $arguments * @return array */ - private function formatArguments(array $arguments): array + public function formatArguments(array $arguments): array { return collect($arguments)->reduce(function ($c, $v, $k) { + $c[] = $this->formatArgument($v, $k); return $c; }, []); @@ -32,7 +27,6 @@ final class FilterParser private function formatArgument(mixed $value, string $filter): Argument { - $operator = $this->detectOperator($filter); $field = $this->detectField($filter, $operator); @@ -92,21 +86,21 @@ final class FilterParser private function formatListNum(mixed $value): array { - if (\is_string($value)) { + if (is_string($value)) { $value = explode(",", $value); } - return \array_map(fn($v) => $this->formatNumber($v), $value); + return array_map(fn($v) => $this->formatNumber($v), $value); } private function detectOperator(string $filter): string { - $exploded = \explode("_", $filter); + $exploded = explode("_", $filter); $candidate = end($exploded); $operatorsListNames = collect(Operator::list())->map(fn($o) => $o->name)->toArray(); - if (\in_array($candidate, $operatorsListNames)) { + if (in_array($candidate, $operatorsListNames)) { return $candidate; } return 'eq'; @@ -123,29 +117,22 @@ final class FilterParser return $filter; } - - private function formatReferences(array $referenceArguments): Argument + public function formatEdgesArguments(array $edgesArguments): Argument { - $subqueries = collect($referenceArguments)->reduce(function ($c, $v, $k) { - $keyWithoutRef = str_replace("children.", "", $k); + $subqueries = collect($edgesArguments)->reduce(function ($c, $v, $k) { + $keyWithoutRef = str_replace("edges.", "", $k); [$field] = explode(".", $keyWithoutRef); $referenceField = str_replace($field . ".", "", $keyWithoutRef); $c[$field][$referenceField] = $v; return $c; }, []); - $sourceIds = collect($subqueries)->reduce(function ($c, $subquery, $k) { - - $query = $this->app->make(Query::class); - $graph = $query->filter($subquery)->run(); - - if (!$graph->hasResults()) { - return $c; - } - - $targetIds = collect($graph->records)->pluck("id"); - $sourceIds = DB::table("edges")->whereIn("target", $targetIds)->where("field", $k)->get()->pluck("source"); + $laravelBuilder = DB::table("edges"); + $queryBuilder = new Builder(); + $queryBuilder->filter($subquery); + $laravelBuilder = $queryBuilder->resolveRecordFilters($laravelBuilder); + $sourceIds = $laravelBuilder->where("field", $k)->get()->pluck("source"); return array_merge($c, $sourceIds->toArray()); }, []); @@ -157,96 +144,42 @@ final class FilterParser } - private function separateMainFromReferenceArguments(Filter $arguments): array + + public function formatReferencesArguments(array $referenceArguments): Argument { - return collect($arguments->toArray())->partition(function ($v, $k) { - if (!str_starts_with($k, "children.")) { - return true; + $subqueries = collect($referenceArguments)->reduce(function ($c, $v, $k) { + $keyWithoutRef = str_replace("children.", "", $k); + [$field] = explode(".", $keyWithoutRef); + $referenceField = str_replace($field . ".", "", $keyWithoutRef); + $c[$field][$referenceField] = $v; + return $c; + }, []); + + + $sourceIds = collect($subqueries)->reduce(function ($c, $subquery, $k) { + $laravelBuilder = DB::table("records"); + $queryBuilder = new Builder(); + $queryBuilder->filter($subquery); + $laravelBuilder = $queryBuilder->resolveRecordFilters($laravelBuilder); + $res = $laravelBuilder->get(); + + if ($res->isEmpty()) { + return $c; } - return false; - })->toArray(); + + $targetIds = $res->pluck("id"); + $sourceIds = DB::table("edges") + ->whereIn("target", $targetIds) + ->where("field", $k) + ->get()->pluck("source"); + return array_merge($c, $sourceIds->toArray()); + }, []); + + return new Argument( + field: "id", + operator: "in", + value: $sourceIds + ); + } - - - /** - * @return array - */ - private function parseArguments(Filter $arguments): array - { - [$normalArguments, $referenceArguments] = $this->separateMainFromReferenceArguments($arguments); - - $formattedArguments = $this->formatArguments($normalArguments); - if (!empty($referenceArguments)) { - $formattedArguments[] = $this->formatReferences($referenceArguments); - } - - return $formattedArguments; - } - - - public function parse(Builder $builder, Filter $filter): Builder - { - $arguments = $this->parseArguments($filter); - return match (get_class($filter)) { - AndFilter::class => $this->parseAnd($builder, $arguments), - OrFilter::class => $this->parseOr($builder, $arguments), - }; - } - - /** - * @param array $arguments - */ - private function parseAnd(Builder $builder, array $arguments): Builder - { - foreach ($arguments as $argument) { - if ($argument->operator == "in") { - $builder->whereIn($argument->field, $argument->value); - } else if ($argument->operator == "nin") { - $builder->whereNotIn($argument->field, $argument->value); - } else if ($argument->operator == "exists") { - $builder->where($argument->field, "!=", ""); - $builder->where($argument->field, "!=", null); - } elseif ($argument->operator == "filter") { - $builder->whereJsonContains($argument->field, [$argument->value]); - // 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 { - $builder->where($argument->field, $argument->operator, $argument->value); - } - } - - return $builder; - } - - /** - * @param array $arguments - */ - private function parseOr(Builder $builder, array $arguments): Builder - { - $builder->where(function (Builder $orBuilder) use ($arguments) { - foreach ($arguments as $argument) { - if ($argument->operator == "in") { - $orBuilder->orWhereIn($argument->field, $argument->value); - } else if ($argument->operator == "nin") { - $orBuilder->orWhereNotIn($argument->field, $argument->value); - } else if ($argument->operator == "exists") { - $orBuilder->where($argument->field, "!=", ""); - $orBuilder->where($argument->field, "!=", null); - } elseif ($argument->operator == "filter") { - $orBuilder->whereJsonContains($argument->field, [$argument->value]); - // 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 { - $orBuilder->orWhere($argument->field, $argument->operator, $argument->value); - } - } - }); - return $builder; - } - - } diff --git a/src/Query/Graph.php b/src/Query/Graph.php index dd6d10c..bd7a61c 100644 --- a/src/Query/Graph.php +++ b/src/Query/Graph.php @@ -2,9 +2,9 @@ namespace Lucent\Query; -use Lucent\Edge\Edge; -use Lucent\Record\QueryRecord; -use Lucent\Record\Record; +use Lucent\Graph\Edge\Edge; +use Lucent\Graph\Record\QueryRecord; +use Lucent\Graph\Record\Record; use Lucent\Support\Collection; use Lucent\Support\Option\Option; @@ -21,7 +21,7 @@ final class Graph public Collection $records, public Collection $edges, public Collection $parentEdges, - public QueryOptions $queryOptions, + public Builder $queryBuilder, public ?int $total = null, ) { @@ -40,7 +40,7 @@ final class Graph public function hasResults(): bool { - return !empty($this->records); + return $this->rootRecords->isNotEmpty(); } public function tree(): Collection @@ -54,16 +54,16 @@ final class Graph public function findChildren(QueryRecord $record, int $depth = 1): QueryRecord { - if ($this->queryOptions->childrenDepth < $depth) { + if ($this->queryBuilder->childrenDepth < $depth) { return $record; } $record->_children = $this->edges ->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->field . $ed->target . $ed->source) ->sort(fn($a, $b) => $a->rank <=> $b->rank) ->values() ->map(function (Edge $edge): Option { - $records = $this->records->filter(fn(Record $rec) => $rec->id == $edge->target)->values(); + $records = $this->records->filter(fn(Record $rec) => $rec->id === $edge->target)->values(); if ($records->isEmpty()) { return none(); } @@ -82,7 +82,7 @@ final class Graph public function findParents(QueryRecord $record, int $depth = 1): QueryRecord { - if ($this->queryOptions->parentsDepth < $depth) { + if ($this->queryBuilder->parentsDepth < $depth) { return $record; } $record->_parents = $this->parentEdges diff --git a/src/Query/Operator.php b/src/Query/Operator.php index 879e6cd..3912ac9 100644 --- a/src/Query/Operator.php +++ b/src/Query/Operator.php @@ -6,7 +6,7 @@ namespace Lucent\Query; final class Operator { /** - * @psalm-param string[] $uis + * @param string[] $uis */ public function __construct( public string $name, diff --git a/src/Query/Query.php b/src/Query/Query.php index d38108f..6ae727d 100644 --- a/src/Query/Query.php +++ b/src/Query/Query.php @@ -2,63 +2,41 @@ namespace Lucent\Query; -use Illuminate\Database\Query\Builder; +use Illuminate\Database\Query\Builder as LaravelBuilder; use Illuminate\Support\Facades\DB; +use Lucent\Graph\Record\Mapper; +use Lucent\Graph\Edge\Mapper as EdgeMapper; use Lucent\Query\DatabaseGraph\DatabaseGraph; -use Lucent\Query\Filter\AndFilter; -use Lucent\Query\Filter\OrFilter; -use Lucent\Record\InputFormatter; -use Lucent\Record\Mapper; -use Lucent\Record\Record; use Lucent\Support\Collection; -final class Query +final class Query { - /** - * @var array $filters - */ - public array $filters; - public QueryOptions $options; - public function __construct( - public readonly FilterParser $filterParser, - public readonly InputFormatter $inputFormatter, - public readonly DatabaseGraph $databaseGraph, - public readonly Mapper $recordMapper, + public readonly FilterParser $filterParser, + public readonly DatabaseGraph $databaseGraph, + public readonly Mapper $recordMapper, + public readonly EdgeMapper $edgeMapper, ) { - $this->options = new QueryOptions(); } - public function filter(array $filterArguments): Query + public function run(callable $builderFunc): Graph { - $this->filters[] = new AndFilter($filterArguments); - return $this; - } - - public function orFilter(array $filterArguments): Query - { - $this->filters[] = new OrFilter($filterArguments); - return $this; - } - - - public function run(): Graph - { - $rootRecords = $this->mainQuery(); + $builder = $builderFunc(new Builder()); + [$rootRecords, $total] = $this->mainQuery($builder); $ids = $rootRecords->pluck("id"); $resultChildrenEdgesTargetIds = []; $resultChildrenEdges = new Collection(); - if ($this->options->childrenDepth > 0 && $ids->isNotEmpty()) { - $resultChildrenEdges = $this->databaseGraph->getChildren($ids->toArray(), $this->options); + if ($builder->childrenDepth > 0 && $ids->isNotEmpty()) { + $resultChildrenEdges = $this->databaseGraph->getChildren($ids->toArray(), $builder)->map([$this->edgeMapper, 'fromDB']); $resultChildrenEdgesTargetIds = $resultChildrenEdges->pluck("target"); } $resultParentSourceTargetIds = []; $resultParentEdges = new Collection(); - if ($this->options->parentsDepth > 0 && $ids->isNotEmpty()) { - $resultParentEdges = $this->databaseGraph->getParents($ids->toArray(), $this->options); + if ($builder->parentsDepth > 0 && $ids->isNotEmpty()) { + $resultParentEdges = $this->databaseGraph->getParents($ids->toArray(), $builder)->map([$this->edgeMapper, 'fromDB']); $resultParentSourceTargetIds = $resultParentEdges->pluck("source"); } @@ -67,7 +45,7 @@ final class Query if (!empty($edgesIds)) { $edgeRecords = new Collection(DB::table('records') ->whereIn("id", $edgesIds) - ->whereIn("status", $this->options->status) + ->whereIn("status", $builder->status) ->get()->map([$this->recordMapper, 'fromDB'])); } @@ -76,127 +54,43 @@ final class Query $edgeRecords, $resultChildrenEdges, $resultParentEdges, - $this->options + $builder, + $total ); - $this->reset(); return $graph; - } - private function reset(): void - { - $this->options = new QueryOptions(); - $this->filters = []; - } - public function tree(): Collection - { - return $this->run()->tree(); - } - - private function parseFilters(Builder $query): Builder - { - foreach ($this->filters as $filter) { - $query = $this->filterParser->parse($query, $filter); - } - $query->whereIn("status", $this->options->status); - return $query; - } /** - * @return Collection + * @return array[Collection,?int] */ - private function mainQuery(): Collection + private function mainQuery(Builder $builder): array { $query = DB::table("records"); - $query = $this->parseFilters($query); - if ($this->options->limit > 0) { - $query->limit($this->options->limit); - $query->offset($this->options->skip); + $query = $builder->resolveRecordFilters($query); + $query = $builder->resolveReferenceFilters($query); + $query = $builder->resolveEdgeFilters($query); + $query->whereIn("status", $builder->status); + + $total = null; + + if ($builder->withCount) { + $total = $query->count(); } - $query = $this->orderByQuery($query); - return new Collection($query->get()->map([$this->recordMapper, 'fromDB'])); + + if ($builder->limit > 0) { + $query->limit($builder->limit); + $query->offset($builder->skip); + } + + $query = $this->orderByQuery($query, $builder); + return [new Collection($query->get()->map([$this->recordMapper, 'fromDB'])), $total]; } - - public - function runWithCount(): Graph + public function orderByQuery(LaravelBuilder $query, Builder $builder): LaravelBuilder { - - $query = DB::table("records"); - $query = $this->parseFilters($query); - $graph = $this->run(); - $graph->total = $query->count(); - return $graph; - } - - - public function limit(int $limit): Query - { - $this->options->limit = $limit; - return $this; - } - - public - function skip(int $skip): Query - { - $this->options->skip = $skip; - return $this; - } - - public function childrenDepth(int $depth): Query - { - $this->options->childrenDepth = $depth; - return $this; - } - - public function childrenLimit(int $limit): Query - { - $this->options->childrenLimit = $limit; - 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; - return $this; - } - - public function parentsLimit(int $limit): Query - { - $this->options->parentsLimit = $limit; - return $this; - } - - - public function sort(string $sort): Query - { - $this->options->sort[] = $sort; - return $this; - } - - public function status(array $status): Query - { - $this->options->status = $status; - return $this; - } - - public - function orderByQuery(Builder $query): Builder - { - foreach ($this->options->sort as $item) { + foreach ($builder->sort as $item) { $field = str_replace(".", "->", ltrim($item, '-')); $dir = str_starts_with($item, '-') ? "desc" : "asc"; if ($field) { diff --git a/src/Query/QueryOptions.php b/src/Query/QueryOptions.php deleted file mode 100644 index 4c03aa0..0000000 --- a/src/Query/QueryOptions.php +++ /dev/null @@ -1,25 +0,0 @@ - response($result->success()->get(), $successCode ?? 200), + Success::class => response(toArray($result->success()->get()), $successCode ?? 200), Error::class => response([ "error" => $result->error()->get() ], $errorCode ?? 400) diff --git a/src/Revision/Revision.php b/src/Revision/Revision.php index c4f83ad..1a80462 100644 --- a/src/Revision/Revision.php +++ b/src/Revision/Revision.php @@ -3,12 +3,10 @@ namespace Lucent\Revision; use Illuminate\Support\Str; -use Lucent\Edge\EdgeCollection; -use Lucent\Record\FileInfo; -use Lucent\Record\Record; -use Lucent\Record\RecordData; -use Lucent\Record\System; -use PhpOption\Option; +use Lucent\Graph\Data\FieldData; +use Lucent\Graph\Edge\EdgeCollection; +use Lucent\Graph\Record\Record; +use Lucent\Graph\Record\System; readonly class Revision { @@ -16,20 +14,16 @@ readonly class Revision /** * @param string $id * @param string $recordId - * @param string $schema * @param System $_sys - * @param RecordData $data + * @param FieldData $data * @param EdgeCollection $_edges - * @param Option $_file */ function __construct( - public string $id, - public string $recordId, - public string $schema, - public System $_sys, - public RecordData $data, - public EdgeCollection $_edges, - public Option $_file, + public string $id, + public string $recordId, + public System $_sys, + public FieldData $data, + public EdgeCollection $_edges, ) { @@ -45,11 +39,9 @@ readonly class Revision return new Revision( id: (string)Str::uuid(), recordId: $record->id, - schema: $record->schema, _sys: $record->_sys, data: $record->data, _edges: $edges, - _file: empty($record->_file) ? none() : some($record->_file) ); } diff --git a/src/Revision/RevisionRepo.php b/src/Revision/RevisionRepo.php index 163feb4..364edd7 100644 --- a/src/Revision/RevisionRepo.php +++ b/src/Revision/RevisionRepo.php @@ -3,10 +3,8 @@ namespace Lucent\Revision; use Illuminate\Support\Facades\DB; -use Lucent\Edge\EdgeCollection; -use Lucent\Record\FileInfo; -use Lucent\Record\RecordData; -use Lucent\Record\System; +use Lucent\Graph\Data\FieldData; +use Lucent\Graph\Record\System; use Lucent\Support\Collection; use PhpOption\Option; use stdClass; @@ -77,11 +75,9 @@ class RevisionRepo return [ "id" => $revision->id, "recordId" => $revision->recordId, - "schema" => $revision->schema, "_sys" => json_encode($revision->_sys), - "_file" => $revision->_file->map(fn($v) => json_encode($v))->getOrElse(null), "data" => json_encode($revision->data), - "_edges" => $revision->_edges->getOrElse(null)->toJson(), + "_edges" => $revision->_edges->toJson(), ]; } @@ -92,11 +88,9 @@ class RevisionRepo return new Revision( id: $data->id, recordId: $data->recordId, - schema: $data->schema, _sys: System::fromArray(json_decode($data->_sys, true)), - data: new RecordData(json_decode($data->data, true)), - _edges: Option::fromValue($data->_edges)->map([EdgeCollection::class,'fromJson']), - _file: Option::fromValue($data->_file)->map([FileInfo::class,'fromJSON']) + data: new FieldData(json_decode($data->data, true)), + _edges: $data->_edges->fromJson($data->_edges), ); } } diff --git a/src/Revision/RevisionService.php b/src/Revision/RevisionService.php index 5b2f3c7..10f0c40 100644 --- a/src/Revision/RevisionService.php +++ b/src/Revision/RevisionService.php @@ -3,8 +3,8 @@ namespace Lucent\Revision; use Lucent\Channel\ChannelService; -use Lucent\Edge\EdgeCollection; -use Lucent\Record\Record; +use Lucent\Graph\Edge\EdgeCollection; +use Lucent\Graph\Record\Record; use Lucent\Support\Collection; use PhpOption\Option; @@ -13,7 +13,7 @@ readonly class RevisionService public function __construct( private ChannelService $channelService, - private RevisionRepo $revisionRepo, + private RevisionRepo $revisionRepo, ) { } @@ -42,15 +42,15 @@ readonly class RevisionService * @param EdgeCollection $edges * @return void */ - public function create(Record $record,EdgeCollection $edges): void + public function create(Record $record, EdgeCollection $edges): void { $schema = $this->channelService->getSchema($record->schema)->get(); - if($schema->revisions <= 0){ + if ($schema->revisions <= 0) { return; } $revision = Revision::fromRecord($record, $edges); $this->revisionRepo->create($revision); - $this->revisionRepo->cleanupRecord($record->id,$schema->revisions); + $this->revisionRepo->cleanupRecord($record->id, $schema->revisions); } diff --git a/src/Schema/BlockUi/Heading.php b/src/Schema/BlockUi/Heading.php index dcfbf86..1e18e83 100644 --- a/src/Schema/BlockUi/Heading.php +++ b/src/Schema/BlockUi/Heading.php @@ -2,7 +2,7 @@ namespace Lucent\Schema\BlockUi; -use Lucent\Record\RecordData; +use Lucent\Graph\Data\FieldData; use Lucent\Schema\Field\FieldDataInterface; use Lucent\Schema\Field\FieldInfo; use Lucent\Schema\Field\FieldInterface; @@ -23,7 +23,7 @@ class Heading implements FieldInterface,FieldDataInterface $this->info = new FieldInfo("heading", "Heading", FieldType::STRING); } - public function format(RecordData $input, RecordData $output): RecordData + public function format(FieldData $input, FieldData $output): FieldData { $value = $input->get($this->name); $output->set($this->name,$value); diff --git a/src/Schema/BlockUi/Markdown.php b/src/Schema/BlockUi/Markdown.php index 0be9082..0610237 100644 --- a/src/Schema/BlockUi/Markdown.php +++ b/src/Schema/BlockUi/Markdown.php @@ -2,7 +2,7 @@ namespace Lucent\Schema\BlockUi; -use Lucent\Record\RecordData; +use Lucent\Graph\Data\FieldData; use Lucent\Schema\Field\FieldDataInterface; use Lucent\Schema\Field\FieldInfo; use Lucent\Schema\Field\FieldInterface; @@ -23,7 +23,7 @@ class Markdown implements FieldInterface,FieldDataInterface $this->info = new FieldInfo("markdown", "Markdown Editor", FieldType::STRING); } - public function format(RecordData $input, RecordData $output): RecordData + public function format(FieldData $input, FieldData $output): FieldData { $value = $input->get($this->name); $output->set($this->name,$value); diff --git a/src/Schema/BlockUi/Rich.php b/src/Schema/BlockUi/Rich.php index 31ec3af..d6ed33d 100644 --- a/src/Schema/BlockUi/Rich.php +++ b/src/Schema/BlockUi/Rich.php @@ -2,7 +2,7 @@ namespace Lucent\Schema\BlockUi; -use Lucent\Record\RecordData; +use Lucent\Graph\Data\FieldData; use Lucent\Schema\Field\FieldDataInterface; use Lucent\Schema\Field\FieldInfo; use Lucent\Schema\Field\FieldInterface; @@ -23,7 +23,7 @@ class Rich implements FieldInterface,FieldDataInterface $this->info = new FieldInfo("rich", "Rich Editor", FieldType::STRING); } - public function format(RecordData $input, RecordData $output): RecordData + public function format(FieldData $input, FieldData $output): FieldData { $value = $input->get($this->name); $output->set($this->name,$value); diff --git a/src/Schema/BlockUi/Textarea.php b/src/Schema/BlockUi/Textarea.php index 35ff320..891252e 100644 --- a/src/Schema/BlockUi/Textarea.php +++ b/src/Schema/BlockUi/Textarea.php @@ -2,7 +2,7 @@ namespace Lucent\Schema\BlockUi; -use Lucent\Record\RecordData; +use Lucent\Graph\Data\FieldData; use Lucent\Schema\Field\FieldDataInterface; use Lucent\Schema\Field\FieldInfo; use Lucent\Schema\Field\FieldInterface; @@ -23,7 +23,7 @@ class Textarea implements FieldInterface,FieldDataInterface $this->info = new FieldInfo("textarea", "Textarea", FieldType::STRING); } - public function format(RecordData $input, RecordData $output): RecordData + public function format(FieldData $input, FieldData $output): FieldData { $value = $input->get($this->name); $output->set($this->name,$value); diff --git a/src/Schema/Field/FieldDataInterface.php b/src/Schema/Field/FieldDataInterface.php index 0f6bc21..cc0241e 100644 --- a/src/Schema/Field/FieldDataInterface.php +++ b/src/Schema/Field/FieldDataInterface.php @@ -3,11 +3,11 @@ namespace Lucent\Schema\Field; -use Lucent\Record\RecordData; +use Lucent\Graph\Data\FieldData; interface FieldDataInterface { - public function format(RecordData $input, RecordData $output): RecordData; + public function format(FieldData $input, FieldData $output): FieldData; public function isRequired(): bool; diff --git a/src/Schema/Ui/Block.php b/src/Schema/Ui/Block.php index 9d01b87..875b737 100644 --- a/src/Schema/Ui/Block.php +++ b/src/Schema/Ui/Block.php @@ -2,10 +2,10 @@ namespace Lucent\Schema\Ui; +use Lucent\Graph\Data\FieldData; use Lucent\JsonSchema\Property\Property; use Lucent\JsonSchema\Property\PropertyType; use Lucent\JsonSchema\Property\TypeProperty; -use Lucent\Record\RecordData; use Lucent\Schema\Field\FieldDataInterface; use Lucent\Schema\Field\FieldInfo; use Lucent\Schema\Field\FieldInterface; @@ -31,7 +31,7 @@ class Block implements FieldInterface, FieldDataInterface, RequiredInterface $this->info = new FieldInfo("block", "Block editor", FieldType::JSON); } - public function format(RecordData $input, RecordData $output): RecordData + public function format(FieldData $input, FieldData $output): FieldData { $value = $input->get($this->name); diff --git a/src/Schema/Ui/Checkbox.php b/src/Schema/Ui/Checkbox.php index d976997..de211d8 100644 --- a/src/Schema/Ui/Checkbox.php +++ b/src/Schema/Ui/Checkbox.php @@ -2,10 +2,10 @@ namespace Lucent\Schema\Ui; +use Lucent\Graph\Data\FieldData; use Lucent\JsonSchema\Property\Property; use Lucent\JsonSchema\Property\PropertyType; use Lucent\JsonSchema\Property\TypeProperty; -use Lucent\Record\RecordData; use Lucent\Schema\Field\FieldDataInterface; use Lucent\Schema\Field\FieldInfo; use Lucent\Schema\Field\FieldInterface; @@ -33,7 +33,7 @@ class Checkbox implements FieldInterface,FieldDataInterface, RequiredInterface $this->info = new FieldInfo("checkbox", "Block Checkbox", FieldType::BOOLEAN); } - public function format(RecordData $input, RecordData $output): RecordData + public function format(FieldData $input, FieldData $output): FieldData { $value = $input->get($this->name); diff --git a/src/Schema/Ui/Color.php b/src/Schema/Ui/Color.php index 19e2d7e..ae527ad 100644 --- a/src/Schema/Ui/Color.php +++ b/src/Schema/Ui/Color.php @@ -2,10 +2,10 @@ namespace Lucent\Schema\Ui; +use Lucent\Graph\Data\FieldData; use Lucent\JsonSchema\Property\Property; use Lucent\JsonSchema\Property\PropertyType; use Lucent\JsonSchema\Property\TypeProperty; -use Lucent\Record\RecordData; use Lucent\Schema\Field\FieldDataInterface; use Lucent\Schema\Field\FieldInfo; use Lucent\Schema\Field\FieldInterface; @@ -34,7 +34,7 @@ class Color implements FieldInterface,FieldDataInterface, RequiredInterface $this->info = new FieldInfo("color", "Color", FieldType::STRING); } - public function format(RecordData $input, RecordData $output): RecordData + public function format(FieldData $input, FieldData $output): FieldData { $value = $input->get($this->name); $output->set($this->name,$value); diff --git a/src/Schema/Ui/Date.php b/src/Schema/Ui/Date.php index 43d28e1..81485a7 100644 --- a/src/Schema/Ui/Date.php +++ b/src/Schema/Ui/Date.php @@ -3,10 +3,10 @@ namespace Lucent\Schema\Ui; use Carbon\Carbon; +use Lucent\Graph\Data\FieldData; use Lucent\JsonSchema\Property\Property; use Lucent\JsonSchema\Property\PropertyType; use Lucent\JsonSchema\Property\TypeProperty; -use Lucent\Record\RecordData; use Lucent\Schema\Field\FieldDataInterface; use Lucent\Schema\Field\FieldInfo; use Lucent\Schema\Field\FieldInterface; @@ -37,7 +37,7 @@ class Date implements FieldInterface,FieldDataInterface, RequiredInterface, MinM $this->info = new FieldInfo("date", "Date", FieldType::STRING); } - public function format(RecordData $input, RecordData $output): RecordData + public function format(FieldData $input, FieldData $output): FieldData { $value = $input->get($this->name); if (empty($value)) { diff --git a/src/Schema/Ui/Datetime.php b/src/Schema/Ui/Datetime.php index 0a305f5..da2bb6c 100644 --- a/src/Schema/Ui/Datetime.php +++ b/src/Schema/Ui/Datetime.php @@ -3,10 +3,10 @@ namespace Lucent\Schema\Ui; use Carbon\Carbon; +use Lucent\Graph\Data\FieldData; use Lucent\JsonSchema\Property\Property; use Lucent\JsonSchema\Property\PropertyType; use Lucent\JsonSchema\Property\TypeProperty; -use Lucent\Record\RecordData; use Lucent\Schema\Field\FieldDataInterface; use Lucent\Schema\Field\FieldInfo; use Lucent\Schema\Field\FieldInterface; @@ -37,7 +37,7 @@ class Datetime implements FieldInterface,FieldDataInterface, RequiredInterface, $this->info = new FieldInfo("datetime", "Datetime", FieldType::STRING); } - public function format(RecordData $input, RecordData $output): RecordData + public function format(FieldData $input, FieldData $output): FieldData { $value = $input->get($this->name); if (empty($value)) { diff --git a/src/Schema/Ui/Json.php b/src/Schema/Ui/Json.php index 13ff423..5d7f3a2 100644 --- a/src/Schema/Ui/Json.php +++ b/src/Schema/Ui/Json.php @@ -2,10 +2,10 @@ namespace Lucent\Schema\Ui; +use Lucent\Graph\Data\FieldData; use Lucent\JsonSchema\Property\Property; use Lucent\JsonSchema\Property\PropertyType; use Lucent\JsonSchema\Property\TypeProperty; -use Lucent\Record\RecordData; use Lucent\Schema\Field\FieldDataInterface; use Lucent\Schema\Field\FieldInfo; use Lucent\Schema\Field\FieldInterface; @@ -32,7 +32,7 @@ class Json implements FieldInterface,FieldDataInterface, RequiredInterface $this->info = new FieldInfo("json", "JSON", FieldType::JSON); } - public function format(RecordData $input, RecordData $output): RecordData + public function format(FieldData $input, FieldData $output): FieldData { $value = $input->get($this->name); diff --git a/src/Schema/Ui/Markdown.php b/src/Schema/Ui/Markdown.php index 64383b5..af20ad6 100644 --- a/src/Schema/Ui/Markdown.php +++ b/src/Schema/Ui/Markdown.php @@ -2,10 +2,10 @@ namespace Lucent\Schema\Ui; +use Lucent\Graph\Data\FieldData; use Lucent\JsonSchema\Property\Property; use Lucent\JsonSchema\Property\PropertyType; use Lucent\JsonSchema\Property\TypeProperty; -use Lucent\Record\RecordData; use Lucent\Schema\Field\FieldDataInterface; use Lucent\Schema\Field\FieldInfo; use Lucent\Schema\Field\FieldInterface; @@ -32,7 +32,7 @@ class Markdown implements FieldInterface,FieldDataInterface, RequiredInterface $this->info = new FieldInfo("markdown", "Markdown editor", FieldType::STRING); } - public function format(RecordData $input, RecordData $output): RecordData + public function format(FieldData $input, FieldData $output): FieldData { $value = $input->get($this->name); $output->set($this->name,$value); diff --git a/src/Schema/Ui/Number.php b/src/Schema/Ui/Number.php index 6086c7d..33e9fbc 100644 --- a/src/Schema/Ui/Number.php +++ b/src/Schema/Ui/Number.php @@ -2,10 +2,10 @@ namespace Lucent\Schema\Ui; +use Lucent\Graph\Data\FieldData; use Lucent\JsonSchema\Property\Property; use Lucent\JsonSchema\Property\PropertyType; use Lucent\JsonSchema\Property\TypeProperty; -use Lucent\Record\RecordData; use Lucent\Schema\Field\FieldDataInterface; use Lucent\Schema\Field\FieldInfo; use Lucent\Schema\Field\FieldInterface; @@ -37,7 +37,7 @@ class Number implements FieldInterface, RequiredInterface,FieldDataInterface, Mi $this->info = new FieldInfo("number", "Number", FieldType::NUMBER); } - public function format(RecordData $input, RecordData $output): RecordData + public function format(FieldData $input, FieldData $output): FieldData { $value = $input->get($this->name); if (!is_numeric($value)) { diff --git a/src/Schema/Ui/Rich.php b/src/Schema/Ui/Rich.php index e501cec..e37c87b 100644 --- a/src/Schema/Ui/Rich.php +++ b/src/Schema/Ui/Rich.php @@ -2,10 +2,10 @@ namespace Lucent\Schema\Ui; +use Lucent\Graph\Data\FieldData; use Lucent\JsonSchema\Property\Property; use Lucent\JsonSchema\Property\PropertyType; use Lucent\JsonSchema\Property\TypeProperty; -use Lucent\Record\RecordData; use Lucent\Schema\Field\FieldDataInterface; use Lucent\Schema\Field\FieldInfo; use Lucent\Schema\Field\FieldInterface; @@ -32,7 +32,7 @@ class Rich implements FieldInterface,FieldDataInterface, RequiredInterface $this->info = new FieldInfo("rich", "Rich editor", FieldType::STRING); } - public function format(RecordData $input, RecordData $output): RecordData + public function format(FieldData $input, FieldData $output): FieldData { $value = $input->get($this->name); $output->set($this->name,$value); diff --git a/src/Schema/Ui/Slug.php b/src/Schema/Ui/Slug.php index 6ad8c1b..ce87f08 100644 --- a/src/Schema/Ui/Slug.php +++ b/src/Schema/Ui/Slug.php @@ -3,10 +3,10 @@ namespace Lucent\Schema\Ui; use Illuminate\Support\Str; +use Lucent\Graph\Data\FieldData; use Lucent\JsonSchema\Property\Property; use Lucent\JsonSchema\Property\PropertyType; use Lucent\JsonSchema\Property\TypeProperty; -use Lucent\Record\RecordData; use Lucent\Schema\Field\FieldDataInterface; use Lucent\Schema\Field\FieldInfo; use Lucent\Schema\Field\FieldInterface; @@ -34,7 +34,7 @@ class Slug implements FieldInterface,FieldDataInterface, RequiredInterface $this->info = new FieldInfo("slug", "Slug", FieldType::STRING); } - public function format(RecordData $input, RecordData $output): RecordData + public function format(FieldData $input, FieldData $output): FieldData { $value = $input->get($this->name); if (empty($value)) { diff --git a/src/Schema/Ui/Text.php b/src/Schema/Ui/Text.php index 330985c..6a15ae8 100644 --- a/src/Schema/Ui/Text.php +++ b/src/Schema/Ui/Text.php @@ -2,10 +2,10 @@ namespace Lucent\Schema\Ui; +use Lucent\Graph\Data\FieldData; use Lucent\JsonSchema\Property\Property; use Lucent\JsonSchema\Property\PropertyType; use Lucent\JsonSchema\Property\TypeProperty; -use Lucent\Record\RecordData; use Lucent\Schema\Field\FieldDataInterface; use Lucent\Schema\Field\FieldInfo; use Lucent\Schema\Field\FieldInterface; @@ -36,7 +36,7 @@ class Text implements FieldInterface,FieldDataInterface, RequiredInterface $this->info = new FieldInfo("text", "Text", FieldType::STRING); } - public function format(RecordData $input, RecordData $output): RecordData + public function format(FieldData $input, FieldData $output): FieldData { $value = $input->get($this->name); $output->set($this->name,$value); diff --git a/src/Schema/Ui/Textarea.php b/src/Schema/Ui/Textarea.php index 9e712fb..10ea88f 100644 --- a/src/Schema/Ui/Textarea.php +++ b/src/Schema/Ui/Textarea.php @@ -2,10 +2,10 @@ namespace Lucent\Schema\Ui; +use Lucent\Graph\Data\FieldData; use Lucent\JsonSchema\Property\Property; use Lucent\JsonSchema\Property\PropertyType; use Lucent\JsonSchema\Property\TypeProperty; -use Lucent\Record\RecordData; use Lucent\Schema\Field\FieldDataInterface; use Lucent\Schema\Field\FieldInfo; use Lucent\Schema\Field\FieldInterface; @@ -33,7 +33,7 @@ class Textarea implements FieldInterface,FieldDataInterface, RequiredInterface $this->info = new FieldInfo("textarea", "Textarea", FieldType::STRING); } - public function format(RecordData $input, RecordData $output): RecordData + public function format(FieldData $input, FieldData $output): FieldData { $value = $input->get($this->name); $output->set($this->name,$value); diff --git a/src/Schema/Ui/Uuid.php b/src/Schema/Ui/Uuid.php index 15d8c21..831424c 100644 --- a/src/Schema/Ui/Uuid.php +++ b/src/Schema/Ui/Uuid.php @@ -2,10 +2,10 @@ namespace Lucent\Schema\Ui; +use Lucent\Graph\Data\FieldData; use Lucent\JsonSchema\Property\Property; use Lucent\JsonSchema\Property\PropertyType; use Lucent\JsonSchema\Property\TypeProperty; -use Lucent\Record\RecordData; use Lucent\Schema\Field\FieldDataInterface; use Lucent\Schema\Field\FieldInfo; use Lucent\Schema\Field\FieldInterface; @@ -30,7 +30,7 @@ class Uuid implements FieldInterface,FieldDataInterface, RequiredInterface $this->info = new FieldInfo("uuid", "FieldType", FieldType::STRING); } - public function format(RecordData $input, RecordData $output): RecordData + public function format(FieldData $input, FieldData $output): FieldData { $value = $input->get($this->name); $output->set($this->name,$value); diff --git a/src/Schema/Validator/Validator.php b/src/Schema/Validator/Validator.php index 2e9cccf..739c142 100644 --- a/src/Schema/Validator/Validator.php +++ b/src/Schema/Validator/Validator.php @@ -3,7 +3,7 @@ namespace Lucent\Schema\Validator; use Lucent\Channel\ChannelService; -use Lucent\Record\RecordData; +use Lucent\Graph\Data\FieldData; use Lucent\Schema\Field\FieldDataInterface; use Lucent\Support\Collection; use Lucent\Support\Option\Option; @@ -23,8 +23,8 @@ class Validator * @return Collection */ public function check( - string $schemaName, - RecordData $data, + string $schemaName, + FieldData $data, ): Collection { @@ -39,10 +39,10 @@ class Validator /** * @param FieldDataInterface $field - * @param RecordData $recordData + * @param FieldData $recordData * @return Option */ - public function validate(FieldDataInterface $field, RecordData $recordData): Option + public function validate(FieldDataInterface $field, FieldData $recordData): Option { $value = $recordData->get($field->name);