Untitled

mail@pastecode.io avatar
unknown
plain_text
a year ago
121 kB
1
Indexable
Never
// Innotrade Enapso Object Related Mapper (ORM) - GraphDB Adapter
// (C) Copyright 2019-2020 Innotrade GmbH, Herzogenrath, NRW, Germany

// Author: Alexander Schulze and Muhammad Yasir
require('@innotrade/enapso-config');
const { EnapsoGraphDBClient } = requireEx('@innotrade/enapso-graphdb-client'),
    { EnapsoGraphDBAdmin } = requireEx('@innotrade/enapso-graphdb-admin'),
    { ensptools } = requireEx('@innotrade/enapso-sparql-tools'),
    { EnapsoLogger, EnapsoLoggerFactory } = requireEx(
        '@innotrade/enapso-logger'
    );
EnapsoLoggerFactory.createGlobalLogger('enLogger');
enLogger.setLevel(EnapsoLogger.ALL);
const SwaggerGenerator = requireEx('@innotrade/enapso-swagger');
const { CodeGenerator } = requireEx('@innotrade/enapso-jsast');

//const spfmt = require('https://cdn.jsdelivr.net/gh/hchiba1/spang@master/js/spfmt_bundled.js');

class EnapsoGraphDBAdapter {
    constructor(config) {
        config = config || {};
        this.repository = config.schema;
        this.prefixes = config.prefixes;
        this.baseUrl = config.dbUrl;
        this.user = config.user;
        this.pass = config.pass;
        this.options = config.options;
        this.triplestore = config.triplestore;
        this.version = config.version;
        this.apiType = config.apiType;
        this.enPrefixManager = new ensptools.PrefixManager(config.prefixes);
        if (config.defaultPrefix) {
            this.enPrefixManager.setDefaultPrefix(config.defaultPrefix);
        }
        if (config.defaultNamespace) {
            this.enPrefixManager.setDefaultNamespace(config.defaultNamespace);
        }

        // in case no prefix is given for a certain resource identifier use the EDO: here
        // this.enPrefixManager.setDefaultPrefix(PREFIX_EDO);

        // create a SPARQL generator using the prefix manager
        this.enSparqlGenerator = new ensptools.Generator({
            prefixManager: this.enPrefixManager
        });
        // allPrefixes:true to show all prefixes which pass in query if its fail then it show only those prefixes which are part of query not all and remove the unnecessary prefixes
        this.enSPARQLBeautifier = new ensptools.SparqlBeautifier({
            prefixes: this.enPrefixManager.getPrefixesInSPARQLFormat()
            //    allPrefixes: true
        });
    }
    // async checkPrefixMangerPrefixes(managerPrefixes) {
    //     //let status = false;
    //     if (managerPrefixes.length > this.prefixes.length) {
    //         let newPrefixes = managerPrefixes.map((rec) => {
    //             return {
    //                 prefix: rec.prefix,
    //                 iri: rec.namespace
    //             };
    //         });
    //         this.prefixes = newPrefixes;
    //         this.graphDBEndpoint.setPrefixes(newPrefixes);
    //         console.log('Hello');
    //     }
    // }

    async connect() {
        try {
            this.graphDBEndpoint = new EnapsoGraphDBClient.Endpoint({
                baseURL: this.baseUrl,
                repository: this.repository,
                prefixes: this.prefixes,
                version: this.version,
                triplestore: this.triplestore,
                apiType: this.apiType
            });
            await this.login(this.user, this.pass);
            this.classCache = await this.buildClassCache();
            //  console.log(this.classCache);
        } catch (err) {
            // console.log(err);
            throw err;
            // await this.connect();
        }
    }
    async login(user, pass) {
        this.authentication = await this.graphDBEndpoint.login(user, pass);

        if (!this.authentication.success) {
            let lMsg = this.authentication.message;
            if (500 === this.authentication.status) {
                if ('ECONNREFUSED' === this.authentication.code) {
                    lMsg +=
                        ', check if GraphDB is running at ' +
                        this.graphDBEndpoint.getBaseURL();
                }
            } else if (401 === this.authentication.status) {
                lMsg +=
                    ', check if user "' +
                    GRAPHDB_USERNAME +
                    '" is set up in your GraphDB at ' +
                    this.graphDBEndpoint.getBaseURL();
            }
            enLogger.error('Login failed: ' + lMsg);
            return;
        }
    }

    async sparqlQuery(sparql, options) {
        //let pr = ;
        // await this.checkPrefixMangerPrefixes(
        //     this.enPrefixManager.getPrefixes()
        // );
        options = options || {};
        options.dropPrefixes = options.dropPrefixes || false;
        let query = await this.graphDBEndpoint.query(sparql);
        let resp;
        if (query.success) {
            resp = await this.graphDBEndpoint.transformBindingsToResultSet(
                query,
                {
                    dropPrefixes: options.dropPrefixes
                }
            );
        } else {
            let lMsg = query.message;
            if (400 === query.status) {
                lMsg += ', check your query for potential errors';
            } else if (403 === query.status) {
                lMsg +=
                    ', check if user "' +
                    GRAPHDB_USERNAME +
                    '" has appropriate access rights to the Repository ' +
                    '"' +
                    this.graphDBEndpoint.getRepository() +
                    '"';
            }
            resp = {
                total: 0,
                success: false,
                message: lMsg
            };
        }
        return resp;
    }

    async sparqlUpdate(sparql, params) {
        let resp = await this.graphDBEndpoint.update(sparql, params);
        if (!resp.success) {
            let lMsg = resp.message;
            if (400 === resp.status) {
                lMsg += ', check your query for potential errors';
            } else if (403 === resp.status) {
                lMsg +=
                    ', check if user "' +
                    GRAPHDB_USERNAME +
                    '" has appropriate access rights to the Repository ' +
                    '"' +
                    this.graphDBEndpoint.getRepository() +
                    '"';
            }
        }
        return resp;
    }
    findAndReplace(object, classCache) {
        let cache = classCache;
        for (var x in object) {
            if (typeof object[x] == typeof {}) {
                this.findAndReplace(object[x], cache);
            }
            if (object['cls']) {
                if (typeof object['cls'] != typeof {}) {
                    object['cls'] = cache.getClassByIRI(object['cls']);
                }
            }
        }
        return object;
    }
    async getSingleClassObjectProperties(cls) {
        let generated =
            this.enSparqlGenerator.getSingleClassObjectProperties(cls);
        //enLogger.debug('SPARQL:\n' + generated.sparql);
        return this.sparqlQuery(generated.sparql);
    }
    async getClassObjectProperties(cls) {
        let properties = cls.getObjectProperties();
        return properties;
    }

    async getIRIClassName(iri) {
        let generated = this.enSparqlGenerator.getIRIClassName(iri);
        //enLogger.debug('SPARQL:\n' + generated.sparql);
        return this.sparqlQuery(generated.sparql);
    }

    async getObjectPropertiesAndClassName(cls, prop) {
        let generated = this.enSparqlGenerator.getObjectPropertiesAndClassName(
            cls,
            prop
        );
        //enLogger.debug('SPARQL:\n' + generated.sparql);
        return this.sparqlQuery(generated.sparql);
    }

    async deleteIndividual(args) {
        let generated = this.enSparqlGenerator.deleteResource({
            iri: args.iri,
            joins: args.joins
        });
        return this.sparqlUpdate(generated.sparql);
    }

    async getIndividualsByClass(args) {
        let generated = this.enSparqlGenerator.getIndividualsByClass(args);
        //  enlogger.log('SPARQL:\n' + generated.sparql);
        return this.sparqlQuery(generated.sparql);
    }
    async getIndividualsByClassOnlyObjectProperties(args) {
        let generated =
            this.enSparqlGenerator.getIndividualsByClassOnlyObjectProperties(
                args
            );
        //  enlogger.log('SPARQL:\n' + generated.sparql);
        return this.sparqlQuery(generated.sparql);
    }
    generateClassFromClassProperties(ns, name, classProps) {
        let cls = new ensptools.Class(ns, name);
        for (let propRec of classProps.records) {
            // todo: here we need to add the restrictions, domain, range, min, max, exactly etc.
            let propParts = this.splitIRI(propRec.prop);
            let prop = new ensptools.Property(
                propParts.namespace,
                propParts.name,
                propRec.type,
                propRec.range,
                propRec.domain,
                propRec.prop
            );
            // add the property to the class
            cls.addProperty(prop);
        }
        return cls;
    }

    getFileExtension(fileFormat) {
        let formats = {
            'application/rdf+json': '.json',
            'application/ld+json': '.jsonld',
            'application/rdf+xml': '.rdf',
            'text/rdf+n3': '.n3',
            'text/plain': '.nt',
            'text/x-nquads': '.nq',
            'text/turtle': '.ttl',
            'application/trix': '.trix',
            'application/x-trig': '.trig',
            'application/x-binary-rdf': '.brf'
        };
        if (formats[fileFormat]) {
            return formats[fileFormat];
        } else {
            return false;
        }
    }
    generateClassDetailsFromClassProperties(
        ns,
        name,
        classProps,
        parent,
        prefix,
        subClasses
    ) {
        let cls = new ensptools.Class(ns, name);
        cls.properties = classProps;
        cls.parentName = parent;
        cls.prefix = prefix;
        cls.subClasses = subClasses;
        return cls;
    }

    splitIRI(iri, options) {
        let separator;
        let nameSpacePart;
        let namePart;
        if (!iri.includes('#')) {
            separator = '/';
            let name = iri.split('/').pop();
            nameSpacePart = iri.split(`/${name}`)[0];
            namePart = name;
        } else {
            separator = '#';
            let parts = iri.split('#');
            nameSpacePart = parts[0];
            namePart = parts[1];
        }
        return {
            namespace: nameSpacePart + separator,
            name: namePart
        };
    }
    async updateClassCache() {
        let classCache = await this.buildClassCache();
        this.classCache = classCache;
        return classCache;
    }

    async getClassCache() {
        return this.classCache;
    }

    async setClassCache(classCache) {
        let newClassCache = new ensptools.ClassCache();

        this.classCache = newClassCache.deserializeClassCache(classCache);
    }
    async getAllIndividualWithClassType() {
        return this.sparqlQuery(`SELECT distinct ?individual ?class
        WHERE {
            ?individual rdf:type owl:NamedIndividual .
            ?individual sesame:directType ?class .
            filter(?class!=owl:NamedIndividual)
        } `);
    }
    async getIndividualType(iri) {
        return this.sparqlQuery(`SELECT distinct ?individual ?class
        WHERE {
            <${iri}> sesame:directType ?class .
            filter(?class!=owl:NamedIndividual)
        } `);
    }
    async buildClassCacheForGenerators(body, maintain, cache) {
        let maintainArray = maintain || [];
        let classesName = [];
        if (!Array.isArray(body.classes)) {
            classesName.push({ class: body.classes });
        } else {
            for (const cls of body.classes) {
                classesName.push({ class: cls });
            }
            //   clsName = { class: body.classes };
        }
        let classCache = cache || new ensptools.ClassCache();

        // // get all classes of the database
        // let generated = this.enSparqlGenerator.getAllClasses();
        // // enLogger.log('SPARQL:\n' + generated.sparql);
        // let classes = await this.sparqlQuery(generated.sparql);

        // iterate through all returned classes
        for (let clsRec of classesName) {
            if (!maintainArray.includes(clsRec.class)) {
                maintainArray.push(clsRec.class);
                let classIri = clsRec.class;
                let properties = await this.getSingleClassProperties({
                    cls: classIri
                });
                const objectPropertiesRanges = properties.records.filter(
                    (item) =>
                        item.type ==
                        'http://www.w3.org/2002/07/owl#ObjectProperty'
                );
                let RangeClassesName = objectPropertiesRanges.map((obj) => {
                    return obj.range;
                });
                let parent = await this.getParentClass({ cls: classIri });
                let prefix = await this.getFullPrefixToIRI({ cls: classIri });
                let subClass = await this.getSubClasses({ cls: classIri });
                let clsproperties, parentClass, subClasses;
                if (properties.records.length) {
                    clsproperties = properties.records;
                }
                if (parent.records.length) {
                    parentClass = parent.records[0].parentClass;
                }
                if (subClass.records.length) {
                    subClasses = subClass.records;
                }
                // generate an in-memory class of the retrieved properties
                let classId = this.splitIRI(classIri);
                let cls = this.generateClassDetailsFromClassProperties(
                    classId.namespace,
                    classId.name,
                    clsproperties,
                    parentClass,
                    prefix.records,
                    subClasses
                );
                // add the class to the cache
                classCache.addClass(cls);
                // for(let i=0;i<RangeClassesName.length;i++)
                // {
                if (subClasses) {
                    if (subClasses.length) {
                        let subClassesName = subClasses.map((obj) => {
                            return obj.subClass;
                        });
                        await this.buildClassCacheForGenerators(
                            {
                                classes: subClassesName
                            },
                            maintainArray,
                            classCache
                        );
                    }
                }

                await this.buildClassCacheForGenerators(
                    {
                        classes: RangeClassesName
                    },
                    maintainArray,
                    classCache
                );

                if (parentClass) {
                    await this.buildClassCacheForGenerators(
                        {
                            classes: parentClass
                        },
                        maintainArray,
                        classCache
                    );
                }

                //}
            }
        }
        return classCache;
    }
    async buildClassCache() {
        let classCache = new ensptools.ClassCache();
        // get all classes of the database
        let generated = this.enSparqlGenerator.getAllClasses();
        // enLogger.log('SPARQL:\n' + generated.sparql);
        let classes = await this.sparqlQuery(generated.sparql);
        let individuals = await this.getAllIndividualWithClassType();
        classCache.addIndividual(individuals.records);
        // iterate through all returned classes
        for (let clsRec of classes.records) {
            let classIri = clsRec.class;
            // get the properties of the given class
            let generated =
                this.enSparqlGenerator.getClassPropertiesByDomainAndRestrictions(
                    classIri
                );

            // enLogger.log('SPARQL:\n' + generated.sparql);
            let res = await this.sparqlQuery(generated.sparql, {
                dropPrefixes: false // here we need the full data types and IRIs
            });

            // generate an in-memory class of the retrieved properties
            let classId = this.splitIRI(classIri);
            let cls = this.generateClassFromClassProperties(
                classId.namespace,
                classId.name,
                res
            );
            // add the class to the cache
            classCache.addClass(cls);
        }

        return classCache;
    }
    async create(reqMeta, reqRecords) {
        try {
            let status = 500;
            let message = '-';
            let success = false;
            let count = 0;
            let records = [];
            let cls = reqMeta.cls;
            let baseiri = reqMeta.baseiri;
            let limit = reqMeta.limit;
            let graph = reqMeta.graph;
            cls = this.classCache.getClassByIRI(cls);
            if (!cls) {
                status = 400;
                message = 'No or invalid class passed';
            }
            if (!reqRecords.length) {
                status = 400;
                message = 'empty records array field passed passed';
            } else {
                let options = this.options;
                let res;

                if (limit) {
                    let currentRecords = await this.read({ cls: reqMeta.cls });
                    if (
                        currentRecords.records.length + reqRecords.length >
                        limit
                    ) {
                        return {
                            status: 404,
                            message: `Only ${limit} individuals are allowed`,
                            success
                        };
                    }
                }
                for (let record of reqRecords) {
                    let generated =
                        this.enSparqlGenerator.createIndividualByClass({
                            cls: cls,
                            baseiri: baseiri,
                            ind: record,
                            options: options,
                            graph: graph
                        });
                    //enLogger.log('SPARQL:\n' + generated.sparql);
                    res = await this.sparqlUpdate(generated.sparql, {
                        iri: generated.iri
                    });
                    record.iri = generated.iri;
                }
                status = res.status;
                message = res.message;
                success = res.success;
                count = reqRecords.length;
                records = reqRecords;
            }
            return {
                status,
                count,
                records,
                message,
                success
            };
        } catch (err) {
            throw err;
        }
    }

    async update(reqMeta, reqRecords) {
        try {
            let status = 500;
            let message = '-';
            let success = false;
            let count = 0;

            // get the data from the API
            let cls = reqMeta.cls;
            let graph = reqMeta.graph;
            cls = this.classCache.getClassByIRI(cls);
            if (!cls) {
                status = 400;
                message = 'No or invalid class passed';
            }
            if (!reqRecords.length) {
                status = 400;
                message = 'empty record array field passed';
            } else {
                for (let record of reqRecords) {
                    let iri = record.iri;
                    if (!iri) {
                        message = 'No iri passed of an individual to update';
                    } else {
                        let generated =
                            this.enSparqlGenerator.updateIndividualByClass({
                                cls: cls,
                                iri: iri,
                                ind: record,
                                graph: graph
                            });
                        // enLogger.log('SPARQL:\n' + generated.sparql);
                        let res = await this.sparqlUpdate(generated.sparql, {
                            iri: generated.iri
                        });
                        // now we need to convert the sparql result into an API result
                        status = res.status;
                        message = res.message;
                        success = res.success;
                        count = reqRecords.length;
                    }
                }
            }
            return {
                status,
                message,
                success,
                count
            };
        } catch (err) {
            throw err;
        }
    }

    async deleteRelation(reqMeta, reqRecords) {
        try {
            let child = reqMeta.child;
            let parent = reqMeta.parent;
            let property = reqMeta.property;
            let generated = this.enSparqlGenerator.deleteRelation(
                parent,
                property,
                child
            );
            //  console.log('SPARQL:\n' + generated.sparql);
            let res = await this.sparqlUpdate(generated.sparql);
            // now we need to convert the sparql result into an API result
            let status = res.status;
            let message = res.message;
            let success = res.success;
            return {
                status,
                message,
                success
            };
        } catch (err) {
            throw err;
        }
    }

    async createRelation(reqMeta, reqRecords) {
        try {
            let child = reqMeta.child;
            let parent = reqMeta.parent;
            let property = reqMeta.property;
            let graph = reqMeta.graph;
            let generated = this.enSparqlGenerator.createRelation(
                parent,
                property,
                child,
                graph
            );
            // console.log('SPARQL:\n' + generated.sparql);
            let res = await this.sparqlUpdate(generated.sparql);
            // now we need to convert the sparql result into an API result
            let status = res.status;
            let message = res.message;
            let success = res.success;
            return {
                status,
                message,
                success
            };
        } catch (err) {
            throw err;
        }
    }
    async findDeleteJoin(iri, relation) {
        let val = await this.getIRIClassName(iri);
        let join = [];
        if (val.records.length) {
            if (relation == 'parent2ChildRelation') {
                let res = await this.getSingleClassObjectProperties(
                    val.records[0].type
                );
                return this.traverseParent2ChildJoin(res.records, join);
            } else if (relation == 'child2ParentRelation') {
                let relationClass, parentClass;
                relationClass = await this.getObjectPropertiesAndClassName(
                    val.records[0].type,
                    'enf:hasParent'
                );
                if (relationClass) {
                    if (relationClass.records.length) {
                        parentClass = await this.getSingleClassObjectProperties(
                            relationClass.records[0].class
                        );
                    }
                }
                if (parentClass) {
                    if (parentClass.records.length) {
                        return this.traverseChild2ParentJoin(
                            parentClass.records,
                            join
                        );
                    }
                }
            }
        } else {
            return join;
        }
    }
    async traverseParent2ChildJoin(params, array) {
        let join = array || [];
        for (const key of params) {
            let objProp = await this.getSingleClassObjectProperties(key.range);
            let relation, constraint;
            if (objProp) {
                if (objProp.records.length) {
                    relation = objProp.records.filter(
                        (item) =>
                            item.prop ==
                            'http://ont.enapso.com/foundation#hasRelations'
                    );
                }
                if (relation) {
                    if (relation.length) {
                        constraint = await this.getSingleClassObjectProperties(
                            relation[0].range
                        );
                        constraint = constraint.records.filter(
                            (item) =>
                                item.prop ==
                                'http://ont.enapso.com/foundation#hasConstraints'
                        );
                        if (constraint) {
                            if (constraint.length) {
                                constraint = constraint[0].range;
                            } else {
                                constraint = constraint[0];
                            }
                        }
                    }
                }
            }
            join.push({
                joins: {
                    cls: key.range,
                    parent2ChildRelation: key.prop
                },
                constraint: constraint
            });
        }
        return join;
    }

    async traverseChild2ParentJoin(parentClass, array) {
        let join = array || [];
        const parent = parentClass.filter(
            (item) => item.prop == 'http://ont.enapso.com/foundation#hasParent'
        );
        const relation = parentClass.filter(
            (item) =>
                item.prop == 'http://ont.enapso.com/foundation#hasRelations'
        );
        let constraint = await this.getSingleClassObjectProperties(
            relation[0].range
        );
        const constraintFilter = constraint.records.filter(
            (item) =>
                item.prop == 'http://ont.enapso.com/foundation#hasConstraints'
        );

        // }
        for (const key of parent) {
            join.push({
                joins: {
                    cls: key.domain,
                    child2ParentRelation: key.prop
                },
                constraint: constraintFilter[0].range
            });
        }

        return join;
    }
    async deleteIntegrityRelation(args) {
        if (args.joins) {
            for (const item of args.joins) {
                if (
                    item.constraint ==
                    'http://ont.enapso.com/foundation#DeleteCascadeConstraint'
                ) {
                    let res = await this.deleteIndividual({
                        joins: [item.joins],
                        iri: args.iri
                    });
                    //    console.log(res);
                    //   return res;
                } else if (
                    item.constraint ==
                    'http://ont.enapso.com/foundation#DeleteRestrictConstraint'
                ) {
                    let res = await this.deleteRestrict({
                        joins: [item.joins],
                        iri: args.iri,
                        cache: args.cache
                    });
                    //console.log(res);
                    //return res;
                } else if (
                    item.constraint ==
                    'http://ont.enapso.com/foundation#DeleteSetNullConstraint'
                ) {
                    await this.deleteParentRelation(args.iri);
                    let res = await this.deleteIndividual({
                        iri: args.iri
                    });
                    //return res;
                } else {
                    let res = await this.deleteIndividual({
                        joins: [item.joins],
                        iri: args.iri
                    });
                    // return res;
                }
            }
            if (args.relation == 'parent2ChildRelation') {
                let res = await this.deleteIndividual({
                    iri: args.iri
                });
                //return res;
            }
        } else {
            let res = await this.deleteIndividual({
                iri: args.iri
            });
            //return res;
        }
    }
    async deleteRestrict(args) {
        let joins;
        if (args.joins) {
            joins = await this.findAndReplace(args.joins, args.cache);
            let cache = args.cache;
            let cls = await this.getIRIClassName(args.iri);
            if (cls.records.length) {
                let res2 = await this.getIndividualsByClass({
                    cls: cache.getClassByIRI(cls.records[0].type),
                    joins: joins,
                    filter: [
                        {
                            key: '$sparql',
                            value: `regEx(str(?ind),  "${args.iri}", "i")`
                        }
                    ]
                });
                const result = res2.records.filter(
                    (item) => item.iri != args.iri
                );
                if (result.length > 0) {
                    return {
                        success: false,
                        message: 'Child need to be deleted first',
                        status: 400
                    };
                } else {
                    return await this.deleteIndividual({
                        iri: args.iri
                    });
                }
            } else {
                return {
                    success: false,
                    message: 'No class found against that individual',
                    status: 400
                };
            }
        } else {
            return await this.deleteIndividual({
                iri: args.iri
            });
        }
    }
    async delete(reqMeta, reqRecords) {
        try {
            let message = '';
            let status = 500;
            let success = false;
            let count = 0;
            for (let record of reqRecords) {
                let iri = record.iri;
                if (!iri) {
                    message = 'No iri passed of an individual to delete';
                }
                // let relation = record.relation;
                // let join;
                // if (relation) {
                //     join = await this.findDeleteJoin(iri, relation);
                // } else {
                //     join = record.joins === undefined ? 0 : record.joins;
                // }
                else {
                    await this.deleteIndividual({
                        iri: iri
                    });
                    status = 200;
                    message = 'OK';
                    success = true;
                    count = reqRecords.length;
                }
            }

            return {
                status,
                message,
                success,
                count
            };
        } catch (err) {
            throw err;
        }
    }
    async read(reqMeta) {
        try {
            // now we need to convert the sparql result into an API result
            let status = 500;
            let message = '';
            let success = false;
            let count = 0;
            let total = 0;
            let offset = reqMeta.offset === undefined ? 0 : reqMeta.offset;
            let limit = reqMeta.limit === undefined ? 0 : reqMeta.limit;
            let filter = reqMeta.filter === undefined ? 0 : reqMeta.filter;
            let records = [];
            let joins = reqMeta.joins === undefined ? 0 : reqMeta.joins;
            let cls = reqMeta.cls;
            let relation = reqMeta.relation;
            let graph = reqMeta.graph;
            let filterProp = reqMeta.filterProp;
            let collapseObject = reqMeta.collapseObject;
            if (relation) {
                let res = await this.findreadJoins({
                    relation,
                    cls,
                    filter
                });

                if (res.records) {
                    joins = res.records;
                }
            }
            cls = this.classCache.getClassByIRI(cls);
            if (!cls) {
                message = 'No or invalid class passed';
            } else {
                // and retrieve all instances by the given in-memory class
                joins = this.findAndReplace(joins, this.classCache);
                let generated;
                // if (calculateCost) {
                // generated = this.enSparqlGenerator.calculateCost({
                //     iri
                // });
                //  } else {
                generated = this.enSparqlGenerator.getIndividualsByClass({
                    cls,
                    offset,
                    limit,
                    filter,
                    joins,
                    graph,
                    filterProp
                });
                // }
                //  fs.writeFile('test', JSON.stringify(obj));

                //    enLogger.debug('SPARQL:\n' + generated.sparql);

                let res = await this.sparqlQuery(generated.sparql);
                if (collapseObject) {
                    let result = this.collapseObjectFn(res.records);
                    res.records = result;
                    res.records.length = result.length;
                }
                status = 200;
                message = 'Ok';
                success = true;
                count = res.records.length;
                total = res.records.length;
                offset = 0;
                limit = 0;
                records = res.records;
            }

            return {
                status,
                message,
                success,
                count,
                total,
                offset,
                limit,
                records
            };
        } catch (e) {
            throw e;
        }
    }
    async getClassesArray(records, array) {
        for (const iterator of records) {
            array.push(iterator.cls);
            if (array.joins) {
                array.concat(await this.getClassesArray(iterator, []));
            }
        }
        return array;
    }
    toLowerCase(option) {
        return `${option[0].toLowerCase()}${option.substr(1)}`;
    }
    findNestedChild(childs, parents) {
        let array = [];
        let per = parents;
        for (const key of childs) {
            let iri = this.findParentIRI(key);
            const childDetail = parents.filter((key) => key.parentIRI == iri);
            if (childDetail.length) {
                this.array = this.array.concat(childDetail);
                this.findNestedChild(childDetail, per);
            }
        }
        return array;
    }
    collapseObjectFn(records) {
        let obj = [];
        const result = records.filter((key) => key.iri);
        for (let i = 0; i < result.length; i++) {
            const childDetail = records.filter(
                (key) => key.parentIRI == result[i].iri
            );
            if (childDetail.length) {
                this.array = childDetail;
                this.findNestedChild(childDetail, records);
                let dupArray = this.findDuplicateKeys(this.array);
                let parent = this.array;
                if (dupArray.length) {
                    for (const iterator of dupArray) {
                        this.array = [iterator];
                        this.findNestedChild([iterator], records);
                        parent = parent.filter((x) => !this.array.includes(x));
                        let arrayDup = this.findAObject(this.array, result[i]);
                        //    for (const iterator of arrayDup.dupVal) {
                        let val = Object.assign(arrayDup.obj, arrayDup.dupVal);
                        //  }
                        obj = obj.concat(arrayDup.obj);
                        // obj.push(Object.assign(arrayDup));
                    }
                }
                if (parent.length) {
                    this.array = parent;
                    let colobject = this.findAObject(this.array, result[i]);
                    let array = colobject.dupVal;
                    for (const iterator of array) {
                        let val = Object.assign(
                            {},
                            colobject.obj,
                            iterator.value
                        );
                        obj = obj.concat(val);
                    }
                    obj = obj.concat(colobject.obj);
                    // obj.push(colobject);
                }
            }
        }
        return obj;
    }
    findDuplicateKeys(array) {
        let keysArray = [];
        let concatKey = [];
        let arr = [];
        for (const iterator of array) {
            let keys = Object.keys(iterator);
            var overlap = concatKey.filter(function (v, i, a) {
                return keys.indexOf(v) > -1;
            });
            if (overlap.length != keys.length) {
                concatKey = concatKey.concat(keys);
                concatKey = concatKey.concat(
                    keys.filter((item) => concatKey.indexOf(item) < 0)
                );
            } else {
                if (keysArray.length == 0) {
                    keysArray = keysArray.concat(iterator);
                }
                const result = keysArray.filter(
                    (item) => item.contentRelation == iterator.contentRelation
                );
                keysArray = keysArray.concat(
                    keys.filter((item) => keysArray.indexOf(item) < 0)
                );
                if (result.length) {
                    arr.push(iterator);
                }
            }
        }
        if (arr.length > 1) {
            return arr;
        } else {
            return [];
        }
    }
    findAObject(child, parent, status) {
        let obj = {};
        let keys = [];
        let dupVal = [];
        for (let i = 0; i < child.length; i++) {
            let newObj = {};
            if (!status) {
                let relation = child[i].contentRelation;
                let relationValue = this.findParentIRI(child[i]);
                child[i][relation] = relationValue;
                delete child[i].parentIRI;
                delete child[i].contentKey;
                for (const key in child[i]) {
                    if (key != 'contentRelation' && key != relation) {
                        newObj[`${relation}${key}`] = child[i][key];
                    }
                }
            }
            let k = Object.keys(newObj);
            const found = keys.some((r) => k.includes(r));
            if (found) {
                dupVal.push({ value: newObj, keys: k });
            } else {
                keys = keys.concat(k);
                obj = Object.assign(parent, newObj);
            }
        }
        // this.finalObj = [];
        // this.finalObj.push(obj);
        // for (const item of dupVal) {
        //     let val = Object.assign(this.finalObj[0], item.value);
        //     console.log(val);
        // }
        // console.log(dupVal);
        return { obj, dupVal };
        //Object.assign(obj, parent);
    }
    findParentIRI(obj) {
        let className = this.removeDot(obj.contentKey);
        className = `${this.toLowerCase(className)}Iri`;
        let relationValue = obj[className];
        return relationValue;
    }
    // async jsonMaker(data) {
    //     for (const item of data) {
    //         await this.traverseRecord(item, data);
    //     }
    // }
    // async traverseRecord(obj, data) {
    //     let empty = [];
    //     let parentClass = obj.className;
    //     let properties = obj.objectProperties;
    //     for (const key of obj.records) {
    //         for (const item in key) {
    //             let findProp = properties.filter(
    //                 (elem) => this.removeIRI(elem.prop) == item
    //             );
    //             if (findProp.length) {
    //                 let res = await this.filterIRI(data, key[item]);
    //                 for (let i = 0; i < res.length; i++) {
    //                     let rec = res[i].records;
    //                     for (const elem of rec) {
    //                         for (const iterator of elem) {
    //                             let findProp = res[i].objectProperties.filter(
    //                                 (elem) =>
    //                                     this.removeIRI(elem.prop) == iterator
    //                             );
    //                         }
    //                         if (findProp.length) {
    //                         }
    //                         console.log(elem);
    //                     }
    //                 }
    //             }
    //         }
    //     }
    // }
    // async filterIRI(data, item) {
    //     try {
    //         let array = [];
    //         for (let i = 0; i < data.length; i++) {
    //             let res = data[i].records.filter((elem) => elem.iri == item);

    //             if (res.length) {
    //                 array.push(data[i]);
    //             }
    //         }
    //         return array;
    //     } catch (e) {
    //         return e;
    //     }
    // }
    removeIRI(item) {
        return item ? item.split('#').pop() : null;
    }
    removeDot(item) {
        return item ? item.split('.').pop() : null;
    }
    async createDatabase(reqMeta) {
        try {
            let schema = reqMeta.schema;
            let title = reqMeta.title;
            let ruleset = reqMeta.ruleset;
            let isShacl = reqMeta.isShacl;
            let res = await this.graphDBEndpoint.createRepository({
                id: schema,
                title,
                ruleset,
                isShacl
            });
            let status = res.status;
            let message = res.message;
            let success = res.success;

            return {
                status,
                message,
                success
            };
        } catch (e) {
            return e;
        }
    }

    async createUser(reqMeta) {
        try {
            let authorities = reqMeta.authorities;
            let username = reqMeta.userName;
            let password = reqMeta.password;
            let res = await this.graphDBEndpoint.createUser({
                authorities,
                username,
                password
            });
            let status = res.status;
            let message = res.message;
            let success = res.success;

            return {
                status,
                message,
                success
            };
        } catch (err) {
            return err;
        }
    }
    async updateUser(reqMeta) {
        try {
            let authorities = reqMeta.authorities;
            let username = reqMeta.userName;
            let password = reqMeta.password;
            let res = await this.graphDBEndpoint.updateUser({
                authorities,
                username,
                password
            });
            let status = res.status;
            let message = res.message;
            let success = res.success;

            return {
                status,
                message,
                success
            };
        } catch (err) {
            return err;
        }
    }
    async deleteUser(reqMeta) {
        try {
            let user = reqMeta.userName;
            let res = await this.graphDBEndpoint.deleteUser({
                user
            });
            let status = res.status;
            let message = res.message;
            let success = res.success;

            return {
                status,
                message,
                success
            };
        } catch (err) {
            return err;
        }
    }

    async deleteDatabase(reqMeta) {
        try {
            let schema = reqMeta.schema;
            let res = await this.graphDBEndpoint.deleteRepository({
                id: schema
            });
            let status = res.status;
            let message = res.message;
            let success = res.success;

            return {
                status,
                message,
                success
            };
        } catch (err) {
            return err;
        }
    }

    async clearDatabase() {
        let res = await this.graphDBEndpoint.clearRepository();
        let status = res.status;
        let message = res.message;
        let success = res.success;

        return {
            status,
            message,
            success
        };
    }

    async clearContext(reqMeta) {
        let context = reqMeta.context;
        let res = await this.graphDBEndpoint.clearContext(context);
        let status = res.status;
        let message = res.message;
        let success = res.success;

        return {
            status,
            message,
            success
        };
    }

    async uploadOntology(reqMeta) {
        let data = reqMeta.fileName.data.toString();
        let fileName = reqMeta.fileName.name;
        let format = reqMeta.format;
        let baseIRI = reqMeta.baseIRI;
        let context = reqMeta.context;
        let res = await this.graphDBEndpoint.upload({
            data: data,
            filename: fileName,
            format: format,
            baseIRI: baseIRI,
            context: context
        });
        await this.graphDBEndpoint.waitForUploadResponse();
        if (res['uploadResponse']) {
            delete res['uploadResponse'];
        }

        return res;
        // let status = res.status;
        // let message = res.message;
        // let success = res.success;

        // return {
        //     status,
        //     message,
        //     success
        // };
    }
    async uploadOntologyFromData(reqMeta) {
        let data = reqMeta.fileData;
        let format = reqMeta.format;
        let baseIRI = reqMeta.baseIRI;
        let context = reqMeta.context;
        let res = await this.graphDBEndpoint.uploadFromData({
            data: data,
            format: format,
            baseIRI: baseIRI,
            context: context
        });
        await this.graphDBEndpoint.waitForUploadResponse();
        if (res['uploadResponse']) {
            delete res['uploadResponse'];
        }

        return res;
        // let status = res.status;
        // let message = res.message;
        // let success = res.success;

        // return {
        //     status,
        //     message,
        //     success
        // };
    }

    async downloadOntology(reqMeta) {
        let filename = reqMeta.filename;
        let type = reqMeta.type;
        let extension = reqMeta.extension;
        let context = reqMeta.context;
        let res = await this.graphDBEndpoint.downloadToFile({
            format: type,
            filename:
                filename + this.graphDBEndpoint.getRepository() + extension,
            context: context
        });
        let status = res.status;
        let message = res.message;
        let success = res.success;
        return {
            status,
            message,
            success
        };
    }
    async downloadOntologyToText(reqMeta) {
        let format = reqMeta.format;
        let context = reqMeta.context;
        let extension = this.getFileExtension(format);
        let status;
        let message;
        let success;
        let data;
        if (extension) {
            let res = await this.graphDBEndpoint.downloadToText({
                format: format,
                context: context
            });
            status = res.status;
            message = res.message;
            success = res.success;
            data = res.data;
        } else {
            status = 500;
            message = `Invalid ontology format (${format}) passed`;
            success = false;
        }

        return {
            status,
            message,
            success,
            extension,
            data
        };
    }

    async getClassProperties(reqMeta) {
        // get the data from the API
        let cls = reqMeta.cls;
        let generated = this.enSparqlGenerator.getClassProperties(cls);
        // enLogger.debug('SPARQL:\n' + generated.sparql);
        let res = await this.sparqlQuery(generated.sparql);

        // now we need to convert the sparql result into an API result
        let status = 200;
        let message = 'Ok';
        let success = true;
        let count = res.records.length;
        let total = res.records.length;
        let offset = 0;
        let limit = 0;
        let records = res.records;

        return {
            status,
            message,
            success,
            count,
            total,
            offset,
            limit,
            records
        };
    }
    async getClassPropertiesByDomain(reqMeta) {
        // get the data from the API
        let cls = reqMeta.cls;
        let generated = this.enSparqlGenerator.getClassPropertiesByDomain(cls);
        // enLogger.debug('SPARQL:\n' + generated.sparql);
        let res = await this.sparqlQuery(generated.sparql);

        // now we need to convert the sparql result into an API result
        let status = 200;
        let message = 'Ok';
        let success = true;
        let count = res.records.length;
        let total = res.records.length;
        let offset = 0;
        let limit = 0;
        let records = res.records;

        return {
            status,
            message,
            success,
            count,
            total,
            offset,
            limit,
            records
        };
    }

    async getClassPropertiesByPropertyShape(reqMeta) {
        // get the data from the API
        let cls = reqMeta.cls;
        let generated =
            this.enSparqlGenerator.getClassPropertiesFromPropertyShape(cls);
        // enLogger.debug('SPARQL:\n' + generated.sparql);
        let res = await this.sparqlQuery(generated.sparql);

        // now we need to convert the sparql result into an API result
        let status = 200;
        let message = 'Ok';
        let success = true;
        let count = res.records.length;
        let total = res.records.length;
        let offset = 0;
        let limit = 0;
        let records = res.records;

        return {
            status,
            message,
            success,
            count,
            total,
            offset,
            limit,
            records
        };
    }

    async getClassAllRestrictions(reqMeta) {
        // get the data from the API
        let cls = reqMeta.cls;
        let generated = this.enSparqlGenerator.getClassAllRestrictions(cls);
        // enLogger.debug('SPARQL:\n' + generated.sparql);
        let res = await this.sparqlQuery(generated.sparql);

        // now we need to convert the sparql result into an API result
        let status = 200;
        let message = 'Ok';
        let success = true;
        let count = res.records.length;
        let total = res.records.length;
        let offset = 0;
        let limit = 0;
        let records = res.records;

        return {
            status,
            message,
            success,
            count,
            total,
            offset,
            limit,
            records
        };
    }
    async getClassPropertiesByDomainAndRestrictions(reqMeta) {
        // get the data from the API
        let cls = reqMeta.cls;
        let generated =
            this.enSparqlGenerator.getClassPropertiesByDomainAndRestrictions(
                cls
            );
        // enLogger.debug('SPARQL:\n' + generated.sparql);
        let res = await this.sparqlQuery(generated.sparql);

        // now we need to convert the sparql result into an API result
        let status = 200;
        let message = 'Ok';
        let success = true;
        let count = res.records.length;
        let total = res.records.length;
        let offset = 0;
        let limit = 0;
        let records = res.records;

        return {
            status,
            message,
            success,
            count,
            total,
            offset,
            limit,
            records
        };
    }

    async getSingleClassProperties(reqMeta) {
        // get the data from the API
        //   console.log(reqMeta);
        let cls = reqMeta.cls;
        let generated = this.enSparqlGenerator.getSingleClassProperties(cls);
        //enLogger.debug('SPARQL:\n' + generated.sparql);
        let res = await this.sparqlQuery(generated.sparql);

        // now we need to convert the sparql result into an API result
        let status = 200;
        let message = 'Ok';
        let success = true;
        let count = res.records.length;
        let total = res.records.length;
        let offset = 0;
        let limit = 0;
        let records = res.records;

        return {
            status,
            message,
            success,
            count,
            total,
            offset,
            limit,
            records
        };
    }
    async getSubClasses(reqMeta) {
        // get sub class data from the API
        let cls = reqMeta.cls;

        let res = await this.sparqlQuery(`select ?subClass
        where{
            ?subClass sesame:directSubClassOf  <${cls}>.
            }`);

        // console.log(res);

        // now we need to convert the sparql result into an API result
        let status = 200;
        let message = 'Ok';
        let success = true;
        let count = res.records.length;
        let total = res.records.length;
        let offset = 0;
        let limit = 0;
        let records = res.records;

        return {
            status,
            message,
            success,
            count,
            total,
            offset,
            limit,
            records
        };
    }

    // async getIRIClassName(reqMeta) {
    //     // get sub class data from the API
    //     let iri = reqMeta.iri;
    //     let generated = this.enSparqlGenerator.getIRIClassName(iri);
    //     let res = await this.sparqlQuery(generated.sparql);
    //     let status = 200;
    //     let message = 'Ok';
    //     let success = true;
    //     let records = res.records;

    //     return {
    //         status,
    //         message,
    //         success,
    //         records
    //     };
    // }

    async getParentClass(reqMeta) {
        // get sub class data from the API
        let cls = reqMeta.cls;

        let res = await this.sparqlQuery(`select ?parentClass
        where{
         <${cls}> sesame:directSubClassOf     ?parentClass.
     filter(!isBlank(?parentClass))
            }`);

        // now we need to convert the sparql result into an API result
        let status = 200;
        let message = 'Ok';
        let success = true;
        let count = res.records.length;
        let total = res.records.length;
        let offset = 0;
        let limit = 0;
        let records = res.records;

        return {
            status,
            message,
            success,
            count,
            total,
            offset,
            limit,
            records
        };
    }
    async getFullPrefixToIRI(reqMeta) {
        // get sub class data from the API
        let cls = reqMeta.cls;

        let res = this.enPrefixManager.fullToPrefixedIRI(cls);
        // now we need to convert the sparql result into an API result
        let status = 200;
        let message = 'Ok';
        let success = true;
        let offset = 0;
        let limit = 0;
        let records = res;

        return {
            status,
            message,
            success,
            offset,
            limit,
            records
        };
    }
    async getPropNameWithNameSpace(prop, item) {
        let property;
        for (const key of prop) {
            if (key.prop.includes(item)) {
                property = key.prop;
            }
        }
        return property;
    }
    async getClassName(iri) {
        let cls = this.classCache.getIndividual(iri);
        if (cls) {
            return cls;
        } else {
            let getClass = await this.getIndividualType(iri);
            let className = getClass.records;
            if (className) {
                return className[0].class;
            } else {
                return null;
            }
        }
        // return cls;
    }
    async findClassesName(record) {
        let classesName = [];
        for (const iterator of record) {
            for (const key in iterator) {
                if (key != 'iri') {
                    let className = await this.getClassName(iterator[key]);
                    classesName.push({
                        iri: iterator[key],
                        cls: className
                    });
                }
            }
        }
        return classesName;
    }
    async readJoinFromInstances(records, prop, array, parentCls) {
        try {
            let maintain = [];
            for (const key of records) {
                let propPrefix = await this.getPropNameWithNameSpace(
                    prop,
                    key.prop
                );
                let index = maintain.some(
                    (el) => el.cls == key.cls && el.prop == propPrefix
                );
                //if (!index) {
                let filter;
                //  if (key.cls == parentCls) {
                filter = [
                    {
                        key: '$sparql',
                        value: `regEx(str(?ind),  '${key.iri}', 'i')`
                    }
                ];
                //}
                let res = await this.getIndividualsByClassOnlyObjectProperties({
                    cls: this.classCache.getClassByIRI(key.cls),
                    filter: filter
                });
                let nestedChild = await this.getClassesNameArray(
                    res.records,
                    key.cls
                );
                let objProp = await this.getClassObjectProperties(
                    this.classCache.getClassByIRI(key.cls)
                );
                maintain.push({
                    cls: key.cls,
                    prop: propPrefix
                });
                if (
                    Object.keys(res.records[0]).length > 1 &&
                    objProp.length &&
                    nestedChild
                ) {
                    let join = await this.readJoinFromInstances(
                        nestedChild,
                        objProp,
                        [],
                        key.cls
                    );
                    array.push({
                        cls: key.cls,
                        parent2ChildRelation: propPrefix,
                        joins: join
                    });
                } else {
                    array.push({
                        cls: key.cls,
                        parent2ChildRelation: propPrefix
                    });
                }
                //}
            }
            return array;
        } catch (e) {
            return e;
        }
    }
    async removeExisting(checkArray) {
        try {
            let array = [];
            for (const key of checkArray) {
                let index = array.filter(
                    (element) =>
                        element.cls == key.cls &&
                        element.parent2ChildRelation == key.parent2ChildRelation
                );
                if (index.length) {
                    let keyIndex = array.indexOf(index[0]);
                    array.splice(keyIndex, 1);
                    if (key.joins) {
                        key.joins = index[0].joins.concat(key.joins);
                        key.joins = await this.removeExisting(key.joins);
                    }
                    array.push(key);
                } else {
                    if (key.joins) {
                        key.joins = await this.removeExisting(key.joins);
                    }
                    array.push(key);
                }
            }
            return array;
        } catch (e) {
            return e;
        }
    }

    async getClassesNameArray(records, parent) {
        let clsArray = [];
        for (const iterator of records) {
            for (const key in iterator) {
                if (key != 'iri') {
                    let cls = await this.getClassName(iterator[key]);
                    // if(clsArray.some(
                    //     (el) => el.cls == cls && el.prop == key && el.iri == iterator[key]
                    // ))
                    // {
                    // }
                    if (cls) {
                        if (
                            !clsArray.some(
                                (el) =>
                                    el.cls == cls &&
                                    el.prop == key &&
                                    el.iri == iterator[key]
                            )
                        ) {
                            if (parent == cls) {
                                clsArray.push({
                                    cls: cls,
                                    prop: key,
                                    iri: iterator[key]
                                });
                            } else {
                                clsArray.push({
                                    cls: cls,
                                    prop: key,
                                    iri: iterator[key]
                                });
                            }
                        }
                    }
                }
            }
        }
        return clsArray;
    }
    async findreadJoins(reqMeta) {
        try {
            // get sub class data from the API
            let relation = reqMeta.relation;
            let cls = reqMeta.cls;
            let filter = reqMeta.filter;
            let join;
            if (relation == 'parent2ChildRelation') {
                let res = await this.getSingleClassObjectProperties(cls);
                join = await this.traverseParent2ChildRelation(
                    res.records,
                    [],
                    []
                );
            } else if (relation == 'child2ParentRelation') {
                let res = await this.getObjectPropertiesAndClassName(
                    cls,
                    'enf:hasParent'
                );
                join = await this.traverseChild2ParentRelation(res.records, []);
            } else if (relation == 'parent2ChildInstanceRelation') {
                let filterStatus;
                if (filter) {
                    if (filter[0].value) {
                        let filterValue = filter[0].value;
                        filterValue = filterValue.replace('ind', 'iri');
                        filterStatus = [
                            {
                                key: '$sparql',
                                value: filterValue
                            }
                        ];
                    }
                }

                let res = await this.getIndividualsByClassOnlyObjectProperties({
                    cls: this.classCache.getClassByIRI(cls)
                });
                let prop = await this.getClassObjectProperties(
                    this.classCache.getClassByIRI(cls)
                );
                let nestedChild = await this.getClassesNameArray(
                    res.records,
                    cls
                );

                join = await this.readJoinFromInstances(
                    nestedChild,
                    prop,
                    [],
                    cls
                );
                join = await this.removeExisting(join);
            }
            let status = 200;
            let message = 'Ok';
            let success = true;
            let offset = 0;
            let limit = 0;
            let records = join;

            return {
                status,
                message,
                success,
                offset,
                limit,
                records
            };
        } catch (e) {
            return e;
        }
    }
    async traverseParent2ChildRelation(res, joins, maintain) {
        let join = joins || [];
        for (const key of res) {
            let check = maintain.find(
                (element) =>
                    element.range == key.range &&
                    element.prop == key.prop &&
                    element.domain == key.domain
            );
            if (!check) {
                maintain.push({
                    range: key.range,
                    prop: key.prop,
                    domain: key.domain
                });
                let objProp = await this.getSingleClassObjectProperties(
                    key.range
                );
                if (objProp.records.length) {
                    join.push({
                        cls: key.range,
                        parent2ChildRelation: key.prop,
                        joins: await this.traverseParent2ChildRelation(
                            objProp.records,
                            [],
                            maintain
                        )
                    });
                } else {
                    join.push({
                        cls: key.range,
                        parent2ChildRelation: key.prop
                    });
                }
            }
        }
        return join;
    }

    async traverseChild2ParentRelation(res, joins) {
        let join = joins || [];
        for (const key of res) {
            let objProp = await this.getObjectPropertiesAndClassName(
                key.class,
                'enf:hasParent'
            );
            if (objProp.records.length) {
                join.push({
                    cls: key.class,
                    child2ParentRelation: 'enf:hasParent',
                    joins: await this.traverseChild2ParentRelation(
                        objProp.records,
                        []
                    )
                });
            } else {
                join.push({
                    cls: key.class,
                    child2ParentRelation: 'enf:hasParent'
                });
            }
        }
        return join;
    }
    async createSPARQL(reqMeta, reqRecords) {
        let status = 500;
        let message = '-';
        let success = false;
        let generated = [];
        let query;
        let cls = reqMeta.cls;
        let baseiri = reqMeta.baseiri;
        cls = this.classCache.getClassByIRI(cls);
        if (!cls) {
            status = 400;
            message = 'No or invalid class passed';
        } else {
            let options = this.options;
            for (let record of reqRecords) {
                let res = this.enSparqlGenerator.createIndividualByClass({
                    cls: cls,
                    baseiri: baseiri,
                    ind: record,
                    options: options
                });
                let query = this.enSPARQLBeautifier.beautify({
                    query: res.sparql
                    // prefixes: { ensw: 'http://ont.enapso.com/model/software#' },
                    // baseIRI: 'http://ont.enapso.com/model#'
                });
                generated.push(query);
                //    generated.push(this.removeSpaces(res.sparql));
            }
            status = 200;
            message = 'Query Successfully Created';
            success = true;
            query = generated;
        }
        return {
            status,
            query,
            message,
            success
        };
    }
    removeSpaces(item) {
        return (
            item
                .replace(/(\r\n\t\\|\n|\r|\t|\\)/gm, '')
                //.replace(/^"(.*)"$/, '$1')
                .replace(/"/g, "'")
        );
    }
    async readSPARQL(reqMeta) {
        // now we need to convert the sparql result into an API result
        let status = 500;
        let message = '';
        let success = false;
        let filter = reqMeta.filter === undefined ? 0 : reqMeta.filter;
        let query;
        let joins = reqMeta.joins === undefined ? 0 : reqMeta.joins;
        // get the data from the API
        let cls = reqMeta.cls;
        cls = this.classCache.getClassByIRI(cls);
        if (!cls) {
            status = 400;
            message = 'No or invalid class passed';
        } else {
            // and retrieve all instances by the given in-memory class
            joins = this.findAndReplace(joins, this.classCache);
            let generated = this.enSparqlGenerator.getIndividualsByClass({
                cls,
                filter,
                joins
            });
            let sparqlQuery = this.enSPARQLBeautifier.beautify({
                query: generated.sparql
                // prefixes: { ensw: 'http://ont.enapso.com/model/software#' },
                // baseIRI: 'http://ont.enapso.com/model#'
            });
            //  console.log(sparqlQuery);
            status = 200;
            message = 'Ok';
            success = true;
            query = sparqlQuery;
        }

        return {
            status,
            message,
            success,
            query
        };
    }
    async updateSPARQL(reqMeta, reqRecords) {
        let status = 500;
        let message = '-';
        let success = false;
        let generated = [];
        let query;
        let cls = reqMeta.cls;
        cls = this.classCache.getClassByIRI(cls);
        if (!cls) {
            status = 400;
            message = 'No or invalid class passed';
        } else {
            for (let record of reqRecords) {
                let iri = record.iri;
                let res = this.enSparqlGenerator.updateIndividualByClass({
                    cls: cls,
                    iri: iri,
                    ind: record
                });
                let query = this.enSPARQLBeautifier.beautify({
                    query: res.sparql
                    // prefixes: { ensw: 'http://ont.enapso.com/model/software#' },
                    // baseIRI: 'http://ont.enapso.com/model#'
                });
                generated.push(query);
            }
            status = 200;
            message = 'Query Successfully Created';
            success = true;
            query = generated;
        }
        return {
            status,
            query,
            message,
            success
        };
    }
    async deleteSPARQL(reqMeta, reqRecords) {
        let generated = [];
        for (let record of reqRecords) {
            let iri = record.iri;
            let join = record.join;
            let res = this.enSparqlGenerator.deleteResource({
                iri: iri,
                joins: join
            });
            let query = this.enSPARQLBeautifier.beautify({
                query: res.sparql
                // prefixes: { ensw: 'http://ont.enapso.com/model/software#' },
                // baseIRI: 'http://ont.enapso.com/model#'
            });
            generated.push(query);
        }
        let status = 200;
        let message = 'OK';
        let success = true;
        let query = generated;

        return {
            status,
            message,
            success,
            query
        };
    }

    async createClassAndAddRestriction(reqMeta) {
        try {
            let generated = this.enSparqlGenerator.createClassAndAddRestriction(
                {
                    cls: reqMeta.cls,
                    parent: reqMeta.parentId || reqMeta.parent,
                    label: reqMeta.label,
                    comment: reqMeta.comment,
                    restriction: reqMeta.restriction
                }
            );

            let res = await this.sparqlUpdate(generated.sparql);
            this.classCache = await this.buildClassCache();
            let status = res.status;
            let message = res.message;
            let success = res.success;

            return {
                status,
                message,
                success
            };
        } catch (e) {
            return e;
        }
    }

    async deleteClassSpecificRestriction(reqMeta, reqRecords) {
        try {
            let generated =
                this.enSparqlGenerator.deleteClassSpecificRestriction({
                    cls: reqMeta.cls,

                    restriction: reqMeta.restriction
                });

            let res = await this.sparqlUpdate(generated.sparql);

            let status = res.status;
            let message = res.message;
            let success = res.success;

            return {
                status,
                message,
                success
            };
        } catch (e) {
            return e;
        }
    }

    async updateClassRestriction(reqMeta) {
        try {
            let generated = this.enSparqlGenerator.updateClassRestriction({
                cls: reqMeta.cls,
                restriction: reqMeta.restriction
            });

            let res = await this.sparqlUpdate(generated.sparql);

            let status = res.status;
            let message = res.message;
            let success = res.success;

            return {
                status,
                message,
                success
            };
        } catch (e) {
            return e;
        }
    }

    async deleteLabel(reqMeta) {
        try {
            let generated = this.enSparqlGenerator.deleteLabel({
                name: reqMeta.name,
                label: reqMeta.label
            });

            let res = await this.sparqlUpdate(generated.sparql);

            let status = res.status;
            let message = res.message;
            let success = res.success;

            return {
                status,
                message,
                success
            };
        } catch (e) {
            return e;
        }
    }

    async addLabel(reqMeta) {
        try {
            let generated = this.enSparqlGenerator.addLabel({
                name: reqMeta.name,
                label: reqMeta.label,
                lang: reqMeta.lang
            });

            let res = await this.sparqlUpdate(generated.sparql);

            let status = res.status;
            let message = res.message;
            let success = res.success;

            return {
                status,
                message,
                success
            };
        } catch (e) {
            return e;
        }
    }

    async changeLabel(reqMeta) {
        try {
            let generated = this.enSparqlGenerator.changeLabel({
                name: reqMeta.name,
                label: reqMeta.label,
                oldLabel: reqMeta.oldLabel,
                lang: reqMeta.lang
            });

            let res = await this.sparqlUpdate(generated.sparql);

            let status = res.status;
            let message = res.message;
            let success = res.success;

            return {
                status,
                message,
                success
            };
        } catch (e) {
            return e;
        }
    }

    async deleteComment(reqMeta) {
        try {
            let generated = this.enSparqlGenerator.deleteComment({
                name: reqMeta.name,
                comment: reqMeta.comment
            });

            let res = await this.sparqlUpdate(generated.sparql);

            let status = res.status;
            let message = res.message;
            let success = res.success;

            return {
                status,
                message,
                success
            };
        } catch (e) {
            return e;
        }
    }

    async addComment(reqMeta) {
        try {
            let generated = this.enSparqlGenerator.addComment({
                name: reqMeta.name,
                comment: reqMeta.comment,
                lang: reqMeta.lang
            });

            let res = await this.sparqlUpdate(generated.sparql);

            let status = res.status;
            let message = res.message;
            let success = res.success;

            return {
                status,
                message,
                success
            };
        } catch (e) {
            return e;
        }
    }

    async changeComment(reqMeta) {
        try {
            let generated = this.enSparqlGenerator.changeComment({
                name: reqMeta.name,
                comment: reqMeta.comment,
                oldComment: reqMeta.oldComment,
                lang: reqMeta.lang
            });

            let res = await this.sparqlUpdate(generated.sparql);

            let status = res.status;
            let message = res.message;
            let success = res.success;

            return {
                status,
                message,
                success
            };
        } catch (e) {
            return e;
        }
    }

    async deleteClassModel(reqMeta) {
        try {
            let generated = this.enSparqlGenerator.deleteClassModel({
                cls: reqMeta.cls
            });

            let res = await this.sparqlUpdate(generated.sparql);

            let status = res.status;
            let message = res.message;
            let success = res.success;

            return {
                status,
                message,
                success
            };
        } catch (e) {
            return e;
        }
    }

    async deleteClassData(reqMeta) {
        try {
            let generated = this.enSparqlGenerator.deleteClassData({
                cls: reqMeta.cls
            });

            let res = await this.sparqlUpdate(generated.sparql);

            let status = res.status;
            let message = res.message;
            let success = res.success;

            return {
                status,
                message,
                success
            };
        } catch (e) {
            return e;
        }
    }

    async deleteClassModelAndData(reqMeta) {
        try {
            let generated = this.enSparqlGenerator.deleteClassModelAndData({
                cls: reqMeta.cls
            });

            let res = await this.sparqlUpdate(generated.sparql);

            let status = res.status;
            let message = res.message;
            let success = res.success;

            return {
                status,
                message,
                success
            };
        } catch (e) {
            return e;
        }
    }

    async deleteClassReferenceModel(reqMeta) {
        try {
            let generated = this.enSparqlGenerator.deleteClassReferenceModel({
                cls: reqMeta.cls
            });

            let res = await this.sparqlUpdate(generated.sparql);

            let status = res.status;
            let message = res.message;
            let success = res.success;

            return {
                status,
                message,
                success
            };
        } catch (e) {
            return e;
        }
    }

    async deleteClassReferenceData(reqMeta) {
        try {
            let generated = this.enSparqlGenerator.deleteClassReferenceData({
                cls: reqMeta.cls
            });

            let res = await this.sparqlUpdate(generated.sparql);

            let status = res.status;
            let message = res.message;
            let success = res.success;

            return {
                status,
                message,
                success
            };
        } catch (e) {
            return e;
        }
    }

    async deleteClassReferenceModelAndData(reqMeta) {
        try {
            let generated =
                this.enSparqlGenerator.deleteClassReferenceModelAndData({
                    cls: reqMeta.cls
                });

            let res = await this.sparqlUpdate(generated.sparql);

            let status = res.status;
            let message = res.message;
            let success = res.success;

            return {
                status,
                message,
                success
            };
        } catch (e) {
            return e;
        }
    }

    async deleteClass(reqMeta) {
        try {
            let generated = this.enSparqlGenerator.deleteClass({
                cls: reqMeta.cls,
                parent: reqMeta.parent
            });
            //   console.log(generated.sparql);

            let res = await this.sparqlUpdate(generated.sparql);
            let status = res.status;
            let message = res.message;
            let success = res.success;

            return {
                status,
                message,
                success
            };
        } catch (e) {
            return e;
        }
    }
    async generateTreeJson(data, array) {
        try {
            for (const item of data) {
                let res = await this.getSubClass(this.data, item.class);
                //  array = array.filter((key) => key.text != item.class);
                if (res.length) {
                    array.push({
                        label: item.label || this.removeIRI(item.class),
                        cls: item.class,
                        lang: item.lang,
                        //  expanded: true,
                        children: await this.generateTreeJson(res, [])
                    });
                } else {
                    array.push({
                        label: item.label || this.removeIRI(item.class),
                        cls: item.class,
                        lang: item.lang,
                        leaf: true
                    });
                }
            }
            return array;
        } catch (e) {
            return e;
        }
    }
    async getSubClass(data, cls) {
        const res = data.filter((key) => key.superClass == cls);
        return res;
    }
    async checkChild(data, cls) {
        const res = data.filter((key) => key.class == cls);
        return res;
    }
    async removeDuplicates(obj) {
        for (let i = 0; i < this.data.length; i++) {
            for (let j = 0; j < obj.length; j++) {
                if (this.data[i].class == obj[j].cls) {
                    if (this.data[i].superClass) {
                        this.tree.splice(j, 1);
                    }
                }
            }
        }
    }
    async getAllClasses(reqMeta) {
        try {
            let generated = this.enSparqlGenerator.getClasses({
                prefix: reqMeta.prefix,
                graph: reqMeta.prefix
            });

            let res = await this.sparqlQuery(generated.sparql);
            let treeJson;
            if (res.records) {
                this.data = res.records;
                treeJson = await this.generateTreeJson(res.records, []);
                this.tree = treeJson;
                await this.removeDuplicates(treeJson);
            }

            let status = 200;
            let message = 'Ok';
            let success = res.success;
            let records = this.tree;
            let count = this.tree.length;
            return {
                status,
                message,
                success,
                records,
                count
            };
        } catch (e) {
            return e;
        }
    }
    async getAllSubClasses(reqMeta) {
        try {
            let generated = this.enSparqlGenerator.getAllSubClasses({
                prefix: reqMeta.prefix,
                parent: reqMeta.parent
            });

            let res = await this.sparqlQuery(generated.sparql);

            let status = 200;
            let message = 'Ok';
            let success = res.success;
            let records = res.records;
            let count = res.records.length;

            return {
                status,
                message,
                success,
                records,
                count
            };
        } catch (e) {
            return e;
        }
    }
    async changeClassIRI(reqMeta) {
        try {
            let generated = this.enSparqlGenerator.changeClassIRI({
                cls: reqMeta.cls,
                newIRI: reqMeta.newIRI,
                parent: reqMeta.parent
            });

            let res = await this.sparqlUpdate(generated.sparql);

            let status = res.status;
            let message = res.message;
            let success = res.success;
            return {
                status,
                message,
                success
            };
        } catch (e) {
            return e;
        }
    }

    async getSpecificClassDetail(reqMeta) {
        try {
            let generated = this.enSparqlGenerator.getSpecificClassDetail({
                cls: reqMeta.cls,
                lang: reqMeta.lang,
                annotation: reqMeta.annotation
            });
            let res = await this.sparqlQuery(generated.sparql);

            let status = 200;
            let message = 'Ok';
            let success = true;
            let records = res.records.filter(
                (value) => Object.keys(value).length !== 0
            );
            return {
                status,
                message,
                success,
                records
            };
        } catch (e) {
            return e;
        }
    }
    async jsCodeGeneration(reqMeta) {
        try {
            let cache = await this.buildClassCacheForGenerators({
                classes: reqMeta.cls
            });
            let classKeys = cache.classes ? Object.keys(cache.classes) : [];
            let records = [];
            for (let classKey of classKeys) {
                let classSpec = cache.classes[classKey];
                classSpec.iri = classKey;
                records.push(classSpec);
            }
            reqMeta.cache = records;
            reqMeta.classes = reqMeta.cls;
            let classGenerator = new CodeGenerator(reqMeta);
            let res = await classGenerator.generator();
            let status = 200;
            let message = 'Ok';
            let success = true;
            let count = res.count;
            let javaScript = res.javaScript;
            return {
                status,
                message,
                success,
                count,
                javaScript
            };
        } catch (e) {
            return e;
        }
    }
    async swaggerJSONGeneration(reqMeta) {
        try {
            let cls = reqMeta.cls;
            let swaggerInfo = reqMeta.swaggerInfo;
            let classesData = await this.getAllClassesData({
                classes: cls,
                lang: reqMeta.lang,
                annotation: reqMeta.annotation
            });
            //reqMeta.classesData = classesData.records;
            let Generator = new SwaggerGenerator({
                cls: cls,
                swaggerInfo: swaggerInfo,
                classesData: classesData.records
            });
            let json = await Generator.createJson();
            let status = 200;
            let message = 'Ok';
            let success = true;
            let swaggerSpecificationJSON = eval('(' + json + ')');
            return {
                status,
                message,
                success,
                swaggerSpecificationJSON
            };
        } catch (e) {
            return e;
        }
    }
    async getAllProperties(reqMeta) {
        try {
            let generated = this.enSparqlGenerator.getAllProperties();
            let res = await this.sparqlQuery(generated.sparql);
            let status = 200;
            let message = 'Ok';
            let success = true;
            let records = res.records;
            return {
                status,
                message,
                success,
                records
            };
        } catch (e) {
            return e;
        }
    }
    async createProperty(reqMeta) {
        try {
            let generated = this.enSparqlGenerator.createProperty({
                prop: reqMeta.prop,
                parent: reqMeta.parentId || reqMeta.parent,
                label: reqMeta.label,
                comment: reqMeta.comment,
                propertyType: reqMeta.propertyType
            });

            let res = await this.sparqlUpdate(generated.sparql);
            let status = res.status;
            let message = res.message;
            let success = res.success;

            return {
                status,
                message,
                success
            };
        } catch (e) {
            return e;
        }
    }
    async getDataProperties(reqMeta) {
        try {
            let generated = this.enSparqlGenerator.getDataProperties(reqMeta);

            let res = await this.sparqlQuery(generated.sparql);
            let status = 200;
            let message = 'ok';
            let success = true;
            let records = res.records;
            let count = res.records.length;

            return {
                status,
                message,
                success,
                records,
                count
            };
        } catch (e) {
            return e;
        }
    }
    async getObjectProperties(reqMeta) {
        try {
            let generated = this.enSparqlGenerator.getObjectProperties(reqMeta);
            let res = await this.sparqlQuery(generated.sparql);
            let status = 200;
            let message = 'ok';
            let success = true;
            let records = res.records;
            let count = res.records.length;

            return {
                status,
                message,
                success,
                records,
                count
            };
        } catch (e) {
            return e;
        }
    }
    async updatePropertyIRI(reqMeta) {
        try {
            let generated = this.enSparqlGenerator.changePropertyIRI(reqMeta);
            let res = await this.sparqlUpdate(generated.sparql);
            let status = res.status;
            let message = res.message;
            let success = res.success;

            return {
                status,
                message,
                success
            };
        } catch (e) {
            return e;
        }
    }
    async deletePropertyFromRestriction(reqMeta) {
        try {
            let generated =
                this.enSparqlGenerator.deletePropertyFromClassRestrictions(
                    reqMeta
                );
            let res = await this.sparqlUpdate(generated.sparql);
            let status = res.status;
            let message = res.message;
            let success = res.success;

            return {
                status,
                message,
                success
            };
        } catch (e) {
            return e;
        }
    }
    async deletePropertyFromIndividuals(reqMeta) {
        try {
            let generated =
                this.enSparqlGenerator.deletePropertyFromIndividuals(reqMeta);
            let res = await this.sparqlUpdate(generated.sparql);
            let status = res.status;
            let message = res.message;
            let success = res.success;

            return {
                status,
                message,
                success
            };
        } catch (e) {
            return e;
        }
    }
    async deletePropertyFromIndividuals(reqMeta) {
        try {
            let generated =
                this.enSparqlGenerator.deletePropertyFromIndividuals(reqMeta);
            let res = await this.sparqlUpdate(generated.sparql);
            let status = res.status;
            let message = res.message;
            let success = res.success;

            return {
                status,
                message,
                success
            };
        } catch (e) {
            return e;
        }
    }
    async deleteProperty(reqMeta) {
        try {
            let generated = this.enSparqlGenerator.deleteProperty(reqMeta);
            let res = await this.sparqlUpdate(generated.sparql);
            let status = res.status;
            let message = res.message;
            let success = res.success;

            return {
                status,
                message,
                success
            };
        } catch (e) {
            return e;
        }
    }
    async getAllClassesData(reqMeta) {
        try {
            let classes = [];
            if (!Array.isArray(reqMeta.classes)) {
                classes.push(reqMeta.classes);
            }
            let data = await this.getEachClassData(
                classes,
                reqMeta.lang,
                reqMeta.annotation
            );
            let status = 200;
            let message = 'Ok';
            let success = true;
            let records = data;
            return {
                status,
                message,
                success,
                records
            };
        } catch (e) {
            status = 400;
            message = 'No';
            success = false;
            records = [];
        }
    }
    async getEachClassData(classes, lang, annotation) {
        try {
            lang = lang || 'en';
            let classesDetail = [];
            for (let i = 0; i < classes.length; i++) {
                let exampleIndividuals = await this.read({
                    cls: `${classes[i]}Example`
                });
                let classDetails = await this.getSpecificClassDetail({
                    cls: classes[i],
                    lang: lang,
                    annotation: annotation
                });
                let classProperties =
                    await this.getClassPropertiesByDomainAndRestrictions({
                        cls: classes[i]
                    });
                // let cls = classes[i];
                classesDetail.push({
                    exampleData: exampleIndividuals.records,
                    classInfo: classDetails.records,
                    propertyInfo: classProperties.records,
                    cls: classes[i]
                });
            }
            return classesDetail;
        } catch (e) {
            console.log(e);
        }
    }
    async getAllNestedSubClasses(reqMeta) {
        try {
            let generated = this.enSparqlGenerator.getAllNestedSubClasses({
                prefix: reqMeta.prefix,
                parent: reqMeta.parent
            });

            let res = await this.sparqlQuery(generated.sparql);

            let status = 200;
            let message = 'Ok';
            let success = res.success;
            let records = res.records;
            let count = res.records.length;

            return {
                status,
                message,
                success,
                records,
                count
            };
        } catch (e) {
            return e;
        }
    }
    async getNestedParentClass(reqMeta) {
        try {
            // get sub class data from the API
            let cls = reqMeta.cls;

            let res = await this.sparqlQuery(`select ?parentClass
        where{
         <${cls}> rdfs:subClassOf     ?parentClass.
     filter(!isBlank(?parentClass))
            }`);

            // now we need to convert the sparql result into an API result
            let status = 200;
            let message = 'Ok';
            let success = true;
            let count = res.records.length;
            let total = res.records.length;
            let offset = 0;
            let limit = 0;
            let records = res.records;

            return {
                status,
                message,
                success,
                count,
                total,
                offset,
                limit,
                records
            };
        } catch (err) {
            return err;
        }
    }
    async getEquivalentClasses(reqMeta) {
        try {
            let generated = this.enSparqlGenerator.getEquivalentClasses({
                prefix: reqMeta.prefix,
                parent: reqMeta.parent
            });

            let res = await this.sparqlQuery(generated.sparql);

            let status = 200;
            let message = 'Ok';
            let success = res.success;
            let records = res.records;
            let count = res.records.length;

            return {
                status,
                message,
                success,
                records,
                count
            };
        } catch (e) {
            return e;
        }
    }
    async executeTemplate(reqMeta) {
        try {
            let template = reqMeta.template;
            let params = reqMeta.variables;
            let record;
            let options = {
                cls: 'http://ont.enapso.com/views#SPARQLTemplate',
                relation: 'parent2ChildInstanceRelation',
                filter: [
                    {
                        key: '$sparql',
                        value: `regEx(str(?ind), \"${template}\", \"i\")`
                    }
                ]
            };
            let config = await this.read(options);
            record = config.records;
            let temp, variables;
            let status, message, success, records, count;
            if (record.length) {
                const result = record.filter((item) => item.iri == template);
                variables = record.filter((item) => item.parentIRI == template);
                temp = result[0].template;
                let query = this.assembleSPARQLquery(temp, variables, params);
                if (query.includes('${')) {
                    status = 500;
                    message = 'variable is not defined in the SPARQL template';
                    success = false;
                } else {
                    query = eval(query);
                    // console.log(query);
                    let res;
                    if (query.includes('select')) {
                        res = await this.sparqlQuery(query);
                        records = res.records;
                        count = res.records.length;
                    } else {
                        res = await this.sparqlUpdate(query);
                    }
                    status = 200;
                    message = 'Ok';
                    success = res.success;
                }
            } else {
                status = 404;
                message = `no SPARQL template found against ${template}`;
                success = false;
            }

            return {
                status,
                message,
                success,
                records,
                count
            };
        } catch (e) {
            return e;
        }
    }
    assembleSPARQLquery(template, variables, iterator) {
        for (const key in iterator) {
            for (const item of variables) {
                if (item.templateVariableName == key) {
                    let start = '${';
                    let end = '}';
                    let params = `${start}${key}${end}`;
                    let value = iterator[key];
                    if (typeof value == 'string') {
                        if (
                            value.includes('http:') ||
                            value.includes('https:')
                        ) {
                            value = `<${value}>`;
                        } else {
                            value = `${value}`;
                        }
                    }
                    template = template.split(params).join(value);
                }
            }
        }
        return template;
    }
    async getRecords(reqMeta, array, parent) {
        try {
            let context = reqMeta.context;
            let search = reqMeta.search;
            let criteria;
            let record = array || [];
            let tolerance_records = array || [];

            for (const item of search) {
                if (item.context) {
                    let re = await this.getRecords(item, record, item.context);

                    if (re.length) {
                        record = re;
                    } else {
                        return re;
                    }
                } else {
                    criteria = item.criteria || 'Default';
                    if (item.goalSpec) {
                        let tempOptions = {
                            template:
                                'http://ont.telekom.de/cia/sparql-template#SPARQLTemplate_733a42cc-1ed5-43c2-98cc-459143d9df38',
                            variables: {
                                context: context,
                                criteria: criteria
                            }
                        };
                        let response = await this.executeTemplate(tempOptions);
                        if (response.records.length > 1) {
                            return {
                                status: 500,
                                message:
                                    'More than one attribute specified in the knowledge graph',
                                success: false,
                                count: 0
                            };
                        } else if (response.records.length == 0) {
                            return {
                                status: 404,
                                message: `no criteria ${criteria} specific for context ${context}`,
                                success: false,
                                count: 0
                            };
                        } else {
                            let options = {
                                template:
                                    'http://ont.telekom.de/cia/sparql-template#SPARQLTemplate_48df67e7-2acd-4bdd-aa06-10ff943fbf3c',
                                variables: {
                                    goal: item.goal
                                }
                            };
                            let express = await this.executeTemplate(options);
                            if (express.records.length) {
                                if (!item.goalSpec.value) {
                                    return {
                                        status: 500,
                                        message: 'No value passed',
                                        success: false,
                                        count: 0
                                    };
                                } else {
                                    response.records[0].goalValue =
                                        item.goalSpec.value;
                                    response.records[0].expression =
                                        express.records[0].expression;
                                    response.records[0].goalType = item.goal;

                                    response.records[0].unitOfGoalValue =
                                        item.goalSpec.unit;

                                    if ('tolerance-absolute' in item) {
                                        Object.assign(response.records[0], {
                                            'tolerance-absolute':
                                                item['tolerance-absolute']
                                        });
                                    }

                                    if ('tolerance-percent' in item) {
                                        Object.assign(response.records[0], {
                                            'tolerance-percent':
                                                item['tolerance-percent']
                                        });
                                    }
                                    //    response.records[0].parent=parent;
                                    record = record.concat(response.records);
                                }
                            } else {
                                return {
                                    status: 404,
                                    message: 'No expression found',
                                    success: false,
                                    count: 0
                                };
                            }
                        }
                    } else {
                        let options = {
                            template:
                                'http://ont.telekom.de/cia/sparql-template#SPARQLTemplate_733a42cc-1ed5-43c2-98cc-459146d9df39',
                            variables: {
                                context: context,
                                term: item.goal || '',
                                criteria: criteria
                            }
                        };
                        let config = await this.executeTemplate(options);
                        if (!config.records.length) {
                            return {
                                status: 404,
                                message: `no criteria ${criteria} specific for context ${context}`,
                                success: false,
                                count: 0
                            };
                        }
                        // config.records[0].parent=parent;
                        record = record.concat(config.records);
                    }
                }
            }
            return record;
        } catch (err) {
            return err;
        }
    }
    async createSPARQLExpression(reqMeta) {
        try {
            let records = await this.getRecords(reqMeta, [], reqMeta.context);

            if (records.length) {
                let toleratedRecords = records.filter(
                    (record) =>
                        'tolerance-percent' in record ||
                        'tolerance-absolute' in record
                );

                let nonToleratedRecords = records.map((record) => {
                    let copy = Object.assign({}, record);
                    delete copy['tolerance-percent'];
                    delete copy['tolerance-absolute'];
                    return copy;
                });

                // console.log(toleratedRecords);
                let allRecords = await this.combineRecords(
                    toleratedRecords,
                    nonToleratedRecords,
                    reqMeta
                );

                return allRecords;
            } else {
                return records;
            }
        } catch (e) {
            return e;
        }
    }
    async findAttributeType(item) {
        let keyword = ``;
        let query = `select ?type where {
            <${item}> rdf:type ?type .
            filter(?type!=rdf:Property)
        }`;
        let res = await this.sparqlQuery(query);
        if (
            res.records[0].type !=
            'http://www.w3.org/2002/07/owl#DatatypeProperty'
        ) {
            keyword = '_value';
        }
        return keyword;
    }
    async createExpression(records) {
        let filterExpression = [];
        let orderExpression = [];
        let havingExpression = [];
        for (const item of records) {
            let operator;
            if (item.goalType == 'exists') {
                if (item.goalValue == true) {
                    operator = '>=';
                } else {
                    operator = '<';
                }
                havingExpression.push(
                    `COUNT(?${item.attribute}) ${operator} 1`
                );
            } else {
                let startBracket = '';
                let endBracket = '';
                let startBracket1 = '';
                let endBracket1 = '';
                let attribute = this.removeHasWord(
                    item.attribute,
                    item.context
                );
                let attributeKeyword = await this.findAttributeType(
                    item.attributeIRI
                );
                if (item.goalType == 'contains') {
                    startBracket = '(';
                    endBracket = ')';
                } else if (
                    item.goalType == 'matches' ||
                    item.goalType == 'matchesCaseInsensitive'
                ) {
                    if (!/^\d+$/.test(item.goalValue)) {
                        startBracket = 'LCASE(';
                        endBracket = ')';
                        startBracket1 = 'LCASE(';
                        endBracket1 = ')';
                    }
                }
                if (/^\d+$/.test(item.goalValue)) {
                    filterExpression.push(
                        `${startBracket1}?${attribute}${attributeKeyword}${endBracket1} ${item.expression} ${startBracket}${item.goalValue}${endBracket}`
                    );
                } else {
                    filterExpression.push(
                        `str(${startBracket1}?${attribute}${attributeKeyword}${endBracket1}) ${item.expression} ${startBracket}"${item.goalValue}"${endBracket}`
                    );
                }
                if (item.rankingValue) {
                    orderExpression.push(
                        `${item.rankingValue} (?${attribute}_value)`
                    );
                }
                if (item.unitOfGoalValue) {
                    let keyword = await this.findKeyword(item.unitOfGoalValue);
                    if (keyword == 'unit') {
                        filterExpression.push(
                            `str(?${attribute}_${keyword}) = "${item.unitOfGoalValue}"`
                        );
                    } else {
                        filterExpression.push(
                            `regEx(str(?${attribute}_${keyword}), "${item.unitOfGoalValue}", 'i')`
                        );
                    }
                }
            }
        }
        return { filterExpression, orderExpression, havingExpression };
    }
    async findKeyword(item) {
        let keyword = 'unit';
        let options = {
            template:
                'http://ont.telekom.de/cia/sparql-template#SPARQLTemplate_bb3bf1d7-1078-4c5b-87bf-184066df091d',
            variables: {
                symbol: item
            }
        };
        let config = await this.executeTemplate(options);
        if (config.records.length) {
            keyword = 'symbol';
        }
        return keyword;
    }
    convertFirstLetterToLowerCase(item) {
        return item.charAt(0).toLowerCase() + item.slice(1);
    }
    removeHasWord(item, parent) {
        {
            let itemWithoutHas = item.replace('has', '');
            let itemName = this.convertFirstLetterToLowerCase(itemWithoutHas);
            parent = this.convertFirstLetterToLowerCase(parent);
            itemName = `${parent}_${itemName}`;
            return itemName;
        }
    }
    async assemblingExpression(expressionArray) {
        let orderArray = expressionArray.orderExpression;
        let filterArray = expressionArray.filterExpression;
        let havingArray = expressionArray.havingExpression;
        let orderStatement = '';
        let filterStatement = '';
        let havingStatement = '';
        for (let i = 0; i < filterArray.length; i++) {
            let operator = '';
            if (i > 0) {
                operator = '&&';
            }
            filterStatement = `${filterStatement} ${operator} ${filterArray[i]}`;
        }
        for (let i = 0; i < havingArray.length; i++) {
            let operator = '';
            if (i > 0) {
                operator = '&&';
            }
            havingStatement = `${havingStatement} ${operator} ${havingArray[i]}`;
        }
        for (const item of orderArray) {
            orderStatement = `${orderStatement} ${item}`;
        }
        if (filterStatement != '') {
            filterStatement = `filter(${filterStatement})`;
        }
        if (orderStatement != '') {
            orderStatement = `order by ${orderStatement}`;
        }
        if (havingStatement != '') {
            havingStatement = `having (${havingStatement})`;
        }
        return { orderStatement, filterStatement, havingStatement };
    }
    async combineExpressionWithTemplate(statements, context) {
        try {
            let res = await this.executeTemplate({
                template:
                    'http://ont.telekom.de/cia/sparql-template#SPARQLTemplate_3073bec8-3daa-41e2-b737-2dc22fc8466d'
            });
            const result = res.records.filter((item) => {
                return (
                    item.SPARQLTemplate.includes(context) &&
                    item.templateVariableNames ==
                        ' [ filterStatement, orderStatement, havingStatement ]'
                );
            });
            if (result.length) {
                return await this.executeTemplate({
                    template: result[0].iri,
                    variables: statements
                });
            } else {
                return {
                    message: 'no template found against that context',
                    status: 404,
                    success: false
                };
            }
        } catch (e) {
            return e;
        }
    }

    async getResults(records, reqMeta) {
        try {
            let expressions = await this.createExpression(records);
            let assembleExpression = await this.assemblingExpression(
                expressions
            );
            let res = await this.combineExpressionWithTemplate(
                assembleExpression,
                reqMeta.context
            );
            return res;
        } catch (e) {
            return e;
        }
    }

    async combineRecords(toleratedRecords, nonToleratedRecords, reqMeta) {
        try {
            let evaluatedToleratedRecords = await this.evaluateToleratedRecords(
                toleratedRecords
            );

            let tolRecords = await this.getResults(
                evaluatedToleratedRecords,
                reqMeta
            );

            let nonTolRecords = await this.getResults(
                nonToleratedRecords,
                reqMeta
            );

            if (!tolRecords.success) {
                return tolRecords;
            } else {
                const mergedRecords = [];

                const iris = new Set();

                for (const record of nonTolRecords.records) {
                    mergedRecords.push({ ...record, tolerated: false });
                    iris.add(record.iri);
                }

                for (const record of tolRecords.records) {
                    if (!iris.has(record.iri)) {
                        mergedRecords.push({ ...record, tolerated: true });
                    }
                }

                return {
                    status: 200,
                    success: true,
                    count: mergedRecords.length,
                    records: mergedRecords
                };

                mergedRecords;
            }
        } catch (e) {
            return e;
        }
    }

    async evaluateToleratedRecords(toleratedRecords) {
        try {
            for (const record of toleratedRecords) {
                let toleratedValue;

                if ('tolerance-absolute' in record) {
                    toleratedValue = record['tolerance-absolute'];
                } else if ('tolerance-percent' in record) {
                    toleratedValue =
                        (record.goalValue * record['tolerance-percent']) / 100;
                }

                if (record.goalType === 'maxValue') {
                    record.goalValue -= toleratedValue;
                } else if (record.goalType === 'minValue') {
                    record.goalValue += toleratedValue;
                }
            }

            return toleratedRecords;
        } catch (e) {
            return e;
        }
    }
}
module.exports = {
    EnapsoGraphDBAdapter
};