package com.buschmais.xo.neo4j.embedded.impl.datastore;
import static com.buschmais.xo.neo4j.spi.helper.MetadataHelper.getIndexedPropertyMetadata;
import java.util.Map;
import java.util.Set;
import org.neo4j.graphdb.GraphDatabaseService;
import org.neo4j.graphdb.Label;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.ResourceIterator;
import com.buschmais.xo.api.ResultIterator;
import com.buschmais.xo.api.XOException;
import com.buschmais.xo.neo4j.embedded.impl.model.EmbeddedLabel;
import com.buschmais.xo.neo4j.embedded.impl.model.EmbeddedNode;
import com.buschmais.xo.neo4j.spi.metadata.NodeMetadata;
import com.buschmais.xo.neo4j.spi.metadata.PropertyMetadata;
import com.buschmais.xo.spi.datastore.DatastoreEntityManager;
import com.buschmais.xo.spi.datastore.TypeMetadataSet;
import com.buschmais.xo.spi.metadata.method.PrimitivePropertyMethodMetadata;
import com.buschmais.xo.spi.metadata.type.EntityTypeMetadata;
/**
* Implementation of a
* {@link com.buschmais.xo.spi.datastore.DatastoreEntityManager} for Neo4j.
*/
public class Neo4jEntityManager extends AbstractNeo4jPropertyManager<EmbeddedNode>
implements DatastoreEntityManager<Long, EmbeddedNode, NodeMetadata<EmbeddedLabel>, EmbeddedLabel, PropertyMetadata> {
private final GraphDatabaseService graphDatabaseService;
public Neo4jEntityManager(GraphDatabaseService graphDatabaseService) {
this.graphDatabaseService = graphDatabaseService;
}
@Override
public boolean isEntity(Object o) {
return EmbeddedNode.class.isAssignableFrom(o.getClass());
}
@Override
public Set<EmbeddedLabel> getEntityDiscriminators(EmbeddedNode node) {
return node.getLabels();
}
@Override
public Long getEntityId(EmbeddedNode entity) {
return Long.valueOf(entity.getId());
}
@Override
public EmbeddedNode createEntity(TypeMetadataSet<EntityTypeMetadata<NodeMetadata<EmbeddedLabel>>> types, Set<EmbeddedLabel> discriminators,
Map<PrimitivePropertyMethodMetadata<PropertyMetadata>, Object> example) {
Label[] labels = new Label[discriminators.size()];
int i = 0;
for (EmbeddedLabel discriminator : discriminators) {
labels[i++] = discriminator.getDelegate();
}
EmbeddedNode node = new EmbeddedNode(graphDatabaseService.createNode(labels));
setProperties(node, example);
return node;
}
@Override
public void deleteEntity(EmbeddedNode entity) {
entity.delete();
}
@Override
public EmbeddedNode findEntityById(EntityTypeMetadata<NodeMetadata<EmbeddedLabel>> metadata, EmbeddedLabel label, Long id) {
return new EmbeddedNode(graphDatabaseService.getNodeById(id));
}
@Override
public ResultIterator<EmbeddedNode> findEntity(EntityTypeMetadata<NodeMetadata<EmbeddedLabel>> entityTypeMetadata, EmbeddedLabel discriminator,
Map<PrimitivePropertyMethodMetadata<PropertyMetadata>, Object> values) {
if (values.size() > 1) {
throw new XOException("Only one property value is supported for find operation");
}
Map.Entry<PrimitivePropertyMethodMetadata<PropertyMetadata>, Object> entry = values.entrySet().iterator().next();
Object value = entry.getValue();
PropertyMetadata propertyMetadata = getIndexedPropertyMetadata(entityTypeMetadata, entry.getKey());
ResourceIterator<Node> iterator = graphDatabaseService.findNodes(discriminator.getDelegate(), propertyMetadata.getName(), value);
return new ResultIterator<EmbeddedNode>() {
@Override
public boolean hasNext() {
return iterator.hasNext();
}
@Override
public EmbeddedNode next() {
return new EmbeddedNode(iterator.next());
}
@Override
public void remove() {
throw new XOException("Remove operation is not supported for find results.");
}
@Override
public void close() {
iterator.close();
}
};
}
@Override
public void addDiscriminators(TypeMetadataSet<EntityTypeMetadata<NodeMetadata<EmbeddedLabel>>> types, EmbeddedNode node, Set<EmbeddedLabel> labels) {
for (EmbeddedLabel label : labels) {
node.addLabel(label);
}
}
@Override
public void removeDiscriminators(TypeMetadataSet<EntityTypeMetadata<NodeMetadata<EmbeddedLabel>>> removedTypes, EmbeddedNode node, Set<EmbeddedLabel> labels) {
for (EmbeddedLabel label : labels) {
node.removeLabel(label);
}
}
@Override
public void clear(Iterable<EmbeddedNode> nodes) {
for (EmbeddedNode node : nodes) {
node.clear();
}
}
@Override
public void flush(Iterable<EmbeddedNode> nodes) {
for (EmbeddedNode node : nodes) {
node.flush();
}
}
}