Created LdSet

main
Jackson Morgan 7 months ago
parent 7abe0fa587
commit 227c94b94f
  1. 4
      packages/jsonld-dataset-proxy/src/ProxyContext.ts
  2. 0
      packages/jsonld-dataset-proxy/src/setProxy/createSetHandler.ts
  3. 25
      packages/jsonld-dataset-proxy/src/setProxy/isSetProxy.ts
  4. 78
      packages/jsonld-dataset-proxy/src/setProxy/ldSet/BasicLdSet.ts
  5. 2
      packages/jsonld-dataset-proxy/src/setProxy/ldSet/LdSet.ts
  6. 2
      packages/jsonld-dataset-proxy/src/setProxy/modifyArray.ts
  7. 204
      packages/jsonld-dataset-proxy/src/setProxy/setProxy.ts
  8. 2
      packages/jsonld-dataset-proxy/src/subjectProxy/SubjectProxy.ts
  9. 2
      packages/jsonld-dataset-proxy/src/types.ts

@ -1,7 +1,7 @@
import type { GraphNode, QuadMatch, SubjectNode } from "@ldo/rdf-utils"; import type { GraphNode, QuadMatch, SubjectNode } from "@ldo/rdf-utils";
import type { BlankNode, Dataset, NamedNode } from "@rdfjs/types"; import type { BlankNode, Dataset, NamedNode } from "@rdfjs/types";
import type { ArrayProxyTarget } from "./setProxy/createArrayHandler"; import type { ArrayProxyTarget } from "./setProxy/createSetHandler";
import { createArrayHandler } from "./setProxy/createArrayHandler"; import { createArrayHandler } from "./setProxy/createSetHandler";
import { createSubjectHandler } from "./subjectProxy/createSubjectHandler"; import { createSubjectHandler } from "./subjectProxy/createSubjectHandler";
import type { SubjectProxy } from "./subjectProxy/SubjectProxy"; import type { SubjectProxy } from "./subjectProxy/SubjectProxy";
import type { ArrayProxy } from "./setProxy/ldSet/LdSet"; import type { ArrayProxy } from "./setProxy/ldSet/LdSet";

@ -1,23 +1,10 @@
import { import type { RawObject } from "../util/RawObject";
_getNodeAtIndex, import { SetProxy } from "./setProxy";
_getUnderlyingArrayTarget,
_getUnderlyingDataset,
_getUnderlyingMatch,
_getUnderlyingNode,
_proxyContext,
_writeGraphs,
} from "../types";
import type { ArrayProxy } from "./ArrayProxy";
export function isArrayProxy(someObject?: unknown): someObject is ArrayProxy { export function isSetProxy(
someObject?: unknown,
): someObject is SetProxy<RawObject> {
if (!someObject) return false; if (!someObject) return false;
if (typeof someObject !== "object") return false; if (typeof someObject !== "object") return false;
const potentialArrayProxy = someObject as ArrayProxy; return someObject instanceof SetProxy;
return !(
typeof potentialArrayProxy[_getUnderlyingDataset] !== "object" ||
typeof potentialArrayProxy[_getUnderlyingMatch] !== "object" ||
typeof potentialArrayProxy[_getNodeAtIndex] !== "function" ||
typeof potentialArrayProxy[_getUnderlyingArrayTarget] !== "object"
);
} }

@ -1,5 +1,67 @@
import type { ProxyContext } from "../../ProxyContext";
import type { SubjectProxy } from "../../subjectProxy/SubjectProxy";
import { _getUnderlyingNode } from "../../types";
import { getNodeFromRawObject } from "../../util/getNodeFromRaw";
import { nodeToString } from "../../util/NodeSet";
import type { RawObject } from "../../util/RawObject";
/* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/no-explicit-any */
export class BasicLdSet<T> extends Set<T> implements LdSet<T> { export class BasicLdSet<T extends RawObject>
extends Set<T>
implements LdSet<T>
{
protected context: ProxyContext;
private hashMap = new Map();
constructor(proxyContext: ProxyContext) {
super();
this.context = proxyContext;
}
private hashFn(value: T) {
return nodeToString(getNodeFromRawObject(value, this.context.contextUtil));
}
/**
* ===========================================================================
* Base Set Functions
* ===========================================================================
*/
add(value: T): this {
const key = this.hashFn(value);
if (!this.hashMap.has(key)) {
this.hashMap.set(key, value);
super.add(value);
}
return this;
}
clear(): void {
this.hashMap.clear();
super.clear();
}
delete(value: T): boolean {
const key = this.hashFn(value);
if (this.hashMap.has(key)) {
this.hashMap.delete(key);
return super.delete(value);
}
return false;
}
has(value: T): boolean {
const key = this.hashFn(value);
return this.hashMap.has(key);
}
/**
* ===========================================================================
* Array Functions
* ===========================================================================
*/
every<S extends T>( every<S extends T>(
predicate: (value: T, set: LdSet<T>) => value is S, predicate: (value: T, set: LdSet<T>) => value is S,
thisArg?: any, thisArg?: any,
@ -54,7 +116,7 @@ export class BasicLdSet<T> extends Set<T> implements LdSet<T> {
predicate: (value: T, set: LdSet<T>) => any, predicate: (value: T, set: LdSet<T>) => any,
thisArg?: unknown, thisArg?: unknown,
): LdSet<T> { ): LdSet<T> {
const newSet = new BasicLdSet<T>(); const newSet = new BasicLdSet<T>(this.context);
for (const value of this) { for (const value of this) {
if (predicate.call(thisArg, value, this)) newSet.add(value); if (predicate.call(thisArg, value, this)) newSet.add(value);
} }
@ -95,12 +157,18 @@ export class BasicLdSet<T> extends Set<T> implements LdSet<T> {
return accumulator; return accumulator;
} }
/**
* ===========================================================================
* Set Methods
* ===========================================================================
*/
difference(other: Set<T>): LdSet<T> { difference(other: Set<T>): LdSet<T> {
return this.filter((value) => !other.has(value)); return this.filter((value) => !other.has(value));
} }
intersection(other: Set<T>): LdSet<T> { intersection(other: Set<T>): LdSet<T> {
const newSet = new BasicLdSet<T>(); const newSet = new BasicLdSet<T>(this.context);
const iteratingSet = this.size < other.size ? this : other; const iteratingSet = this.size < other.size ? this : other;
const comparingSet = this.size < other.size ? other : this; const comparingSet = this.size < other.size ? other : this;
for (const value of iteratingSet) { for (const value of iteratingSet) {
@ -137,7 +205,7 @@ export class BasicLdSet<T> extends Set<T> implements LdSet<T> {
} }
symmetricDifference(other: Set<T>): LdSet<T> { symmetricDifference(other: Set<T>): LdSet<T> {
const newSet = new BasicLdSet<T>(); const newSet = new BasicLdSet<T>(this.context);
this.forEach((value) => newSet.add(value)); this.forEach((value) => newSet.add(value));
other.forEach((value) => { other.forEach((value) => {
if (newSet.has(value)) { if (newSet.has(value)) {
@ -150,7 +218,7 @@ export class BasicLdSet<T> extends Set<T> implements LdSet<T> {
} }
union(other: Set<T>): LdSet<T> { union(other: Set<T>): LdSet<T> {
const newSet = new BasicLdSet<T>(); const newSet = new BasicLdSet<T>(this.context);
this.forEach((value) => newSet.add(value)); this.forEach((value) => newSet.add(value));
other.forEach((value) => newSet.add(value)); other.forEach((value) => newSet.add(value));
return newSet; return newSet;

@ -13,7 +13,7 @@ interface LdSet<T> extends Set<T> {
*/ */
add(value: T): this; add(value: T): this;
/** /**
* Clears the set of value * Clears this set of all values, but keeps the values in the datastore
*/ */
clear(): void; clear(): void;
/** /**

@ -15,7 +15,7 @@ import {
import { nodeToString } from "../util/NodeSet"; import { nodeToString } from "../util/NodeSet";
import type { ObjectJsonRepresentation } from "../util/nodeToJsonldRepresentation"; import type { ObjectJsonRepresentation } from "../util/nodeToJsonldRepresentation";
import type { RawObject, RawValue } from "../util/RawObject"; import type { RawObject, RawValue } from "../util/RawObject";
import type { ArrayProxyTarget } from "./createArrayHandler"; import type { ArrayProxyTarget } from "./createSetHandler";
export function checkArrayModification( export function checkArrayModification(
target: ArrayProxyTarget, target: ArrayProxyTarget,

@ -3,139 +3,181 @@
* helper methods * helper methods
*/ */
import type { Dataset } from "@rdfjs/types"; import type { Dataset } from "@rdfjs/types";
import type { ObjectNode, QuadMatch } from "@ldo/rdf-utils";
import type { ArrayProxyTarget } from "./createArrayHandler";
import type { import type {
_getNodeAtIndex, ObjectNode,
_getUnderlyingArrayTarget, PredicateNode,
QuadMatch,
SubjectNode,
} from "@ldo/rdf-utils";
import {
_isSubjectOriented,
_getUnderlyingDataset, _getUnderlyingDataset,
_getUnderlyingMatch,
_proxyContext, _proxyContext,
_isLangString,
_getUnderlyingMatch,
_getUnderlyingNode,
} from "../types"; } from "../types";
import { _getUnderlyingNode } from "../types";
import type { ProxyContext } from "../ProxyContext"; import type { ProxyContext } from "../ProxyContext";
import { addObjectToDataset } from "../util/addObjectToDataset";
import type { RawObject } from "../util/RawObject";
import { nodeToJsonldRepresentation } from "../util/nodeToJsonldRepresentation";
import { BasicLdSet } from "./ldSet/BasicLdSet";
import { getNodeFromRawObject } from "../util/getNodeFromRaw";
export class SetProxy<T> implements LdSet<T> { export class SetProxy<T extends RawObject> extends BasicLdSet<T> {
context: ProxyContext; private quadMatch: QuadMatch;
quadMatch: QuadMatch; private isLangStringSet?: boolean;
isSubjectOriented?: boolean;
isLangStringSet?: boolean;
constructor( constructor(
context: ProxyContext, context: ProxyContext,
quadMatch: QuadMatch, quadMatch: QuadMatch,
isSubjectOriented?: boolean,
isLangStringSet?: boolean, isLangStringSet?: boolean,
) { ) {
this.context = context; super(context);
this.quadMatch = quadMatch; this.quadMatch = quadMatch;
this.isSubjectOriented = isSubjectOriented;
this.isLangStringSet = isLangStringSet; this.isLangStringSet = isLangStringSet;
} }
/**
* Detects if this set is subject oriented. The set is subject oriented if the
* given quadMatch has a predicate and an object but no subject, meanting
*/
private isSubjectOriented(): boolean {
if (this.quadMatch[0] && this.quadMatch[1] && !this.quadMatch[2])
return false;
if (this.quadMatch[1] && !this.quadMatch[0]) return true;
throw new Error(
`SetProxy has an invalid quad match: [${this.quadMatch[0]}, ${this.quadMatch[1]}, ${this.quadMatch[2]}, ${this.quadMatch[3]}]`,
);
}
/**
* Gets the subject, predicate and object for this set
*/
private getSPO(value?: T): {
subject?: SubjectNode;
predicate: PredicateNode;
object?: ObjectNode;
} {
const valueNode = value
? getNodeFromRawObject(value, this.context.contextUtil)
: undefined;
const subject: SubjectNode | undefined = this.isSubjectOriented()
? valueNode
: this.quadMatch[0]!;
const predicate = this.quadMatch[1]!;
const object: ObjectNode | undefined = this.isSubjectOriented()
? this.quadMatch[2] ?? undefined
: valueNode;
return { subject, predicate, object };
}
add(value: T): this { add(value: T): this {
throw new Error("Method not implemented."); // Add value
const added = addObjectToDataset(value as RawObject, false, this.context);
// Add connecting edges
if (!this.isSubjectOriented) {
addObjectToDataset(
{
"@id": this.quadMatch[0],
[this.context.contextUtil.iriToKey(
this.quadMatch[1]!.value,
this.context.getRdfType(this.quadMatch[0]!),
)]: added,
} as RawObject,
false,
this.context,
);
} else {
// Account for subject-oriented
added[
this.context.contextUtil.iriToKey(
this.quadMatch[1]!.value,
this.context.getRdfType(added[_getUnderlyingNode]),
)
] = nodeToJsonldRepresentation(this.quadMatch[2]!, this.context);
}
return this;
} }
clear(): void { clear(): void {
throw new Error("Method not implemented."); for (const value of this) {
this.delete(value);
}
} }
delete(value: T): boolean { delete(value: T): boolean {
throw new Error("Method not implemented."); const { dataset } = this.context;
const { subject, predicate, object } = this.getSPO(value);
dataset.deleteMatches(subject, predicate, object);
return true;
} }
has(value: T): boolean { has(value: T): boolean {
throw new Error("Method not implemented."); const { dataset } = this.context;
const { subject, predicate, object } = this.getSPO(value);
return dataset.match(subject, predicate, object).size > 0;
} }
get size(): number { get size() {
throw new Error("Method not implemented."); const { dataset } = this.context;
const { subject, predicate, object } = this.getSPO();
return dataset.match(subject, predicate, object).size;
} }
entries(): SetIterator<[T, T]> { entries(): SetIterator<[T, T]> {
throw new Error("Method not implemented."); const iteratorSet = new Set<[T, T]>();
for (const value of this) {
iteratorSet.add([value, value]);
}
return iteratorSet[Symbol.iterator]();
} }
keys(): SetIterator<T> { keys(): SetIterator<T> {
throw new Error("Method not implemented."); return this.values();
} }
values(): SetIterator<T> { values(): SetIterator<T> {
throw new Error("Method not implemented."); return this[Symbol.iterator]();
}
every<S extends T>(predicate: (value: T, set: LdSet<T>) => value is S, thisArg?: any): this is LdSet<S>;
every(predicate: (value: T, set: LdSet<T>) => unknown, thisArg?: any): boolean;
every(predicate: unknown, thisArg?: unknown): boolean {
throw new Error("Method not implemented.");
}
some(predicate: (value: T, set: LdSet<T>) => unknown, thisArg?: any): boolean {
throw new Error("Method not implemented.");
}
forEach(callbackfn: (value: T, value2: T, set: LdSet<T>) => void, thisArg?: any): void {
throw new Error("Method not implemented.");
} }
map<U>(callbackfn: (value: T, set: LdSet<T>) => U, thisArg?: any): LdSet<T> { [Symbol.iterator](): SetIterator<T> {
throw new Error("Method not implemented."); const { dataset } = this.context;
} const { subject, predicate, object } = this.getSPO();
const quads = dataset.match(subject, predicate, object);
filter<S extends T>(predicate: (value: T, set: LdSet<T>) => value is S, thisArg?: any): LdSet<S>; const collection: T[] = quads.toArray().map((quad) => {
filter(predicate: (value: T, set: LdSet<T>) => unknown, thisArg?: any): LdSet<T>; const quadSubject = this.isSubjectOriented() ? quad.object : quad.subject;
filter(predicate: unknown, thisArg?: unknown): LdSet<T> | LdSet<S> { return nodeToJsonldRepresentation(quadSubject, this.context) as T;
throw new Error("Method not implemented."); });
} return new Set(collection)[Symbol.iterator]();
reduce(callbackfn: (previousValue: T, currentValue: T, set: LdSet<T>) => T): T;
reduce(callbackfn: (previousValue: T, currentValue: T, set: LdSet<T>) => T, initialValue: T): T;
reduce<U>(callbackfn: (previousValue: U, currentValue: T, array: LdSet<T>) => U, initialValue: U): U;
reduce(callbackfn: unknown, initialValue?: unknown): T | U {
throw new Error("Method not implemented.");
}
difference(other: Set<T>): LdSet<T> {
throw new Error("Method not implemented.");
} }
intersection(other: Set<T>): LdSet<T> { get [Symbol.toStringTag]() {
throw new Error("Method not implemented."); // TODO: Change this to be human readable.
return "LdSet";
} }
isDisjointFrom(other: Set<T>): boolean { get [_getUnderlyingDataset](): Dataset {
throw new Error("Method not implemented."); return this.context.dataset;
} }
isSubsetOf(other: Set<T>): boolean { get [_getUnderlyingMatch](): QuadMatch {
throw new Error("Method not implemented."); return this.quadMatch;
} }
isSupersetOf(other: Set<T>): boolean { get [_isSubjectOriented](): boolean {
throw new Error("Method not implemented."); return this.isSubjectOriented();
} }
symmetricDifference(other: Set<T>): LdSet<T> { get [_isLangString](): boolean {
throw new Error("Method not implemented."); return !!this.isLangStringSet;
} }
union(other: Set<T>): LdSet<T> { get [_proxyContext](): ProxyContext {
throw new Error("Method not implemented."); return this.context;
} }
[Symbol.iterator](): SetIterator<T> { set [_proxyContext](newContext: ProxyContext) {
throw new Error("Method not implemented."); this.context = newContext;
} }
[Symbol.toStringTag]: string;
} }
export type ArrayProxy = Array<unknown> & {
readonly [_getUnderlyingDataset]: Dataset;
readonly [_getUnderlyingMatch]: ArrayProxyTarget[0];
readonly [_getNodeAtIndex]: (index: number) => ObjectNode | undefined;
readonly [_getUnderlyingArrayTarget]: ArrayProxyTarget;
[_proxyContext]: ProxyContext;
};

@ -12,7 +12,7 @@ import type {
export type SubjectProxy = { export type SubjectProxy = {
"@id"?: string; "@id"?: string;
"@context": ContextDefinition; "@context": ContextDefinition;
readonly [key: string | number | symbol]: unknown; [key: string | number | symbol]: unknown;
readonly [_getUnderlyingDataset]: Dataset; readonly [_getUnderlyingDataset]: Dataset;
readonly [_getUnderlyingNode]: NamedNode | BlankNode; readonly [_getUnderlyingNode]: NamedNode | BlankNode;
[_proxyContext]: ProxyContext; [_proxyContext]: ProxyContext;

@ -1,9 +1,7 @@
export const _getUnderlyingNode = Symbol("_getUnderlyingNode"); export const _getUnderlyingNode = Symbol("_getUnderlyingNode");
export const _getUnderlyingMatch = Symbol("_getUnderlyingMatch"); export const _getUnderlyingMatch = Symbol("_getUnderlyingMatch");
export const _isSubjectOriented = Symbol("_isSubjectOriented"); export const _isSubjectOriented = Symbol("_isSubjectOriented");
export const _getNodeAtIndex = Symbol("_getNodeAtIndex");
export const _getUnderlyingDataset = Symbol("_getUnderlyingDataset"); export const _getUnderlyingDataset = Symbol("_getUnderlyingDataset");
export const _getUnderlyingArrayTarget = Symbol("_getUnderlyingArrayTarget");
export const _proxyContext = Symbol("_proxyContext"); export const _proxyContext = Symbol("_proxyContext");
export const _writeGraphs = Symbol("_writeGraphs"); export const _writeGraphs = Symbol("_writeGraphs");

Loading…
Cancel
Save