diff --git a/packages/solid/src/SolidLdoDataset.ts b/packages/solid/src/SolidLdoDataset.ts index e464642..34d8012 100644 --- a/packages/solid/src/SolidLdoDataset.ts +++ b/packages/solid/src/SolidLdoDataset.ts @@ -7,10 +7,11 @@ import type { } from "./requester/requests/updateDataResource"; import { AggregateError } from "./requester/results/error/ErrorResult"; import { InvalidUriError } from "./requester/results/error/InvalidUriError"; -import { AggregateSuccess } from "./requester/results/success/SuccessResult"; +import type { AggregateSuccess } from "./requester/results/success/SuccessResult"; import type { UpdateSuccess } from "./requester/results/success/UpdateSuccess"; import type { Container } from "./resource/Container"; import type { Leaf } from "./resource/Leaf"; +import type { ResourceResult } from "./resource/resourceResult/ResourceResult"; import type { ResourceGetterOptions } from "./ResourceStore"; import type { SolidLdoDatasetContext } from "./SolidLdoDatasetContext"; import { splitChangesByGraph } from "./util/splitChangesByGraph"; @@ -39,7 +40,7 @@ export class SolidLdoDataset extends LdoDataset { async commitChangesToPod( changes: DatasetChanges, ): Promise< - | AggregateSuccess + | AggregateSuccess> | AggregateError > { const changesByGraph = splitChangesByGraph(changes); @@ -84,12 +85,15 @@ export class SolidLdoDataset extends LdoDataset { ), ); } - return new AggregateSuccess( - results + return { + isError: false, + type: "aggregateSuccess", + results: results .map((result) => result[2]) .filter( - (result): result is UpdateSuccess => result.type === "updateSuccess", + (result): result is ResourceResult => + result.type === "updateSuccess", ), - ); + }; } } diff --git a/packages/solid/src/requester/requests/checkRootContainer.ts b/packages/solid/src/requester/requests/checkRootContainer.ts index 0269178..8900f05 100644 --- a/packages/solid/src/requester/requests/checkRootContainer.ts +++ b/packages/solid/src/requester/requests/checkRootContainer.ts @@ -1,7 +1,7 @@ import type { BasicRequestOptions } from "./requestOptions"; import { parse as parseLinkHeader } from "http-link-header"; import { NoncompliantPodError } from "../results/error/NoncompliantPodError"; -import { CheckRootContainerSuccess } from "../results/success/CheckRootContainerSuccess"; +import type { CheckRootContainerSuccess } from "../results/success/CheckRootContainerSuccess"; import type { HttpErrorResultType, UnexpectedHttpError, @@ -28,10 +28,15 @@ export function checkHeadersForRootContainer( } const parsedLinkHeader = parseLinkHeader(linkHeader); const types = parsedLinkHeader.get("rel", "type"); - const isRoot = types.some( + const isRootContainer = types.some( (type) => type.uri === "http://www.w3.org/ns/pim/space#Storage", ); - return new CheckRootContainerSuccess(uri, isRoot); + return { + uri, + isRootContainer, + type: "checkRootContainerSuccess", + isError: false, + }; } export async function checkRootContainer( diff --git a/packages/solid/src/requester/requests/createDataResource.ts b/packages/solid/src/requester/requests/createDataResource.ts index 95dab55..b9d848a 100644 --- a/packages/solid/src/requester/requests/createDataResource.ts +++ b/packages/solid/src/requester/requests/createDataResource.ts @@ -9,7 +9,7 @@ import { isContainerUri } from "../../util/uriTypes"; import { UnexpectedResourceError } from "../results/error/ErrorResult"; import type { HttpErrorResultType } from "../results/error/HttpErrorResult"; import { HttpErrorResult } from "../results/error/HttpErrorResult"; -import { CreateSuccess } from "../results/success/CreateSuccess"; +import type { CreateSuccess } from "../results/success/CreateSuccess"; import type { AbsentReadSuccess } from "../results/success/ReadSuccess"; import type { DeleteResultError } from "./deleteResource"; import { deleteResource } from "./deleteResource"; @@ -134,7 +134,12 @@ export async function createDataResource( if (options?.dataset) { addResourceRdfToContainer(uri, options.dataset); } - return new CreateSuccess(uri, !!overwrite); + return { + isError: false, + type: "createSuccess", + uri, + didOverwrite: !!overwrite, + }; } catch (err) { return UnexpectedResourceError.fromThrown(uri, err); } diff --git a/packages/solid/src/requester/requests/deleteResource.ts b/packages/solid/src/requester/requests/deleteResource.ts index 1e6b0e7..0479d05 100644 --- a/packages/solid/src/requester/requests/deleteResource.ts +++ b/packages/solid/src/requester/requests/deleteResource.ts @@ -5,7 +5,7 @@ import { UnexpectedResourceError } from "../results/error/ErrorResult"; import type { HttpErrorResultType } from "../results/error/HttpErrorResult"; import { UnexpectedHttpError } from "../results/error/HttpErrorResult"; import { HttpErrorResult } from "../results/error/HttpErrorResult"; -import { DeleteSuccess } from "../results/success/DeleteSuccess"; +import type { DeleteSuccess } from "../results/success/DeleteSuccess"; import type { DatasetRequestOptions } from "./requestOptions"; export type DeleteResult = DeleteSuccess | DeleteResultError; @@ -36,7 +36,12 @@ export async function deleteResource( ); deleteResourceRdfFromContainer(uri, options.dataset); } - return new DeleteSuccess(uri, response.status === 205); + return { + isError: false, + type: "deleteSuccess", + uri, + resourceExisted: response.status === 205, + }; } return new UnexpectedHttpError(uri, response); } catch (err) { diff --git a/packages/solid/src/requester/requests/readResource.ts b/packages/solid/src/requester/requests/readResource.ts index 4b82d87..1643ff3 100644 --- a/packages/solid/src/requester/requests/readResource.ts +++ b/packages/solid/src/requester/requests/readResource.ts @@ -10,12 +10,12 @@ import { import type { DatasetRequestOptions } from "./requestOptions"; import type { ContainerUri, LeafUri } from "../../util/uriTypes"; import { isContainerUri } from "../../util/uriTypes"; -import { BinaryReadSuccess } from "../results/success/ReadSuccess"; -import { +import type { BinaryReadSuccess } from "../results/success/ReadSuccess"; +import type { ContainerReadSuccess, DataReadSuccess, } from "../results/success/ReadSuccess"; -import { AbsentReadSuccess } from "../results/success/ReadSuccess"; +import type { AbsentReadSuccess } from "../results/success/ReadSuccess"; import { NoncompliantPodError } from "../results/error/NoncompliantPodError"; import { guaranteeFetch } from "../../util/guaranteeFetch"; import { UnexpectedResourceError } from "../results/error/ErrorResult"; @@ -57,7 +57,12 @@ export async function readResource( // Fetch options to determine the document type const response = await fetch(uri); if (response.status === 404) { - return new AbsentReadSuccess(uri, false); + return { + isError: false, + type: "absentReadSuccess", + uri, + recalledFromMemory: false, + }; } const httpErrorResult = HttpErrorResult.checkResponse(uri, response); if (httpErrorResult) return httpErrorResult; @@ -89,13 +94,31 @@ export async function readResource( if (isContainerUri(uri)) { const result = checkHeadersForRootContainer(uri, response.headers); if (result.isError) return result; - return new ContainerReadSuccess(uri, false, result.isRootContainer); + return { + isError: false, + type: "containerReadSuccess", + uri, + recalledFromMemory: false, + isRootContainer: result.isRootContainer, + }; } - return new DataReadSuccess(uri, false); + return { + isError: false, + type: "dataReadSuccess", + uri, + recalledFromMemory: false, + }; } else { // Load Blob const blob = await response.blob(); - return new BinaryReadSuccess(uri, false, blob, contentType); + return { + isError: false, + type: "binaryReadSuccess", + uri, + recalledFromMemory: false, + blob, + mimeType: contentType, + }; } } catch (err) { return UnexpectedResourceError.fromThrown(uri, err); diff --git a/packages/solid/src/requester/requests/setAccessRules.ts b/packages/solid/src/requester/requests/setAccessRules.ts index 4202492..daaace2 100644 --- a/packages/solid/src/requester/requests/setAccessRules.ts +++ b/packages/solid/src/requester/requests/setAccessRules.ts @@ -15,8 +15,8 @@ import { import { guaranteeFetch } from "../../util/guaranteeFetch"; import { isContainerUri } from "../../util/uriTypes"; import type { AccessRule } from "../results/success/AccessRule"; -import { SetAccessRuleSuccess } from "../results/success/AccessRule"; -import { AccessRuleFetchError } from "../results/success/AccessRule"; +import type { SetAccessRuleSuccess } from "../results/success/AccessRule"; +import { AccessRuleFetchError } from "../results/error/AccessControlError"; import type { BasicRequestOptions } from "./requestOptions"; export type SetAccessRulesResult = @@ -78,5 +78,9 @@ export async function setAccessRules( // Now save the ACL: await saveAclFor(myDatasetWithAcl, updatedAcl, { fetch }); - return new SetAccessRuleSuccess(uri); + return { + isError: false, + uri, + type: "setAccessRuleSuccess", + }; } diff --git a/packages/solid/src/requester/results/RequesterResult.ts b/packages/solid/src/requester/results/RequesterResult.ts index 1517c23..978ad6d 100644 --- a/packages/solid/src/requester/results/RequesterResult.ts +++ b/packages/solid/src/requester/results/RequesterResult.ts @@ -1,8 +1,4 @@ -import type { Container } from "../../resource/Container"; -import type { Leaf } from "../../resource/Leaf"; - export interface RequesterResult { type: string; isError: boolean; - resource?: Leaf | Container; } diff --git a/packages/solid/src/requester/results/error/AccessControlError.ts b/packages/solid/src/requester/results/error/AccessControlError.ts new file mode 100644 index 0000000..c9d128a --- /dev/null +++ b/packages/solid/src/requester/results/error/AccessControlError.ts @@ -0,0 +1,9 @@ +import { ResourceError } from "./ErrorResult"; + +export class AccessRuleFetchError extends ResourceError { + readonly type = "accessRuleFetchError" as const; + + constructor(uri: string, message?: string) { + super(uri, message || `${uri} had trouble fetching access rules.`); + } +} diff --git a/packages/solid/src/requester/results/error/ErrorResult.ts b/packages/solid/src/requester/results/error/ErrorResult.ts index e8fa15e..0940884 100644 --- a/packages/solid/src/requester/results/error/ErrorResult.ts +++ b/packages/solid/src/requester/results/error/ErrorResult.ts @@ -1,11 +1,8 @@ -import type { Container } from "../../../resource/Container"; -import type { Leaf } from "../../../resource/Leaf"; import type { RequesterResult } from "../RequesterResult"; export abstract class ErrorResult extends Error implements RequesterResult { abstract type: string; readonly isError = true as const; - resource?: Leaf | Container; constructor(message?: string) { super(message || "An error unkown error was encountered."); diff --git a/packages/solid/src/requester/results/error/InvalidUriError.ts b/packages/solid/src/requester/results/error/InvalidUriError.ts index 477721c..9d4ae6d 100644 --- a/packages/solid/src/requester/results/error/InvalidUriError.ts +++ b/packages/solid/src/requester/results/error/InvalidUriError.ts @@ -2,4 +2,8 @@ import { ResourceError } from "./ErrorResult"; export class InvalidUriError extends ResourceError { readonly type = "invalidUriError" as const; + + constructor(uri: string, message?: string) { + super(uri, message || `${uri} is an invalid uri.`); + } } diff --git a/packages/solid/src/requester/results/success/AccessRule.ts b/packages/solid/src/requester/results/success/AccessRule.ts index 7090c18..975d834 100644 --- a/packages/solid/src/requester/results/success/AccessRule.ts +++ b/packages/solid/src/requester/results/success/AccessRule.ts @@ -1,20 +1,11 @@ import type { Access } from "@inrupt/solid-client"; -import { ResourceError } from "../error/ErrorResult"; -import { ResourceSuccess } from "./SuccessResult"; +import type { ResourceSuccess } from "./SuccessResult"; export interface AccessRule { public?: Access; agent?: Record; } -export class SetAccessRuleSuccess extends ResourceSuccess { - type = "setAccessRuleSuccess" as const; -} - -export class AccessRuleFetchError extends ResourceError { - readonly type = "accessRuleFetchError" as const; - - constructor(uri: string, message?: string) { - super(uri, message || `Cannot get access rules for ${uri}.`); - } +export interface SetAccessRuleSuccess extends ResourceSuccess { + type: "setAccessRuleSuccess"; } diff --git a/packages/solid/src/requester/results/success/CheckRootContainerSuccess.ts b/packages/solid/src/requester/results/success/CheckRootContainerSuccess.ts index a4aad08..5f75605 100644 --- a/packages/solid/src/requester/results/success/CheckRootContainerSuccess.ts +++ b/packages/solid/src/requester/results/success/CheckRootContainerSuccess.ts @@ -1,11 +1,6 @@ -import { ResourceSuccess } from "./SuccessResult"; +import type { ResourceSuccess } from "./SuccessResult"; -export class CheckRootContainerSuccess extends ResourceSuccess { - readonly type = "checkRootContainerSuccess" as const; - readonly isRootContainer: boolean; - - constructor(uri: string, isRootContainer: boolean) { - super(uri); - this.isRootContainer = isRootContainer; - } +export interface CheckRootContainerSuccess extends ResourceSuccess { + type: "checkRootContainerSuccess"; + isRootContainer: boolean; } diff --git a/packages/solid/src/requester/results/success/CreateSuccess.ts b/packages/solid/src/requester/results/success/CreateSuccess.ts index c6de236..190209f 100644 --- a/packages/solid/src/requester/results/success/CreateSuccess.ts +++ b/packages/solid/src/requester/results/success/CreateSuccess.ts @@ -1,11 +1,6 @@ -import { ResourceSuccess } from "./SuccessResult"; +import type { ResourceSuccess } from "./SuccessResult"; -export class CreateSuccess extends ResourceSuccess { - readonly type = "createSuccess"; - readonly didOverwrite: boolean; - - constructor(uri: string, didOverwrite: boolean) { - super(uri); - this.didOverwrite = didOverwrite; - } +export interface CreateSuccess extends ResourceSuccess { + type: "createSuccess"; + didOverwrite: boolean; } diff --git a/packages/solid/src/requester/results/success/DeleteSuccess.ts b/packages/solid/src/requester/results/success/DeleteSuccess.ts index f7fd259..4cb131f 100644 --- a/packages/solid/src/requester/results/success/DeleteSuccess.ts +++ b/packages/solid/src/requester/results/success/DeleteSuccess.ts @@ -1,11 +1,6 @@ -import { ResourceSuccess } from "./SuccessResult"; +import type { ResourceSuccess } from "./SuccessResult"; -export class DeleteSuccess extends ResourceSuccess { - readonly type = "deleteSuccess" as const; - readonly resourceExisted: boolean; - - constructor(uri: string, resourceExisted: boolean) { - super(uri); - this.resourceExisted = resourceExisted; - } +export interface DeleteSuccess extends ResourceSuccess { + type: "deleteSuccess"; + resourceExisted: boolean; } diff --git a/packages/solid/src/requester/results/success/ReadSuccess.ts b/packages/solid/src/requester/results/success/ReadSuccess.ts index 65c5bb1..419c984 100644 --- a/packages/solid/src/requester/results/success/ReadSuccess.ts +++ b/packages/solid/src/requester/results/success/ReadSuccess.ts @@ -1,56 +1,33 @@ -import { ResourceSuccess } from "./SuccessResult"; +import type { ResourceSuccess, SuccessResult } from "./SuccessResult"; -export abstract class ReadSuccess extends ResourceSuccess { +export interface ReadSuccess extends ResourceSuccess { recalledFromMemory: boolean; - constructor(uri: string, recalledFromMemory: boolean) { - super(uri); - this.recalledFromMemory = recalledFromMemory; - } } -export class BinaryReadSuccess extends ReadSuccess { - readonly type = "binaryReadSuccess" as const; - readonly blob: Blob; - readonly mimeType: string; - - constructor( - uri: string, - recalledFromMemory: boolean, - blob: Blob, - mimeType: string, - ) { - super(uri, recalledFromMemory); - this.blob = blob; - this.mimeType = mimeType; - } +export interface BinaryReadSuccess extends ReadSuccess { + type: "binaryReadSuccess"; + blob: Blob; + mimeType: string; } -export class DataReadSuccess extends ReadSuccess { - readonly type = "dataReadSuccess" as const; - - constructor(uri: string, recalledFromMemory: boolean) { - super(uri, recalledFromMemory); - } +export interface DataReadSuccess extends ReadSuccess { + type: "dataReadSuccess"; } -export class ContainerReadSuccess extends ReadSuccess { - readonly type = "containerReadSuccess" as const; - readonly isRootContainer: boolean; - - constructor( - uri: string, - recalledFromMemory: boolean, - isRootContainer: boolean, - ) { - super(uri, recalledFromMemory); - this.isRootContainer = isRootContainer; - } +export interface ContainerReadSuccess extends ReadSuccess { + type: "containerReadSuccess"; + isRootContainer: boolean; } -export class AbsentReadSuccess extends ReadSuccess { - readonly type = "absentReadSuccess" as const; +export interface AbsentReadSuccess extends ReadSuccess { + type: "absentReadSuccess"; +} - constructor(uri: string, recalledFromMemory: boolean) { - super(uri, recalledFromMemory); - } +export function isReadSuccess(result: SuccessResult): result is ReadSuccess { + return ( + result.type === "binaryReadSuccess" || + result.type === "dataReadSuccess" || + result.type === "absentReadSuccess" || + result.type === "containerReadSuccess" + ); } diff --git a/packages/solid/src/requester/results/success/SuccessResult.ts b/packages/solid/src/requester/results/success/SuccessResult.ts index 512812d..f79275c 100644 --- a/packages/solid/src/requester/results/success/SuccessResult.ts +++ b/packages/solid/src/requester/results/success/SuccessResult.ts @@ -1,30 +1,15 @@ -import type { Container } from "../../../resource/Container"; -import type { Leaf } from "../../../resource/Leaf"; import type { RequesterResult } from "../RequesterResult"; -export abstract class SuccessResult implements RequesterResult { - readonly isError = false as const; - abstract readonly type: string; - resource?: Leaf | Container; +export interface SuccessResult extends RequesterResult { + isError: false; } -export abstract class ResourceSuccess extends SuccessResult { - readonly uri: string; - - constructor(uri: string) { - super(); - this.uri = uri; - } +export interface ResourceSuccess extends SuccessResult { + uri: string; } -export class AggregateSuccess< - SuccessType extends SuccessResult, -> extends SuccessResult { - readonly type = "aggregateError" as const; - readonly results: SuccessType[]; - - constructor(results: SuccessType[]) { - super(); - this.results = results; - } +export interface AggregateSuccess + extends SuccessResult { + type: "aggregateSuccess"; + results: SuccessType[]; } diff --git a/packages/solid/src/requester/results/success/Unfetched.ts b/packages/solid/src/requester/results/success/Unfetched.ts index ec4b6a7..6eacacb 100644 --- a/packages/solid/src/requester/results/success/Unfetched.ts +++ b/packages/solid/src/requester/results/success/Unfetched.ts @@ -1,5 +1,5 @@ -import { ResourceSuccess } from "./SuccessResult"; +import type { ResourceSuccess } from "./SuccessResult"; -export class Unfetched extends ResourceSuccess { - readonly type = "unfetched" as const; +export interface Unfetched extends ResourceSuccess { + type: "unfetched"; } diff --git a/packages/solid/src/requester/results/success/UpdateSuccess.ts b/packages/solid/src/requester/results/success/UpdateSuccess.ts index 512a8c5..643ccc4 100644 --- a/packages/solid/src/requester/results/success/UpdateSuccess.ts +++ b/packages/solid/src/requester/results/success/UpdateSuccess.ts @@ -1,5 +1,5 @@ -import { ResourceSuccess } from "./SuccessResult"; +import type { ResourceSuccess } from "./SuccessResult"; -export class UpdateSuccess extends ResourceSuccess { - readonly type = "updateSuccess"; +export interface UpdateSuccess extends ResourceSuccess { + type: "updateSuccess"; } diff --git a/packages/solid/src/resource/Container.ts b/packages/solid/src/resource/Container.ts index 96f6d0d..a8b41d2 100644 --- a/packages/solid/src/resource/Container.ts +++ b/packages/solid/src/resource/Container.ts @@ -21,19 +21,16 @@ import type { import { AggregateError } from "../requester/results/error/ErrorResult"; import { NoncompliantPodError } from "../requester/results/error/NoncompliantPodError"; import type { DeleteSuccess } from "../requester/results/success/DeleteSuccess"; -import { - AbsentReadSuccess, - ContainerReadSuccess, -} from "../requester/results/success/ReadSuccess"; -import { AggregateSuccess } from "../requester/results/success/SuccessResult"; -import { Unfetched } from "../requester/results/success/Unfetched"; +import type { AbsentReadSuccess } from "../requester/results/success/ReadSuccess"; +import type { ContainerReadSuccess } from "../requester/results/success/ReadSuccess"; +import type { AggregateSuccess } from "../requester/results/success/SuccessResult"; import type { SolidLdoDatasetContext } from "../SolidLdoDatasetContext"; import { getParentUri, ldpContains } from "../util/rdfUtils"; import type { ContainerUri, LeafUri } from "../util/uriTypes"; import type { Leaf } from "./Leaf"; import type { SharedStatuses } from "./Resource"; import { Resource } from "./Resource"; -import { GetRootContainerSuccess } from "./resourceResults/GetRootContainerSuccess"; +import type { ResourceResult } from "./ResourceResult"; export class Container extends Resource { readonly uri: ContainerUri; @@ -52,7 +49,7 @@ export class Container extends Resource { super(context); this.uri = uri; this.requester = new ContainerRequester(uri, context); - this.status = new Unfetched(this.uri); + this.status = { isError: false, type: "unfetched", uri }; } isRootContainer(): boolean | undefined { @@ -68,39 +65,58 @@ export class Container extends Resource { } } - async read(): Promise { - return (await super.read()) as ReadContainerResult; + async read(): Promise> { + const result = (await this.handleRead()) as ReadContainerResult; + if (result.isError) return result; + return { ...result, resource: this }; } - protected toReadResult(): ReadContainerResult { + protected toReadResult(): ResourceResult { if (this.isAbsent()) { - return new AbsentReadSuccess(this.uri, true); + return { + isError: false, + type: "absentReadSuccess", + uri: this.uri, + recalledFromMemory: true, + resource: this, + }; } else { - return new ContainerReadSuccess(this.uri, true, this.isRootContainer()!); + return { + isError: false, + type: "containerReadSuccess", + uri: this.uri, + recalledFromMemory: true, + isRootContainer: this.isRootContainer()!, + resource: this, + }; } } - async readIfUnfetched(): Promise { - return super.readIfUnfetched() as Promise; + async readIfUnfetched(): Promise< + ResourceResult + > { + return super.readIfUnfetched() as Promise< + ResourceResult + >; } // Parent Container Methods - private async checkIfIsRootContainer(): Promise { + private async checkIfIsRootContainer(): Promise< + ResourceResult + > { const rootContainerResult = await this.requester.isRootContainer(); this.status = rootContainerResult; if (rootContainerResult.isError) return rootContainerResult; this.rootContainer = rootContainerResult.isRootContainer; this.emit("update"); - return rootContainerResult; + return { ...rootContainerResult, resource: this }; } - async getRootContainer(): Promise< - GetRootContainerSuccess | CheckRootResultError - > { + async getRootContainer(): Promise { const checkResult = await this.checkIfIsRootContainer(); if (checkResult.isError) return checkResult; if (this.rootContainer) { - return new GetRootContainerSuccess(this); + return this; } const parentUri = getParentUri(this.uri); if (!parentUri) { @@ -150,25 +166,51 @@ export class Container extends Resource { // Child Creators createChildAndOverwrite( slug: ContainerUri, - ): Promise; - createChildAndOverwrite(slug: LeafUri): Promise; + ): Promise>; + createChildAndOverwrite( + slug: LeafUri, + ): Promise>; createChildAndOverwrite( slug: string, - ): Promise; + ): Promise< + ResourceResult< + ContainerCreateAndOverwriteResult | LeafCreateAndOverwriteResult, + Leaf | Container + > + >; createChildAndOverwrite( slug: string, - ): Promise { + ): Promise< + ResourceResult< + ContainerCreateAndOverwriteResult | LeafCreateAndOverwriteResult, + Leaf | Container + > + > { return this.child(slug).createAndOverwrite(); } - createChildIfAbsent(slug: ContainerUri): Promise; - createChildIfAbsent(slug: LeafUri): Promise; + createChildIfAbsent( + slug: ContainerUri, + ): Promise>; + createChildIfAbsent( + slug: LeafUri, + ): Promise>; createChildIfAbsent( slug: string, - ): Promise; + ): Promise< + ResourceResult< + ContainerCreateIfAbsentResult | LeafCreateIfAbsentResult, + Leaf | Container + > + >; createChildIfAbsent( slug: string, - ): Promise { + ): Promise< + ResourceResult< + ContainerCreateIfAbsentResult | LeafCreateIfAbsentResult, + Leaf | Container + > + > { return this.child(slug).createIfAbsent(); } @@ -176,7 +218,7 @@ export class Container extends Resource { slug: LeafUri, blob: Blob, mimeType: string, - ): Promise { + ): Promise> { return this.child(slug).uploadAndOverwrite(blob, mimeType); } @@ -184,13 +226,16 @@ export class Container extends Resource { slug: LeafUri, blob: Blob, mimeType: string, - ): Promise { + ): Promise> { return this.child(slug).uploadIfAbsent(blob, mimeType); } async clear(): Promise< - | AggregateSuccess - | AggregateError + ResourceResult< + | AggregateSuccess> + | AggregateError, + Container + > > { const readResult = await this.read(); if (readResult.isError) return new AggregateError([readResult]); @@ -211,14 +256,42 @@ export class Container extends Resource { if (errors.length > 0) { return new AggregateError(errors); } - return new AggregateSuccess(results as DeleteSuccess[]); + return { + isError: false, + type: "aggregateSuccess", + results: results as ResourceResult[], + resource: this, + }; } async delete(): Promise< - DeleteResult | AggregateError + ResourceResult< + DeleteResult | AggregateError, + Container + > > { const clearResult = await this.clear(); if (clearResult.isError) return clearResult; - return this.handleDelete(); + const deleteResult = await this.handleDelete(); + if (deleteResult.isError) return deleteResult; + return { ...deleteResult, resource: this }; + } + + async createAndOverwrite(): Promise< + ResourceResult + > { + const createResult = + (await this.handleCreateAndOverwrite()) as ContainerCreateAndOverwriteResult; + if (createResult.isError) return createResult; + return { ...createResult, resource: this }; + } + + async createIfAbsent(): Promise< + ResourceResult + > { + const createResult = + (await this.handleCreateAndOverwrite()) as ContainerCreateIfAbsentResult; + if (createResult.isError) return createResult; + return { ...createResult, resource: this }; } } diff --git a/packages/solid/src/resource/Leaf.ts b/packages/solid/src/resource/Leaf.ts index e2f3405..ee5af4c 100644 --- a/packages/solid/src/resource/Leaf.ts +++ b/packages/solid/src/resource/Leaf.ts @@ -10,20 +10,19 @@ import type { DeleteResult } from "../requester/requests/deleteResource"; import type { ReadLeafResult } from "../requester/requests/readResource"; import type { UpdateResult } from "../requester/requests/updateDataResource"; import type { DeleteSuccess } from "../requester/results/success/DeleteSuccess"; -import { +import type { AbsentReadSuccess } from "../requester/results/success/ReadSuccess"; +import type { BinaryReadSuccess, DataReadSuccess, - AbsentReadSuccess, } from "../requester/results/success/ReadSuccess"; import type { ResourceSuccess } from "../requester/results/success/SuccessResult"; -import { Unfetched } from "../requester/results/success/Unfetched"; import type { SolidLdoDatasetContext } from "../SolidLdoDatasetContext"; import { getParentUri } from "../util/rdfUtils"; import type { LeafUri } from "../util/uriTypes"; import type { Container } from "./Container"; import type { SharedStatuses } from "./Resource"; import { Resource } from "./Resource"; -import type { GetRootContainerSuccess } from "./resourceResults/GetRootContainerSuccess"; +import type { ResourceResult } from "./ResourceResult"; export class Leaf extends Resource { readonly uri: LeafUri; @@ -43,7 +42,7 @@ export class Leaf extends Resource { super(context); this.uri = uri; this.requester = new LeafRequester(uri, context); - this.status = new Unfetched(this.uri); + this.status = { isError: false, type: "unfetched", uri }; } // Getters @@ -81,27 +80,46 @@ export class Leaf extends Resource { } } - async read(): Promise { - return (await super.read()) as ReadLeafResult; + async read(): Promise> { + const result = (await this.handleRead()) as ReadLeafResult; + if (result.isError) return result; + return { ...result, resource: this }; } - protected toReadResult(): ReadLeafResult { + protected toReadResult(): ResourceResult { if (this.isAbsent()) { - return new AbsentReadSuccess(this.uri, true); + return { + isError: false, + type: "absentReadSuccess", + uri: this.uri, + recalledFromMemory: true, + resource: this, + }; } else if (this.isBinary()) { - return new BinaryReadSuccess( - this.uri, - true, - this.binaryData!.blob, - this.binaryData!.mimeType, - ); + return { + isError: false, + type: "binaryReadSuccess", + uri: this.uri, + recalledFromMemory: true, + blob: this.binaryData!.blob, + mimeType: this.binaryData!.mimeType, + resource: this, + }; } else { - return new DataReadSuccess(this.uri, true); + return { + isError: false, + type: "dataReadSuccess", + uri: this.uri, + recalledFromMemory: true, + resource: this, + }; } } - async readIfUnfetched(): Promise { - return super.readIfUnfetched() as Promise; + async readIfUnfetched(): Promise> { + return super.readIfUnfetched() as Promise< + ResourceResult + >; } // Parent Container Methods @@ -109,7 +127,7 @@ export class Leaf extends Resource { const parentUri = getParentUri(this.uri)!; return this.context.resourceStore.get(parentUri); } - getRootContainer(): Promise { + getRootContainer(): Promise { const parentUri = getParentUri(this.uri)!; const parent = this.context.resourceStore.get(parentUri); return parent.getRootContainer(); @@ -129,40 +147,60 @@ export class Leaf extends Resource { async uploadAndOverwrite( blob: Blob, mimeType: string, - ): Promise { + ): Promise> { const result = await this.requester.upload(blob, mimeType, true); this.status = result; if (result.isError) return result; super.updateWithCreateSuccess(result); this.binaryData = { blob, mimeType }; this.emitThisAndParent(); - return result; + return { ...result, resource: this }; } async uploadIfAbsent( blob: Blob, mimeType: string, - ): Promise { + ): Promise> { const result = await this.requester.upload(blob, mimeType); this.status = result; if (result.isError) return result; super.updateWithCreateSuccess(result); this.binaryData = { blob, mimeType }; this.emitThisAndParent(); - return result; + return { ...result, resource: this }; } - async update(changes: DatasetChanges): Promise { + async update( + changes: DatasetChanges, + ): Promise> { const result = await this.requester.updateDataResource(changes); this.status = result; if (result.isError) return result; this.binaryData = undefined; this.absent = false; this.emitThisAndParent(); - return result; + return { ...result, resource: this }; } async delete(): Promise { return this.handleDelete(); } + + async createAndOverwrite(): Promise< + ResourceResult + > { + const createResult = + (await this.handleCreateAndOverwrite()) as LeafCreateAndOverwriteResult; + if (createResult.isError) return createResult; + return { ...createResult, resource: this }; + } + + async createIfAbsent(): Promise< + ResourceResult + > { + const createResult = + (await this.handleCreateAndOverwrite()) as LeafCreateIfAbsentResult; + if (createResult.isError) return createResult; + return { ...createResult, resource: this }; + } } diff --git a/packages/solid/src/resource/Resource.ts b/packages/solid/src/resource/Resource.ts index b14aa3b..5c2aa20 100644 --- a/packages/solid/src/resource/Resource.ts +++ b/packages/solid/src/resource/Resource.ts @@ -19,16 +19,15 @@ import EventEmitter from "events"; import { getParentUri } from "../util/rdfUtils"; import type { RequesterResult } from "../requester/results/RequesterResult"; import type { DeleteResult } from "../requester/requests/deleteResource"; -import { ReadSuccess } from "../requester/results/success/ReadSuccess"; +import type { ReadSuccess } from "../requester/results/success/ReadSuccess"; +import { isReadSuccess } from "../requester/results/success/ReadSuccess"; import type { DeleteSuccess } from "../requester/results/success/DeleteSuccess"; import type { ResourceSuccess } from "../requester/results/success/SuccessResult"; import type { Unfetched } from "../requester/results/success/Unfetched"; import type { CreateSuccess } from "../requester/results/success/CreateSuccess"; -import type { GetRootContainerSuccess } from "./resourceResults/GetRootContainerSuccess"; -import type { - ReadResourceSuccessContainerTypes, - ReadResourceSuccessLeafTypes, -} from "./resourceResults/ReadResourceSuccess"; +import type { ResourceResult } from "./resourceResult/ResourceResult"; +import type { Container } from "./Container"; +import type { Leaf } from "./Leaf"; export type SharedStatuses = Unfetched | DeleteResult | CreateSuccess; @@ -96,9 +95,7 @@ export abstract class Resource extends (EventEmitter as new () => TypedEmitter<{ this.didInitialFetch = true; } - async read(): Promise< - ReadResourceSuccessContainerTypes | ReadResourceSuccessLeafTypes - > { + protected async handleRead(): Promise { const result = await this.requester.read(); this.status = result; if (result.isError) return result; @@ -107,9 +104,18 @@ export abstract class Resource extends (EventEmitter as new () => TypedEmitter<{ return result; } - protected abstract toReadResult(): ReadContainerResult | ReadLeafResult; + protected abstract toReadResult(): ResourceResult< + ReadLeafResult | ReadContainerResult, + Container | Leaf + >; - async readIfUnfetched(): Promise { + abstract read(): Promise< + ResourceResult + >; + + async readIfUnfetched(): Promise< + ResourceResult + > { if (this.didInitialFetch) { const readResult = this.toReadResult(); this.status = readResult; @@ -137,12 +143,19 @@ export abstract class Resource extends (EventEmitter as new () => TypedEmitter<{ protected updateWithCreateSuccess(result: ResourceSuccess) { this.absent = false; this.didInitialFetch = true; - if (result instanceof ReadSuccess) { + if (isReadSuccess(result)) { this.updateWithReadSuccess(result); } } - async createAndOverwrite(): Promise< + abstract createAndOverwrite(): Promise< + ResourceResult< + ContainerCreateAndOverwriteResult | LeafCreateAndOverwriteResult, + Leaf | Container + > + >; + + protected async handleCreateAndOverwrite(): Promise< ContainerCreateAndOverwriteResult | LeafCreateAndOverwriteResult > { const result = await this.requester.createDataResource(true); @@ -153,7 +166,14 @@ export abstract class Resource extends (EventEmitter as new () => TypedEmitter<{ return result; } - async createIfAbsent(): Promise< + abstract createIfAbsent(): Promise< + ResourceResult< + ContainerCreateIfAbsentResult | LeafCreateIfAbsentResult, + Leaf | Container + > + >; + + protected async handleCreateIfAbsent(): Promise< ContainerCreateIfAbsentResult | LeafCreateIfAbsentResult > { const result = await this.requester.createDataResource(true); @@ -165,20 +185,19 @@ export abstract class Resource extends (EventEmitter as new () => TypedEmitter<{ } // Parent Container Methods -- Remember to change for Container - abstract getRootContainer(): Promise< - GetRootContainerSuccess | CheckRootResultError - >; + abstract getRootContainer(): Promise; // Access Rules Methods // async getAccessRules(): Promise { // return getAccessRules({ uri: this.uri, fetch: this.context.fetch }); // } - async setAccessRules( newAccessRules: AccessRule, - ): Promise { - return setAccessRules(this.uri, newAccessRules, { + ): Promise> { + const result = await setAccessRules(this.uri, newAccessRules, { fetch: this.context.fetch, }); + if (result.isError) return result; + return { ...result, resource: this as unknown as Leaf | Container }; } } diff --git a/packages/solid/src/resource/ResourceResult.ts b/packages/solid/src/resource/ResourceResult.ts deleted file mode 100644 index 5b840cf..0000000 --- a/packages/solid/src/resource/ResourceResult.ts +++ /dev/null @@ -1,10 +0,0 @@ -import type { LeafCreateAndOverwriteResult } from "../requester/requests/createDataResource"; -import { createDataResource } from "../requester/requests/createDataResource"; -import type { RequesterResult } from "../requester/results/RequesterResult"; -import type { Container } from "./Container"; -import type { Leaf } from "./Leaf"; - -export type ResourceResult< - Result extends RequesterResult, - ResourceType extends Leaf | Container, -> = Result & { resource: ResourceType }; diff --git a/packages/solid/src/resource/resourceResult/ResourceResult.ts b/packages/solid/src/resource/resourceResult/ResourceResult.ts new file mode 100644 index 0000000..4b411e8 --- /dev/null +++ b/packages/solid/src/resource/resourceResult/ResourceResult.ts @@ -0,0 +1,13 @@ +import type { RequesterResult } from "../../requester/results/RequesterResult"; +import type { Container } from "../Container"; +import type { Leaf } from "../Leaf"; + +export type ResourceSuccess< + Result extends RequesterResult, + ResourceType extends Leaf | Container, +> = Result & { resource: ResourceType }; + +export type ResourceResult< + Result extends RequesterResult, + ResourceType extends Leaf | Container, +> = Result extends Error ? Result : ResourceSuccess; diff --git a/packages/solid/src/resource/resourceResults/CreateResourceSuccess.ts b/packages/solid/src/resource/resourceResults/CreateResourceSuccess.ts deleted file mode 100644 index d1962ef..0000000 --- a/packages/solid/src/resource/resourceResults/CreateResourceSuccess.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { CreateSuccess } from "../../requester/results/success/CreateSuccess"; -import type { Container } from "../Container"; -import type { Leaf } from "../Leaf"; - -export class CreateResourceSuccess< - ResourceType extends Leaf | Container, -> extends CreateSuccess { - readonly createdResource: ResourceType; - - constructor(uri: string, didOverwrite: boolean, resource: ResourceType) { - super(uri, didOverwrite); - this.createdResource = resource; - } -} diff --git a/packages/solid/src/resource/resourceResults/DeleteResourceSuccess.ts b/packages/solid/src/resource/resourceResults/DeleteResourceSuccess.ts deleted file mode 100644 index 17ac5a2..0000000 --- a/packages/solid/src/resource/resourceResults/DeleteResourceSuccess.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { DeleteSuccess } from "../../requester/results/success/DeleteSuccess"; -import type { Container } from "../Container"; -import type { Leaf } from "../Leaf"; - -export class DeleteResourceSuccess< - ResourceType extends Leaf | Container, -> extends DeleteSuccess { - readonly deletedResource: ResourceType; - - constructor(uri: string, resourceExisted: boolean, resource: ResourceType) { - super(uri, resourceExisted); - this.deletedResource = resource; - } -} diff --git a/packages/solid/src/resource/resourceResults/GetRootContainerSuccess.ts b/packages/solid/src/resource/resourceResults/GetRootContainerSuccess.ts deleted file mode 100644 index 99a5c7b..0000000 --- a/packages/solid/src/resource/resourceResults/GetRootContainerSuccess.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { SuccessResult } from "../../requester/results/success/SuccessResult"; -import type { Container } from "../Container"; - -export class GetRootContainerSuccess extends SuccessResult { - readonly type = "getRootContainerSuccess" as const; - readonly rootContainer: Container; - - constructor(rootContainer: Container) { - super(); - this.rootContainer = rootContainer; - } -} diff --git a/packages/solid/src/resource/resourceResults/ReadResourceSuccess.ts b/packages/solid/src/resource/resourceResults/ReadResourceSuccess.ts deleted file mode 100644 index 4184070..0000000 --- a/packages/solid/src/resource/resourceResults/ReadResourceSuccess.ts +++ /dev/null @@ -1,72 +0,0 @@ -import type { ReadResultError } from "../../requester/requests/readResource"; -import { - AbsentReadSuccess, - BinaryReadSuccess, - ContainerReadSuccess, - DataReadSuccess, -} from "../../requester/results/success/ReadSuccess"; -import type { Container } from "../Container"; -import type { Leaf } from "../Leaf"; - -export type ReadResourceSuccessContainerTypes = - | ContainerResourceReadSuccess - | AbsentResourceReadSuccess - | ReadResultError; -export type ReadResourceSuccessLeafTypes = - | DataResourceReadSuccess - | BinaryResourceReadSuccess - | AbsentResourceReadSuccess - | ReadResultError; - -export class DataResourceReadSuccess extends DataReadSuccess { - readonly readResource: Leaf; - - constructor(uri: string, recalledFromMemory: boolean, resource: Leaf) { - super(uri, recalledFromMemory); - this.readResource = resource; - } -} - -export class BinaryResourceReadSuccess extends BinaryReadSuccess { - readonly readResource: Leaf; - - constructor( - uri: string, - recalledFromMemory: boolean, - blob: Blob, - mimeType: string, - resource: Leaf, - ) { - super(uri, recalledFromMemory, blob, mimeType); - this.readResource = resource; - } -} - -export class ContainerResourceReadSuccess extends ContainerReadSuccess { - readonly readResource: Container; - - constructor( - uri: string, - recalledFromMemory: boolean, - isRootContainer: boolean, - resource: Container, - ) { - super(uri, recalledFromMemory, isRootContainer); - this.readResource = resource; - } -} - -export class AbsentResourceReadSuccess< - ResourceType extends Leaf | Container, -> extends AbsentReadSuccess { - readonly readResource: ResourceType; - - constructor( - uri: string, - recalledFromMemory: boolean, - resource: ResourceType, - ) { - super(uri, recalledFromMemory); - this.readResource = resource; - } -} diff --git a/packages/solid/src/resource/resourceResults/UpdateResourceSuccess.ts b/packages/solid/src/resource/resourceResults/UpdateResourceSuccess.ts deleted file mode 100644 index e6e1306..0000000 --- a/packages/solid/src/resource/resourceResults/UpdateResourceSuccess.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { UpdateSuccess } from "../../requester/results/success/UpdateSuccess"; -import type { Leaf } from "../Leaf"; - -export class UpdateResourceSuccess extends UpdateSuccess { - readonly updatedResource: Leaf; - - constructor(uri: string, resource: Leaf) { - super(uri); - this.updatedResource = resource; - } -}