Added update method

main
Jackson Morgan 6 months ago
parent 11bf103980
commit 8dd341bb87
  1. 8
      packages/connected/src/ConnectedContext.ts
  2. 11
      packages/connected/src/ConnectedLdoDataset.ts
  3. 51
      packages/connected/src/ConnectedLdoTransactionDataset.ts
  4. 7
      packages/connected/src/ConnectedPlugin.ts
  5. 5
      packages/connected/src/util/splitChangesByGraph.d.ts
  6. 45
      packages/connected/src/util/splitChangesByGraph.js
  7. 1
      packages/connected/src/util/splitChangesByGraph.js.map
  8. 14
      packages/connected/test/MockResource.ts
  9. 5
      packages/connected/tsconfig.build.json

@ -0,0 +1,8 @@
import type { ConnectedLdoDataset } from "./ConnectedLdoDataset";
import type { ConnectedPlugin } from "./ConnectedPlugin";
export type ConnectedContext<Plugins extends ConnectedPlugin[]> = {
dataset: ConnectedLdoDataset<Plugins>;
} & {
[P in Plugins[number] as P["name"]]: P["types"]["context"];
};

@ -33,6 +33,8 @@ export class ConnectedLdoDataset<Plugins extends ConnectedPlugin[]>
super(datasetFactory, transactionDatasetFactory, initialDataset); super(datasetFactory, transactionDatasetFactory, initialDataset);
this.plugins = plugins; this.plugins = plugins;
this.resourceMap = new Map(); this.resourceMap = new Map();
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore this is a builder. It will eventually match
this.context = { this.context = {
dataset: this, dataset: this,
}; };
@ -91,6 +93,7 @@ export class ConnectedLdoDataset<Plugins extends ConnectedPlugin[]>
resource = plugin.getResource(uri, this.context); resource = plugin.getResource(uri, this.context);
this.resourceMap.set(normalizedUri, resource); this.resourceMap.set(normalizedUri, resource);
} }
// HACK: cast to any
return resource as any; return resource as any;
} }
@ -99,10 +102,14 @@ export class ConnectedLdoDataset<Plugins extends ConnectedPlugin[]>
Plugin extends Extract<Plugins[number], { name: Name }>, Plugin extends Extract<Plugins[number], { name: Name }>,
>(name: Name): Promise<ReturnType<Plugin["createResource"]>> { >(name: Name): Promise<ReturnType<Plugin["createResource"]>> {
const validPlugin = this.plugins.find((plugin) => name === plugin.name)!; const validPlugin = this.plugins.find((plugin) => name === plugin.name)!;
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore I'm not sure why this doesn't work
const newResourceResult = await validPlugin.createResource(this.context); const newResourceResult = await validPlugin.createResource(this.context);
if (newResourceResult.isError) return newResourceResult; // HACK: cast to any
if (newResourceResult.isError) return newResourceResult as any;
this.resourceMap.set(newResourceResult.uri, newResourceResult); this.resourceMap.set(newResourceResult.uri, newResourceResult);
return newResourceResult; // HACK: cast to any
return newResourceResult as any;
} }
setContext< setContext<

@ -6,19 +6,19 @@ import {
type ITransactionDatasetFactory, type ITransactionDatasetFactory,
} from "@ldo/subscribable-dataset"; } from "@ldo/subscribable-dataset";
import type { DatasetChanges, GraphNode } from "@ldo/rdf-utils"; import type { DatasetChanges, GraphNode } from "@ldo/rdf-utils";
import type { ConnectedLdoDataset } from "./ConnectedLdoDataset";
import type { ConnectedPlugin } from "./ConnectedPlugin"; import type { ConnectedPlugin } from "./ConnectedPlugin";
import type { ConnectedContext } from "./ConnectedContext"; import type { ConnectedContext } from "./ConnectedContext";
import type { InvalidIdentifierResource } from "./InvalidIdentifierResource"; import type { InvalidIdentifierResource } from "./InvalidIdentifierResource";
import type { IConnectedLdoDataset } from "./IConnectedLdoDataset"; import type { IConnectedLdoDataset } from "./IConnectedLdoDataset";
import { splitChangesByGraph } from "./util/splitChangesByGraph"; import { splitChangesByGraph } from "./util/splitChangesByGraph";
import type { import type { IgnoredInvalidUpdateSuccess } from "./results/success/UpdateSuccess";
IgnoredInvalidUpdateSuccess,
UpdateSuccess,
} from "./results/success/UpdateSuccess";
import { UpdateDefaultGraphSuccess } from "./results/success/UpdateSuccess"; import { UpdateDefaultGraphSuccess } from "./results/success/UpdateSuccess";
import type { ErrorResult } from "./results/error/ErrorResult";
import { AggregateError } from "./results/error/ErrorResult"; import { AggregateError } from "./results/error/ErrorResult";
import type { AggregateSuccess } from "./results/success/SuccessResult"; import type {
AggregateSuccess,
SuccessResult,
} from "./results/success/SuccessResult";
/** /**
* A SolidLdoTransactionDataset has all the functionality of a SolidLdoDataset * A SolidLdoTransactionDataset has all the functionality of a SolidLdoDataset
@ -138,12 +138,16 @@ export class ConnectedLdoTransactionDataset<Plugins extends ConnectedPlugin[]>
async commitChanges(): Promise< async commitChanges(): Promise<
| AggregateSuccess< | AggregateSuccess<
| UpdateSuccess<Plugins[number]["types"]["resource"]> | Extract<
Awaited<ReturnType<Plugins[number]["types"]["resource"]["update"]>>,
{ isError: false }
>
| UpdateDefaultGraphSuccess | UpdateDefaultGraphSuccess
| IgnoredInvalidUpdateSuccess<Plugins[number]["types"]["resource"]>
> >
| AggregateError< | AggregateError<
Extract< Extract<
ReturnType<Plugins[number]["types"]["resource"]["update"]>, Awaited<ReturnType<Plugins[number]["types"]["resource"]["update"]>>,
{ isError: true } { isError: true }
> >
> >
@ -156,7 +160,7 @@ export class ConnectedLdoTransactionDataset<Plugins extends ConnectedPlugin[]>
GraphNode, GraphNode,
DatasetChanges<Quad>, DatasetChanges<Quad>,
( (
| ReturnType<Plugins[number]["types"]["resource"]["update"]> | Awaited<ReturnType<Plugins[number]["types"]["resource"]["update"]>>
| IgnoredInvalidUpdateSuccess<any> | IgnoredInvalidUpdateSuccess<any>
| UpdateDefaultGraphSuccess | UpdateDefaultGraphSuccess
), ),
@ -168,32 +172,33 @@ export class ConnectedLdoTransactionDataset<Plugins extends ConnectedPlugin[]>
updateDatasetInBulk(this.parentDataset, datasetChanges); updateDatasetInBulk(this.parentDataset, datasetChanges);
return [graph, datasetChanges, new UpdateDefaultGraphSuccess()]; return [graph, datasetChanges, new UpdateDefaultGraphSuccess()];
} }
const resource = this.getResource(graph.value); const resource = this.getResource(
const updateResult = await resource.update(datasetChanges); graph.value,
) as Plugins[number]["types"]["resource"];
const updateResult = (await resource.update(
datasetChanges,
)) as Awaited<
ReturnType<Plugins[number]["types"]["resource"]["update"]>
>;
return [graph, datasetChanges, updateResult]; return [graph, datasetChanges, updateResult];
}, },
), ),
); );
// If one has errored, return error // If one has errored, return error
const errors = results.filter((result) => result[2].isError); const errors = (
results.map((result) => result[2]) as (SuccessResult | ErrorResult)[]
).filter((result): result is ErrorResult => result.isError);
if (errors.length > 0) { if (errors.length > 0) {
return new AggregateError( // HACK: Cast to Any
errors.map((result) => result[2] as UpdateResultError), return new AggregateError(errors) as any;
);
} }
return { return {
isError: false, isError: false,
type: "aggregateSuccess", type: "aggregateSuccess",
results: results // HACK: Cast to Any
.map((result) => result[2]) results: results.map((result) => result[2]) as any,
.filter(
(result): result is ResourceResult<UpdateSuccess, Leaf> =>
result.type === "updateSuccess" ||
result.type === "updateDefaultGraphSuccess" ||
result.type === "ignoredInvalidUpdateSuccess",
),
}; };
} }
} }

@ -10,9 +10,12 @@ export interface ConnectedPlugin<
ContextType = any, ContextType = any,
> { > {
name: Name; name: Name;
getResource(uri: UriType, context: ConnectedContext<this[]>): ResourceType; getResource(
uri: UriType,
context: ConnectedContext<ConnectedPlugin[]>,
): ResourceType;
createResource( createResource(
context: ConnectedContext<this[]>, context: ConnectedContext<ConnectedPlugin[]>,
): Promise<ResourceType | ErrorResult>; ): Promise<ResourceType | ErrorResult>;
isUriValid(uri: UriType): uri is UriType; isUriValid(uri: UriType): uri is UriType;
normalizeUri?: (uri: UriType) => UriType; normalizeUri?: (uri: UriType) => UriType;

@ -0,0 +1,5 @@
import type { GraphNode, DatasetChanges } from "@ldo/rdf-utils";
import type { Quad } from "@rdfjs/types";
export declare function graphNodeToString(graphNode: GraphNode): string;
export declare function stringToGraphNode(input: string): GraphNode;
export declare function splitChangesByGraph(changes: DatasetChanges<Quad>): Map<GraphNode, DatasetChanges<Quad>>;

@ -0,0 +1,45 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.splitChangesByGraph = exports.stringToGraphNode = exports.graphNodeToString = void 0;
const dataset_1 = require("@ldo/dataset");
const data_model_1 = require("@rdfjs/data-model");
function graphNodeToString(graphNode) {
return graphNode.termType === "DefaultGraph"
? "defaultGraph()"
: graphNode.value;
}
exports.graphNodeToString = graphNodeToString;
function stringToGraphNode(input) {
return input === "defaultGraph()" ? (0, data_model_1.defaultGraph)() : (0, data_model_1.namedNode)(input);
}
exports.stringToGraphNode = stringToGraphNode;
function splitChangesByGraph(changes) {
const changesMap = {};
changes.added?.forEach((quad) => {
const graphHash = graphNodeToString(quad.graph);
if (!changesMap[graphHash]) {
changesMap[graphHash] = {};
}
if (!changesMap[graphHash].added) {
changesMap[graphHash].added = (0, dataset_1.createDataset)();
}
changesMap[graphHash].added?.add((0, data_model_1.quad)(quad.subject, quad.predicate, quad.object, quad.graph));
});
changes.removed?.forEach((quad) => {
const graphHash = graphNodeToString(quad.graph);
if (!changesMap[graphHash]) {
changesMap[graphHash] = {};
}
if (!changesMap[graphHash].removed) {
changesMap[graphHash].removed = (0, dataset_1.createDataset)();
}
changesMap[graphHash].removed?.add((0, data_model_1.quad)(quad.subject, quad.predicate, quad.object, quad.graph));
});
const finalMap = new Map();
Object.entries(changesMap).forEach(([key, value]) => {
finalMap.set(stringToGraphNode(key), value);
});
return finalMap;
}
exports.splitChangesByGraph = splitChangesByGraph;
//# sourceMappingURL=splitChangesByGraph.js.map

@ -0,0 +1 @@
{"version":3,"file":"splitChangesByGraph.js","sourceRoot":"","sources":["splitChangesByGraph.ts"],"names":[],"mappings":";;;AAAA,0CAA6C;AAG7C,kDAAgF;AAQhF,SAAgB,iBAAiB,CAAC,SAAoB;IACpD,OAAO,SAAS,CAAC,QAAQ,KAAK,cAAc;QAC1C,CAAC,CAAC,gBAAgB;QAClB,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC;AACtB,CAAC;AAJD,8CAIC;AAQD,SAAgB,iBAAiB,CAAC,KAAa;IAC7C,OAAO,KAAK,KAAK,gBAAgB,CAAC,CAAC,CAAC,IAAA,yBAAY,GAAE,CAAC,CAAC,CAAC,IAAA,sBAAS,EAAC,KAAK,CAAC,CAAC;AACxE,CAAC;AAFD,8CAEC;AASD,SAAgB,mBAAmB,CACjC,OAA6B;IAE7B,MAAM,UAAU,GAAyC,EAAE,CAAC;IAC5D,OAAO,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE;QAC9B,MAAM,SAAS,GAAG,iBAAiB,CAAC,IAAI,CAAC,KAAkB,CAAC,CAAC;QAC7D,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE;YAC1B,UAAU,CAAC,SAAS,CAAC,GAAG,EAAE,CAAC;SAC5B;QACD,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,KAAK,EAAE;YAChC,UAAU,CAAC,SAAS,CAAC,CAAC,KAAK,GAAG,IAAA,uBAAa,GAAE,CAAC;SAC/C;QACD,UAAU,CAAC,SAAS,CAAC,CAAC,KAAK,EAAE,GAAG,CAC9B,IAAA,iBAAU,EAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,CAClE,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,OAAO,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE;QAChC,MAAM,SAAS,GAAG,iBAAiB,CAAC,IAAI,CAAC,KAAkB,CAAC,CAAC;QAC7D,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE;YAC1B,UAAU,CAAC,SAAS,CAAC,GAAG,EAAE,CAAC;SAC5B;QACD,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,OAAO,EAAE;YAClC,UAAU,CAAC,SAAS,CAAC,CAAC,OAAO,GAAG,IAAA,uBAAa,GAAE,CAAC;SACjD;QACD,UAAU,CAAC,SAAS,CAAC,CAAC,OAAO,EAAE,GAAG,CAChC,IAAA,iBAAU,EAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,CAClE,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAmC,CAAC;IAC5D,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE;QAClD,QAAQ,CAAC,GAAG,CAAC,iBAAiB,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC,CAAC;IAC9C,CAAC,CAAC,CAAC;IACH,OAAO,QAAQ,CAAC;AAClB,CAAC;AAnCD,kDAmCC"}

@ -1,12 +1,15 @@
/* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/no-explicit-any */
import EventEmitter from "events"; import EventEmitter from "events";
import type { ResourceError } from "../src";
import { import {
Unfetched, Unfetched,
type ConnectedResult, type ConnectedResult,
type Resource, type Resource,
type ResourceEventEmitter, type ResourceEventEmitter,
type ResourceResult,
} from "../src"; } from "../src";
import type { DatasetChanges } from "@ldo/rdf-utils";
import type { ReadSuccess } from "../src/results/success/ReadSuccess";
import type { UpdateSuccess } from "../src/results/success/UpdateSuccess";
export class MockResouce export class MockResouce
extends (EventEmitter as new () => ResourceEventEmitter) extends (EventEmitter as new () => ResourceEventEmitter)
@ -44,10 +47,15 @@ export class MockResouce
isSubscribedToNotifications(): boolean { isSubscribedToNotifications(): boolean {
throw new Error("Method not implemented."); throw new Error("Method not implemented.");
} }
read(): Promise<ResourceResult<any>> { read(): Promise<ReadSuccess<any> | ResourceError<any>> {
throw new Error("Method not implemented."); throw new Error("Method not implemented.");
} }
readIfAbsent(): Promise<ResourceResult<any>> { readIfAbsent(): Promise<ReadSuccess<any> | ResourceError<any>> {
throw new Error("Method not implemented.");
}
update(
_datasetChanges: DatasetChanges,
): Promise<UpdateSuccess<any> | ResourceError<any>> {
throw new Error("Method not implemented."); throw new Error("Method not implemented.");
} }
subscribeToNotifications(_callbacks?: { subscribeToNotifications(_callbacks?: {

@ -1,7 +1,8 @@
{ {
"extends": "../../tsconfig.base.json", "extends": "../../tsconfig.base.json",
"compilerOptions": { "compilerOptions": {
"outDir": "./dist", "outDir": "./dist"
}, },
"include": ["./src"] "include": ["./src"],
"exclude": ["./dist", "./coverage"]
} }
Loading…
Cancel
Save