public async listRelated()

in source/packages/services/assetlibrary-export/src/data/common.full.dao.ts [38:132]


    public async listRelated(entityDbId: string, relationship: string, direction:string, template:string, filterRelatedBy:{ [key: string] : ModelAttributeValue}, offset:number, count:number, sort:SortKeys) : Promise<Node> {
        logger.debug(`common.full.dao listRelated: in: entityDbId:${entityDbId}, relationship:${relationship}, direction:${direction}, template:${template}, filterRelatedBy:${JSON.stringify(filterRelatedBy)}, offset:${offset}, count:${count}, ${JSON.stringify(sort)}`);

        // define the traversers that handle finding associated edges/vertices
        const relatedIn = __.inE();
        const relatedOut = __.outE();

        // filter the edges based on the relationship type (if requiested)
        if (relationship==='*') {
            relationship=undefined;
        }
        if (relationship) {
            [relatedIn, relatedOut].forEach(t=> t.hasLabel(relationship).as('e'));
        }

        // navigate to the linked vertex for each relation, filtering the type
        [relatedIn, relatedOut].forEach(t=> t.as('e').otherV().hasLabel(template).as('v'));

        // apply filtering to the linked vertex (if required)
        if (filterRelatedBy!==undefined) {
            Object.keys(filterRelatedBy).forEach(k=> {
                [relatedIn, relatedOut].forEach(t=> t.has(k, filterRelatedBy[k]));
            });
        }

        // return the info we need to understand about each relation
        [relatedIn, relatedOut].forEach(t=> t.valueMap().with_(process.withOptions.tokens).as('vProps'));
        relatedIn.constant('in').as('dir');
        relatedOut.constant('out').as('dir');
        [relatedIn, relatedOut].forEach(t=> t.select('dir','e','vProps'));

        // build the union traversal that combines the incoming and outgoing relations (depending on what was requested)
        let relatedUnion : process.GraphTraversal;
        if (direction==='in') {
            relatedUnion = relatedIn;
        } else if (direction==='out') {
            relatedUnion = relatedOut;
        } else {
           relatedUnion = __.union(relatedIn, relatedOut);
        }

        // apply sorting to the related (if requested)
        if (sort?.length>0) {
            relatedUnion.order();
            sort.forEach(s=> {
                const order = (s.direction==='ASC') ? process.order.asc : process.order.desc;
                // sort using an attribute from the connected vertices, with a failsafe incase the attribute is undefined
                relatedUnion.by(__.coalesce(__.select('v').values(s.field),__.constant('')), order);
            });
        }

        // apply pagination to the related (if requested)
        if (offset!==undefined && count!==undefined) {
            // note: workaround for weird typescript issue. even though offset/count are declared as numbers
            // throughout, they are being interpreted as strings within gremlin, therefore need to force to int beforehand
            const offsetAsInt = this.typeUtils.parseInt(offset);
            const countAsInt = this.typeUtils.parseInt(count);
            relatedUnion.range(offsetAsInt, offsetAsInt + countAsInt);
        }

        // build the main part of the query, unioning the related traversers with the main entity we want to return
        let results;
        const conn = super.getConnection();
        try {
            const traverser = conn.traversal.V(entityDbId).as('main')
                .union(
                    relatedUnion,
                    __.select('main').valueMap().with_(process.withOptions.tokens)
                );

            // execute and retrieve the results
            logger.debug(`common.full.dao listRelated: traverser: ${JSON.stringify(traverser.toString())}`);
            results = await traverser.toList();
            logger.debug(`common.full.dao listRelated: results: ${JSON.stringify(results)}`);
        } finally {
            await conn.close();
        }

        if (results===undefined || results.length===0) {
            logger.debug(`common.full.dao listRelated: exit: node: undefined`);
            return undefined;
        }

        // the result should contain a vertex representing the entity requested as 1 row, then all requested relations as other rows
        // find the main entity first
        const mainEntity = results.filter(r=> isVertexDto(r))[0] as VertexDto;
        const node = this.fullAssembler.assembleNode(mainEntity);

        const relatedEntities = results.filter(r=> isRelatedEntityDto(r)).map(r=> r as unknown as RelatedEntityDto);
        relatedEntities.forEach(r=> this.fullAssembler.assembleAssociation(node,r));

        logger.debug(`common.full.dao listRelated: exit: node: ${JSON.stringify(node)}`);
        return node;

    }