Page MenuHomec4science

editor-resources.ts
No OneTemporary

File Metadata

Created
Sat, Oct 12, 00:32

editor-resources.ts

// The main super class for every thing which has to be added/edited or deleted in the triple store
import {StatementHandler, ChangeMgmntDef, TlnStatementCollection, OnDelete, StatementOperations} from './statement-handler';
import {QueryService} from '../services/query.service';
import {RdfData, RdfEditorData, RdfStoredData} from './rdf-editor-DataSets';
import * as N3 from "node_modules/n3/src";
export class TlnResource {
iri: string;
label: string;
_rdfDatasetFromStore: RdfStoredData; // the data from store if there is such a thing
_rdfDatasetToEdit: RdfEditorData; // the data which is edited or created
_deprecatedVersions: DeprecatedVersion[]; // all previous depricated versions of the resource
parentIri: string;
parentLabel: string;
private _inStore: boolean; // exists in Store or in memory/JS only
private _deprecated: boolean; // states that a resource has either been edited or deleted.
private _edited: boolean; // whether an existing thing has been edited or not
private _deleted: boolean; // whether a thing has been deleted in the frontend
constructor(iri: string,
label?: string,
rdfsType?: string,
parentIri?: string,
parentLabel?: string) {
this.iri = iri;
this._inStore = false;
this._deleted = false;
this._edited = false;
this._deprecated = false;
this._rdfDatasetToEdit = new RdfEditorData(this.iri, rdfsType);
this.parentIri = parentIri;
this.parentLabel = parentLabel;
}
// loads an existing resource (or a predicate) from store
static async buildFromStoreAsync( queryService: QueryService,
existingIri: string,
label?: string,
editorDef?: ChangeMgmntDef ){
const resource = new TlnResource(existingIri, label);
resource._inStore = await RdfStoredData.askIfInStore(queryService, existingIri);
if (resource._inStore) {
resource._rdfDatasetFromStore = await RdfStoredData.buildAsync(queryService, existingIri, editorDef);
resource._rdfDatasetToEdit = await resource._rdfDatasetFromStore.exportAsEditorData(editorDef);
if (resource._rdfDatasetFromStore.statements() === resource._rdfDatasetToEdit.statements()) {console.log('shiiiit not be the same')}
} else {
console.error('resource ', existingIri, ' not found in store');
}
return resource;
}
// returns the iri's of all children depending on a given childsPredicate
async getChildIris(childsPredicate: string): Promise<string[]> {
let childIris = [];
// guard if childspredicate is not available or there are no statements for the thing
if (!this._rdfDatasetToEdit.isPredicateAvailable(childsPredicate)) { return childIris }
// else we get the childIris
if (this._rdfDatasetToEdit.availablePredicates().get(childsPredicate).takesListAsObject()) { // get children out of a list as object
if (this._rdfDatasetToEdit.listsAsStatements().size === 0) { return childIris } // another guard
childIris = this._rdfDatasetToEdit.listsAsStatements().get(childsPredicate).getNodes().map(node => node.value);
} else { // get children from statements
if (this._rdfDatasetToEdit.agentStatements().size === 0) { return childIris } // another guard
childIris = this._rdfDatasetToEdit.agentStatements().get(childsPredicate).getNodes().map(node => node.value);
}
return childIris;
}
isInStore() {
return this._inStore;
}
isEdited() {
return this._edited;
}
ignore() { // if the resource is not in the store and is set to deleted it must not be processed
return (!this._inStore && this._deleted);
}
isDeleted() {
return this._deleted;
}
rdfDatasetFromStore() {
return this._rdfDatasetFromStore;
}
// creates a deprecated data set from the original dataset - we only deprecate existing things in store
public async deprecate(timestamp: string, def: ChangeMgmntDef): Promise<TlnDeprecation> {
if (!this._inStore) { return null } // guard
if (!this._deleted) { // if it is not deleted, we have to deprecate the thing against the new one
return await TlnDeprecation.buildAsync(this._rdfDatasetFromStore, timestamp, def, this._rdfDatasetToEdit) } else {
// it has been deleted, so we just depricate the whole thing without passing a new version
return await TlnDeprecation.buildAsync(this._rdfDatasetFromStore, timestamp, def)
}
}
// Marks the TlnResource as deleted and starts deprecation of that resource with all its properties
public setDeleted() {
this._deleted = true;
}
public setUndeleted() {
this._deleted = false;
}
// returns all statements of a thing as n3.Quad[];
// First getting all outgoing/agent statements. patientStatements are not needed, hence they are in the parent and handled by deprecation:
// if
// (properties with object) as n3 quad array in which there are both: the usual spo as well as a list containing all o's
// public getAllAgentStatementQuads(): N3.Quad[] {
// let quads: N3.Quad[] = this._rdfDatasetToEdit.statements().agentStmAsQuads(this._rdfDatasetToEdit.iri()) // getting all outgoing statements as quads
// console.log(quads);
// return quads;
// }
//
// // returns the new thing with all its poperties & objects as N3-quads/lists
// async buildRdfTransaction(): Promise<N3.Quad[]> {
// // get all agent statements
// let quads: N3.Quads[] = [].concat(this.getAllAgentStatementQuads()); // concadinating with [] so never undefined
// // Sometimes there is none e.g. an existing page is part of identifiesAsVersion so we don't have to create iris & properties
// // TODO get selfStatement from statementHandler - and get rid of the variable this.selfstatement
// if (this._rdfDatasetToEdit.selfStatement() !== undefined && this._rdfDatasetToEdit.selfStatement() !== null) {
// quads.splice(0,0, this._rdfDatasetToEdit.selfStatement());
// }
// return quads;
// }
// get all deprecated versionsof a given resource iri
async getDeprecations(queryService: QueryService, iri: string): Promise<DeprecatedVersion[]> {
let deprecations: DeprecatedVersion[];
let iris: string[] = []; // the versions iri's
// Todo: get versions by query
for (const iri of iris) {
let formerVeersion: DeprecatedVersion = await DeprecatedVersion.buildFromStoreAsync(queryService, iri);
deprecations.push(formerVeersion)
}
return deprecations;
}
async getDeprecatedResources(resourceIri: string) {
}
undeprecate(iri: string) {
// Todo: pass resource iri or verion iri? -> gui decision
let resource = this._deprecatedVersions[this._deprecatedVersions.findIndex(version => version.version.iri === iri)];
// map resource (a tln resource) to what it is, i.e.
// populate all edcitorData with the data needed
// populate cascading! so if a Version is populated, also its textUnits must be restored/undeprecated!
// => get child from deprecatedChild???
// if someOne saves it
// ...
}
}
// for undeprecating
export class DeprecatedVersion {
version: TlnResource;
resource: TlnResource;
constructor() {
}
static async buildFromStoreAsync(queryService, iri) {
let version = new DeprecatedVersion();
version.version = await TlnResource.buildFromStoreAsync(queryService,iri, 'Version');
const resourceIri = version.version._rdfDatasetFromStore.getFirstObject('http://www.nie.org/ontology/nietzsche#deprecates');
version.resource = await TlnResource.buildFromStoreAsync(queryService,resourceIri, 'Resource');
return version;
}
}
// a canvas for a resource with basic funcionality/features, i.e. only an rdf represenation of a resource with its agent statements.
// Used for not yet existing things which have to be added to the store when a deprecation takes place.
export class TlnShortHandResource {
protected _iri: string;
protected _rdfType: string;
protected _statements: N3.Quad[] = []; // all the statements of a given thing as agent, e.g. subject
constructor() {
}
// puts a deprecated statement
putNamedNodeStatement(predicate: string, o: string ) {
this._statements.push(RdfData.createNamedNodeQuad(this._iri, predicate, o))
}
// puts a deprecated statement
putLiteralStatement(predicate: string, o: string, standOffType?: string ) {
let quad = RdfData.createLiteralStatement(this._iri, predicate, o, standOffType);
this._statements.push(quad);
}
iri() {
return this._iri;
}
public statements() {
return this._statements;
}
}
// The dep:classes
export class TlnDeprecatedAgentStatement extends TlnShortHandResource{
constructor(predicate: string, node: N3.Literal|N3.NamedNode) {
super();
// always put basic props
this._rdfType = 'https://nietzsche.philhist.unibas.ch/ontology/deprecation#AgentStatement';
this._iri = RdfData.createIri('DepAgentStm');
this.putNamedNodeStatement('http://www.w3.org/1999/02/22-rdf-syntax-ns#type', this._rdfType);
this.putLiteralStatement('https://nietzsche.philhist.unibas.ch/ontology/deprecation#hasProperty',
predicate, '^^http://www.w3.org/2001/XMLSchema#anyURI');
// the node itsel will be written as ...
if ( node instanceof N3.Literal){ // a anyUri if the thing "was" a namednode ...
this.putLiteralStatement('https://nietzsche.philhist.unibas.ch/ontology/deprecation#hasObject', node.value, `^^${node.datatypeString}`);
}
if (node instanceof N3.NamedNode) { // ... or it will be writte as a literal with its standofftype
this.putLiteralStatement('https://nietzsche.philhist.unibas.ch/ontology/deprecation#hasObject', node.value,
'^^http://www.w3.org/2001/XMLSchema#anyURI');
}
}
}
// the deprecated patient class: All deprecated statements/triples where the thing acted as a patient, i.e. an object
export class TlnDeprecatedPatientStatement extends TlnShortHandResource{
constructor(predicate: string, subject: string) {
super();
this._rdfType = 'https://nietzsche.philhist.unibas.ch/ontology/deprecation#PatientStatement';
this._iri = RdfData.createIri('DepPatientStm');
this.putNamedNodeStatement('http://www.w3.org/1999/02/22-rdf-syntax-ns#type', this._rdfType);
this.putLiteralStatement('https://nietzsche.philhist.unibas.ch/ontology/deprecation#hasProperty', predicate,
'^^http://www.w3.org/2001/XMLSchema#anyURI');
this.putLiteralStatement('https://nietzsche.philhist.unibas.ch/ontology/deprecation#hasSubject', subject,
'^^http://www.w3.org/2001/XMLSchema#anyURI');
}
}
// The deprecated resource with all its properties
export class TlnDeprecatedResource extends TlnShortHandResource { // creates a new instance of dep:Deprecation to be imported
private _deprecatedStatements: any[] = []; // all statements that were valid before deprecation
protected _rdfType = 'https://nietzsche.philhist.unibas.ch/ontology/deprecation#DeprecatedResource'; // the class of any deprecated Resource
private _depTypePredicate = 'https://nietzsche.philhist.unibas.ch/ontology/deprecation#wasOfType'; // the predicate stating the former class
private _linkToDerivate = 'https://nietzsche.philhist.unibas.ch/ontology/deprecation#hasDerivate'; // predicate to link to the derivate
//use only builder
constructor() {
super();
}
//
static async buildAsync(ancestor: RdfStoredData, timeStamp: string, derivate?: RdfEditorData): Promise<TlnDeprecatedResource> {
let build = new TlnDeprecatedResource();
if (derivate !== null && derivate !== undefined) {
build.deprecateResourceWith(ancestor, derivate, timeStamp) } else {
// the resource has no derivate, so it was "deleted" completely
build.buildForDeletion(ancestor);
}
// Changing the type of the resource, but storing its old type
build.putNamedNodeStatement('http://www.w3.org/1999/02/22-rdf-syntax-ns#type', build._rdfType);
build.putNamedNodeStatement(build._depTypePredicate, ancestor.rdfType());
return build;
}
// deprecates a resource completely without any newer state, i.e. a deletion
private buildForDeletion(ancestor: RdfStoredData) {
this._iri = ancestor.iri(); // if we delete a resource, its iri is still kept/valid and used for the deprecatedResource
// get stuff to delete: simply delete all!
// todo: add patientstatements ...
this._deprecatedStatements = this.createDeprecatedStatements(ancestor.statements());
}
// deprecates a resource (ancestor) with its updated version (derivate)
private async deprecateResourceWith(ancestor: RdfStoredData, derivate: RdfEditorData, timeStamp: string) {
this._iri = `${ancestor.iri()}_deprecated_${timeStamp}`; // setting new deprecated iri
this.putNamedNodeStatement(this._linkToDerivate, derivate.iri()); // put a link to the derivate/the latest valid version
// Finally deprecating all statements which changed or got deleted
}
// gets all the triples which need to be created in order to deprecate, i.e. the deprecations of the resources statements
createDeprecatedStatements(ancestorStatements: StatementHandler): any[]{
const agentStatements: TlnDeprecatedAgentStatement[] = this.createDeprecatedAgentStatements(ancestorStatements.agentStatements());
const patientStatements: TlnDeprecatedPatientStatement[] = this.createDeprecatedPatientStatements(ancestorStatements.patientStatements());
// Todo: get deprecatedAgentlistStatements & patientlistStatements, deletion and change mgm will be outside this method
return [... agentStatements, ... patientStatements];
}
createDeprecatedAgentStatements(statements: Map<string, TlnStatementCollection>): TlnDeprecatedAgentStatement[] {
let depAgentStatements: TlnDeprecatedAgentStatement[] = [];
for (let [key, value] of statements) {
value.getNodes().forEach( node => {
depAgentStatements.push(new TlnDeprecatedAgentStatement(key, node))
});
}
return depAgentStatements;
}
// only needed if resource gets deleted
createDeprecatedPatientStatements(statements: Map<string, TlnStatementCollection>): TlnDeprecatedPatientStatement[] {
let depAgentStatements: TlnDeprecatedPatientStatement[] = [];
for (let [key, value] of statements) {
value.getNodes().forEach( node => {
depAgentStatements.push(new TlnDeprecatedPatientStatement(key, node.id));
})
}
return depAgentStatements;
}
createDeprecatedAgentListAsStatements(statements: Map<string, TlnStatementCollection>): TlnDeprecatedAgentStatement[] {
let depAgentStatements: TlnDeprecatedAgentStatement[] = [];
for (let [key, value] of statements) {
value.getNodes().forEach( node => {
depAgentStatements.push(new TlnDeprecatedAgentStatement(key, node))
});
}
return depAgentStatements;
}
// returns all statements of the deprecated thing as an n3.Quad array, including the own statements of the dep:DeprecatedResource
// as well as the deprecatedStatements, i.e. its statements
quads(): N3.Quad[] {
let deprStatements: N3.Quad[] = [];
this._deprecatedStatements.forEach( stm => {
deprStatements.push(...stm.statements())
});
return [].concat(this._statements, deprStatements)
}
}
// contains all the triples/meta data of one transaction.
export class TlnTransaction extends TlnShortHandResource {
_rdfType = 'https://nietzsche.philhist.unibas.ch/ontology/deprecation#Transaction';
committedAdditions: string; // the final ttl file
committedDeletions: string; // the final written ttl file
_additions: N3.Quad[] = []; // all the additions including additions, changes & lists to write
_deletions: N3.Quad[] = []; // all the deletions including changes
_listsToDelete: string[] = []; // all sparql queries for deleting lists
public committed = false;
constructor() {
super();
}
private addTimeStampStm(ts: string) {
this.putLiteralStatement('https://nietzsche.philhist.unibas.ch/ontology/deprecation#hasTime',
ts, 'http://www.w3.org/2001/XMLSchema#dateTimeStamp');
}
private addUserStm(user: string) {
if (!user || user !== '') { return } // guard
this.putLiteralStatement('https://nietzsche.philhist.unibas.ch/ontology/deprecation#hasResponsible', user);
}
private addCommentStm(comment: string) {
if (!comment || comment !== '') { return } // guard
this.putLiteralStatement( 'https://nietzsche.philhist.unibas.ch/ontology/deprecation#hasComment', comment, '@de');
}
private addOperationType(resources: TlnResource[]) {
let oType = 'multi';
let delCount = resources.map(res => res.isDeleted()).filter(del => del === true).length;
let edCount = resources.map(res => res.isEdited()).filter(ed => ed === true).length;
console.log('resources deleted :', delCount, ' resources edites: ', edCount, ' total resources: ', resources.length)
let inStore = resources.map(res => res.isInStore()).filter(st => st === true).length; // amount of resources in store
if (!inStore) { // nothing was in store means creation only
oType = 'creation' }
if (edCount === inStore && edCount === resources.length && delCount === 0) { // if all edited are in store & nothing has been edited
oType = 'edition' }
if (delCount === resources.length) { // all have been deleted
oType = 'deletion' }
this.putLiteralStatement( 'https://nietzsche.philhist.unibas.ch/ontology/deprecation#transactionHasOperationType', oType, '@en');
}
// writes out all transaction triples as ttl
public writeOut() {
this.writeOutAdditions();
this.writeOutDeletions();
}
writeOutAdditions() {
let addWriter = new N3.Writer();
// writing statements of the Transaction
for (const statement of this._statements) {
addWriter.addQuad(statement)
}
// writing statements for the resources/deprecated resources
for (const addition of this._additions) {
addWriter.addQuad(addition) }
addWriter.end((error, result) => {
if (error) {console.error(error); return}
this.committedAdditions = result;
})
}
writeOutDeletions() {
let delWriter = new N3.Writer();
for (const deletion of this._deletions) {
delWriter.addQuad(deletion) }
delWriter.end((error, result) => {
if (error) {console.error(error); return}
this.committedDeletions = result;
})
}
// creates the commitment from any given array of TlnResources, runs all deprecation needed
public async build(resources: TlnResource[], user: string, comment: string, def: ChangeMgmntDef): Promise<boolean> {
const ts = Date.now().valueOf().toString(); // timeStamp as string
if (def.metaData) {
// creating metadata about the transaction to perform
this._iri = RdfData.createIri('transaction');
this.putNamedNodeStatement('http://www.w3.org/1999/02/22-rdf-syntax-ns#type', this._rdfType);
this.addTimeStampStm(ts);
this.addUserStm(user);
this.addCommentStm(comment);
this.addOperationType(resources);
}
for (let resource of resources) {
if (resource.ignore() === false) {
if (resource.isInStore()) {
const deprecation = await resource.deprecate(ts, def);
this._additions.push(...deprecation.quadsToCreate());
this._deletions.push(...deprecation.quadsToDelete());
this._listsToDelete.push(...deprecation.listDeletionQueries());
} else {
// nothing to deprecate, only add new resource/statements so
// we simply add all quads directly to the transactions additions. We only handle statements top down, i.e. agentStatements only,
// hence patient statements are handled by their agents && a new resource to be created does not have any patientStatements
this._additions.push(...resource._rdfDatasetToEdit.getAllAgentStatementQuads());
}
}
}
console.log('additions: ', this._additions);
console.log('deletions: ', this._deletions);
if (this._additions.length + this._deletions.length === 0) {
return false } else { return true }
}
preview() {
this.writeOut();
}
push(queryServeice: QueryService) {
if (!this.committed) {
console.warn('nothing to push. Commit before pushing');
return; }
this.writeOut();
//todo: import
}
}
// creates/contains all rdf data needed if a resource gets deleted or deprecated due to changes
export class TlnDeprecation {
private _iri: string;
private deprecatedResource: TlnDeprecatedResource; // the deprecated thing dep:DeprecatedRescource with its props to be imported
private _productiveOperations: StatementOperations; // the operations needed to perform for the new valid resouce, e.g.creating, updating, deleting, ...
private _predecessor: RdfStoredData; // the original thing which needs to be depricated/deleted
private _additions: N3.Quad[] = []; // new statements of the dep:deprecation
private _depTreeDeletions: N3.Quad[] = []; // MetaData only: former statements of the deprecation tree which have to be deleted in order to update the tree
// Todo: lists???
constructor(predecessor: RdfStoredData) {
this._iri = RdfData.createIri('Deprecation_');
this._predecessor = predecessor;
this._productiveOperations = new StatementOperations();
}
// asnc builder for the deprecation
public static async buildAsync(predecessor: RdfStoredData, timestamp: string, def: ChangeMgmntDef, derivate?: RdfEditorData): Promise<TlnDeprecation> {
let deprecation = new TlnDeprecation(predecessor);
if (derivate && derivate !== undefined) { // If there is a newer version of the resource we make the diff
deprecation._productiveOperations = await StatementOperations.getProductiveOperationsAsync(predecessor,
derivate,
def.updateLists);
}
if (!derivate || derivate === undefined) { // if there is no derivate at all, the resource and its statements got deleted in the gui
deprecation._productiveOperations = await deprecation.getOpsOnDelete(def.onDelete);
console.log('deprecation._productiveOperations', deprecation._productiveOperations)
}
if (def.metaData && deprecation._productiveOperations.hasChanges()) {
deprecation.addSelfStatement();
deprecation.addOperationTypeStm(!!derivate);
// if metaData should be written and if there are any changes made, we build a deprecated resource && update the derivation tree
deprecation.deprecatedResource = await TlnDeprecatedResource.buildAsync(deprecation._predecessor, timestamp, derivate);
if (derivate && derivate !== undefined) {
deprecation.updateDerivationTree(derivate.iri());
}
}
return deprecation;
}
private async getOpsOnDelete(onDelete: OnDelete): Promise<StatementOperations> {
let ops = new StatementOperations();
if (!onDelete.keepAgentStatements) {
ops.deletions.push(... this._predecessor.statements().getAgentStmQuads(this._predecessor.iri()));
}
if (!onDelete.keepAgentLists) {
ops.setListUpdates(this._predecessor)
}
if (!onDelete.keepPatientStatements) { // deleting also all patient statements
ops.deletions.push(... this._predecessor.statements().getPatientStmAsQuads(this._predecessor.iri()));
}
// /Todo: pATIENT Lists???!
return ops;
}
// Statements for the dep:deprecation
// adds the statement with the rdf:type of the dep:Deprecation
private addSelfStatement() {
const selfStatement = RdfData.selfStatement(this._iri, 'https://nietzsche.philhist.unibas.ch/ontology/deprecation#Deprecation');
this._additions.push(selfStatement);
}
private addOperationTypeStm(edited: boolean) {
if (edited) {
this._additions.push(RdfData.createLiteralStatement(this._iri,
'https://nietzsche.philhist.unibas.ch/ontology/deprecation#deprecationHasOperationType',
'edition', '@en')); } else {
this._additions.push(RdfData.createLiteralStatement(this._iri,
'https://nietzsche.philhist.unibas.ch/ontology/deprecation#deprecationHasOperationType',
'deletion', '@en'));
}
}
// Updates the derivation tree with the latest changes: Changes the link from the latest Version to this depretaion and takes over the link to the former deprecation
private updateDerivationTree(derivateIri: string) {
if (!derivateIri || derivateIri === '') { return } // guard
const formerDerivation = this._predecessor.getFirstObject('https://nietzsche.philhist.unibas.ch/ontology/deprecation#derivesFrom');
if ( formerDerivation !== '') {
// deleting the "dep:derivesFrom" statement from the valid resource to the latest predecessor/deprecation
this._depTreeDeletions.push(RdfData.createNamedNodeQuad(derivateIri,'https://nietzsche.philhist.unibas.ch/ontology/deprecation#derivesFrom',
formerDerivation));
// adding the "dep:derivesFrom" statement from this deprecation to the former one, i.e. its predecessor
this._additions.push(RdfData.createNamedNodeQuad(this._iri,
'https://nietzsche.philhist.unibas.ch/ontology/deprecation#derivesFrom',
formerDerivation));
}
// Add the link between the new valid version/ the derivate to this deprecation which is the latest predecessor
this._additions.push(RdfData.createNamedNodeQuad(derivateIri,
'https://nietzsche.philhist.unibas.ch/ontology/deprecation#derivesFrom',
this._iri));
}
// public methods/accessors
public iri() {
return this._iri;
}
// returns all the quads which have to be added/created as an N3.Quad array, so all the new additions as well as all
// the quads of the Dep:deprecatedResource we like to add to the store
public quadsToCreate(): N3.Quad[] {
if (this.deprecatedResource) {
return this._additions.concat(this._productiveOperations.additions, this._productiveOperations.listsToWrite, this.deprecatedResource.quads());
} else {
return this._additions.concat(this._productiveOperations.additions, this._productiveOperations.listsToWrite)
}
}
public quadsToDelete(): N3.Quad[] {
return [].concat(this._depTreeDeletions, this._productiveOperations.deletions);
}
public listDeletionQueries(): string[] {
return this._productiveOperations.delListQueries;
}
}

Event Timeline