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 { BlankNode, Dataset, NamedNode } from "@rdfjs/types";
import type { ArrayProxyTarget } from "./setProxy/createArrayHandler";
import { createArrayHandler } from "./setProxy/createArrayHandler";
import type { ArrayProxyTarget } from "./setProxy/createSetHandler";
import { createArrayHandler } from "./setProxy/createSetHandler";
import { createSubjectHandler } from "./subjectProxy/createSubjectHandler";
import type { SubjectProxy } from "./subjectProxy/SubjectProxy";
import type { ArrayProxy } from "./setProxy/ldSet/LdSet";

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

@ -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 */
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>(
predicate: (value: T, set: LdSet<T>) => value is S,
thisArg?: any,
@ -54,7 +116,7 @@ export class BasicLdSet<T> extends Set<T> implements LdSet<T> {
predicate: (value: T, set: LdSet<T>) => any,
thisArg?: unknown,
): LdSet<T> {
const newSet = new BasicLdSet<T>();
const newSet = new BasicLdSet<T>(this.context);
for (const value of this) {
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;
}
/**
* ===========================================================================
* Set Methods
* ===========================================================================
*/
difference(other: Set<T>): LdSet<T> {
return this.filter((value) => !other.has(value));
}
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 comparingSet = this.size < other.size ? other : this;
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> {
const newSet = new BasicLdSet<T>();
const newSet = new BasicLdSet<T>(this.context);
this.forEach((value) => newSet.add(value));
other.forEach((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> {
const newSet = new BasicLdSet<T>();
const newSet = new BasicLdSet<T>(this.context);
this.forEach((value) => newSet.add(value));
other.forEach((value) => newSet.add(value));
return newSet;

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

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

@ -3,139 +3,181 @@
* helper methods
*/
import type { Dataset } from "@rdfjs/types";
import type { ObjectNode, QuadMatch } from "@ldo/rdf-utils";
import type { ArrayProxyTarget } from "./createArrayHandler";
import type {
_getNodeAtIndex,
_getUnderlyingArrayTarget,
ObjectNode,
PredicateNode,
QuadMatch,
SubjectNode,
} from "@ldo/rdf-utils";
import {
_isSubjectOriented,
_getUnderlyingDataset,
_getUnderlyingMatch,
_proxyContext,
_isLangString,
_getUnderlyingMatch,
_getUnderlyingNode,
} from "../types";
import { _getUnderlyingNode } from "../types";
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> {
context: ProxyContext;
quadMatch: QuadMatch;
isSubjectOriented?: boolean;
isLangStringSet?: boolean;
export class SetProxy<T extends RawObject> extends BasicLdSet<T> {
private quadMatch: QuadMatch;
private isLangStringSet?: boolean;
constructor(
context: ProxyContext,
quadMatch: QuadMatch,
isSubjectOriented?: boolean,
isLangStringSet?: boolean,
) {
this.context = context;
super(context);
this.quadMatch = quadMatch;
this.isSubjectOriented = isSubjectOriented;
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 {
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 {
throw new Error("Method not implemented.");
for (const value of this) {
this.delete(value);
}
}
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 {
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 {
throw new Error("Method not implemented.");
get size() {
const { dataset } = this.context;
const { subject, predicate, object } = this.getSPO();
return dataset.match(subject, predicate, object).size;
}
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> {
throw new Error("Method not implemented.");
return this.values();
}
values(): SetIterator<T> {
throw new Error("Method not implemented.");
}
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.");
return this[Symbol.iterator]();
}
map<U>(callbackfn: (value: T, set: LdSet<T>) => U, thisArg?: any): LdSet<T> {
throw new Error("Method not implemented.");
}
filter<S extends T>(predicate: (value: T, set: LdSet<T>) => value is S, thisArg?: any): LdSet<S>;
filter(predicate: (value: T, set: LdSet<T>) => unknown, thisArg?: any): LdSet<T>;
filter(predicate: unknown, thisArg?: unknown): LdSet<T> | LdSet<S> {
throw new Error("Method not implemented.");
}
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.");
[Symbol.iterator](): SetIterator<T> {
const { dataset } = this.context;
const { subject, predicate, object } = this.getSPO();
const quads = dataset.match(subject, predicate, object);
const collection: T[] = quads.toArray().map((quad) => {
const quadSubject = this.isSubjectOriented() ? quad.object : quad.subject;
return nodeToJsonldRepresentation(quadSubject, this.context) as T;
});
return new Set(collection)[Symbol.iterator]();
}
intersection(other: Set<T>): LdSet<T> {
throw new Error("Method not implemented.");
get [Symbol.toStringTag]() {
// TODO: Change this to be human readable.
return "LdSet";
}
isDisjointFrom(other: Set<T>): boolean {
throw new Error("Method not implemented.");
get [_getUnderlyingDataset](): Dataset {
return this.context.dataset;
}
isSubsetOf(other: Set<T>): boolean {
throw new Error("Method not implemented.");
get [_getUnderlyingMatch](): QuadMatch {
return this.quadMatch;
}
isSupersetOf(other: Set<T>): boolean {
throw new Error("Method not implemented.");
get [_isSubjectOriented](): boolean {
return this.isSubjectOriented();
}
symmetricDifference(other: Set<T>): LdSet<T> {
throw new Error("Method not implemented.");
get [_isLangString](): boolean {
return !!this.isLangStringSet;
}
union(other: Set<T>): LdSet<T> {
throw new Error("Method not implemented.");
get [_proxyContext](): ProxyContext {
return this.context;
}
[Symbol.iterator](): SetIterator<T> {
throw new Error("Method not implemented.");
set [_proxyContext](newContext: ProxyContext) {
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 = {
"@id"?: string;
"@context": ContextDefinition;
readonly [key: string | number | symbol]: unknown;
[key: string | number | symbol]: unknown;
readonly [_getUnderlyingDataset]: Dataset;
readonly [_getUnderlyingNode]: NamedNode | BlankNode;
[_proxyContext]: ProxyContext;

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

Loading…
Cancel
Save