diff --git a/src/main/java/com/arangodb/tinkerpop/gremlin/cache/VertexLoader.java b/src/main/java/com/arangodb/tinkerpop/gremlin/cache/VertexLoader.java index 83be689..c37d1f1 100644 --- a/src/main/java/com/arangodb/tinkerpop/gremlin/cache/VertexLoader.java +++ b/src/main/java/com/arangodb/tinkerpop/gremlin/cache/VertexLoader.java @@ -35,6 +35,4 @@ public Map loadAll(Iterable keys) { return result; } - - } \ No newline at end of file diff --git a/src/main/java/com/arangodb/tinkerpop/gremlin/client/ArangoDBPropertyFilter.java b/src/main/java/com/arangodb/tinkerpop/gremlin/client/ArangoDBPropertyFilter.java index ed205c1..d5d2526 100644 --- a/src/main/java/com/arangodb/tinkerpop/gremlin/client/ArangoDBPropertyFilter.java +++ b/src/main/java/com/arangodb/tinkerpop/gremlin/client/ArangoDBPropertyFilter.java @@ -19,7 +19,7 @@ /** * The ArangoDB property filter class constructs AQL segments for comparing a document property - * with a given value. + * with a given baseValue. * * @author Achim Brandt (http://www.triagens.de) * @author Johannes Gocke (http://www.triagens.de) @@ -103,12 +103,12 @@ public ArangoDBPropertyFilter has( } /** - * Constructs the the AQL segment for each property filter and adds the required name-value + * Constructs the the AQL segment for each property filter and adds the required name-baseValue * entries to the bind parameters map. * * @param prefix the iterator/variable to which the property filter will be applied * @param filterSegments the list to populate with the AQL segments - * @param bindVars the map to populate with the name-value bindings + * @param bindVars the map to populate with the name-baseValue bindings */ public void addAqlSegments( @@ -170,7 +170,7 @@ public void addAqlSegments( * * @param bindVars the bind vars * @param propertyName the property name - * @param value the value + * @param value the baseValue * @return the string */ @@ -213,7 +213,7 @@ private class PropertyContainer { public final String key; - /** The value. */ + /** The baseValue. */ public final Object value; @@ -225,7 +225,7 @@ private class PropertyContainer { * Instantiates a new property container. * * @param key the name - * @param value the value + * @param value the baseValue * @param compare the compare */ public PropertyContainer(final String key, final Object value, final Compare compare) { diff --git a/src/main/java/com/arangodb/tinkerpop/gremlin/client/ArngDatabaseClient.java b/src/main/java/com/arangodb/tinkerpop/gremlin/client/ArngDatabaseClient.java index 8c90a04..53925b9 100644 --- a/src/main/java/com/arangodb/tinkerpop/gremlin/client/ArngDatabaseClient.java +++ b/src/main/java/com/arangodb/tinkerpop/gremlin/client/ArngDatabaseClient.java @@ -269,7 +269,7 @@ public ArangoGraph createGraph( // * Get a document from the database. The method is generic so we it can be used to retrieve // * vertices, elementProperties or variables. // * -// * @param the value type +// * @param the baseValue type // * @param id the id of the document (should be a valid ArangoDB handle) // * @param docClass the returned document class // * @return the document @@ -419,7 +419,7 @@ public ArangoGraph createGraph( // /** // * Get an edge from the graph. // * -// * @param the value type +// * @param the baseValue type // * @param id the id (name) of the edge // * @param label the label from which the edge is retrieved // * @param edgeClass the edge's specialised class @@ -537,7 +537,7 @@ public ArangoGraph createGraph( // * @param document the document // * @param edgeLabelsFilter a list of edge types to follow // * @param direction a direction -// * @param propertyFilter filter the neighbours on the given property:value values +// * @param propertyFilter filter the neighbours on the given property:baseValue values // * @param resultType the result type // * @return ArangoDBBaseQuery the query object // */ @@ -571,7 +571,7 @@ public ArangoGraph createGraph( // * @param the generic type // * @param document the document // * @param edgeLabelsFilter a list of edge types to follow -// * @param propertyFilter Filter the neighbours on the given property:value values +// * @param propertyFilter Filter the neighbours on the given property:baseValue values // * @param propertyType the property type // * @return ArangoDBBaseQuery the query object // */ diff --git a/src/main/java/com/arangodb/tinkerpop/gremlin/client/DatabaseClient.java b/src/main/java/com/arangodb/tinkerpop/gremlin/client/DatabaseClient.java index f2a8f4f..7a48b69 100644 --- a/src/main/java/com/arangodb/tinkerpop/gremlin/client/DatabaseClient.java +++ b/src/main/java/com/arangodb/tinkerpop/gremlin/client/DatabaseClient.java @@ -46,7 +46,7 @@ public GraphCreationException(String message) { /** * Execute the AQL query against the database * @param query the AQL query - * @param bindVars a map of primaryKey:value for bind variables + * @param bindVars a map of primaryKey:baseValue for bind variables * @param aqlQueryOptions AQL query options * @param type The type of the elements in the result * @param The type of the elements in the result diff --git a/src/main/java/com/arangodb/tinkerpop/gremlin/client/GraphClient.java b/src/main/java/com/arangodb/tinkerpop/gremlin/client/GraphClient.java index d1b2216..913de88 100644 --- a/src/main/java/com/arangodb/tinkerpop/gremlin/client/GraphClient.java +++ b/src/main/java/com/arangodb/tinkerpop/gremlin/client/GraphClient.java @@ -36,7 +36,7 @@ public interface GraphClient extends AutoCloseable { /** * Execute the AQL query against the database * @param query the AQL query - * @param bindVars a map of primaryKey:value for bind variables + * @param bindVars a map of primaryKey:baseValue for bind variables * @param aqlQueryOptions AQL query options * @param type The type of the elements in the result * @param The type of the elements in the result @@ -50,7 +50,7 @@ ArangoCursor executeAqlQuery(String query, Map bindVars, * Insert a new vertex in the graph. * @param key the vertex's primary key (can be null) * @param label the vertex's label - * @param keyValues the key:value edge property pairs + * @param keyValues the key:baseValue edge property pairs * @return a new instance of the vertex that uses the provided client. */ ArangoDBVertex insertVertex(String key, String label, Object... keyValues); @@ -74,7 +74,7 @@ ArangoCursor executeAqlQuery(String query, Map bindVars, * @param from the source vertex of the edge * @param to the target vertex of the edge * @param edgeClient the edge clien to assing to the edge - * @param keyValues the key:value edge property pairs + * @param keyValues the key:baseValue edge property pairs * @return */ ArangoDBEdge insertEdge(String key, String label, diff --git a/src/main/java/com/arangodb/tinkerpop/gremlin/client/GraphConfiguration.java b/src/main/java/com/arangodb/tinkerpop/gremlin/client/GraphConfiguration.java index 1689a02..7cc0aad 100644 --- a/src/main/java/com/arangodb/tinkerpop/gremlin/client/GraphConfiguration.java +++ b/src/main/java/com/arangodb/tinkerpop/gremlin/client/GraphConfiguration.java @@ -69,7 +69,7 @@ public interface GraphConfiguration { * * The graph name is configured via the {@link #PROPERTY_KEY_GRAPH_NAME} setting. * - * @return An Optional containing the graph name, or empty if the configuration does not have the value + * @return An Optional containing the graph name, or empty if the configuration does not have the baseValue */ Optional graphName(); @@ -78,25 +78,25 @@ public interface GraphConfiguration { * * The database name is configured via the {@link #PROPERTY_KEY_DB_NAME} setting. * - * @return An Optional containing the database name, or empty if the configuration does not have the value + * @return An Optional containing the database name, or empty if the configuration does not have the baseValue */ Optional databaseName(); /** - * Get the should prefix label names flag value from the configuration. If not present the default value is true. + * Get the should prefix label names flag baseValue from the configuration. If not present the default baseValue is true. * * The shouldPrefixCollectionNames name is configured via the {@link #PROPERTY_KEY_SHOULD_PREFIX_COLLECTION_NAMES} setting. * - * @return The flag value. + * @return The flag baseValue. */ boolean shouldPrefixCollectionNames(); /** - * Get the create db flag value from the configuration. If not present the default value is false. + * Get the create db flag baseValue from the configuration. If not present the default baseValue is false. * * The create db is configured via the {@link #PROPERTY_KEY_DB_CREATE} setting. * - * @return The flag value. + * @return The flag baseValue. */ boolean createDatabase(); diff --git a/src/main/java/com/arangodb/tinkerpop/gremlin/structure/ArangoDBEdge.java b/src/main/java/com/arangodb/tinkerpop/gremlin/structure/ArangoDBEdge.java index 1353a9d..6bd5aaa 100644 --- a/src/main/java/com/arangodb/tinkerpop/gremlin/structure/ArangoDBEdge.java +++ b/src/main/java/com/arangodb/tinkerpop/gremlin/structure/ArangoDBEdge.java @@ -94,6 +94,14 @@ public ArangoDBEdge( this(null, key, null, label, from, to, null, new ArngElementProperties()); } + public ArangoDBEdge( + String id, + String key, + String rev, + String label) { + this(id, key, rev, label, null, null, null, new ArngElementProperties()); + } + /** * * @param id the edge handle @@ -148,19 +156,23 @@ public ArangoDBEdge( vertices = CacheBuilder.newBuilder() .expireAfterAccess(10, TimeUnit.SECONDS) .build(new EdgeVertexLoader(this, client)); - vertices.put("from", from); - vertices.put("to", to); + if (from != null) { + vertices.put("from", from); + } + if (to != null) { + vertices.put("to", to); + } this.properties = properties; } -// // FIXME Move to interface -// public ArangoDBEdge useClient(EdgeClient client) { -// try { -// return new ArangoDBEdge(_id, _key, _rev, label, vertices.get("from"), vertices.get("to"), client); -// } catch (ExecutionException e) { -// throw new IllegalStateException("Error assigning client to edge", e); -// } -// } + // FIXME Move to interface + public ArangoDBEdge useClient(EdgeClient client) { + try { + return new ArangoDBEdge(_id, _key, _rev, label, vertices.get("from"), vertices.get("to"), client, properties); + } catch (ExecutionException e) { + throw new IllegalStateException("Error assigning client to edge", e); + } + } @Override public String from() { @@ -185,7 +197,7 @@ public Object id() { try { return handle(); } catch (ElementNotPairedException e) { - throw new IllegalStateException("Id of unpaired elements can't be retrieved.", e); + return primaryKey(); } } @@ -276,7 +288,7 @@ public Iterator values(String... propertyKeys) { @Override public Property property(final String key, final V value) { - Property result = properties.property(key, value, this); + Property result = properties.property(this, key, value); update(); return result; } diff --git a/src/main/java/com/arangodb/tinkerpop/gremlin/structure/ArangoDBGraph.java b/src/main/java/com/arangodb/tinkerpop/gremlin/structure/ArangoDBGraph.java index 3cef975..cb48719 100644 --- a/src/main/java/com/arangodb/tinkerpop/gremlin/structure/ArangoDBGraph.java +++ b/src/main/java/com/arangodb/tinkerpop/gremlin/structure/ArangoDBGraph.java @@ -58,7 +58,7 @@ * graphClient name. If no vertex, edge and relation information is provided, the graphClient will be considered * schema-less. *

- * All settings are prefixed with "gremlin.arangodb.conf". So, for example, to set the value of the + * All settings are prefixed with "gremlin.arangodb.conf". So, for example, to set the baseValue of the * Arango DB hosts property (arango db configuration), the configuration must read: *

gremlin.arangodb.conf.arangodb.hosts = 127.0.0.1:8529
  * 
@@ -107,7 +107,7 @@ * In order to allow multiple graphs in the same databaseClient, vertex and edge collections can be prefixed with the * graphClient name in order to avoid label clashes. To enable this function the graphClient.shouldPrefixCollectionNames * property should be set to true. If you have an existing graphClient/collections and want to reuse those, - * the flag should be set to false. The default value is true. + * the flag should be set to false. The default baseValue is true. *

* The list of allowed settings is: *

    @@ -309,7 +309,7 @@ public boolean supportsUuidIds() { * the string representation of these is fine for ArangoDB, which makes the test * complain because it expects the actual class to be deserialized. We can test * to see if a string is accepted for deserialization. - * TODO As with elementProperties, a way to support this is to store the id value class + * TODO As with elementProperties, a way to support this is to store the id baseValue class */ return false; } @@ -392,7 +392,7 @@ public boolean supportsUuidIds() { * the string representation of these is fine for ArangoDB, which makes the test * complain because it expects the actual class to be deserialized. We can test * to see if a string is accepted for deserialization. - * TODO As with elementProperties, a way to support this is to store the id value class + * TODO As with elementProperties, a way to support this is to store the id baseValue class */ return false; } diff --git a/src/main/java/com/arangodb/tinkerpop/gremlin/structure/ArangoDBGraphVariables.java b/src/main/java/com/arangodb/tinkerpop/gremlin/structure/ArangoDBGraphVariables.java index 63b088b..205ac14 100644 --- a/src/main/java/com/arangodb/tinkerpop/gremlin/structure/ArangoDBGraphVariables.java +++ b/src/main/java/com/arangodb/tinkerpop/gremlin/structure/ArangoDBGraphVariables.java @@ -37,7 +37,7 @@ public static class ArangoDBGraphVariableFeatures implements Graph.Features.Vari } - /** The primaryKey:value store for elementProperties. */ + /** The primaryKey:baseValue store for elementProperties. */ private final Map store = new HashMap<>(4); diff --git a/src/main/java/com/arangodb/tinkerpop/gremlin/structure/ArangoDBVertex.java b/src/main/java/com/arangodb/tinkerpop/gremlin/structure/ArangoDBVertex.java index 5bc8a6d..fdaeff1 100644 --- a/src/main/java/com/arangodb/tinkerpop/gremlin/structure/ArangoDBVertex.java +++ b/src/main/java/com/arangodb/tinkerpop/gremlin/structure/ArangoDBVertex.java @@ -10,7 +10,8 @@ import com.arangodb.tinkerpop.gremlin.client.ArangoDBGraphException; import com.arangodb.tinkerpop.gremlin.client.VertexClient; -import com.arangodb.tinkerpop.gremlin.structure.properties.*; +import com.arangodb.tinkerpop.gremlin.structure.properties.ArngVertexProperties; +import com.arangodb.tinkerpop.gremlin.structure.properties.VertexProperties; import com.arangodb.tinkerpop.gremlin.utils.ArangoDBUtil; import org.apache.tinkerpop.gremlin.structure.*; import org.apache.tinkerpop.gremlin.structure.VertexProperty.Cardinality; @@ -19,7 +20,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.Collection; import java.util.Iterator; import java.util.Set; import java.util.regex.Matcher; @@ -34,7 +34,7 @@ * @author Horacio Hoyos Rodriguez (https://www.york.ac.uk) */ -public class ArangoDBVertex extends BaseArngDocument implements Vertex, ArngElement { +public class ArangoDBVertex extends BaseArngDocument implements ArngVertex { public static class CantAddValueToSinglePropertyException extends Exception { @@ -44,7 +44,9 @@ public CantAddValueToSinglePropertyException(String message) { } public static class CantRemoveValueFromSinglePropertyException extends Exception { + public CantRemoveValueFromSinglePropertyException(String message) { + super(message); } } @@ -65,7 +67,25 @@ public CantRemoveValueFromSinglePropertyException(String message) { public ArangoDBVertex( String key, String label) { - this(null, key, null, label, null); + this(null, key, null, label, null, new ArngVertexProperties()); + } + + /** + * Instantiates a new arango DB vertex. + * + * @param id the edge handle + * @param key the edge primary key + * @param rev the edge revision + * @param label the edge label + * @param client the client + */ + public ArangoDBVertex( + String id, + String key, + String rev, + String label, + VertexClient client) { + this(id, key, rev, label, client,new ArngVertexProperties()); } /** @@ -82,15 +102,16 @@ public ArangoDBVertex( String key, String rev, String label, - VertexClient client) { + VertexClient client, + VertexProperties properties) { super(id, key, rev, label); this.client = client; - properties = new ArngVertexProperties(this); + this.properties = properties; } // FIXME Move to interface public ArangoDBVertex useClient(VertexClient client) { - return new ArangoDBVertex(_id, _key, _rev, label, client); + return new ArangoDBVertex(_id, _key, _rev, label, client, properties); } @Override @@ -98,7 +119,7 @@ public Object id() { try { return handle(); } catch (ElementNotPairedException e) { - throw new IllegalStateException("Id of unpaired elements can't be retrieved.", e); + return primaryKey(); } } @@ -175,6 +196,11 @@ public VertexProperty property(final String key) { return properties.property(key); } + @Override + public VertexProperty property(final String key, final V value) { + return properties.property(this, key, value); + } + @Override public VertexProperty property( Cardinality cardinality, @@ -182,7 +208,7 @@ public VertexProperty property( V value, Object... keyValues) { logger.debug("setting vertex property {} = {} ({})", key, value, keyValues); - VertexProperty result = properties.property(cardinality, key, value, keyValues); + VertexProperty result = properties.property(this, cardinality, key, value, keyValues); update(); return result; } @@ -216,12 +242,6 @@ public void update() { client.update(this); } -// @Override -// public void attachProperties(String key, Collection elementProperties) { -// this.elementProperties.attachVertexProperties(key, elementProperties); -// } - - @Override public String toString() { return StringFactory.vertexString(this); diff --git a/src/main/java/com/arangodb/tinkerpop/gremlin/structure/ArngVertex.java b/src/main/java/com/arangodb/tinkerpop/gremlin/structure/ArngVertex.java new file mode 100644 index 0000000..d80dfc9 --- /dev/null +++ b/src/main/java/com/arangodb/tinkerpop/gremlin/structure/ArngVertex.java @@ -0,0 +1,8 @@ +package com.arangodb.tinkerpop.gremlin.structure; + +import org.apache.tinkerpop.gremlin.structure.Vertex; + +public interface ArngVertex extends Vertex, ArngElement { + + +} diff --git a/src/main/java/com/arangodb/tinkerpop/gremlin/structure/BaseArngDocument.java b/src/main/java/com/arangodb/tinkerpop/gremlin/structure/BaseArngDocument.java index 418d437..bda1e51 100644 --- a/src/main/java/com/arangodb/tinkerpop/gremlin/structure/BaseArngDocument.java +++ b/src/main/java/com/arangodb/tinkerpop/gremlin/structure/BaseArngDocument.java @@ -66,7 +66,10 @@ public final String primaryKey() { } @Override - public final String revision() { + public final String revision() throws ElementNotPairedException { + if (!paired) { + throw new ElementNotPairedException("Id of an unpaired element can't be accessed"); + } return _rev; } diff --git a/src/main/java/com/arangodb/tinkerpop/gremlin/structure/properties/ArngElementProperties.java b/src/main/java/com/arangodb/tinkerpop/gremlin/structure/properties/ArngElementProperties.java index 4e0c645..d8ebdab 100644 --- a/src/main/java/com/arangodb/tinkerpop/gremlin/structure/properties/ArngElementProperties.java +++ b/src/main/java/com/arangodb/tinkerpop/gremlin/structure/properties/ArngElementProperties.java @@ -7,14 +7,14 @@ import java.util.*; /** - * An implementation of {@link ElementProperties} that uses a {@link HashMap} to store value information for each key. + * An implementation of {@link ElementProperties} that uses a {@link HashMap} to store baseValue information for each key. * The stored values are instances of {@link ElementProperty}. * * @author Horacio Hoyos Rodriguez (https://www.york.ac.uk) */ public class ArngElementProperties implements ElementProperties { - /** The value(s) of the elementProperties, keyd by property primaryKey (name) */ + /** The baseValue(s) of the elementProperties, keyd by property primaryKey (name) */ protected final Map elementProperties = new HashMap<>(); @@ -34,9 +34,9 @@ public Property property(final String key) { @Override public Property property( - final String key, - final V value, - ArngElement element) { + ArngElement element, + final String key, + final V value) { final ElementProperty property = new ArngElementProperty<>(key, value, element); elementProperties.put(key, property); return property; diff --git a/src/main/java/com/arangodb/tinkerpop/gremlin/structure/properties/ArngElementProperty.java b/src/main/java/com/arangodb/tinkerpop/gremlin/structure/properties/ArngElementProperty.java index 8964796..4e0e165 100644 --- a/src/main/java/com/arangodb/tinkerpop/gremlin/structure/properties/ArngElementProperty.java +++ b/src/main/java/com/arangodb/tinkerpop/gremlin/structure/properties/ArngElementProperty.java @@ -22,7 +22,7 @@ /** * Implementation of {@link Property} for ArangoDB elements (Edges and VertexProperties) * - * @param the property value type + * @param the property baseValue type * * @author Horacio Hoyos Rodriguez (https://www.york.ac.uk) */ @@ -37,20 +37,14 @@ public class ArngElementProperty implements ElementProperty { protected ArngElement element; - /** The value of the property */ + /** The baseValue of the property */ protected V value; - /** The canonical name of the value's Java type */ - - protected String type; - - public ArngElementProperty(String key, V value, ArngElement element) { this.key = key; this.value = value; this.element = element; - this.type = value == null ? null : value.getClass().getCanonicalName(); } @Override diff --git a/src/main/java/com/arangodb/tinkerpop/gremlin/structure/properties/ArngVertexProperties.java b/src/main/java/com/arangodb/tinkerpop/gremlin/structure/properties/ArngVertexProperties.java index bb79e00..f6035e8 100644 --- a/src/main/java/com/arangodb/tinkerpop/gremlin/structure/properties/ArngVertexProperties.java +++ b/src/main/java/com/arangodb/tinkerpop/gremlin/structure/properties/ArngVertexProperties.java @@ -9,7 +9,7 @@ /** * An implementation of {@link VertexProperties} for an {@link ArangoDBVertex} that uses a {@link HashMap} to store - * value information for each key. + * baseValue information for each key. * * The stored values are instances of {@link ArngVertexPropertyValue}. * @@ -17,18 +17,12 @@ */ public class ArngVertexProperties implements VertexProperties { - /** The element that owns the property */ + // ArangoDBVertex vertex; - protected final ArangoDBVertex vertex; - - /** The value(s) of the elementProperties, keyd by property primaryKey (name) */ + /** The baseValue(s) of the elementProperties, keyd by property primaryKey (name) */ protected final Map properties = new HashMap<>(); - public ArngVertexProperties(ArangoDBVertex element) { - this.vertex = element; - } - @Override public Set keys() { return Collections.unmodifiableSet(properties.keySet()); @@ -40,16 +34,9 @@ public VertexProperty property(final String key) { return properties.get(key).one(key); } - /** - * Get the {@link VertexProperty} for the provided primaryKey. If the property does not exist, return - * {@link VertexProperty#empty}. - * - * @param the expected type of the vertex property value - * @param key the primaryKey of the vertex property to get - * @return the retrieved vertex property - */ @Override public VertexProperty property( + final ArangoDBVertex vertex, final String key, final V value) { final ArngVertexProperty property = new ArngVertexProperty<>(key, value, vertex); @@ -67,6 +54,7 @@ public Iterator values(String... propertyKeys) { @Override public VertexProperty property( + ArangoDBVertex vertex, VertexProperty.Cardinality cardinality, String key, V value, @@ -81,7 +69,7 @@ public VertexProperty property( } else { try { - return multivalue(key, value, cardinality, keyValues); + return multivalue(vertex, key, value, cardinality, keyValues); } catch (ArangoDBVertex.CantAddValueToSinglePropertyException e) { throw new IllegalArgumentException("The property couldn't be created", e); } @@ -99,6 +87,7 @@ public Iterator> properties(String... propertyKeys) { @SuppressWarnings("unchecked") private VertexProperty multivalue( + ArangoDBVertex vertex, String key, V value, VertexProperty.Cardinality cardinality, @@ -126,8 +115,12 @@ public void removeProperty(VertexProperty property) { properties.remove(property.key()); } else { - if (value.removeOne((ArngVertexProperty) property)) { - properties.remove(property.key()); + try { + if (value.removeOne((ArngVertexProperty) property)) { + properties.remove(property.key()); + } + } catch (ArangoDBVertex.CantRemoveValueFromSinglePropertyException e) { + throw new IllegalArgumentException("Unable to remove the property.", e); } } } diff --git a/src/main/java/com/arangodb/tinkerpop/gremlin/structure/properties/ArngVertexProperty.java b/src/main/java/com/arangodb/tinkerpop/gremlin/structure/properties/ArngVertexProperty.java index 5ac0d2b..0fc043e 100644 --- a/src/main/java/com/arangodb/tinkerpop/gremlin/structure/properties/ArngVertexProperty.java +++ b/src/main/java/com/arangodb/tinkerpop/gremlin/structure/properties/ArngVertexProperty.java @@ -24,7 +24,7 @@ * An implementation of {@link VertexProperty} for ArangoDB vertices. This implementation delegates property access to * an {@link ElementProperties} instance. * - * @param the type of the property value + * @param the type of the property baseValue * * @author Horacio Hoyos Rodriguez (https://www.york.ac.uk) */ @@ -40,7 +40,7 @@ public class ArngVertexProperty extends ArngElementProperty implements Ver * property acess. * * @param name the property name - * @param value the property value + * @param value the property baseValue * @param owner the property owner */ @@ -54,7 +54,7 @@ public ArngVertexProperty( * Instantiates a new arango DB vertex property. * * @param name the property name - * @param value the property value + * @param value the property baseValue * @param owner the property owner * @param properties the delegate responsible of property access */ @@ -104,7 +104,7 @@ public Iterator values(String... propertyKeys) { @Override public Property property(String key, U value) { - final Property property = properties.property(key, value, this); + final Property property = properties.property(this, key, value); update(); return property; } diff --git a/src/main/java/com/arangodb/tinkerpop/gremlin/structure/properties/ArngVertexPropertyValue.java b/src/main/java/com/arangodb/tinkerpop/gremlin/structure/properties/ArngVertexPropertyValue.java index 0116f62..2dba632 100644 --- a/src/main/java/com/arangodb/tinkerpop/gremlin/structure/properties/ArngVertexPropertyValue.java +++ b/src/main/java/com/arangodb/tinkerpop/gremlin/structure/properties/ArngVertexPropertyValue.java @@ -2,6 +2,8 @@ import com.arangodb.tinkerpop.gremlin.structure.ArangoDBVertex; import com.arangodb.tinkerpop.gremlin.structure.ArangoDBVertex.CantAddValueToSinglePropertyException; +import com.arangodb.tinkerpop.gremlin.velocipack.ArngVPackVertexProperty; +import com.arangodb.tinkerpop.gremlin.velocipack.VPackVertexProperty; import org.apache.tinkerpop.gremlin.structure.Vertex; import org.apache.tinkerpop.gremlin.structure.VertexProperty; @@ -108,5 +110,28 @@ public boolean removeOne(ArngVertexProperty value) throws ArangoDBVertex.Cant return multiValue.isEmpty(); } + @Override + public VPackVertexProperty preSerialize() { + VPackVertexProperty result = null; + switch(cardinality) { + case set: + case list: + for (ArngVertexProperty p : multiValue) { + if (result == null) { + result = new ArngVPackVertexProperty(cardinality, singleValue); + } + else { + result = result.addPropertyInformation(p); + } + } + break; + case single: + default: { + result = new ArngVPackVertexProperty(cardinality, singleValue); + } + } + return result; + } + } diff --git a/src/main/java/com/arangodb/tinkerpop/gremlin/structure/properties/ElementProperties.java b/src/main/java/com/arangodb/tinkerpop/gremlin/structure/properties/ElementProperties.java index b052566..07a7063 100644 --- a/src/main/java/com/arangodb/tinkerpop/gremlin/structure/properties/ElementProperties.java +++ b/src/main/java/com/arangodb/tinkerpop/gremlin/structure/properties/ElementProperties.java @@ -44,7 +44,10 @@ public interface ElementProperties { * @see Element#property(String, Object) * @param element the element that owns the property */ - Property property(String key, V value, ArngElement element); + Property property( + ArngElement element, + String key, + V value); /** * @see Element#values(String...) diff --git a/src/main/java/com/arangodb/tinkerpop/gremlin/structure/properties/ElementProperty.java b/src/main/java/com/arangodb/tinkerpop/gremlin/structure/properties/ElementProperty.java index 9ad6855..44d601a 100644 --- a/src/main/java/com/arangodb/tinkerpop/gremlin/structure/properties/ElementProperty.java +++ b/src/main/java/com/arangodb/tinkerpop/gremlin/structure/properties/ElementProperty.java @@ -6,14 +6,14 @@ /** * Additional methods for ElementProperties - * @param the type of the property value + * @param the type of the property baseValue * * @author Horacio Hoyos Rodriguez (https://www.york.ac.uk) */ public interface ElementProperty extends Property { /** - * Return an {@link Iterator} of this property's value + * Return an {@link Iterator} of this property's baseValue * @return iterator of values */ Iterator values(); diff --git a/src/main/java/com/arangodb/tinkerpop/gremlin/structure/properties/VertexProperties.java b/src/main/java/com/arangodb/tinkerpop/gremlin/structure/properties/VertexProperties.java index b6a627e..1e5d13b 100644 --- a/src/main/java/com/arangodb/tinkerpop/gremlin/structure/properties/VertexProperties.java +++ b/src/main/java/com/arangodb/tinkerpop/gremlin/structure/properties/VertexProperties.java @@ -1,5 +1,6 @@ package com.arangodb.tinkerpop.gremlin.structure.properties; +import com.arangodb.tinkerpop.gremlin.structure.ArangoDBVertex; import org.apache.tinkerpop.gremlin.structure.Element; import org.apache.tinkerpop.gremlin.structure.Vertex; import org.apache.tinkerpop.gremlin.structure.VertexProperty; @@ -30,7 +31,7 @@ public interface VertexProperties { /** * @see Vertex#property(String, Object) */ - VertexProperty property(String key, V value); + VertexProperty property(ArangoDBVertex vertex, String key, V value); /** * @see Element#values(String...) @@ -41,7 +42,7 @@ public interface VertexProperties { /** * @see Vertex#property(VertexProperty.Cardinality, String, Object, Object...) */ - VertexProperty property(VertexProperty.Cardinality cardinality, String key, V value, Object... keyValues); + VertexProperty property(ArangoDBVertex vertex, VertexProperty.Cardinality cardinality, String key, V value, Object... keyValues); /** * @see Vertex#properties(String...) diff --git a/src/main/java/com/arangodb/tinkerpop/gremlin/structure/properties/VertexPropertyValue.java b/src/main/java/com/arangodb/tinkerpop/gremlin/structure/properties/VertexPropertyValue.java index c5b32da..397876a 100644 --- a/src/main/java/com/arangodb/tinkerpop/gremlin/structure/properties/VertexPropertyValue.java +++ b/src/main/java/com/arangodb/tinkerpop/gremlin/structure/properties/VertexPropertyValue.java @@ -1,6 +1,7 @@ package com.arangodb.tinkerpop.gremlin.structure.properties; import com.arangodb.tinkerpop.gremlin.structure.ArangoDBVertex; +import com.arangodb.tinkerpop.gremlin.velocipack.VPackVertexProperty; import org.apache.tinkerpop.gremlin.structure.VertexProperty; import java.util.Iterator; @@ -16,7 +17,7 @@ public interface VertexPropertyValue { /** * Get one VertexProperty for the given key. If the property's cardinality is {@link org.apache.tinkerpop.gremlin.structure.VertexProperty.Cardinality#list} - * or {@link org.apache.tinkerpop.gremlin.structure.VertexProperty.Cardinality#set} and more than one value is + * or {@link org.apache.tinkerpop.gremlin.structure.VertexProperty.Cardinality#set} and more than one baseValue is * stored, an IllegalStateException is thrown. * @param key the property key * @return a VertexProperty for the matching key @@ -51,24 +52,31 @@ public interface VertexPropertyValue { void addValues(Iterator> values) throws ArangoDBVertex.CantAddValueToSinglePropertyException; /** - * Add the given value to the existing ones. If the property's cardinality is {@link org.apache.tinkerpop.gremlin.structure.VertexProperty.Cardinality#single} + * Add the given baseValue to the existing ones. If the property's cardinality is {@link org.apache.tinkerpop.gremlin.structure.VertexProperty.Cardinality#single} * a {@link com.arangodb.tinkerpop.gremlin.structure.ArangoDBVertex.CantAddValueToSinglePropertyException} exception * is thrown. * - * @param value the value to add + * @param value the baseValue to add * @throws ArangoDBVertex.CantAddValueToSinglePropertyException */ void addValue(VertexProperty value) throws ArangoDBVertex.CantAddValueToSinglePropertyException; /** - * Remove the given value to the existing ones. If the property's cardinality is {@link org.apache.tinkerpop.gremlin.structure.VertexProperty.Cardinality#single} + * Remove the given baseValue to the existing ones. If the property's cardinality is {@link org.apache.tinkerpop.gremlin.structure.VertexProperty.Cardinality#single} * a {@link com.arangodb.tinkerpop.gremlin.structure.ArangoDBVertex.CantRemoveValueFromSinglePropertyException} exception * is thrown. * - * @param value the value to remove + * @param value the baseValue to remove * @throws ArangoDBVertex.CantRemoveValueFromSinglePropertyException */ boolean removeOne(ArngVertexProperty value) throws ArangoDBVertex.CantRemoveValueFromSinglePropertyException; + + /** + * Create a VPackVertexProperty that represents this {@link VertexPropertyValue} as required for serialization + * via VPack. + * @return a VPackVertexProperty that contains the required information for serialization + */ + VPackVertexProperty preSerialize(); } diff --git a/src/main/java/com/arangodb/tinkerpop/gremlin/utils/ArangoDBUtil.java b/src/main/java/com/arangodb/tinkerpop/gremlin/utils/ArangoDBUtil.java index 8eb609f..556d608 100644 --- a/src/main/java/com/arangodb/tinkerpop/gremlin/utils/ArangoDBUtil.java +++ b/src/main/java/com/arangodb/tinkerpop/gremlin/utils/ArangoDBUtil.java @@ -251,7 +251,7 @@ public static void checkGraphForErrors(List verticesCollectionNames, GraphEntity ge = graph.getInfo(); Collection graphEdgeDefinitions = ge.getEdgeDefinitions(); if (CollectionUtils.isEmpty(relations)) { - // If no relations are defined, vertices and edges can only have one value + // If no relations are defined, vertices and edges can only have one baseValue if ((verticesCollectionNames.size() != 1) || (edgesCollectionNames.size() != 1)) { throw new ArangoDBGraphException("No relations where specified but more than one vertex/edge where defined."); } @@ -343,7 +343,7 @@ public static EdgeDefinition createPropertyEdgeDefinitions( * * @param the generic type * @param key the primaryKey - * @param value the value + * @param value the baseValue * @param edge the edge * @return the created Arango DB edge property */ @@ -367,7 +367,7 @@ public static ArangoDBEdgeProperty createArangoDBEdgeProperty( * * @param the generic type * @param key the primaryKey - * @param value the value + * @param value the baseValue * @param vertex the vertex * @return the created Arango DB vertex property */ @@ -389,7 +389,7 @@ public static ArngVertexProperty createArangoDBVertexProperty(String key, * @param the generic type * @param id the id * @param key the primaryKey - * @param value the value + * @param value the baseValue * @param vertex the vertex * @return the created Arango DB vertex property */ @@ -412,7 +412,7 @@ public static ArngVertexProperty createArangoDBVertexProperty(String id, * * @param the generic type * @param key the primaryKey - * @param value the value + * @param value the baseValue * @param vertexProperty the vertex property * @return the created Arango DB property property */ @@ -428,135 +428,5 @@ public static ArangoDBPropertyProperty createArangoDBPropertyProperty(Str return p; } - /** - * Gets the correct primitive. - * - * @param the value type - * @param value the value - * @return the correct Java primitive - */ - @SuppressWarnings("unchecked") - public static Object getCorretctPrimitive(V value, String valueClass) { - - switch(valueClass) { - case "java.lang.Float": - { - if (value instanceof Double) { - double dv = (Double) value; - return (float) dv; - } - else if (value instanceof Long) { - return ((Long) value) * 1.0f; - } - else { - logger.debug("Add conversion for " + value.getClass().getName() + " to " + valueClass); - } - break; - } - case "java.lang.Double": - { - if (value instanceof Double) { - return value; - } - else if (value instanceof Long) { - return ((Long) value) * 1.0; - } - else { - logger.debug("Add conversion for " + value.getClass().getName() + " to " + valueClass); - } - break; - } - case "java.lang.Long": - { - if (value instanceof Long) { - return value; - } - else if (value instanceof Double) { - return ((Double)value).longValue(); - } - else { - logger.debug("Add conversion for " + value.getClass().getName() + " to " + valueClass); - } - break; - } - case "java.lang.Integer": - { - if (value instanceof Long) { - long lv = (Long) value; - return (int) lv; - } - break; - } - case "java.lang.String": - case "java.lang.Boolean": - case "": - return value; - case "java.util.HashMap": - //logger.debug(((Map)value).keySet().stream().map(Object::getClass).collect(Collectors.toList())); - //logger.debug("Add conversion for map values to " + valueClass); - // Maps are handled by ArangoOK, but we have an extra field, remove it - Map valueMap = (Map)value; - for (String key : valueMap.keySet()) { - if (key.startsWith("_")) { - valueMap.remove(key); - } - // We might need to check individual values... - } - break; - case "java.util.ArrayList": - // Should we save the type per item? - List list = new ArrayList<>(); - ((ArrayList)value).forEach(e -> list.add(getCorretctPrimitive(e, ""))); - return list; - case "boolean[]": - List barray = (List)value; - boolean[] br = new boolean[barray.size()]; - IntStream.range(0, barray.size()) - .forEach(i -> br[i] = (boolean) barray.get(i)); - return br; - case "double[]": - List darray = (List)value; - double[] dr = new double[darray.size()]; - IntStream.range(0, darray.size()) - .forEach(i -> dr[i] = (double) getCorretctPrimitive(darray.get(i), "java.lang.Double")); - return dr; - case "float[]": - List farray = (List)value; - float[] fr = new float[farray.size()]; - IntStream.range(0, farray.size()) - .forEach(i -> fr[i] = (float) getCorretctPrimitive(farray.get(i), "java.lang.Float")); - return fr; - case "int[]": - List iarray = (List)value; - int[] ir = new int[iarray.size()]; - IntStream.range(0, iarray.size()) - .forEach(i -> ir[i] = (int) getCorretctPrimitive(iarray.get(i), "java.lang.Integer")); - return ir; - case "long[]": - List larray = (List)value; - long[] lr = new long[larray.size()]; - IntStream.range(0, larray.size()) - .forEach(i -> lr[i] = (long) getCorretctPrimitive(larray.get(i), "java.lang.Long")); - return lr; - case "java.lang.String[]": - List sarray = (List)value; - String[] sr = new String[sarray.size()]; - IntStream.range(0, sarray.size()) - .forEach(i -> sr[i] = (String) sarray.get(i)); - return sr; - default: - VPack vpack = new VPack.Builder().build(); - VPackSlice slice = vpack.serialize(value); - Object result; - try { - result = vpack.deserialize(slice, Class.forName(valueClass)); - return result; - } catch (VPackParserException | ClassNotFoundException e1) { - logger.warn("Type not deserializable using VPack", e1); - } - logger.debug("Add conversion for " + value.getClass().getName() + " to " + valueClass); - } - return value; - } } diff --git a/src/main/java/com/arangodb/tinkerpop/gremlin/velocipack/ArangoDBEdgeVPack.java b/src/main/java/com/arangodb/tinkerpop/gremlin/velocipack/ArangoDBEdgeVPack.java index 4edc358..60124d9 100644 --- a/src/main/java/com/arangodb/tinkerpop/gremlin/velocipack/ArangoDBEdgeVPack.java +++ b/src/main/java/com/arangodb/tinkerpop/gremlin/velocipack/ArangoDBEdgeVPack.java @@ -1,30 +1,33 @@ package com.arangodb.tinkerpop.gremlin.velocipack; import com.arangodb.tinkerpop.gremlin.structure.ArangoDBEdge; +import com.arangodb.tinkerpop.gremlin.structure.ArngDocument; +import com.arangodb.tinkerpop.gremlin.structure.ArngEdge; import com.arangodb.tinkerpop.gremlin.structure.properties.ArngElementProperty; -import com.arangodb.tinkerpop.gremlin.utils.ArangoDBUtil; import com.arangodb.velocypack.*; +import com.arangodb.velocypack.exception.VPackBuilderException; import com.arangodb.velocypack.exception.VPackException; -import com.arangodb.velocypack.exception.VPackParserException; import org.apache.tinkerpop.gremlin.structure.Property; import org.apache.tinkerpop.gremlin.structure.VertexProperty; +import org.apache.tinkerpop.gremlin.structure.util.ElementHelper; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; import java.util.*; /** * The ArangoDBEdgeVPack is a specialized VPackSerializer/Deserializer that can traverse the edges's elementProperties - * and store both their values and additional required Tinkerpop metadata: their expected Java types. For edges the - * cardinality is always {@link VertexProperty.Cardinality#single} and no nested elementProperties are allowed. In order to - * avoid breaking the expectations of the serialized documents, the Tinkerpop metadata is stored separately under the - * "!tinkerpop" property. This allows reusing existing collections with Tinkerpop and quering the documents via AQL - * without having to worry about the Tinkerpop metadata. The property's value is stored with the property in the root - * JSON object using a single value. - * - * We use the following JSON structure to persist the Tinkerpop metadata. For each property we have a value that - * captures the type. Note that the type and elementProperties values - * are arrays so we can persist type and nested elementProperties for each of the property's values. + * and store both their values and additional required Tinkerpop metadata: their expected Java types. For + * {@link org.apache.tinkerpop.gremlin.structure.Edge}s and {@link VertexProperty}s the cardinality is always + * {@link VertexProperty.Cardinality#single} and no nested properties are allowed. + *

    + * In order to avoid breaking the expectations of the serialized documents (i.e. to allow reuse of exising graphs), the + * Tinkerpop metadata is stored separately under the "!tinkerpop" property. This allows existing documents to be used + * transparently as well as existing AQL queries that rely on previously defined attribtues. + *

    + * The property's baseValue is stored with the property in the root JSON object using a single baseValue. The only additional + * metadata stored is the actual java type of the baseValue. + *

    + * We use the following JSON structure to persist the Tinkerpop metadata. For each property we have a baseValue that + * captures the type. *

    *

    {@code
      *   {
    @@ -52,7 +55,7 @@
      * }
      * }
    */ -public class ArangoDBEdgeVPack implements VPackSerializer, VPackDeserializer { +public class ArangoDBEdgeVPack implements VPackSerializer, VPackDeserializer { public static final String TINKERPOP_METADATA_KEY = "!tinkerpop"; @@ -60,22 +63,20 @@ public class ArangoDBEdgeVPack implements VPackSerializer, VPackDe public void serialize( VPackBuilder builder, String attribute, - ArangoDBEdge value, + ArngEdge value, VPackSerializationContext context) throws VPackException { - builder.add(attribute, ValueType.OBJECT); - if (value.handle() != null) { - builder.add("handle", value.handle()); - } - if (value.primaryKey() != null) { - builder.add("primaryKey", value.primaryKey()); - } - if (value._from() != null) { - builder.add("_from", value._from()); - } - if (value._to() != null) { - builder.add("_to", value._to()); + try (VPackElement element = new VPackElement(builder)) { + element.startObject(attribute); + element.addEdgeAttributes(value); + + + } catch (Exception e) { + throw new VPackBuilderException(e); } + + + Map pTypes = new HashMap<>(); Iterator> itty = value.properties(); while (itty.hasNext()) { @@ -91,9 +92,11 @@ public void serialize( builder.close(); } + + @Override public ArangoDBEdge deserialize(VPackSlice parent, VPackSlice vpack, VPackDeserializationContext context) throws VPackException { - final ArangoDBEdge edge = new ArangoDBEdge(); + VPackSlice temp = vpack.get(TINKERPOP_METADATA_KEY); Iterator> it = temp.objectIterator(); Map pTypes = new HashMap<>(); @@ -101,36 +104,39 @@ public ArangoDBEdge deserialize(VPackSlice parent, VPackSlice vpack, VPackDeseri Map.Entry entry = it.next(); pTypes.put(entry.getKey(), context.deserialize(entry.getValue(), String.class)); } - // FIXME We KNOW the keys we want, so we wan use a constructor, not reflection! it = vpack.objectIterator(); - List> properties = new ArrayList<>(); + String _id = null; + String _key = null; + String _rev = null; + String label = null; + List keyValues = new ArrayList<>(); while (it.hasNext()) { Map.Entry entry = it.next(); String key = entry.getKey(); if (key.equals(TINKERPOP_METADATA_KEY)) { continue; } - else if (key.startsWith("_")) { - Method method = null; - try { - method = edge.getClass().getMethod(key, String.class); - } catch (NoSuchMethodException e) { - throw new VPackParserException(e); - } - try { - method.invoke(edge, entry.getValue().getAsString()); - } catch (IllegalAccessException | InvocationTargetException e) { - throw new VPackParserException(e); - } - } - else { - Object rawValue = context.deserialize(entry.getValue(), Object.class); - Object v = ArangoDBUtil.getCorretctPrimitive(rawValue, pTypes.get(key)); - ArngElementProperty p = new ArngElementProperty<>(key, v, edge); - properties.add(p); + switch(key) { + case "_id": + _id = entry.getValue().getAsString(); + label = _id.split("/")[1]; + break; + case "_key": + _key = entry.getValue().getAsString(); + break; + case "_rev": + _rev = entry.getValue().getAsString(); + break; + default: + keyValues.add(key); + keyValues.add(new JavaPrmitiveType( + context.deserialize(entry.getValue(), Object.class) + ).getCorretctPrimitive(pTypes.get(key))); } + } - edge.attachProperties(properties); + ArangoDBEdge edge = new ArangoDBEdge(_id, _key, _rev, label); + ElementHelper.attachProperties(edge, keyValues.toArray()); return edge; } diff --git a/src/main/java/com/arangodb/tinkerpop/gremlin/velocipack/ArangoDBVertexVPack.java b/src/main/java/com/arangodb/tinkerpop/gremlin/velocipack/ArangoDBVertexVPack.java index 070ef92..24800fe 100644 --- a/src/main/java/com/arangodb/tinkerpop/gremlin/velocipack/ArangoDBVertexVPack.java +++ b/src/main/java/com/arangodb/tinkerpop/gremlin/velocipack/ArangoDBVertexVPack.java @@ -5,6 +5,7 @@ import com.arangodb.tinkerpop.gremlin.structure.properties.ArngVertexProperty; import com.arangodb.tinkerpop.gremlin.utils.ArangoDBUtil; import com.arangodb.velocypack.*; +import com.arangodb.velocypack.exception.VPackBuilderException; import com.arangodb.velocypack.exception.VPackException; import com.arangodb.velocypack.exception.VPackParserException; import org.apache.tinkerpop.gremlin.structure.Property; @@ -17,12 +18,16 @@ /** * The ArangoDBVertexVPack is a specialized VPackSerializer/Deserializer that can traverse the vertex's vertexProperties * and store both their values and additional required Tinkerpop metadata: their expected Java types, the cardinality - * and nested vertexProperties. In order to avoid breaking the expectations of the serialized documents, the Tinkerpop - * metadata is stored separately under the "!tinkerpop" property. This allows reusing existing collections with - * Tinkerpop and quering the documents via AQL without having to worry about the Tinkerpop metadata. The property's - * value is stored with the property in the root JSON object using a single value for {@link VertexProperty.Cardinality#single} + * and nested vertexProperties. + *

    + * In order to avoid breaking the expectations of the serialized documents (i.e. to allow reuse of exising graphs), the + * Tinkerpop metadata is stored separately under the "!tinkerpop" property. This allows existing documents to be used + * transparently as well as existing AQL queries that rely on previously defined attribtues. + *

    + * The property's baseValue is stored with the property in the root JSON object using a single baseValue for {@link VertexProperty.Cardinality#single} * and an array for {@link VertexProperty.Cardinality#set} and {@link VertexProperty.Cardinality#list}. - * + * The Tinkerpop metadata will hold type informartion accordingly. + *

    * We use the following JSON structure to persist the Tinkerpop metadata. For each property we have an entry which * captures the cardinality, type(s) and nested elementProperties. Note that the type and elementProperties values * are arrays so we can persist type and nested elementProperties for each of the property's values. @@ -37,8 +42,8 @@ * "elementProperties": [ * { * "primaryKey": "" - * "value": "" - * "type: "" + * "baseValue": "" + * "type: "" * }, * { ... } * ... @@ -61,11 +66,7 @@ * "street" : "Road To Nowhere 1", * "city" : "Gotham" * }, - * "hobbies" : [ - * {name: "swimming", "howFavorite": 10}, - * {name: "biking", "howFavorite": 6}, - * {name: "programming", "howFavorite": 4} - * ], + * "hobbies" : [ "swimming","biking", "programming"], * "!tinkerpop": { * "firstName" : { * "cardinality": "single", @@ -89,7 +90,7 @@ * [], * [], * [{ - * "primaryKey": "since", + * "key": "since", * "value": 1996, * "type": "lang.java.Integer" * }], @@ -103,21 +104,7 @@ public class ArangoDBVertexVPack implements VPackSerializer, VPa public static final String TINKERPOP_METADATA_KEY = "!tinkerpop"; - /** - * A Class to capture the metadata information and let VPack serialize it - */ - public static class TinkerPopMetadata { - public VertexProperty.Cardinality cardinality; - public List type; - public List> properties; - - public TinkerPopMetadata() { } - - public TinkerPopMetadata(final VertexProperty.Cardinality cardinality) { - this.cardinality = cardinality; - } - } @Override public void serialize( @@ -126,17 +113,21 @@ public void serialize( ArangoDBVertex value, VPackSerializationContext context) throws VPackException { - builder.add(attribute, ValueType.OBJECT); - if (value.handle() != null) { - builder.add("handle", value.handle()); - } - if (value.primaryKey() != null) { - builder.add("primaryKey", value.primaryKey()); + try (VPackElement element = new VPackElement(builder)) { + element.startObject(attribute); + element.addSpecialAttributes(value); + + + } catch (Exception e) { + throw new VPackBuilderException(e); } - Map metadataMap = new HashMap<>(); + + + Map metadataMap = new HashMap<>(); Map> pValues = new HashMap<>(); Map> pTypes = new HashMap<>(); Map>> pProperties = new HashMap<>(); + Iterator> itty = value.properties(); while (itty.hasNext()) { ArngVertexProperty p = (ArngVertexProperty) itty.next(); @@ -161,12 +152,16 @@ public void serialize( properties.add(nps); } } + + for (String k : pValues.keySet()) { context.serialize(builder, k, pValues.get(k)); TinkerPopMetadata md = metadataMap.get(k); md.type = pTypes.get(k); md.properties = pProperties.get(k); } + + builder.add(TINKERPOP_METADATA_KEY, ValueType.OBJECT); for (String k : metadataMap.keySet()) { context.serialize(builder, k, metadataMap.get(k)); @@ -175,6 +170,7 @@ public void serialize( builder.close(); } + @Override public ArangoDBVertex deserialize(VPackSlice parent, VPackSlice vpack, VPackDeserializationContext context) throws VPackException { final ArangoDBVertex vertex = new ArangoDBVertex(); diff --git a/src/main/java/com/arangodb/tinkerpop/gremlin/velocipack/ArngVPackVertexProperty.java b/src/main/java/com/arangodb/tinkerpop/gremlin/velocipack/ArngVPackVertexProperty.java new file mode 100644 index 0000000..af256fa --- /dev/null +++ b/src/main/java/com/arangodb/tinkerpop/gremlin/velocipack/ArngVPackVertexProperty.java @@ -0,0 +1,72 @@ +package com.arangodb.tinkerpop.gremlin.velocipack; + +import com.arangodb.tinkerpop.gremlin.structure.properties.ArngVertexProperty; +import com.arangodb.tinkerpop.gremlin.structure.properties.ElementProperties; +import com.arangodb.tinkerpop.gremlin.structure.properties.ElementProperty; +import org.apache.tinkerpop.gremlin.structure.VertexProperty; + +import java.util.*; + +public class ArngVPackVertexProperty implements VPackVertexProperty { + + private final String key; + private final TinkerPopMetadata metadata; + private final List values; + + public ArngVPackVertexProperty(VertexProperty.Cardinality cardinality, ArngVertexProperty value) { + this(value.key(), cardinality, + Collections.singletonList(value.value()), + Collections.singletonList(value.getClass().getCanonicalName()), + value.properties()); + } + + public ArngVPackVertexProperty( + String key, + VertexProperty.Cardinality cardinality, + Collection values, + Collection types, + Iterator properties) { + this(key, values, new TinkerPopMetadata(cardinality, types, properties)); + } + + public ArngVPackVertexProperty( + String key, + Collection values, + TinkerPopMetadata metadata) { + this.key = key; + this.values = new ArrayList<>(values); + this.metadata = metadata; + } + + @Override + public ArngVPackVertexProperty addPropertyInformation(ArngVertexProperty property) { + if (!property.key().equals(key)) { + throw new IllegalArgumentException("Property can only be added to ArngVPackVertexProperty with same key."); + } + List newValues = new ArrayList<>(values); + newValues.add(property.value()); + List newProps = new ArrayList<>(); + property.properties().forEachRemaining(p -> newProps.add((ElementProperty)p)); + return new ArngVPackVertexProperty(key, newValues, metadata.addMetadata(property.value().getClass().getCanonicalName(), newProps)); + } + + @Override + public String key() { + return key; + } + + @Override + public Object baseValue() { + if (values.size() == 1) { + return values.get(0); + } + else { + return values; + } + } + + @Override + public TinkerPopMetadata metadata() { + return metadata; + } +} diff --git a/src/main/java/com/arangodb/tinkerpop/gremlin/velocipack/JavaPrmitiveType.java b/src/main/java/com/arangodb/tinkerpop/gremlin/velocipack/JavaPrmitiveType.java new file mode 100644 index 0000000..1b04764 --- /dev/null +++ b/src/main/java/com/arangodb/tinkerpop/gremlin/velocipack/JavaPrmitiveType.java @@ -0,0 +1,152 @@ +package com.arangodb.tinkerpop.gremlin.velocipack; + +import com.arangodb.velocypack.VPack; +import com.arangodb.velocypack.VPackSlice; +import com.arangodb.velocypack.exception.VPackParserException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.stream.IntStream; + +public class JavaPrmitiveType { + + private static final Logger logger = LoggerFactory.getLogger(JavaPrmitiveType.class); + private final Object value; + + public JavaPrmitiveType(Object value) { + this.value = value; + } + + /** + * Gets the correct primitive. + * @param valueClass the canonical name of the class. + * @return the correct Java primitive + */ + + @SuppressWarnings("unchecked") + public Object getCorretctPrimitive(String valueClass) { + + switch(valueClass) { + case "java.lang.Float": + { + if (value instanceof Double) { + double dv = (Double) value; + return (float) dv; + } + else if (value instanceof Long) { + return ((Long) value) * 1.0f; + } + else { + logger.debug("Add conversion for " + value.getClass().getName() + " to " + valueClass); + } + break; + } + case "java.lang.Double": + { + if (value instanceof Double) { + return value; + } + else if (value instanceof Long) { + return ((Long) value) * 1.0; + } + else { + logger.debug("Add conversion for " + value.getClass().getName() + " to " + valueClass); + } + break; + } + case "java.lang.Long": + { + if (value instanceof Long) { + return value; + } + else if (value instanceof Double) { + return ((Double)value).longValue(); + } + else { + logger.debug("Add conversion for " + value.getClass().getName() + " to " + valueClass); + } + break; + } + case "java.lang.Integer": + { + if (value instanceof Long) { + long lv = (Long) value; + return (int) lv; + } + break; + } + case "java.lang.String": + case "java.lang.Boolean": + case "": + return value; + case "java.util.HashMap": + //logger.debug(((Map)baseValue).keySet().stream().map(Object::getClass).collect(Collectors.toList())); + //logger.debug("Add conversion for map values to " + valueClass); + // Maps are handled by ArangoOK, but we have an extra field, remove it + Map valueMap = (Map)value; + for (String key : valueMap.keySet()) { + if (key.startsWith("_")) { + valueMap.remove(key); + } + // We might need to check individual values... + } + break; + case "java.util.ArrayList": + // Should we save the type per item? + List list = new ArrayList<>(); + ((ArrayList)value).forEach(e -> list.add(new JavaPrmitiveType(e).getCorretctPrimitive(""))); + return list; + case "boolean[]": + List barray = (List)value; + boolean[] br = new boolean[barray.size()]; + IntStream.range(0, barray.size()) + .forEach(i -> br[i] = (boolean) barray.get(i)); + return br; + case "double[]": + List varray = (List)value; + double[] dr = new double[varray.size()]; + IntStream.range(0, varray.size()) + .forEach(i -> dr[i] = (double) new JavaPrmitiveType(varray.get(i)).getCorretctPrimitive("java.lang.Double")); + return dr; + case "float[]": + List farray = (List)value; + float[] fr = new float[farray.size()]; + IntStream.range(0, farray.size()) + .forEach(i -> fr[i] = (float) new JavaPrmitiveType(farray.get(i)).getCorretctPrimitive("java.lang.Float")); + return fr; + case "int[]": + List iarray = (List)value; + int[] ir = new int[iarray.size()]; + IntStream.range(0, iarray.size()) + .forEach(i -> ir[i] = (int) new JavaPrmitiveType(iarray.get(i)).getCorretctPrimitive("java.lang.Integer")); + return ir; + case "long[]": + List larray = (List)value; + long[] lr = new long[larray.size()]; + IntStream.range(0, larray.size()) + .forEach(i -> lr[i] = (long) new JavaPrmitiveType(larray.get(i)).getCorretctPrimitive("java.lang.Long")); + return lr; + case "java.lang.String[]": + List sarray = (List)value; + String[] sr = new String[sarray.size()]; + IntStream.range(0, sarray.size()) + .forEach(i -> sr[i] = (String) sarray.get(i)); + return sr; + default: + VPack vpack = new VPack.Builder().build(); + VPackSlice slice = vpack.serialize(value); + Object result; + try { + result = vpack.deserialize(slice, Class.forName(valueClass)); + return result; + } catch (VPackParserException | ClassNotFoundException e1) { + logger.warn("Type not deserializable using VPack", e1); + } + logger.debug("Add conversion for " + value.getClass().getName() + " to " + valueClass); + } + return value; + } +} diff --git a/src/main/java/com/arangodb/tinkerpop/gremlin/velocipack/VPackElement.java b/src/main/java/com/arangodb/tinkerpop/gremlin/velocipack/VPackElement.java new file mode 100644 index 0000000..dd479d6 --- /dev/null +++ b/src/main/java/com/arangodb/tinkerpop/gremlin/velocipack/VPackElement.java @@ -0,0 +1,47 @@ +package com.arangodb.tinkerpop.gremlin.velocipack; + +import com.arangodb.tinkerpop.gremlin.structure.ArngDocument; +import com.arangodb.tinkerpop.gremlin.structure.ArngEdge; +import com.arangodb.velocypack.VPackBuilder; +import com.arangodb.velocypack.ValueType; + +public class VPackElement implements AutoCloseable { + + private final VPackBuilder builder; + + public VPackElement(VPackBuilder builder) { + this.builder = builder; + } + + @Override + public void close() throws Exception { + builder.close(); + } + + public void startObject(String name) { + builder.add(name, ValueType.OBJECT); + } + + + public void addSpecialAttributes(ArngDocument value) { + try { + builder.add("_id", value.handle()); + } catch (ArngDocument.ElementNotPairedException e) { + // Pass, simply dont provide id + } + if (value.primaryKey() != null) { + builder.add("_key", value.primaryKey()); + } + try { + builder.add("_rev", value.revision()); + } catch (ArngDocument.ElementNotPairedException e) { + // Pass, simply dont provide rev + } + } + + public void addEdgeAttributes(ArngEdge value) { + addSpecialAttributes(value); + builder.add("_from", value.from()); + builder.add("_to", value.to()); + } +} diff --git a/src/main/java/com/arangodb/tinkerpop/gremlin/velocipack/VPackVertexProperty.java b/src/main/java/com/arangodb/tinkerpop/gremlin/velocipack/VPackVertexProperty.java new file mode 100644 index 0000000..23da149 --- /dev/null +++ b/src/main/java/com/arangodb/tinkerpop/gremlin/velocipack/VPackVertexProperty.java @@ -0,0 +1,101 @@ +package com.arangodb.tinkerpop.gremlin.velocipack; + +import com.arangodb.tinkerpop.gremlin.structure.properties.ArngVertexProperty; +import com.arangodb.tinkerpop.gremlin.structure.properties.ElementProperty; +import org.apache.tinkerpop.gremlin.structure.VertexProperty; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; + +/** + * The interface V pack vertex properties. + */ +public interface VPackVertexProperty { + /** + * A Class to capture the metadata information and let VPack serialize it + */ + public static class TinkerPopMetadata { + + /** + * The Cardinality. + */ + private final VertexProperty.Cardinality cardinality; + /** + * The Type. + */ + private final List types; + /** + * The Properties. + */ + private final List> properties; + + /** + * Instantiates a new Tinker pop metadata. + * + * @param cardinality the cardinality + */ + public TinkerPopMetadata( + VertexProperty.Cardinality cardinality, + Collection types, + Iterator properties) { + this.cardinality = cardinality; + this.types = new ArrayList<>(types); + this.properties = new ArrayList<>(); +// StreamSupport.stream(new Iterable() { +// +// @Override +// public Iterator iterator() { +// return properties; +// } +// }).collect(Collectors.toList()); + List currentProps = new ArrayList<>(); + properties.forEachRemaining(currentProps::add); + this.properties.add(currentProps); + } + + private TinkerPopMetadata( + VertexProperty.Cardinality cardinality, + Collection types, + List> properties) { + this.cardinality = cardinality; + this.types = new ArrayList<>(types); + this.properties = new ArrayList<>(properties); + } + + + public TinkerPopMetadata addMetadata(String type, Collection properties) { + ArrayList newtypes = new ArrayList<>(types); + newtypes.add(type); + ArrayList> newProperties = new ArrayList<>(this.properties); + newProperties.add(properties); + return new TinkerPopMetadata(cardinality, newtypes, newProperties); + + } + } + + ArngVPackVertexProperty addPropertyInformation(ArngVertexProperty property); + + /** + * Key string. + * + * @return the string + */ + public String key(); + + /** + * Value object. + * + * @return the object + */ + public Object baseValue(); + + /** + * Metadata tinker pop metadata. + * + * @return the tinker pop metadata + */ + public TinkerPopMetadata metadata(); + +}