You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
203 lines
6.0 KiB
203 lines
6.0 KiB
import { ANY_KEY, RequestBatcher } from "../util/RequestBatcher.js";
|
|
import type { ConnectedContext } from "@ldo/connected";
|
|
import type {
|
|
ContainerCreateAndOverwriteResult,
|
|
ContainerCreateIfAbsentResult,
|
|
LeafCreateAndOverwriteResult,
|
|
LeafCreateIfAbsentResult,
|
|
} from "./requests/createDataResource.js";
|
|
import { createDataResource } from "./requests/createDataResource.js";
|
|
import type {
|
|
ReadContainerResult,
|
|
ReadLeafResult,
|
|
} from "./requests/readResource.js";
|
|
import { readResource } from "./requests/readResource.js";
|
|
import type { DeleteResult } from "./requests/deleteResource.js";
|
|
import { deleteResource } from "./requests/deleteResource.js";
|
|
import { modifyQueueByMergingEventsWithTheSameKeys } from "./util/modifyQueueFuntions.js";
|
|
import type { SolidConnectedPlugin } from "../SolidConnectedPlugin.js";
|
|
import type { SolidContainer } from "../resources/SolidContainer.js";
|
|
import type { SolidLeaf } from "../resources/SolidLeaf.js";
|
|
|
|
const READ_KEY = "read";
|
|
const CREATE_KEY = "createDataResource";
|
|
const DELETE_KEY = "delete";
|
|
|
|
/**
|
|
* @internal
|
|
*
|
|
* A singleton for handling batched requests
|
|
*/
|
|
export abstract class BatchedRequester<
|
|
ResourceType extends SolidContainer | SolidLeaf,
|
|
> {
|
|
/**
|
|
* @internal
|
|
* A request batcher to maintain state for ongoing requests
|
|
*/
|
|
protected readonly requestBatcher = new RequestBatcher();
|
|
|
|
/**
|
|
* The uri of the resource
|
|
*/
|
|
abstract readonly resource: ResourceType;
|
|
|
|
/**
|
|
* @internal
|
|
* ConnectedContext for the parent Dataset
|
|
*/
|
|
protected context: ConnectedContext<SolidConnectedPlugin[]>;
|
|
|
|
/**
|
|
* @param context - SolidLdoDatasetContext for the parent SolidLdoDataset
|
|
*/
|
|
constructor(context: ConnectedContext<SolidConnectedPlugin[]>) {
|
|
this.context = context;
|
|
}
|
|
|
|
/**
|
|
* Checks if the resource is currently making any request
|
|
* @returns true if the resource is making any requests
|
|
*/
|
|
isLoading(): boolean {
|
|
return this.requestBatcher.isLoading(ANY_KEY);
|
|
}
|
|
|
|
/**
|
|
* Checks if the resource is currently executing a create request
|
|
* @returns true if the resource is currently executing a create request
|
|
*/
|
|
isCreating(): boolean {
|
|
return this.requestBatcher.isLoading(CREATE_KEY);
|
|
}
|
|
|
|
/**
|
|
* Checks if the resource is currently executing a read request
|
|
* @returns true if the resource is currently executing a read request
|
|
*/
|
|
isReading(): boolean {
|
|
return this.requestBatcher.isLoading(READ_KEY);
|
|
}
|
|
|
|
/**
|
|
* Checks if the resource is currently executing a delete request
|
|
* @returns true if the resource is currently executing a delete request
|
|
*/
|
|
isDeletinng(): boolean {
|
|
return this.requestBatcher.isLoading(DELETE_KEY);
|
|
}
|
|
|
|
/**
|
|
* Read this resource.
|
|
* @returns A ReadLeafResult or a ReadContainerResult depending on the uri of
|
|
* this resource
|
|
*/
|
|
async read(): Promise<ReadLeafResult | ReadContainerResult> {
|
|
const transaction = this.context.dataset.startTransaction();
|
|
const result = await this.requestBatcher.queueProcess({
|
|
name: READ_KEY,
|
|
args: [
|
|
this.resource,
|
|
{ dataset: transaction, fetch: this.context.solid.fetch },
|
|
],
|
|
perform: readResource,
|
|
modifyQueue: modifyQueueByMergingEventsWithTheSameKeys(READ_KEY),
|
|
after: (result) => {
|
|
if (!result.isError) {
|
|
transaction.commit();
|
|
}
|
|
},
|
|
});
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Delete this resource
|
|
* @returns A DeleteResult
|
|
*/
|
|
async delete(): Promise<DeleteResult<ResourceType>> {
|
|
const transaction = this.context.dataset.startTransaction();
|
|
const result = await this.requestBatcher.queueProcess({
|
|
name: DELETE_KEY,
|
|
args: [
|
|
this.resource,
|
|
{ dataset: transaction, fetch: this.context.solid.fetch },
|
|
],
|
|
perform: deleteResource,
|
|
modifyQueue: modifyQueueByMergingEventsWithTheSameKeys(DELETE_KEY),
|
|
after: (result) => {
|
|
if (!result.isError) {
|
|
transaction.commit();
|
|
}
|
|
},
|
|
});
|
|
return result as DeleteResult<ResourceType>;
|
|
}
|
|
|
|
/**
|
|
* Creates a Resource
|
|
* @param overwrite - If true, this will orverwrite the resource if it already
|
|
* exists
|
|
* @returns A ContainerCreateAndOverwriteResult or a
|
|
* LeafCreateAndOverwriteResult depending on this resource's URI
|
|
*/
|
|
createDataResource(
|
|
overwrite: true,
|
|
): Promise<ContainerCreateAndOverwriteResult | LeafCreateAndOverwriteResult>;
|
|
createDataResource(
|
|
overwrite?: false,
|
|
): Promise<ContainerCreateIfAbsentResult | LeafCreateIfAbsentResult>;
|
|
createDataResource(
|
|
overwrite?: boolean,
|
|
): Promise<
|
|
| ContainerCreateAndOverwriteResult
|
|
| LeafCreateAndOverwriteResult
|
|
| ContainerCreateIfAbsentResult
|
|
| LeafCreateIfAbsentResult
|
|
>;
|
|
async createDataResource(
|
|
overwrite?: boolean,
|
|
): Promise<
|
|
| ContainerCreateAndOverwriteResult
|
|
| LeafCreateAndOverwriteResult
|
|
| ContainerCreateIfAbsentResult
|
|
| LeafCreateIfAbsentResult
|
|
> {
|
|
const transaction = this.context.dataset.startTransaction();
|
|
const result = await this.requestBatcher.queueProcess({
|
|
name: CREATE_KEY,
|
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
// @ts-ignore Apparently this is a nasty type and I can't be bothered to fix it
|
|
args: [
|
|
this.resource,
|
|
overwrite ?? false,
|
|
{ dataset: transaction, fetch: this.context.solid.fetch },
|
|
],
|
|
perform: createDataResource,
|
|
modifyQueue: (queue, currentlyLoading, args) => {
|
|
const lastElementInQueue = queue[queue.length - 1];
|
|
if (
|
|
lastElementInQueue &&
|
|
lastElementInQueue.name === CREATE_KEY &&
|
|
!!lastElementInQueue.args[1] === !!args[1]
|
|
) {
|
|
return lastElementInQueue;
|
|
}
|
|
if (
|
|
currentlyLoading &&
|
|
currentlyLoading.name === CREATE_KEY &&
|
|
!!currentlyLoading.args[1] === !!args[1]
|
|
) {
|
|
return currentlyLoading;
|
|
}
|
|
return undefined;
|
|
},
|
|
after: (result) => {
|
|
if (!result.isError) {
|
|
transaction.commit();
|
|
}
|
|
},
|
|
});
|
|
return result;
|
|
}
|
|
}
|
|
|