Refactored to have include a direct link to the object in the return

main
Ailin Luca 2 years ago
parent 50c44354dd
commit fea6e3096a
  1. 16
      packages/solid/src/SolidLdoDataset.ts
  2. 11
      packages/solid/src/requester/requests/checkRootContainer.ts
  3. 9
      packages/solid/src/requester/requests/createDataResource.ts
  4. 9
      packages/solid/src/requester/requests/deleteResource.ts
  5. 37
      packages/solid/src/requester/requests/readResource.ts
  6. 10
      packages/solid/src/requester/requests/setAccessRules.ts
  7. 4
      packages/solid/src/requester/results/RequesterResult.ts
  8. 9
      packages/solid/src/requester/results/error/AccessControlError.ts
  9. 3
      packages/solid/src/requester/results/error/ErrorResult.ts
  10. 4
      packages/solid/src/requester/results/error/InvalidUriError.ts
  11. 15
      packages/solid/src/requester/results/success/AccessRule.ts
  12. 13
      packages/solid/src/requester/results/success/CheckRootContainerSuccess.ts
  13. 13
      packages/solid/src/requester/results/success/CreateSuccess.ts
  14. 13
      packages/solid/src/requester/results/success/DeleteSuccess.ts
  15. 65
      packages/solid/src/requester/results/success/ReadSuccess.ts
  16. 31
      packages/solid/src/requester/results/success/SuccessResult.ts
  17. 6
      packages/solid/src/requester/results/success/Unfetched.ts
  18. 6
      packages/solid/src/requester/results/success/UpdateSuccess.ts
  19. 145
      packages/solid/src/resource/Container.ts
  20. 88
      packages/solid/src/resource/Leaf.ts
  21. 59
      packages/solid/src/resource/Resource.ts
  22. 10
      packages/solid/src/resource/ResourceResult.ts
  23. 13
      packages/solid/src/resource/resourceResult/ResourceResult.ts
  24. 14
      packages/solid/src/resource/resourceResults/CreateResourceSuccess.ts
  25. 14
      packages/solid/src/resource/resourceResults/DeleteResourceSuccess.ts
  26. 12
      packages/solid/src/resource/resourceResults/GetRootContainerSuccess.ts
  27. 72
      packages/solid/src/resource/resourceResults/ReadResourceSuccess.ts
  28. 11
      packages/solid/src/resource/resourceResults/UpdateResourceSuccess.ts

@ -7,10 +7,11 @@ import type {
} from "./requester/requests/updateDataResource"; } from "./requester/requests/updateDataResource";
import { AggregateError } from "./requester/results/error/ErrorResult"; import { AggregateError } from "./requester/results/error/ErrorResult";
import { InvalidUriError } from "./requester/results/error/InvalidUriError"; 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 { UpdateSuccess } from "./requester/results/success/UpdateSuccess";
import type { Container } from "./resource/Container"; import type { Container } from "./resource/Container";
import type { Leaf } from "./resource/Leaf"; import type { Leaf } from "./resource/Leaf";
import type { ResourceResult } from "./resource/resourceResult/ResourceResult";
import type { ResourceGetterOptions } from "./ResourceStore"; import type { ResourceGetterOptions } from "./ResourceStore";
import type { SolidLdoDatasetContext } from "./SolidLdoDatasetContext"; import type { SolidLdoDatasetContext } from "./SolidLdoDatasetContext";
import { splitChangesByGraph } from "./util/splitChangesByGraph"; import { splitChangesByGraph } from "./util/splitChangesByGraph";
@ -39,7 +40,7 @@ export class SolidLdoDataset extends LdoDataset {
async commitChangesToPod( async commitChangesToPod(
changes: DatasetChanges<Quad>, changes: DatasetChanges<Quad>,
): Promise< ): Promise<
| AggregateSuccess<UpdateSuccess> | AggregateSuccess<ResourceResult<UpdateSuccess, Leaf>>
| AggregateError<UpdateResultError | InvalidUriError> | AggregateError<UpdateResultError | InvalidUriError>
> { > {
const changesByGraph = splitChangesByGraph(changes); const changesByGraph = splitChangesByGraph(changes);
@ -84,12 +85,15 @@ export class SolidLdoDataset extends LdoDataset {
), ),
); );
} }
return new AggregateSuccess( return {
results isError: false,
type: "aggregateSuccess",
results: results
.map((result) => result[2]) .map((result) => result[2])
.filter( .filter(
(result): result is UpdateSuccess => result.type === "updateSuccess", (result): result is ResourceResult<UpdateSuccess, Leaf> =>
result.type === "updateSuccess",
), ),
); };
} }
} }

@ -1,7 +1,7 @@
import type { BasicRequestOptions } from "./requestOptions"; import type { BasicRequestOptions } from "./requestOptions";
import { parse as parseLinkHeader } from "http-link-header"; import { parse as parseLinkHeader } from "http-link-header";
import { NoncompliantPodError } from "../results/error/NoncompliantPodError"; import { NoncompliantPodError } from "../results/error/NoncompliantPodError";
import { CheckRootContainerSuccess } from "../results/success/CheckRootContainerSuccess"; import type { CheckRootContainerSuccess } from "../results/success/CheckRootContainerSuccess";
import type { import type {
HttpErrorResultType, HttpErrorResultType,
UnexpectedHttpError, UnexpectedHttpError,
@ -28,10 +28,15 @@ export function checkHeadersForRootContainer(
} }
const parsedLinkHeader = parseLinkHeader(linkHeader); const parsedLinkHeader = parseLinkHeader(linkHeader);
const types = parsedLinkHeader.get("rel", "type"); 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", (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( export async function checkRootContainer(

@ -9,7 +9,7 @@ import { isContainerUri } from "../../util/uriTypes";
import { UnexpectedResourceError } from "../results/error/ErrorResult"; import { UnexpectedResourceError } from "../results/error/ErrorResult";
import type { HttpErrorResultType } from "../results/error/HttpErrorResult"; import type { HttpErrorResultType } from "../results/error/HttpErrorResult";
import { HttpErrorResult } 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 { AbsentReadSuccess } from "../results/success/ReadSuccess";
import type { DeleteResultError } from "./deleteResource"; import type { DeleteResultError } from "./deleteResource";
import { deleteResource } from "./deleteResource"; import { deleteResource } from "./deleteResource";
@ -134,7 +134,12 @@ export async function createDataResource(
if (options?.dataset) { if (options?.dataset) {
addResourceRdfToContainer(uri, options.dataset); addResourceRdfToContainer(uri, options.dataset);
} }
return new CreateSuccess(uri, !!overwrite); return {
isError: false,
type: "createSuccess",
uri,
didOverwrite: !!overwrite,
};
} catch (err) { } catch (err) {
return UnexpectedResourceError.fromThrown(uri, err); return UnexpectedResourceError.fromThrown(uri, err);
} }

@ -5,7 +5,7 @@ import { UnexpectedResourceError } from "../results/error/ErrorResult";
import type { HttpErrorResultType } from "../results/error/HttpErrorResult"; import type { HttpErrorResultType } from "../results/error/HttpErrorResult";
import { UnexpectedHttpError } from "../results/error/HttpErrorResult"; import { UnexpectedHttpError } from "../results/error/HttpErrorResult";
import { HttpErrorResult } 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"; import type { DatasetRequestOptions } from "./requestOptions";
export type DeleteResult = DeleteSuccess | DeleteResultError; export type DeleteResult = DeleteSuccess | DeleteResultError;
@ -36,7 +36,12 @@ export async function deleteResource(
); );
deleteResourceRdfFromContainer(uri, options.dataset); 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); return new UnexpectedHttpError(uri, response);
} catch (err) { } catch (err) {

@ -10,12 +10,12 @@ import {
import type { DatasetRequestOptions } from "./requestOptions"; import type { DatasetRequestOptions } from "./requestOptions";
import type { ContainerUri, LeafUri } from "../../util/uriTypes"; import type { ContainerUri, LeafUri } from "../../util/uriTypes";
import { isContainerUri } from "../../util/uriTypes"; import { isContainerUri } from "../../util/uriTypes";
import { BinaryReadSuccess } from "../results/success/ReadSuccess"; import type { BinaryReadSuccess } from "../results/success/ReadSuccess";
import { import type {
ContainerReadSuccess, ContainerReadSuccess,
DataReadSuccess, DataReadSuccess,
} from "../results/success/ReadSuccess"; } from "../results/success/ReadSuccess";
import { AbsentReadSuccess } from "../results/success/ReadSuccess"; import type { AbsentReadSuccess } from "../results/success/ReadSuccess";
import { NoncompliantPodError } from "../results/error/NoncompliantPodError"; import { NoncompliantPodError } from "../results/error/NoncompliantPodError";
import { guaranteeFetch } from "../../util/guaranteeFetch"; import { guaranteeFetch } from "../../util/guaranteeFetch";
import { UnexpectedResourceError } from "../results/error/ErrorResult"; import { UnexpectedResourceError } from "../results/error/ErrorResult";
@ -57,7 +57,12 @@ export async function readResource(
// Fetch options to determine the document type // Fetch options to determine the document type
const response = await fetch(uri); const response = await fetch(uri);
if (response.status === 404) { if (response.status === 404) {
return new AbsentReadSuccess(uri, false); return {
isError: false,
type: "absentReadSuccess",
uri,
recalledFromMemory: false,
};
} }
const httpErrorResult = HttpErrorResult.checkResponse(uri, response); const httpErrorResult = HttpErrorResult.checkResponse(uri, response);
if (httpErrorResult) return httpErrorResult; if (httpErrorResult) return httpErrorResult;
@ -89,13 +94,31 @@ export async function readResource(
if (isContainerUri(uri)) { if (isContainerUri(uri)) {
const result = checkHeadersForRootContainer(uri, response.headers); const result = checkHeadersForRootContainer(uri, response.headers);
if (result.isError) return result; 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 { } else {
// Load Blob // Load Blob
const blob = await response.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) { } catch (err) {
return UnexpectedResourceError.fromThrown(uri, err); return UnexpectedResourceError.fromThrown(uri, err);

@ -15,8 +15,8 @@ import {
import { guaranteeFetch } from "../../util/guaranteeFetch"; import { guaranteeFetch } from "../../util/guaranteeFetch";
import { isContainerUri } from "../../util/uriTypes"; import { isContainerUri } from "../../util/uriTypes";
import type { AccessRule } from "../results/success/AccessRule"; import type { AccessRule } from "../results/success/AccessRule";
import { SetAccessRuleSuccess } from "../results/success/AccessRule"; import type { SetAccessRuleSuccess } from "../results/success/AccessRule";
import { AccessRuleFetchError } from "../results/success/AccessRule"; import { AccessRuleFetchError } from "../results/error/AccessControlError";
import type { BasicRequestOptions } from "./requestOptions"; import type { BasicRequestOptions } from "./requestOptions";
export type SetAccessRulesResult = export type SetAccessRulesResult =
@ -78,5 +78,9 @@ export async function setAccessRules(
// Now save the ACL: // Now save the ACL:
await saveAclFor(myDatasetWithAcl, updatedAcl, { fetch }); await saveAclFor(myDatasetWithAcl, updatedAcl, { fetch });
return new SetAccessRuleSuccess(uri); return {
isError: false,
uri,
type: "setAccessRuleSuccess",
};
} }

@ -1,8 +1,4 @@
import type { Container } from "../../resource/Container";
import type { Leaf } from "../../resource/Leaf";
export interface RequesterResult { export interface RequesterResult {
type: string; type: string;
isError: boolean; isError: boolean;
resource?: Leaf | Container;
} }

@ -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.`);
}
}

@ -1,11 +1,8 @@
import type { Container } from "../../../resource/Container";
import type { Leaf } from "../../../resource/Leaf";
import type { RequesterResult } from "../RequesterResult"; import type { RequesterResult } from "../RequesterResult";
export abstract class ErrorResult extends Error implements RequesterResult { export abstract class ErrorResult extends Error implements RequesterResult {
abstract type: string; abstract type: string;
readonly isError = true as const; readonly isError = true as const;
resource?: Leaf | Container;
constructor(message?: string) { constructor(message?: string) {
super(message || "An error unkown error was encountered."); super(message || "An error unkown error was encountered.");

@ -2,4 +2,8 @@ import { ResourceError } from "./ErrorResult";
export class InvalidUriError extends ResourceError { export class InvalidUriError extends ResourceError {
readonly type = "invalidUriError" as const; readonly type = "invalidUriError" as const;
constructor(uri: string, message?: string) {
super(uri, message || `${uri} is an invalid uri.`);
}
} }

@ -1,20 +1,11 @@
import type { Access } from "@inrupt/solid-client"; import type { Access } from "@inrupt/solid-client";
import { ResourceError } from "../error/ErrorResult"; import type { ResourceSuccess } from "./SuccessResult";
import { ResourceSuccess } from "./SuccessResult";
export interface AccessRule { export interface AccessRule {
public?: Access; public?: Access;
agent?: Record<string, Access>; agent?: Record<string, Access>;
} }
export class SetAccessRuleSuccess extends ResourceSuccess { export interface SetAccessRuleSuccess extends ResourceSuccess {
type = "setAccessRuleSuccess" as const; type: "setAccessRuleSuccess";
}
export class AccessRuleFetchError extends ResourceError {
readonly type = "accessRuleFetchError" as const;
constructor(uri: string, message?: string) {
super(uri, message || `Cannot get access rules for ${uri}.`);
}
} }

@ -1,11 +1,6 @@
import { ResourceSuccess } from "./SuccessResult"; import type { ResourceSuccess } from "./SuccessResult";
export class CheckRootContainerSuccess extends ResourceSuccess { export interface CheckRootContainerSuccess extends ResourceSuccess {
readonly type = "checkRootContainerSuccess" as const; type: "checkRootContainerSuccess";
readonly isRootContainer: boolean; isRootContainer: boolean;
constructor(uri: string, isRootContainer: boolean) {
super(uri);
this.isRootContainer = isRootContainer;
}
} }

@ -1,11 +1,6 @@
import { ResourceSuccess } from "./SuccessResult"; import type { ResourceSuccess } from "./SuccessResult";
export class CreateSuccess extends ResourceSuccess { export interface CreateSuccess extends ResourceSuccess {
readonly type = "createSuccess"; type: "createSuccess";
readonly didOverwrite: boolean; didOverwrite: boolean;
constructor(uri: string, didOverwrite: boolean) {
super(uri);
this.didOverwrite = didOverwrite;
}
} }

@ -1,11 +1,6 @@
import { ResourceSuccess } from "./SuccessResult"; import type { ResourceSuccess } from "./SuccessResult";
export class DeleteSuccess extends ResourceSuccess { export interface DeleteSuccess extends ResourceSuccess {
readonly type = "deleteSuccess" as const; type: "deleteSuccess";
readonly resourceExisted: boolean; resourceExisted: boolean;
constructor(uri: string, resourceExisted: boolean) {
super(uri);
this.resourceExisted = resourceExisted;
}
} }

@ -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; 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( export interface BinaryReadSuccess extends ReadSuccess {
uri: string, type: "binaryReadSuccess";
recalledFromMemory: boolean, blob: Blob;
blob: Blob, mimeType: string;
mimeType: string,
) {
super(uri, recalledFromMemory);
this.blob = blob;
this.mimeType = mimeType;
}
} }
export class DataReadSuccess extends ReadSuccess { export interface DataReadSuccess extends ReadSuccess {
readonly type = "dataReadSuccess" as const; type: "dataReadSuccess";
constructor(uri: string, recalledFromMemory: boolean) {
super(uri, recalledFromMemory);
}
} }
export class ContainerReadSuccess extends ReadSuccess { export interface ContainerReadSuccess extends ReadSuccess {
readonly type = "containerReadSuccess" as const; type: "containerReadSuccess";
readonly isRootContainer: boolean; isRootContainer: boolean;
constructor(
uri: string,
recalledFromMemory: boolean,
isRootContainer: boolean,
) {
super(uri, recalledFromMemory);
this.isRootContainer = isRootContainer;
}
} }
export class AbsentReadSuccess extends ReadSuccess { export interface AbsentReadSuccess extends ReadSuccess {
readonly type = "absentReadSuccess" as const; 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"
);
} }

@ -1,30 +1,15 @@
import type { Container } from "../../../resource/Container";
import type { Leaf } from "../../../resource/Leaf";
import type { RequesterResult } from "../RequesterResult"; import type { RequesterResult } from "../RequesterResult";
export abstract class SuccessResult implements RequesterResult { export interface SuccessResult extends RequesterResult {
readonly isError = false as const; isError: false;
abstract readonly type: string;
resource?: Leaf | Container;
} }
export abstract class ResourceSuccess extends SuccessResult { export interface ResourceSuccess extends SuccessResult {
readonly uri: string; uri: string;
constructor(uri: string) {
super();
this.uri = uri;
}
} }
export class AggregateSuccess< export interface AggregateSuccess<SuccessType extends SuccessResult>
SuccessType extends SuccessResult, extends SuccessResult {
> extends SuccessResult { type: "aggregateSuccess";
readonly type = "aggregateError" as const; results: SuccessType[];
readonly results: SuccessType[];
constructor(results: SuccessType[]) {
super();
this.results = results;
}
} }

@ -1,5 +1,5 @@
import { ResourceSuccess } from "./SuccessResult"; import type { ResourceSuccess } from "./SuccessResult";
export class Unfetched extends ResourceSuccess { export interface Unfetched extends ResourceSuccess {
readonly type = "unfetched" as const; type: "unfetched";
} }

@ -1,5 +1,5 @@
import { ResourceSuccess } from "./SuccessResult"; import type { ResourceSuccess } from "./SuccessResult";
export class UpdateSuccess extends ResourceSuccess { export interface UpdateSuccess extends ResourceSuccess {
readonly type = "updateSuccess"; type: "updateSuccess";
} }

@ -21,19 +21,16 @@ import type {
import { AggregateError } from "../requester/results/error/ErrorResult"; import { AggregateError } from "../requester/results/error/ErrorResult";
import { NoncompliantPodError } from "../requester/results/error/NoncompliantPodError"; import { NoncompliantPodError } from "../requester/results/error/NoncompliantPodError";
import type { DeleteSuccess } from "../requester/results/success/DeleteSuccess"; import type { DeleteSuccess } from "../requester/results/success/DeleteSuccess";
import { import type { AbsentReadSuccess } from "../requester/results/success/ReadSuccess";
AbsentReadSuccess, import type { ContainerReadSuccess } from "../requester/results/success/ReadSuccess";
ContainerReadSuccess, import type { AggregateSuccess } from "../requester/results/success/SuccessResult";
} from "../requester/results/success/ReadSuccess";
import { AggregateSuccess } from "../requester/results/success/SuccessResult";
import { Unfetched } from "../requester/results/success/Unfetched";
import type { SolidLdoDatasetContext } from "../SolidLdoDatasetContext"; import type { SolidLdoDatasetContext } from "../SolidLdoDatasetContext";
import { getParentUri, ldpContains } from "../util/rdfUtils"; import { getParentUri, ldpContains } from "../util/rdfUtils";
import type { ContainerUri, LeafUri } from "../util/uriTypes"; import type { ContainerUri, LeafUri } from "../util/uriTypes";
import type { Leaf } from "./Leaf"; import type { Leaf } from "./Leaf";
import type { SharedStatuses } from "./Resource"; import type { SharedStatuses } from "./Resource";
import { Resource } from "./Resource"; import { Resource } from "./Resource";
import { GetRootContainerSuccess } from "./resourceResults/GetRootContainerSuccess"; import type { ResourceResult } from "./ResourceResult";
export class Container extends Resource { export class Container extends Resource {
readonly uri: ContainerUri; readonly uri: ContainerUri;
@ -52,7 +49,7 @@ export class Container extends Resource {
super(context); super(context);
this.uri = uri; this.uri = uri;
this.requester = new ContainerRequester(uri, context); this.requester = new ContainerRequester(uri, context);
this.status = new Unfetched(this.uri); this.status = { isError: false, type: "unfetched", uri };
} }
isRootContainer(): boolean | undefined { isRootContainer(): boolean | undefined {
@ -68,39 +65,58 @@ export class Container extends Resource {
} }
} }
async read(): Promise<ReadContainerResult> { async read(): Promise<ResourceResult<ReadContainerResult, Container>> {
return (await super.read()) as ReadContainerResult; const result = (await this.handleRead()) as ReadContainerResult;
if (result.isError) return result;
return { ...result, resource: this };
} }
protected toReadResult(): ReadContainerResult { protected toReadResult(): ResourceResult<ReadContainerResult, Container> {
if (this.isAbsent()) { if (this.isAbsent()) {
return new AbsentReadSuccess(this.uri, true); return {
isError: false,
type: "absentReadSuccess",
uri: this.uri,
recalledFromMemory: true,
resource: this,
};
} else { } 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<ReadContainerResult> { async readIfUnfetched(): Promise<
return super.readIfUnfetched() as Promise<ReadContainerResult>; ResourceResult<ReadContainerResult, Container>
> {
return super.readIfUnfetched() as Promise<
ResourceResult<ReadContainerResult, Container>
>;
} }
// Parent Container Methods // Parent Container Methods
private async checkIfIsRootContainer(): Promise<CheckRootResult> { private async checkIfIsRootContainer(): Promise<
ResourceResult<CheckRootResult, Container>
> {
const rootContainerResult = await this.requester.isRootContainer(); const rootContainerResult = await this.requester.isRootContainer();
this.status = rootContainerResult; this.status = rootContainerResult;
if (rootContainerResult.isError) return rootContainerResult; if (rootContainerResult.isError) return rootContainerResult;
this.rootContainer = rootContainerResult.isRootContainer; this.rootContainer = rootContainerResult.isRootContainer;
this.emit("update"); this.emit("update");
return rootContainerResult; return { ...rootContainerResult, resource: this };
} }
async getRootContainer(): Promise< async getRootContainer(): Promise<Container | CheckRootResultError> {
GetRootContainerSuccess | CheckRootResultError
> {
const checkResult = await this.checkIfIsRootContainer(); const checkResult = await this.checkIfIsRootContainer();
if (checkResult.isError) return checkResult; if (checkResult.isError) return checkResult;
if (this.rootContainer) { if (this.rootContainer) {
return new GetRootContainerSuccess(this); return this;
} }
const parentUri = getParentUri(this.uri); const parentUri = getParentUri(this.uri);
if (!parentUri) { if (!parentUri) {
@ -150,25 +166,51 @@ export class Container extends Resource {
// Child Creators // Child Creators
createChildAndOverwrite( createChildAndOverwrite(
slug: ContainerUri, slug: ContainerUri,
): Promise<ContainerCreateAndOverwriteResult>; ): Promise<ResourceResult<ContainerCreateAndOverwriteResult, Container>>;
createChildAndOverwrite(slug: LeafUri): Promise<LeafCreateAndOverwriteResult>; createChildAndOverwrite(
slug: LeafUri,
): Promise<ResourceResult<LeafCreateAndOverwriteResult, Leaf>>;
createChildAndOverwrite( createChildAndOverwrite(
slug: string, slug: string,
): Promise<ContainerCreateAndOverwriteResult | LeafCreateAndOverwriteResult>; ): Promise<
ResourceResult<
ContainerCreateAndOverwriteResult | LeafCreateAndOverwriteResult,
Leaf | Container
>
>;
createChildAndOverwrite( createChildAndOverwrite(
slug: string, slug: string,
): Promise<ContainerCreateAndOverwriteResult | LeafCreateAndOverwriteResult> { ): Promise<
ResourceResult<
ContainerCreateAndOverwriteResult | LeafCreateAndOverwriteResult,
Leaf | Container
>
> {
return this.child(slug).createAndOverwrite(); return this.child(slug).createAndOverwrite();
} }
createChildIfAbsent(slug: ContainerUri): Promise<LeafCreateIfAbsentResult>; createChildIfAbsent(
createChildIfAbsent(slug: LeafUri): Promise<LeafCreateIfAbsentResult>; slug: ContainerUri,
): Promise<ResourceResult<ContainerCreateIfAbsentResult, Container>>;
createChildIfAbsent(
slug: LeafUri,
): Promise<ResourceResult<LeafCreateIfAbsentResult, Leaf>>;
createChildIfAbsent( createChildIfAbsent(
slug: string, slug: string,
): Promise<ContainerCreateIfAbsentResult | LeafCreateIfAbsentResult>; ): Promise<
ResourceResult<
ContainerCreateIfAbsentResult | LeafCreateIfAbsentResult,
Leaf | Container
>
>;
createChildIfAbsent( createChildIfAbsent(
slug: string, slug: string,
): Promise<ContainerCreateIfAbsentResult | LeafCreateIfAbsentResult> { ): Promise<
ResourceResult<
ContainerCreateIfAbsentResult | LeafCreateIfAbsentResult,
Leaf | Container
>
> {
return this.child(slug).createIfAbsent(); return this.child(slug).createIfAbsent();
} }
@ -176,7 +218,7 @@ export class Container extends Resource {
slug: LeafUri, slug: LeafUri,
blob: Blob, blob: Blob,
mimeType: string, mimeType: string,
): Promise<LeafCreateAndOverwriteResult> { ): Promise<ResourceResult<LeafCreateAndOverwriteResult, Leaf>> {
return this.child(slug).uploadAndOverwrite(blob, mimeType); return this.child(slug).uploadAndOverwrite(blob, mimeType);
} }
@ -184,13 +226,16 @@ export class Container extends Resource {
slug: LeafUri, slug: LeafUri,
blob: Blob, blob: Blob,
mimeType: string, mimeType: string,
): Promise<LeafCreateIfAbsentResult> { ): Promise<ResourceResult<LeafCreateIfAbsentResult, Leaf>> {
return this.child(slug).uploadIfAbsent(blob, mimeType); return this.child(slug).uploadIfAbsent(blob, mimeType);
} }
async clear(): Promise< async clear(): Promise<
| AggregateSuccess<DeleteSuccess> ResourceResult<
| AggregateError<DeleteResultError | ReadResultError> | AggregateSuccess<ResourceResult<DeleteSuccess, Container | Leaf>>
| AggregateError<DeleteResultError | ReadResultError>,
Container
>
> { > {
const readResult = await this.read(); const readResult = await this.read();
if (readResult.isError) return new AggregateError([readResult]); if (readResult.isError) return new AggregateError([readResult]);
@ -211,14 +256,42 @@ export class Container extends Resource {
if (errors.length > 0) { if (errors.length > 0) {
return new AggregateError(errors); return new AggregateError(errors);
} }
return new AggregateSuccess<DeleteSuccess>(results as DeleteSuccess[]); return {
isError: false,
type: "aggregateSuccess",
results: results as ResourceResult<DeleteSuccess, Container | Leaf>[],
resource: this,
};
} }
async delete(): Promise< async delete(): Promise<
DeleteResult | AggregateError<DeleteResultError | ReadResultError> ResourceResult<
DeleteResult | AggregateError<DeleteResultError | ReadResultError>,
Container
>
> { > {
const clearResult = await this.clear(); const clearResult = await this.clear();
if (clearResult.isError) return clearResult; 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<ContainerCreateAndOverwriteResult, Container>
> {
const createResult =
(await this.handleCreateAndOverwrite()) as ContainerCreateAndOverwriteResult;
if (createResult.isError) return createResult;
return { ...createResult, resource: this };
}
async createIfAbsent(): Promise<
ResourceResult<ContainerCreateIfAbsentResult, Container>
> {
const createResult =
(await this.handleCreateAndOverwrite()) as ContainerCreateIfAbsentResult;
if (createResult.isError) return createResult;
return { ...createResult, resource: this };
} }
} }

@ -10,20 +10,19 @@ import type { DeleteResult } from "../requester/requests/deleteResource";
import type { ReadLeafResult } from "../requester/requests/readResource"; import type { ReadLeafResult } from "../requester/requests/readResource";
import type { UpdateResult } from "../requester/requests/updateDataResource"; import type { UpdateResult } from "../requester/requests/updateDataResource";
import type { DeleteSuccess } from "../requester/results/success/DeleteSuccess"; import type { DeleteSuccess } from "../requester/results/success/DeleteSuccess";
import { import type { AbsentReadSuccess } from "../requester/results/success/ReadSuccess";
import type {
BinaryReadSuccess, BinaryReadSuccess,
DataReadSuccess, DataReadSuccess,
AbsentReadSuccess,
} from "../requester/results/success/ReadSuccess"; } from "../requester/results/success/ReadSuccess";
import type { ResourceSuccess } from "../requester/results/success/SuccessResult"; import type { ResourceSuccess } from "../requester/results/success/SuccessResult";
import { Unfetched } from "../requester/results/success/Unfetched";
import type { SolidLdoDatasetContext } from "../SolidLdoDatasetContext"; import type { SolidLdoDatasetContext } from "../SolidLdoDatasetContext";
import { getParentUri } from "../util/rdfUtils"; import { getParentUri } from "../util/rdfUtils";
import type { LeafUri } from "../util/uriTypes"; import type { LeafUri } from "../util/uriTypes";
import type { Container } from "./Container"; import type { Container } from "./Container";
import type { SharedStatuses } from "./Resource"; import type { SharedStatuses } from "./Resource";
import { Resource } from "./Resource"; import { Resource } from "./Resource";
import type { GetRootContainerSuccess } from "./resourceResults/GetRootContainerSuccess"; import type { ResourceResult } from "./ResourceResult";
export class Leaf extends Resource { export class Leaf extends Resource {
readonly uri: LeafUri; readonly uri: LeafUri;
@ -43,7 +42,7 @@ export class Leaf extends Resource {
super(context); super(context);
this.uri = uri; this.uri = uri;
this.requester = new LeafRequester(uri, context); this.requester = new LeafRequester(uri, context);
this.status = new Unfetched(this.uri); this.status = { isError: false, type: "unfetched", uri };
} }
// Getters // Getters
@ -81,27 +80,46 @@ export class Leaf extends Resource {
} }
} }
async read(): Promise<ReadLeafResult> { async read(): Promise<ResourceResult<ReadLeafResult, Leaf>> {
return (await super.read()) as ReadLeafResult; const result = (await this.handleRead()) as ReadLeafResult;
if (result.isError) return result;
return { ...result, resource: this };
} }
protected toReadResult(): ReadLeafResult { protected toReadResult(): ResourceResult<ReadLeafResult, Leaf> {
if (this.isAbsent()) { 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()) { } else if (this.isBinary()) {
return new BinaryReadSuccess( return {
this.uri, isError: false,
true, type: "binaryReadSuccess",
this.binaryData!.blob, uri: this.uri,
this.binaryData!.mimeType, recalledFromMemory: true,
); blob: this.binaryData!.blob,
mimeType: this.binaryData!.mimeType,
resource: this,
};
} else { } else {
return new DataReadSuccess(this.uri, true); return {
isError: false,
type: "dataReadSuccess",
uri: this.uri,
recalledFromMemory: true,
resource: this,
};
} }
} }
async readIfUnfetched(): Promise<ReadLeafResult> { async readIfUnfetched(): Promise<ResourceResult<ReadLeafResult, Leaf>> {
return super.readIfUnfetched() as Promise<ReadLeafResult>; return super.readIfUnfetched() as Promise<
ResourceResult<ReadLeafResult, Leaf>
>;
} }
// Parent Container Methods // Parent Container Methods
@ -109,7 +127,7 @@ export class Leaf extends Resource {
const parentUri = getParentUri(this.uri)!; const parentUri = getParentUri(this.uri)!;
return this.context.resourceStore.get(parentUri); return this.context.resourceStore.get(parentUri);
} }
getRootContainer(): Promise<GetRootContainerSuccess | CheckRootResultError> { getRootContainer(): Promise<Container | CheckRootResultError> {
const parentUri = getParentUri(this.uri)!; const parentUri = getParentUri(this.uri)!;
const parent = this.context.resourceStore.get(parentUri); const parent = this.context.resourceStore.get(parentUri);
return parent.getRootContainer(); return parent.getRootContainer();
@ -129,40 +147,60 @@ export class Leaf extends Resource {
async uploadAndOverwrite( async uploadAndOverwrite(
blob: Blob, blob: Blob,
mimeType: string, mimeType: string,
): Promise<LeafCreateAndOverwriteResult> { ): Promise<ResourceResult<LeafCreateAndOverwriteResult, Leaf>> {
const result = await this.requester.upload(blob, mimeType, true); const result = await this.requester.upload(blob, mimeType, true);
this.status = result; this.status = result;
if (result.isError) return result; if (result.isError) return result;
super.updateWithCreateSuccess(result); super.updateWithCreateSuccess(result);
this.binaryData = { blob, mimeType }; this.binaryData = { blob, mimeType };
this.emitThisAndParent(); this.emitThisAndParent();
return result; return { ...result, resource: this };
} }
async uploadIfAbsent( async uploadIfAbsent(
blob: Blob, blob: Blob,
mimeType: string, mimeType: string,
): Promise<LeafCreateIfAbsentResult> { ): Promise<ResourceResult<LeafCreateIfAbsentResult, Leaf>> {
const result = await this.requester.upload(blob, mimeType); const result = await this.requester.upload(blob, mimeType);
this.status = result; this.status = result;
if (result.isError) return result; if (result.isError) return result;
super.updateWithCreateSuccess(result); super.updateWithCreateSuccess(result);
this.binaryData = { blob, mimeType }; this.binaryData = { blob, mimeType };
this.emitThisAndParent(); this.emitThisAndParent();
return result; return { ...result, resource: this };
} }
async update(changes: DatasetChanges<Quad>): Promise<UpdateResult> { async update(
changes: DatasetChanges<Quad>,
): Promise<ResourceResult<UpdateResult, Leaf>> {
const result = await this.requester.updateDataResource(changes); const result = await this.requester.updateDataResource(changes);
this.status = result; this.status = result;
if (result.isError) return result; if (result.isError) return result;
this.binaryData = undefined; this.binaryData = undefined;
this.absent = false; this.absent = false;
this.emitThisAndParent(); this.emitThisAndParent();
return result; return { ...result, resource: this };
} }
async delete(): Promise<DeleteResult> { async delete(): Promise<DeleteResult> {
return this.handleDelete(); return this.handleDelete();
} }
async createAndOverwrite(): Promise<
ResourceResult<LeafCreateAndOverwriteResult, Leaf>
> {
const createResult =
(await this.handleCreateAndOverwrite()) as LeafCreateAndOverwriteResult;
if (createResult.isError) return createResult;
return { ...createResult, resource: this };
}
async createIfAbsent(): Promise<
ResourceResult<LeafCreateIfAbsentResult, Leaf>
> {
const createResult =
(await this.handleCreateAndOverwrite()) as LeafCreateIfAbsentResult;
if (createResult.isError) return createResult;
return { ...createResult, resource: this };
}
} }

@ -19,16 +19,15 @@ import EventEmitter from "events";
import { getParentUri } from "../util/rdfUtils"; import { getParentUri } from "../util/rdfUtils";
import type { RequesterResult } from "../requester/results/RequesterResult"; import type { RequesterResult } from "../requester/results/RequesterResult";
import type { DeleteResult } from "../requester/requests/deleteResource"; 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 { DeleteSuccess } from "../requester/results/success/DeleteSuccess";
import type { ResourceSuccess } from "../requester/results/success/SuccessResult"; import type { ResourceSuccess } from "../requester/results/success/SuccessResult";
import type { Unfetched } from "../requester/results/success/Unfetched"; import type { Unfetched } from "../requester/results/success/Unfetched";
import type { CreateSuccess } from "../requester/results/success/CreateSuccess"; import type { CreateSuccess } from "../requester/results/success/CreateSuccess";
import type { GetRootContainerSuccess } from "./resourceResults/GetRootContainerSuccess"; import type { ResourceResult } from "./resourceResult/ResourceResult";
import type { import type { Container } from "./Container";
ReadResourceSuccessContainerTypes, import type { Leaf } from "./Leaf";
ReadResourceSuccessLeafTypes,
} from "./resourceResults/ReadResourceSuccess";
export type SharedStatuses = Unfetched | DeleteResult | CreateSuccess; export type SharedStatuses = Unfetched | DeleteResult | CreateSuccess;
@ -96,9 +95,7 @@ export abstract class Resource extends (EventEmitter as new () => TypedEmitter<{
this.didInitialFetch = true; this.didInitialFetch = true;
} }
async read(): Promise< protected async handleRead(): Promise<ReadContainerResult | ReadLeafResult> {
ReadResourceSuccessContainerTypes | ReadResourceSuccessLeafTypes
> {
const result = await this.requester.read(); const result = await this.requester.read();
this.status = result; this.status = result;
if (result.isError) return result; if (result.isError) return result;
@ -107,9 +104,18 @@ export abstract class Resource extends (EventEmitter as new () => TypedEmitter<{
return result; return result;
} }
protected abstract toReadResult(): ReadContainerResult | ReadLeafResult; protected abstract toReadResult(): ResourceResult<
ReadLeafResult | ReadContainerResult,
Container | Leaf
>;
async readIfUnfetched(): Promise<ReadContainerResult | ReadLeafResult> { abstract read(): Promise<
ResourceResult<ReadLeafResult | ReadContainerResult, Container | Leaf>
>;
async readIfUnfetched(): Promise<
ResourceResult<ReadLeafResult | ReadContainerResult, Container | Leaf>
> {
if (this.didInitialFetch) { if (this.didInitialFetch) {
const readResult = this.toReadResult(); const readResult = this.toReadResult();
this.status = readResult; this.status = readResult;
@ -137,12 +143,19 @@ export abstract class Resource extends (EventEmitter as new () => TypedEmitter<{
protected updateWithCreateSuccess(result: ResourceSuccess) { protected updateWithCreateSuccess(result: ResourceSuccess) {
this.absent = false; this.absent = false;
this.didInitialFetch = true; this.didInitialFetch = true;
if (result instanceof ReadSuccess) { if (isReadSuccess(result)) {
this.updateWithReadSuccess(result); this.updateWithReadSuccess(result);
} }
} }
async createAndOverwrite(): Promise< abstract createAndOverwrite(): Promise<
ResourceResult<
ContainerCreateAndOverwriteResult | LeafCreateAndOverwriteResult,
Leaf | Container
>
>;
protected async handleCreateAndOverwrite(): Promise<
ContainerCreateAndOverwriteResult | LeafCreateAndOverwriteResult ContainerCreateAndOverwriteResult | LeafCreateAndOverwriteResult
> { > {
const result = await this.requester.createDataResource(true); const result = await this.requester.createDataResource(true);
@ -153,7 +166,14 @@ export abstract class Resource extends (EventEmitter as new () => TypedEmitter<{
return result; return result;
} }
async createIfAbsent(): Promise< abstract createIfAbsent(): Promise<
ResourceResult<
ContainerCreateIfAbsentResult | LeafCreateIfAbsentResult,
Leaf | Container
>
>;
protected async handleCreateIfAbsent(): Promise<
ContainerCreateIfAbsentResult | LeafCreateIfAbsentResult ContainerCreateIfAbsentResult | LeafCreateIfAbsentResult
> { > {
const result = await this.requester.createDataResource(true); 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 // Parent Container Methods -- Remember to change for Container
abstract getRootContainer(): Promise< abstract getRootContainer(): Promise<Container | CheckRootResultError>;
GetRootContainerSuccess | CheckRootResultError
>;
// Access Rules Methods // Access Rules Methods
// async getAccessRules(): Promise<AccessRuleResult | AccessRuleFetchError> { // async getAccessRules(): Promise<AccessRuleResult | AccessRuleFetchError> {
// return getAccessRules({ uri: this.uri, fetch: this.context.fetch }); // return getAccessRules({ uri: this.uri, fetch: this.context.fetch });
// } // }
async setAccessRules( async setAccessRules(
newAccessRules: AccessRule, newAccessRules: AccessRule,
): Promise<SetAccessRulesResult> { ): Promise<ResourceResult<SetAccessRulesResult, Leaf | Container>> {
return setAccessRules(this.uri, newAccessRules, { const result = await setAccessRules(this.uri, newAccessRules, {
fetch: this.context.fetch, fetch: this.context.fetch,
}); });
if (result.isError) return result;
return { ...result, resource: this as unknown as Leaf | Container };
} }
} }

@ -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 };

@ -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<Result, ResourceType>;

@ -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;
}
}

@ -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;
}
}

@ -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;
}
}

@ -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<Container>
| ReadResultError;
export type ReadResourceSuccessLeafTypes =
| DataResourceReadSuccess
| BinaryResourceReadSuccess
| AbsentResourceReadSuccess<Leaf>
| 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;
}
}

@ -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;
}
}
Loading…
Cancel
Save