parent
3c004980e0
commit
ea6a860c3e
@ -0,0 +1,147 @@ |
|||||||
|
import type { |
||||||
|
ShapeType, |
||||||
|
Shape, |
||||||
|
Predicate, |
||||||
|
Schema, |
||||||
|
} from "@nextgraph-monorepo/ng-shex-orm"; |
||||||
|
|
||||||
|
interface Triple { |
||||||
|
s: string; |
||||||
|
p: string; |
||||||
|
o: string; |
||||||
|
} |
||||||
|
interface TrackedSubject { |
||||||
|
shape: Shape; |
||||||
|
parentObject?: TrackedSubject; |
||||||
|
valid?: boolean; |
||||||
|
trackedPredicates: Record<string, TrackedPredicate>; |
||||||
|
/** For Sub-objects only */ |
||||||
|
untracked?: boolean; |
||||||
|
} |
||||||
|
|
||||||
|
interface TrackedPredicate { |
||||||
|
shape: Predicate; |
||||||
|
currentCardinality: number; |
||||||
|
childSubjects?: TrackedSubject[]; |
||||||
|
} |
||||||
|
|
||||||
|
export function buildObjects(shapeType: ShapeType<any>) { |
||||||
|
//
|
||||||
|
} |
||||||
|
|
||||||
|
export function onTriplesRemoved( |
||||||
|
trackedSubjects: Record<string, TrackedSubject[]>, |
||||||
|
triplesRemoved: string[][], |
||||||
|
shapeType: ShapeType<any> |
||||||
|
) { |
||||||
|
//
|
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Adds new triples to tracked subjects and creates and returns |
||||||
|
* new tracked (possibly nested) subjects. |
||||||
|
*/ |
||||||
|
export function onTriplesAdded( |
||||||
|
trackedSubjects: Record<string, TrackedSubject[]>, |
||||||
|
triplesAdded: Triple[], |
||||||
|
schema: Schema, |
||||||
|
rootShape?: Shape |
||||||
|
): { newTrackedSubjects: Record<string, TrackedSubject[]> } { |
||||||
|
// Track for secondary iterations.
|
||||||
|
const newTrackedSubjectsCreated: Record<string, TrackedSubject[]> = {}; |
||||||
|
|
||||||
|
for (const triple of triplesAdded) { |
||||||
|
if (!trackedSubjects[triple.s]) { |
||||||
|
// If rootShape is not set, we are applying the triples new nested objects
|
||||||
|
// and we don't create new tracked subjects.
|
||||||
|
if (!rootShape) continue; |
||||||
|
|
||||||
|
// Check if predicate is in root shape type.
|
||||||
|
const matchedPredicate = rootShape.predicates.find((p) => triple.p); |
||||||
|
if (!matchedPredicate) { |
||||||
|
// Nothing to track.
|
||||||
|
continue; |
||||||
|
} |
||||||
|
// The triple should be tracked. Create new tracked subject.
|
||||||
|
const newTrackedSubject: TrackedSubject = { |
||||||
|
shape: rootShape, |
||||||
|
trackedPredicates: { |
||||||
|
[triple.p]: { |
||||||
|
shape: matchedPredicate, |
||||||
|
currentCardinality: 1, |
||||||
|
}, |
||||||
|
}, |
||||||
|
}; |
||||||
|
trackedSubjects[triple.s] = [newTrackedSubject]; |
||||||
|
} else { |
||||||
|
// Add triple to tracked subject(s).
|
||||||
|
// In the case of nested shapes, the same subject can be tracked
|
||||||
|
// in multiple shapes.
|
||||||
|
const trackedSubjectsMatching = trackedSubjects[triple.s]; |
||||||
|
for (const trackedSubject of trackedSubjectsMatching) { |
||||||
|
// Is predicate tracked in this subject's shape?
|
||||||
|
const matchedPredShape = trackedSubject.shape.predicates.find( |
||||||
|
(predShape) => predShape.iri === triple.p |
||||||
|
); |
||||||
|
if (!matchedPredShape) continue; |
||||||
|
// Get or create tracked predicate for tracked shape.
|
||||||
|
let trackedPredicate = |
||||||
|
trackedSubject.trackedPredicates[matchedPredShape?.iri]; |
||||||
|
if (!trackedSubjects) { |
||||||
|
trackedPredicate = { |
||||||
|
currentCardinality: 0, |
||||||
|
shape: matchedPredShape, |
||||||
|
}; |
||||||
|
} |
||||||
|
// Increase cardinality.
|
||||||
|
trackedPredicate.currentCardinality += 1; |
||||||
|
|
||||||
|
// If predicate shape has nested object, track that too.
|
||||||
|
if (trackedPredicate.shape.nestedShape) { |
||||||
|
const newTrackedObject: TrackedSubject = { |
||||||
|
shape: schema[matchedPredShape.nestedShape as string], |
||||||
|
trackedPredicates: {}, |
||||||
|
parentObject: trackedSubject, |
||||||
|
}; |
||||||
|
// Remember for adding to registry and for re-running on nested shapes.
|
||||||
|
const newTracked = newTrackedSubjectsCreated[triple.o]; |
||||||
|
if (!newTracked) |
||||||
|
newTrackedSubjectsCreated[triple.o] = [ |
||||||
|
newTrackedObject, |
||||||
|
]; |
||||||
|
newTracked.push(newTrackedObject); |
||||||
|
|
||||||
|
// Link to parent
|
||||||
|
const childSubjects = trackedPredicate.childSubjects; |
||||||
|
if (childSubjects) childSubjects.push(newTrackedObject); |
||||||
|
else trackedPredicate.childSubjects = [newTrackedObject]; |
||||||
|
} |
||||||
|
|
||||||
|
// TODO: Inform tracked subjects about change
|
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Rerun triples on new tracked subjects created.
|
||||||
|
// Then merge with parent tracked subjects
|
||||||
|
const newNestedSubjectsCreated = onTriplesAdded( |
||||||
|
newTrackedSubjectsCreated, |
||||||
|
triplesAdded, |
||||||
|
schema |
||||||
|
); |
||||||
|
|
||||||
|
// TODO: Is it correct to do this?
|
||||||
|
const ret: Record<string, TrackedSubject[]> = {}; |
||||||
|
for (const subjectIri of Object.keys(newTrackedSubjectsCreated)) { |
||||||
|
ret[subjectIri] = [ |
||||||
|
...newTrackedSubjectsCreated[subjectIri], |
||||||
|
...newNestedSubjectsCreated.newTrackedSubjects[subjectIri], |
||||||
|
]; |
||||||
|
} |
||||||
|
|
||||||
|
// Update Valid invalid
|
||||||
|
|
||||||
|
return { newTrackedSubjects: ret }; |
||||||
|
} |
||||||
|
|
||||||
|
// Do we have infinite-loop issues?
|
Loading…
Reference in new issue