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.
127 lines
4.1 KiB
127 lines
4.1 KiB
import { parseRdf } from "@ldo/ldo";
|
|
import type { ResourceDependencies } from "../Resource";
|
|
import { Resource } from "../Resource";
|
|
import { DocumentFetchError } from "../../errors/DocumentFetchError";
|
|
import { DocumentError } from "../../errors/DocumentError";
|
|
import { namedNode, quad as createQuad } from "@rdfjs/data-model";
|
|
import type { DatasetChanges } from "@ldo/subscribable-dataset";
|
|
import type { Quad } from "@rdfjs/types";
|
|
import { changesToSparqlUpdate } from "../../../util/changesToSparqlUpdate";
|
|
import type { SolidLdoDataset } from "../../../SolidLdoDataset";
|
|
|
|
export interface DataResourceDependencies extends ResourceDependencies {
|
|
dataset: SolidLdoDataset;
|
|
}
|
|
|
|
export class DataResource extends Resource {
|
|
private dependencies2;
|
|
|
|
constructor(uri: string, dependencies: DataResourceDependencies) {
|
|
super(uri, dependencies);
|
|
this.dependencies2 = dependencies;
|
|
}
|
|
|
|
/**
|
|
* ===========================================================================
|
|
* Getters
|
|
* ===========================================================================
|
|
*/
|
|
protected get dataset() {
|
|
return this.dependencies2.dataset;
|
|
}
|
|
|
|
protected get updateManager() {
|
|
return this.dependencies2.updateManager;
|
|
}
|
|
|
|
/**
|
|
* ===========================================================================
|
|
* Methods
|
|
* ===========================================================================
|
|
*/
|
|
async create() {
|
|
// TODO
|
|
}
|
|
|
|
protected async fetchDocument(): Promise<DocumentError | undefined> {
|
|
// Fetch the document using auth fetch
|
|
const response = await this.fetch(this.uri, {
|
|
headers: {
|
|
accept: "text/turtle",
|
|
},
|
|
});
|
|
// Handle Error
|
|
if (response.status !== 200) {
|
|
// TODO: Handle edge cases
|
|
return new DocumentFetchError(
|
|
this,
|
|
response.status,
|
|
`Error fetching resource ${this.uri}`,
|
|
);
|
|
}
|
|
// Parse the incoming turtle into a dataset
|
|
const rawTurtle = await response.text();
|
|
let loadedDataset;
|
|
try {
|
|
loadedDataset = await parseRdf(rawTurtle, {
|
|
baseIRI: this.uri,
|
|
});
|
|
} catch (err) {
|
|
if (typeof err === "object" && (err as Error).message) {
|
|
return new DocumentError(this, (err as Error).message);
|
|
}
|
|
return new DocumentError(this, "Server returned poorly formatted Turtle");
|
|
}
|
|
// Start transaction
|
|
const transactionalDataset = this.dataset.startTransaction();
|
|
const graphNode = namedNode(this.uri);
|
|
// Destroy all triples that were once a part of this resouce
|
|
loadedDataset.deleteMatches(undefined, undefined, undefined, graphNode);
|
|
// Add the triples from the fetched item
|
|
loadedDataset.forEach((quad) => {
|
|
transactionalDataset.add(
|
|
createQuad(quad.subject, quad.predicate, quad.object, graphNode),
|
|
);
|
|
});
|
|
const changes = transactionalDataset.getChanges();
|
|
this.updateManager.notifyListenersOfChanges(changes);
|
|
transactionalDataset.commit();
|
|
return undefined;
|
|
}
|
|
|
|
async update(
|
|
changes: DatasetChanges<Quad>,
|
|
): Promise<DocumentError | undefined> {
|
|
this.beginWrite();
|
|
// Convert changes to transactional Dataset
|
|
const transactionalDataset = this.dataset.startTransaction();
|
|
changes.added?.forEach((quad) => transactionalDataset.add(quad));
|
|
changes.removed?.forEach((quad) => transactionalDataset.delete(quad));
|
|
// Commit data optimistically
|
|
transactionalDataset.commit();
|
|
this.updateManager.notifyListenersOfChanges(changes);
|
|
// Make request
|
|
const sparqlUpdate = await changesToSparqlUpdate(changes);
|
|
const response = await this.fetch(this.uri, {
|
|
method: "PATCH",
|
|
body: sparqlUpdate,
|
|
headers: {
|
|
"Content-Type": "application/sparql-update",
|
|
},
|
|
});
|
|
if (response.status < 200 || response.status > 299) {
|
|
// Handle Error by rollback
|
|
transactionalDataset.rollback();
|
|
this.updateManager.notifyListenersOfChanges(changes);
|
|
this.endWrite(
|
|
new DocumentFetchError(
|
|
this,
|
|
response.status,
|
|
`Problem writing to ${this.uri}`,
|
|
),
|
|
);
|
|
return;
|
|
}
|
|
this.endWrite();
|
|
}
|
|
}
|
|
|