huridocs/uwazi

View on GitHub
app/api/relationships.v2/model/specs/RelationshipDeterminingQueries.spec.ts

Summary

Maintainability
A
0 mins
Test Coverage
import { MatchQueryNode } from '../MatchQueryNode';
import { TraversalQueryNode } from '../TraversalQueryNode';

describe('when checking if, given an entity, the query defines a relationship', () => {
  it('should be true if it is a 1 hop, 1 relationship type query', () => {
    const query = new MatchQueryNode({}, [
      new TraversalQueryNode('out', { types: ['type1'] }, [new MatchQueryNode({})]),
    ]);

    expect(query.determinesRelationships()).toEqual([]);
  });

  it('should be false if any branch is longer than 1', () => {
    const query = new MatchQueryNode({}, [
      new TraversalQueryNode('out', { types: ['type1'] }, [new MatchQueryNode({})]),
      new TraversalQueryNode('out', { types: ['type2'] }, [
        new MatchQueryNode({}, [
          new TraversalQueryNode('out', { types: ['type1'] }, [new MatchQueryNode({})]),
        ]),
      ]),
    ]);

    expect(query.determinesRelationships()).toEqual(false);
  });

  it('should be false if not every branch has only one relationship type', () => {
    const query = new MatchQueryNode({}, [
      new TraversalQueryNode('out', { types: ['type1'] }, [new MatchQueryNode({})]),
      new TraversalQueryNode('out', { types: ['type2', 'type3'] }, [new MatchQueryNode({})]),
    ]);

    expect(query.determinesRelationships()).toBe(false);
  });

  it('should be false if a template appears in 2 or more branches', () => {
    const query = new MatchQueryNode({}, [
      new TraversalQueryNode('out', { types: ['type1'] }, [
        new MatchQueryNode({ templates: ['template1'] }),
      ]),
      new TraversalQueryNode('out', { types: ['type2'] }, [
        new MatchQueryNode({ templates: ['template1'] }),
      ]),
    ]);

    expect(query.determinesRelationships()).toBe(false);
  });

  it('should be false if "all templates" is used and there are more than one branches', () => {
    const query = new MatchQueryNode({}, [
      new TraversalQueryNode('out', { types: ['type1'] }, [new MatchQueryNode()]),
      new TraversalQueryNode('out', { types: ['type2'] }, [
        new MatchQueryNode({ templates: ['template1'] }),
      ]),
    ]);

    expect(query.determinesRelationships()).toBe(false);
  });

  it('should be true if it is 1 hop, 1 rel type per branch and templates appear once', () => {
    const query1 = new MatchQueryNode({}, [
      new TraversalQueryNode('out', { types: ['type1'] }, [
        new MatchQueryNode({ templates: ['template1'] }),
      ]),
      new TraversalQueryNode('out', { types: ['type2'] }, [
        new MatchQueryNode({ templates: ['template2'] }),
      ]),
    ]);

    const query2 = new MatchQueryNode({}, [
      new TraversalQueryNode('out', { types: ['type1'] }, [new MatchQueryNode()]),
    ]);

    expect(query1.determinesRelationships()).toEqual(['template1', 'template2']);
    expect(query2.determinesRelationships()).toEqual([]);
  });
});

describe('when determining a relationship', () => {
  const entity = { sharedId: 'sharedId', template: 'template4' };
  const rootEntity = { sharedId: 'shared1', template: 'some template' };

  it('should validate that the query is rooted in an entity', () => {
    const nonRootedQuery = new MatchQueryNode({}, [
      new TraversalQueryNode('out', { types: ['type1'] }, [
        new MatchQueryNode({ templates: ['template1', 'template2'] }),
      ]),
      new TraversalQueryNode('in', { types: ['type2'] }, [
        new MatchQueryNode({ templates: ['template3', 'template4'] }),
      ]),
    ]);

    const rootedQuery = new MatchQueryNode({ sharedId: 'someSharedId' }, [
      new TraversalQueryNode('out', { types: ['type1'] }, [
        new MatchQueryNode({ templates: ['template1', 'template2'] }),
      ]),
      new TraversalQueryNode('in', { types: ['type2'] }, [
        new MatchQueryNode({ templates: ['template3', 'template4'] }),
      ]),
    ]);

    expect(() => nonRootedQuery.determineRelationship(entity)).toThrow();
    expect(() => rootedQuery.determineRelationship(entity)).not.toThrow();
  });

  it('should validate that the entity is matched by one of the match nodes', () => {
    const query = new MatchQueryNode({ sharedId: rootEntity.sharedId }, [
      new TraversalQueryNode('out', { types: ['type1'] }, [
        new MatchQueryNode({ templates: ['template1', 'template2'] }),
      ]),
      new TraversalQueryNode('out', { types: ['type2'] }, [
        new MatchQueryNode({ templates: ['template3'] }),
      ]),
    ]);

    expect(() => query.determineRelationship(entity)).toThrow();
  });

  it('should return the correct relationship', () => {
    const query = new MatchQueryNode({ sharedId: rootEntity.sharedId }, [
      new TraversalQueryNode('out', { types: ['type1'] }, [
        new MatchQueryNode({ templates: ['template1', 'template2'] }),
      ]),
      new TraversalQueryNode('in', { types: ['type2'] }, [
        new MatchQueryNode({ templates: ['template3', 'template4'] }),
      ]),
    ]);

    expect(query.determineRelationship(entity)).toEqual({
      type: 'type2',
      from: entity.sharedId,
      to: 'shared1',
    });
  });
});

describe('when calculating the depth of a query', () => {
  it('shuold return 0 for a single node', () => {
    const query = new MatchQueryNode({});
    expect(query.getDepth()).toBe(0);
  });

  it('should return the max depth of the tree', () => {
    const query = new MatchQueryNode({}, [
      new TraversalQueryNode('out', {}, [new MatchQueryNode({})]),
      new TraversalQueryNode('out', {}, [
        new MatchQueryNode({}, [new TraversalQueryNode('out', {}, [new MatchQueryNode({})])]),
      ]),
    ]);

    expect(query.getDepth()).toBe(4);
  });
});