Skip to content
This repository was archived by the owner on Apr 16, 2022. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,11 @@ public class Constants {
public static final String PROPERTY_LABEL = "label";
public static final String PROPERTY_TYPE = "type";
public static final String PROPERTY_VALUE = "value";
public static final String PROPERTY_VALUE_WITH_AT = "@value";
public static final String PROPERTY_PROPERTIES = "properties";
public static final String PROPERTY_INV = "inV";
public static final String PROPERTY_OUTV = "outV";
public static final String PROPERTY_RELATION_ID = "relationId";

public static final String RESULT_TYPE_VERTEX = "vertex";
public static final String RESULT_TYPE_EDGE = "edge";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,40 @@
import java.util.LinkedHashMap;
import java.util.Map;

import static com.microsoft.spring.data.gremlin.common.Constants.PROPERTY_VALUE_WITH_AT;

@NoArgsConstructor
// TODO: seems only for Vertex.
public abstract class AbstractGremlinResultReader {

/**
* Vertex's properties returned from gremlin-driver has a complicated data structure
* This function helps to renovate it to a simple Map
* @return Map of list properties
*/
protected Map<String, Object> getProperties (@NonNull Map<String, Object> map) {
Map<String, Object> propertyMap = map;
while ((propertyMap instanceof LinkedHashMap) && propertyMap.containsKey(PROPERTY_VALUE_WITH_AT)) {
final Object value = propertyMap.get(PROPERTY_VALUE_WITH_AT);
if (value instanceof ArrayList && ((ArrayList) value).size() > 0) {
propertyMap = (Map<String, Object>) ((ArrayList) value).get(0);
} else {
propertyMap = (Map<String, Object>) value;
}
}

return propertyMap;
}

protected Object getPropertyValue (@NonNull Map<String, Object> map, @NonNull String propertyKey) {
Object value = map.get(propertyKey);

while ((value instanceof LinkedHashMap) && ((LinkedHashMap) value).containsKey(PROPERTY_VALUE_WITH_AT)) {
value = ((LinkedHashMap) value).get(PROPERTY_VALUE_WITH_AT);
}

return value;
}

/**
* properties's organization is a little complicated.
* <p>
Expand All @@ -28,14 +58,18 @@ public abstract class AbstractGremlinResultReader {
* T is LinkedHashMap<String, String>
*/
private Object readProperty(@NonNull Object value) {
Assert.isInstanceOf(ArrayList.class, value, "should be instance of ArrayList");
if (value instanceof ArrayList) {
@SuppressWarnings("unchecked") final ArrayList<LinkedHashMap<String, Object>> mapList
= (ArrayList<LinkedHashMap<String, Object>>) value;

Assert.isTrue(mapList.size() == 1, "should be only 1 element in ArrayList");

@SuppressWarnings("unchecked") final ArrayList<LinkedHashMap<String, String>> mapList
= (ArrayList<LinkedHashMap<String, String>>) value;
value = mapList.get(0);
}

Assert.isTrue(mapList.size() == 1, "should be only 1 element in ArrayList");
final Map<String, Object> renovatedMap = getProperties((Map<String, Object>) value);

return mapList.get(0).get(Constants.PROPERTY_VALUE);
return renovatedMap.get(Constants.PROPERTY_VALUE);
}

protected void readResultProperties(@NonNull Map<String, Object> properties, @NonNull GremlinSource source) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@
import com.microsoft.spring.data.gremlin.conversion.source.GremlinSourceEdge;
import com.microsoft.spring.data.gremlin.exception.GremlinUnexpectedSourceTypeException;
import lombok.NoArgsConstructor;
import lombok.NonNull;
import org.apache.tinkerpop.gremlin.driver.Result;
import org.springframework.lang.Nullable;
import org.springframework.lang.NonNull;
import org.springframework.util.Assert;

import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

Expand All @@ -23,31 +23,38 @@
@NoArgsConstructor
public class GremlinResultEdgeReader extends AbstractGremlinResultReader implements GremlinResultsReader {

private void readProperties(@NonNull GremlinSource source, @Nullable Map map) {
if (map != null) {
@SuppressWarnings("unchecked") final Map<String, Object> properties = (Map<String, Object>) map;

properties.forEach(source::setProperty);
}
}

private void validate(List<Result> results, GremlinSource source) {
Assert.notNull(results, "Results should not be null.");
Assert.notNull(source, "GremlinSource should not be null.");
Assert.isTrue(results.size() == 1, "Edge should contain only one result.");
}

final Result result = results.get(0);

private Map<String, Object> getEdgeProperties (@NonNull Result result) {
Assert.isInstanceOf(Map.class, result.getObject(), "should be one instance of Map");

@SuppressWarnings("unchecked") final Map<String, Object> map = (Map<String, Object>) result.getObject();
Map<String, Object> map = (Map<String, Object>) result.getObject();

map = getProperties(map);

Assert.isTrue(map.containsKey(PROPERTY_ID), "should contain id property");
Assert.isTrue(map.containsKey(PROPERTY_LABEL), "should contain label property");
Assert.isTrue(map.containsKey(PROPERTY_TYPE), "should contain type property");
// Assert.isTrue(map.containsKey(PROPERTY_TYPE), "should contain type property");
Assert.isTrue(map.containsKey(PROPERTY_INV), "should contain inV property");
Assert.isTrue(map.containsKey(PROPERTY_OUTV), "should contain outV property");
Assert.isTrue(map.get(PROPERTY_TYPE).equals(RESULT_TYPE_EDGE), "must be vertex type");
// Assert.isTrue(map.get(PROPERTY_TYPE).equals(RESULT_TYPE_EDGE), "must be vertex type");

return map;
}

@Override
protected Object getPropertyValue (@NonNull Map<String, Object> map, @NonNull String propertyKey) {
Object value = super.getPropertyValue(map, propertyKey);

if (value instanceof LinkedHashMap && ((LinkedHashMap) value).containsKey(PROPERTY_RELATION_ID)) {
value = ((LinkedHashMap) value).get(PROPERTY_RELATION_ID);
}

return value;
}

@Override
Expand All @@ -60,16 +67,16 @@ public void read(@NonNull List<Result> results, @NonNull GremlinSource source) {
validate(results, source);

final GremlinSourceEdge sourceEdge = (GremlinSourceEdge) source;
final Map<String, Object> map = (Map<String, Object>) results.get(0).getObject();
final Map<String, Object> map = getEdgeProperties(results.get(0));

this.readProperties(source, (Map) map.get(PROPERTY_PROPERTIES));
super.readResultProperties((Map) map.get(PROPERTY_PROPERTIES), source);

final String className = source.getProperties().get(GREMLIN_PROPERTY_CLASSNAME).toString();

sourceEdge.setIdField(GremlinUtils.getIdField(GremlinUtils.toEntityClass(className)));
sourceEdge.setId(map.get(PROPERTY_ID));
sourceEdge.setLabel(map.get(PROPERTY_LABEL).toString());
sourceEdge.setVertexIdFrom(map.get(PROPERTY_OUTV));
sourceEdge.setVertexIdTo(map.get(PROPERTY_INV));
sourceEdge.setId(getPropertyValue(map, PROPERTY_ID));
sourceEdge.setLabel(getPropertyValue(map, PROPERTY_LABEL).toString());
sourceEdge.setVertexIdFrom(getPropertyValue(map, PROPERTY_OUTV));
sourceEdge.setVertexIdTo(getPropertyValue(map, PROPERTY_INV));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,20 +26,23 @@ private void validate(List<Result> results, GremlinSource source) {
Assert.notNull(results, "Results should not be null.");
Assert.notNull(source, "GremlinSource should not be null.");
Assert.isTrue(results.size() == 1, "Vertex should contain only one result.");
}

final Result result = results.get(0);

private Map<String, Object> getVertexProperties (@NonNull Result result) {
Assert.isInstanceOf(Map.class, result.getObject(), "should be one instance of Map");

@SuppressWarnings("unchecked") final Map<String, Object> map = (Map<String, Object>) result.getObject();
Map<String, Object> map = (Map<String, Object>) result.getObject();

map = getProperties(map);

Assert.isTrue(map.containsKey(PROPERTY_ID), "should contain id property");
Assert.isTrue(map.containsKey(PROPERTY_LABEL), "should contain label property");
Assert.isTrue(map.containsKey(PROPERTY_TYPE), "should contain type property");
// Assert.isTrue(map.containsKey(PROPERTY_TYPE), "should contain type property");
Assert.isTrue(map.containsKey(PROPERTY_PROPERTIES), "should contain properties property");
Assert.isTrue(map.get(PROPERTY_TYPE).equals(RESULT_TYPE_VERTEX), "must be vertex type");

// Assert.isTrue(map.get(PROPERTY_TYPE).equals(RESULT_TYPE_VERTEX), "must be vertex type");
Assert.isInstanceOf(Map.class, map.get(PROPERTY_PROPERTIES), "should be one instance of Map");

return map;
}

@Override
Expand All @@ -51,15 +54,15 @@ public void read(@NonNull List<Result> results, @NonNull GremlinSource source) {

validate(results, source);

final Map<String, Object> map = (Map<String, Object>) results.get(0).getObject();
final Map<String, Object> map = getVertexProperties(results.get(0));
final Map<String, Object> properties = (Map<String, Object>) map.get(PROPERTY_PROPERTIES);

super.readResultProperties(properties, source);

final String className = source.getProperties().get(GREMLIN_PROPERTY_CLASSNAME).toString();

source.setIdField(GremlinUtils.getIdField(GremlinUtils.toEntityClass(className)));
source.setId(map.get(PROPERTY_ID));
source.setLabel(map.get(PROPERTY_LABEL).toString());
source.setId(getPropertyValue(map, PROPERTY_ID));
source.setLabel(getPropertyValue(map, PROPERTY_LABEL).toString());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,5 +49,7 @@ public interface GremlinOperations {

<T> List<T> find(GremlinQuery query, GremlinSource<T> source);

<T> List<T> findByQuery(List<String> queries, GremlinSource<T> source);

MappingGremlinConverter getMappingConverter();
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import com.microsoft.spring.data.gremlin.annotation.EdgeFrom;
import com.microsoft.spring.data.gremlin.annotation.EdgeTo;
import com.microsoft.spring.data.gremlin.annotation.GeneratedValue;
import com.microsoft.spring.data.gremlin.common.Constants;
import com.microsoft.spring.data.gremlin.common.GremlinEntityType;
import com.microsoft.spring.data.gremlin.common.GremlinFactory;
import com.microsoft.spring.data.gremlin.common.GremlinUtils;
Expand Down Expand Up @@ -41,9 +42,7 @@

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.*;
import java.util.concurrent.ExecutionException;

import static java.util.stream.Collectors.toList;
Expand Down Expand Up @@ -94,13 +93,31 @@ private List<Result> executeQuery(@NonNull List<String> queries) {
private List<Result> executeQueryParallel(@NonNull List<String> queries) {
return queries.parallelStream()
.map(q -> getGremlinClient().submit(q).all())
.collect(toList()).parallelStream().flatMap(f -> {
.collect(toList())
.parallelStream()
.flatMap(f -> {
try {
return f.get().stream();
} catch (InterruptedException | ExecutionException e) {
throw new GremlinQueryException("unable to complete query from gremlin", e);
}
})
.flatMap(r -> {
final List<Result> results = new ArrayList<>();
Object object = r.getObject();
while (object instanceof LinkedHashMap
&& ((LinkedHashMap) object).containsKey(Constants.PROPERTY_VALUE_WITH_AT)) {
object = ((LinkedHashMap) object).get(Constants.PROPERTY_VALUE_WITH_AT);
}

if (object instanceof ArrayList) {
((ArrayList) object).forEach(o -> results.add(new Result(o)));
} else {
results.add(new Result(object));
}

return results.stream();
})
.collect(toList());
}

Expand Down Expand Up @@ -349,7 +366,10 @@ private <T> T recoverDomain(@NonNull GremlinSource<T> source, @NonNull List<Resu
}

private <T> List<T> recoverDomainList(@NonNull GremlinSource<T> source, @NonNull List<Result> results) {
return results.stream().map(r -> recoverDomain(source, Collections.singletonList(r))).collect(toList());
return results
.stream()
.map(r -> recoverDomain(source, Collections.singletonList(r)))
.collect(toList());
}

private <T> T recoverGraphDomain(@NonNull GremlinSourceGraph<T> source, @NonNull List<Result> results) {
Expand Down Expand Up @@ -382,5 +402,16 @@ public <T> List<T> find(@NonNull GremlinQuery query, @NonNull GremlinSource<T> s

return this.recoverDomainList(source, results);
}

@Override
public <T> List<T> findByQuery(@NonNull List<String> queryList, @NonNull GremlinSource<T> source) {
final List<Result> results = this.executeQuery(queryList);

if (results.isEmpty()) {
return Collections.emptyList();
}

return this.recoverDomainList(source, results);
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,15 @@
import org.springframework.data.repository.NoRepositoryBean;

import java.io.Serializable;
import java.util.List;

@NoRepositoryBean
public interface GremlinRepository<T, ID extends Serializable> extends CrudRepository<T, ID> {

Iterable<T> findAll(Class<T> domainClass);

Iterable<T> findAllByQuery(List<String> queryList);

void deleteAll(GremlinEntityType type);

void deleteAll(Class<T> domainClass);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,5 +133,9 @@ public void deleteAll(@NonNull Class<T> domainClass) {
public boolean existsById(@NonNull ID id) {
return this.operations.existsById(id, this.information.createGremlinSource());
}

public Iterable<T> findAllByQuery(@NonNull List<String> queries) {
return this.operations.findByQuery(queries, this.information.createGremlinSource());
}
}