Skip to content

Commit

Permalink
OGM-783 [Neo4j] Create DSL to assert the mapping in tests
Browse files Browse the repository at this point in the history
  • Loading branch information
DavideD committed May 15, 2015
1 parent b0aa8b4 commit 6518382
Show file tree
Hide file tree
Showing 3 changed files with 334 additions and 0 deletions.
@@ -0,0 +1,74 @@
/*
* Hibernate OGM, Domain model persistence for NoSQL datastores
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.ogm.datastore.neo4j.test.dsl;

import static org.fest.assertions.Assertions.assertThat;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import org.fest.assertions.Fail;
import org.neo4j.cypher.javacompat.ExecutionEngine;
import org.neo4j.graphdb.PropertyContainer;
import org.neo4j.graphdb.ResourceIterator;

/**
* Assertion methods to check the mapping of nodes and relationships in Neo4j.
*
* @author Davide D'Alto
*/
public class GraphAssertions {

public static NodeForGraphAssertions node(String alias, String... labels) {
return new NodeForGraphAssertions( alias, labels);
}

public static void assertThatExists(ExecutionEngine engine, NodeForGraphAssertions node) throws Exception {
String nodeAsCypher = node.toCypher();
String query = "MATCH " + nodeAsCypher + " RETURN " + node.getAlias();
ResourceIterator<Object> columnAs = engine.execute( query, node.getParams() ).columnAs( node.getAlias() );
assertThat( columnAs.hasNext() ).as( "Node [" + node.getAlias() + "] not found, Looked for " + nodeAsCypher + " with parameters: " + node.getParams() ).isTrue();

PropertyContainer propertyContainer = (PropertyContainer) columnAs.next();
Iterable<String> propertyKeys = propertyContainer.getPropertyKeys();
List<String> unexpectedProperties = new ArrayList<String>();
Set<String> expectedProperties = node.getProperties().keySet();
for ( Iterator<String> iterator = propertyKeys.iterator(); iterator.hasNext(); ) {
String actual = iterator.next();
if ( !expectedProperties.contains( actual ) ) {
unexpectedProperties.add( actual );
}
}
List<String> missingProperties = new ArrayList<String>();
if ( expectedProperties != null ) {
for ( String expected : expectedProperties ) {
if ( !propertyContainer.hasProperty( expected ) ) {
missingProperties.add( expected );
}
}
}
assertThat( unexpectedProperties ).as( "Unexpected properties for node [" + node.getAlias() + "]" ).isEmpty();
assertThat( missingProperties ).as( "Missing properties for node [" + node.getAlias() + "]" ).isEmpty();
if ( columnAs.hasNext() ) {
Fail.fail( "Unexpected result returned: " + columnAs.next() );
}
}

public static void assertThatExists(ExecutionEngine engine, RelationshipsChainForGraphAssertions relationship) throws Exception {
String relationshipAsCypher = relationship.toCypher();
NodeForGraphAssertions node = relationship.getStart();
String query = "MATCH " + relationshipAsCypher + " RETURN " + node.getAlias();
ResourceIterator<Object> columnAs = engine.execute( query, relationship.getParams() ).columnAs( node.getAlias() );
assertThat( columnAs.hasNext() ).as( "Relationships not found, Looked for " + relationshipAsCypher + " with parameters: " + relationship.getParams() ).isTrue();
columnAs.next();
if ( columnAs.hasNext() ) {
Fail.fail( "Unexpected result returned: " + columnAs.next() );
}
}
}
@@ -0,0 +1,102 @@
/*
* Hibernate OGM, Domain model persistence for NoSQL datastores
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.ogm.datastore.neo4j.test.dsl;

import static org.hibernate.ogm.datastore.neo4j.query.parsing.cypherdsl.impl.CypherDSL.escapeIdentifier;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

/**
* /**
* A DSL to define a node like the following:
* <p>
* <pre>
* (n:ENTITY:StoryGame {id: {n}.id})
* </pre>
*
* @author Davide D'Alto
*/
public class NodeForGraphAssertions {

private final String alias;
private final String[] labels;
private final Map<String, Object> properties = new HashMap<String, Object>();
private final Map<String, Object> params = new HashMap<String, Object>();

public NodeForGraphAssertions(String alias, String[] labels) {
this.alias = alias;
this.labels = labels;
this.params.put( alias, properties );
}

public NodeForGraphAssertions property(String property, Object value) {
properties.put( property, value );
return this;
}

public RelationshipsChainForGraphAssertions relationshipTo(NodeForGraphAssertions endNode, String relationshipType) {
Map<String, Object> emptyMap = Collections.emptyMap();
return relationshipTo( endNode, relationshipType, emptyMap );
}

public RelationshipsChainForGraphAssertions relationshipTo(NodeForGraphAssertions endNode, String relationshipType, Map<String, Object> properties) {
return new RelationshipsChainForGraphAssertions( this, endNode, relationshipType );
}

public String toCypher() {
StringBuilder builder = new StringBuilder();
builder.append( "(" );
builder.append( alias );
for ( String label : labels ) {
builder.append( ":" );
builder.append( label );
}
if ( !properties.isEmpty() ) {
builder.append( " {" );
int index = 0;
for ( String property : properties.keySet() ) {
escapeIdentifier( builder, property );
builder.append( ": " );
builder.append( "{" );
builder.append( alias );
builder.append( "}" );
builder.append( "." );
escapeIdentifier( builder, property );
index++;
if ( index < properties.size() ) {
builder.append( ", " );
}
}
builder.append( "}" );
}
builder.append( ")" );
return builder.toString();
}

/**
* The node alias.
*/
public String getAlias() {
return alias;
}

/**
* The map with the values for the parameters in the cypher representation of the node.
*/
public Map<String, Object> getParams() {
return Collections.unmodifiableMap( params );
}

/**
* Returns the properties for the node.
*/
public Map<String, Object> getProperties() {
return Collections.unmodifiableMap( properties );
}
}
@@ -0,0 +1,158 @@
/*
* Hibernate OGM, Domain model persistence for NoSQL datastores
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.ogm.datastore.neo4j.test.dsl;

import static org.hibernate.ogm.datastore.neo4j.query.parsing.cypherdsl.impl.CypherDSL.escapeIdentifier;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
* A DSL to define a chain of relationships like the following:
* <p>
* <pre>
* () -> [r1:type1 {property: {r1}.property}] -> () -[r2:type2]-> ()
* </pre>
*
* @author Davide D'Alto
*/
public class RelationshipsChainForGraphAssertions {

private final NodeForGraphAssertions start;
private final List<NextRelationship> stream = new ArrayList<NextRelationship>();
private final Map<String, Object> params = new HashMap<String, Object>();

public RelationshipsChainForGraphAssertions(NodeForGraphAssertions start, NodeForGraphAssertions end, String relationshipType) {
this.start = start;
this.params.put( start.getAlias(), start.getProperties() );
addToStream( end, relationshipType );
}

private void addToStream(NodeForGraphAssertions end, String relationshipType) {
stream.add( new NextRelationship( end, relationshipType, "r" + stream.size() ) );
params.put( end.getAlias(), end.getProperties() );
}

public RelationshipsChainForGraphAssertions relationshipTo(NodeForGraphAssertions next, String relationshipType) {
addToStream( next, relationshipType );
return this;
}

/**
* Get the starting node of the current chain of relationships.
*/
public NodeForGraphAssertions getStart() {
return start;
}

/**
* The map with the values for the parameters in the cypher representation of the current chain.
*/
public Map<String, Object> getParams() {
return params;
}

/**
* The number of relationships in the chain.
*/
public int getSize() {
return stream.size();
}

/**
* Define a property on the last relationship of the chain.
*/
public RelationshipsChainForGraphAssertions property(String name, Object value) {
NextRelationship relationship = stream.get( stream.size() - 1 );
@SuppressWarnings("unchecked")
Map<String, Object> properties = (Map<String, Object>) params.get( relationship.getAlias() );
if ( properties == null ) {
params.put( relationship.getAlias(), relationship.getProperties() );
}
relationship.addProperty( name, value );
return this;
}

/**
* Returns the cypher representation of the chain of relationships,
* <p>
* Example:
* <pre>
* (n1:ENTITY {id: {n1}.id}) -[r0:type0 {property: {r0}.property}]-> (n2:EMBEDDED {property: {n2}.property}) -[r1:type1]-> (n3:EMBEDDED)
* <pre>
*/
public String toCypher() {
StringBuilder builder = new StringBuilder();
builder.append( start.toCypher() );
for ( NextRelationship relationship : stream ) {
builder.append( " -[" );
if ( !relationship.getProperties().isEmpty() ) {
builder.append( relationship.getAlias() );
}
builder.append( ":" );
builder.append( relationship.getRelationshipType() );
if ( !relationship.getProperties().isEmpty() ) {
builder.append( " {" );
boolean first = true;
for ( String property : relationship.getProperties().keySet() ) {
if ( first ) {
first = false;
}
else {
builder.append( ", " );
}
escapeIdentifier( builder, property );
builder.append( ": {" );
builder.append( relationship.getAlias() );
builder.append( "}." );
escapeIdentifier( builder, property );
}
builder.append( " }" );
}
builder.append( "]-> " );
builder.append( relationship.getEnd().toCypher() );
}
return builder.toString();
}

private static class NextRelationship {

private final NodeForGraphAssertions end;
private final String relationshipType;
private final Map<String, Object> properties = new HashMap<String, Object>();
private final String alias;

public NextRelationship(NodeForGraphAssertions to, String relationshipType, String alias) {
this.end = to;
this.relationshipType = relationshipType;
this.alias = alias;
}

public String getAlias() {
return alias;
}

public Map<String, Object> getProperties() {
return properties;
}

public NodeForGraphAssertions getEnd() {
return end;
}

public String getRelationshipType() {
return relationshipType;
}

public void addProperty( String name, Object value ) {
properties.put( name, value );
}
}

}

0 comments on commit 6518382

Please sign in to comment.