parent
81aa841f6b
commit
a2d03e5431
@ -0,0 +1,62 @@ |
||||
/* eslint-disable @typescript-eslint/no-explicit-any */ |
||||
import type { ConnectedLdoDataset, ConnectedPlugin } from "@ldo/connected"; |
||||
import type { SolidContainerUri, SolidLeafUri } from "./types"; |
||||
import type { GetStorageContainerFromWebIdSuccess } from "./requester/results/success/CheckRootContainerSuccess"; |
||||
import type { CheckRootResultError } from "./requester/requests/checkRootContainer"; |
||||
import type { ReadResultError } from "./requester/requests/readResource"; |
||||
import type { NoRootContainerError } from "./requester/results/error/NoRootContainerError"; |
||||
import type { SolidLeaf } from "./resources/SolidLeaf"; |
||||
import type { SolidContainer } from "./resources/SolidContainer"; |
||||
import type { SolidConnectedPlugin } from "./SolidConnectedPlugin"; |
||||
import { ProfileWithStorageShapeType } from "./.ldo/solid.shapeTypes"; |
||||
|
||||
/** |
||||
* Gets a list of root storage containers for a user given their WebId |
||||
* @param webId: The webId for the user |
||||
* @returns A list of storages if successful, an error if not |
||||
* @example |
||||
* ```typescript
|
||||
* const result = await getStorageFromWebId( |
||||
* solidLdoDataset, |
||||
* "https://example.com/profile/card#me" |
||||
* ); |
||||
* if (result.isError) { |
||||
* // Do something
|
||||
* } |
||||
* console.log(result.storageContainer[0].uri); |
||||
* ``` |
||||
*/ |
||||
export async function getStorageFromWebId( |
||||
webId: SolidLeafUri, |
||||
dataset: ConnectedLdoDataset<(SolidConnectedPlugin | ConnectedPlugin)[]>, |
||||
): Promise< |
||||
| GetStorageContainerFromWebIdSuccess |
||||
| CheckRootResultError |
||||
| ReadResultError<SolidLeaf | SolidContainer> |
||||
| NoRootContainerError<SolidContainer> |
||||
> { |
||||
const webIdResource = dataset.getResource(webId) as SolidLeaf; |
||||
const readResult = await webIdResource.readIfUnfetched(); |
||||
if (readResult.isError) return readResult; |
||||
const profile = this.usingType(ProfileWithStorageShapeType).fromSubject( |
||||
webId, |
||||
); |
||||
if (profile.storage && profile.storage.size > 0) { |
||||
const containers = profile.storage.map((storageNode) => |
||||
this.getResource(storageNode["@id"] as SolidContainerUri), |
||||
); |
||||
return { |
||||
type: "getStorageContainerFromWebIdSuccess", |
||||
isError: false, |
||||
storageContainers: containers, |
||||
}; |
||||
} |
||||
const getContainerResult = await webIdResource.getRootContainer(); |
||||
if (getContainerResult.type === "container") |
||||
return { |
||||
type: "getStorageContainerFromWebIdSuccess", |
||||
isError: false, |
||||
storageContainers: [getContainerResult], |
||||
}; |
||||
return getContainerResult; |
||||
} |
@ -1,64 +0,0 @@ |
||||
import { |
||||
AggregateError, |
||||
ErrorResult, |
||||
ResourceError, |
||||
UnexpectedResourceError, |
||||
} from "../src/requester/results/error/ErrorResult"; |
||||
import { InvalidUriError } from "../src/requester/results/error/InvalidUriError"; |
||||
|
||||
describe("ErrorResult", () => { |
||||
describe("fromThrown", () => { |
||||
it("returns an UnexpecteResourceError if a string is provided", () => { |
||||
expect( |
||||
UnexpectedResourceError.fromThrown("https://example.com/", "hello") |
||||
.message, |
||||
).toBe("hello"); |
||||
}); |
||||
|
||||
it("returns an UnexpecteResourceError if an odd valud is provided", () => { |
||||
expect( |
||||
UnexpectedResourceError.fromThrown("https://example.com/", 5).message, |
||||
).toBe("Error of type number thrown: 5"); |
||||
}); |
||||
}); |
||||
|
||||
describe("AggregateError", () => { |
||||
it("flattens aggregate errors provided to the constructor", () => { |
||||
const err1 = UnexpectedResourceError.fromThrown("https://abc.com", "1"); |
||||
const err2 = UnexpectedResourceError.fromThrown("https://abc.com", "2"); |
||||
const err3 = UnexpectedResourceError.fromThrown("https://abc.com", "3"); |
||||
const err4 = UnexpectedResourceError.fromThrown("https://abc.com", "4"); |
||||
const aggErr1 = new AggregateError([err1, err2]); |
||||
const aggErr2 = new AggregateError([err3, err4]); |
||||
const finalAgg = new AggregateError([aggErr1, aggErr2]); |
||||
expect(finalAgg.errors.length).toBe(4); |
||||
}); |
||||
}); |
||||
|
||||
describe("default messages", () => { |
||||
class ConcreteResourceError extends ResourceError { |
||||
readonly type = "concreteResourceError" as const; |
||||
} |
||||
class ConcreteErrorResult extends ErrorResult { |
||||
readonly type = "concreteErrorResult" as const; |
||||
} |
||||
|
||||
it("ResourceError fallsback to a default message if none is provided", () => { |
||||
expect(new ConcreteResourceError("https://example.com/").message).toBe( |
||||
"An unkown error for https://example.com/", |
||||
); |
||||
}); |
||||
|
||||
it("ErrorResult fallsback to a default message if none is provided", () => { |
||||
expect(new ConcreteErrorResult().message).toBe( |
||||
"An unkown error was encountered.", |
||||
); |
||||
}); |
||||
|
||||
it("InvalidUriError fallsback to a default message if none is provided", () => { |
||||
expect(new InvalidUriError("https://example.com/").message).toBe( |
||||
"https://example.com/ is an invalid uri.", |
||||
); |
||||
}); |
||||
}); |
||||
}); |
@ -0,0 +1,91 @@ |
||||
import { startTransaction, type LdoBase, write, getDataset } from "@ldo/ldo"; |
||||
import type { Quad } from "@rdfjs/types"; |
||||
import { _proxyContext, getProxyFromObject } from "@ldo/jsonld-dataset-proxy"; |
||||
import type { SubscribableDataset } from "@ldo/subscribable-dataset"; |
||||
import type { Resource } from "./Resource"; |
||||
import type { ConnectedLdoTransactionDataset } from "./ConnectedLdoTransactionDataset"; |
||||
import type { |
||||
AggregateSuccess, |
||||
SuccessResult, |
||||
} from "./results/success/SuccessResult"; |
||||
import type { AggregateError, ErrorResult } from "./results/error/ErrorResult"; |
||||
|
||||
/** |
||||
* Begins tracking changes to eventually commit. |
||||
* |
||||
* @param input - A linked data object to track changes on |
||||
* @param resource - A resource that all additions will eventually be committed to |
||||
* @param additionalResources - Any additional resources that changes will eventually be committed to |
||||
* |
||||
* @returns A transactable Linked Data Object |
||||
* |
||||
* @example |
||||
* ```typescript
|
||||
* import { changeData } from "@ldo/solid"; |
||||
* |
||||
* // ...
|
||||
* |
||||
* const profile = solidLdoDataset |
||||
* .using(ProfileShapeType) |
||||
* .fromSubject("https://example.com/profile#me"); |
||||
* const resource = solidLdoDataset.getResource("https://example.com/profile"); |
||||
* |
||||
* const cProfile = changeData(profile, resource); |
||||
* cProfile.name = "My New Name"; |
||||
* const result = await commitData(cProfile); |
||||
* ``` |
||||
*/ |
||||
export function changeData<Type extends LdoBase>( |
||||
input: Type, |
||||
resource: Resource, |
||||
...additionalResources: Resource[] |
||||
): Type { |
||||
const resources = [resource, ...additionalResources]; |
||||
// Clone the input and set a graph
|
||||
const [transactionLdo] = write(...resources.map((r) => r.uri)).usingCopy( |
||||
input, |
||||
); |
||||
// Start a transaction with the input
|
||||
startTransaction(transactionLdo); |
||||
// Return
|
||||
return transactionLdo; |
||||
} |
||||
|
||||
/** |
||||
* Commits the transaction to the global dataset, syncing all subscribing |
||||
* components and Solid Pods |
||||
* |
||||
* @param input - A transactable linked data object |
||||
* |
||||
* @example |
||||
* ```typescript
|
||||
* import { changeData } from "@ldo/solid"; |
||||
* |
||||
* // ...
|
||||
* |
||||
* const profile = solidLdoDataset |
||||
* .using(ProfileShapeType) |
||||
* .fromSubject("https://example.com/profile#me"); |
||||
* const resource = solidLdoDataset.getResource("https://example.com/profile"); |
||||
* |
||||
* const cProfile = changeData(profile, resource); |
||||
* cProfile.name = "My New Name"; |
||||
* const result = await commitData(cProfile); |
||||
* ``` |
||||
*/ |
||||
export async function commitData( |
||||
input: LdoBase, |
||||
): Promise<AggregateSuccess<SuccessResult> | AggregateError<ErrorResult>> { |
||||
const transactionDataset = getDataset( |
||||
input, |
||||
) as ConnectedLdoTransactionDataset<[]>; |
||||
const result = await transactionDataset.commitToRemote(); |
||||
if (result.isError) return result; |
||||
// Take the LdoProxy out of commit mode. This uses hidden methods of JSONLD-DATASET-PROXY
|
||||
const proxy = getProxyFromObject(input); |
||||
proxy[_proxyContext] = proxy[_proxyContext].duplicate({ |
||||
dataset: proxy[_proxyContext].state |
||||
.parentDataset as SubscribableDataset<Quad>, |
||||
}); |
||||
return result; |
||||
} |
Loading…
Reference in new issue