Skip to content

Commit

Permalink
feat: add converter
Browse files Browse the repository at this point in the history
Signed-off-by: Otavio Santana <otaviopolianasantana@gmail.com>
  • Loading branch information
otaviojava committed Mar 9, 2024
1 parent a8bb721 commit e1f3942
Show file tree
Hide file tree
Showing 7 changed files with 496 additions and 43 deletions.
Expand Up @@ -5,7 +5,7 @@

import java.util.function.Function;

enum EntityConverter implements Function<Vertex, CommunicationEntity>{
public enum CommunicationEntityConverter implements Function<Vertex, CommunicationEntity>{
INSTANCE;


Expand Down
Expand Up @@ -145,7 +145,7 @@ public Stream<CommunicationEntity> select(SelectQuery query) {
traversal.order().by(s.property(), desc);
}
});
return traversal.toStream().map(EntityConverter.INSTANCE);
return traversal.toStream().map(CommunicationEntityConverter.INSTANCE);
}

@Override
Expand Down
@@ -1,9 +1,188 @@
package org.eclipse.jnosql.mapping.graph;

import jakarta.data.exceptions.EmptyResultException;
import org.apache.tinkerpop.gremlin.process.traversal.Traverser;
import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
import org.apache.tinkerpop.gremlin.structure.Direction;
import org.apache.tinkerpop.gremlin.structure.Edge;
import org.apache.tinkerpop.gremlin.structure.Graph;
import org.apache.tinkerpop.gremlin.structure.Transaction;
import org.apache.tinkerpop.gremlin.structure.Vertex;
import org.eclipse.jnosql.communication.graph.GraphDatabaseManager;
import org.eclipse.jnosql.mapping.IdNotFoundException;
import org.eclipse.jnosql.mapping.metadata.EntityMetadata;
import org.eclipse.jnosql.mapping.metadata.FieldMetadata;
import org.eclipse.jnosql.mapping.semistructured.AbstractSemistructuredTemplate;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Optional;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;

import static java.util.Objects.isNull;
import static java.util.Objects.requireNonNull;
import static org.apache.tinkerpop.gremlin.structure.T.id;

abstract class AbstractGraphTemplate extends AbstractSemistructuredTemplate implements GraphTemplate {

protected abstract GraphDatabaseManager manager();
protected abstract GraphTraversalSource traversal();
protected abstract Graph graph();


@Override
public <T> void delete(T id) {
requireNonNull(id, "id is required");
traversal().V(id).toStream().forEach(Vertex::remove);
}

@Override
public <T> void deleteEdge(T id) {
requireNonNull(id, "id is required");
traversal().E(id).toStream().forEach(Edge::remove);
}

@Override
public <T> void deleteEdge(Iterable<T> ids) {
requireNonNull(ids, "ids is required");
final Object[] edgeIds = StreamSupport.stream(ids.spliterator(), false).toArray(Object[]::new);
traversal().E(edgeIds).toStream().forEach(Edge::remove);
}

@Override
public <O, I> EdgeEntity edge(O outgoing, String label, I incoming) {
requireNonNull(incoming, "incoming is required");
requireNonNull(label, "label is required");
requireNonNull(outgoing, "outgoing is required");

checkId(outgoing);
checkId(incoming);

if (isIdNull(outgoing)) {
throw new IllegalStateException("outgoing Id field is required");
}

if (isIdNull(incoming)) {
throw new IllegalStateException("incoming Id field is required");
}

Vertex outVertex = vertex(outgoing).orElseThrow(() -> new EmptyResultException("Outgoing entity does not found"));
Vertex inVertex = vertex(incoming).orElseThrow(() -> new EmptyResultException("Incoming entity does not found"));

final Predicate<Traverser<Edge>> predicate = t -> {
Edge e = t.get();
return e.inVertex().id().equals(inVertex.id())
&& e.outVertex().id().equals(outVertex.id());
};

Optional<Edge> edge = traversal().V(outVertex.id())
.out(label).has(id, inVertex.id()).inE(label).filter(predicate).tryNext();

return edge.<EdgeEntity>map(edge1 -> new DefaultEdgeEntity<>(edge1, incoming, outgoing))
.orElseGet(() -> new DefaultEdgeEntity<>(getEdge(label, outVertex, inVertex), incoming, outgoing));
}

@Override
public <K> Collection<EdgeEntity> edgesById(K id, Direction direction, String... labels) {
requireNonNull(id, "id is required");
requireNonNull(direction, "direction is required");

Iterator<Vertex> vertices = vertices(id);
if (vertices.hasNext()) {
List<Edge> edges = new ArrayList<>();
vertices.next().edges(direction, labels).forEachRemaining(edges::add);
return edges.stream().map(converter()::toEdgeEntity).toList();
}
return Collections.emptyList();
}

@Override
public <K> Collection<EdgeEntity> edgesById(K id, Direction direction, Supplier<String>... labels) {
return null;
}

@Override
public <K> Collection<EdgeEntity> edgesById(K id, Direction direction) {
return null;
}

@Override
public <T> Collection<EdgeEntity> edges(T entity, Direction direction, String... labels) {
return null;
}

@Override
public <T> Collection<EdgeEntity> edges(T entity, Direction direction, Supplier<String>... labels) {
return null;
}

@Override
public <T> Collection<EdgeEntity> edges(T entity, Direction direction) {
return null;
}

@Override
public <E> Optional<EdgeEntity> edge(E edgeId) {
return Optional.empty();
}

@Override
public VertexTraversal traversalVertex(Object... vertexIds) {
return null;
}

@Override
public EdgeTraversal traversalEdge(Object... edgeIds) {
return null;
}

@Override
public Transaction transaction() {
return null;
}

@Override
public <T> Stream<T> gremlin(String gremlin) {
return null;
}

private <T> void checkId(T entity) {
EntityMetadata entityMetadata = entities().get(entity.getClass());
entityMetadata.id().orElseThrow(() -> IdNotFoundException.newInstance(entity.getClass()));
}

private <T> boolean isIdNull(T entity) {
EntityMetadata entityMetadata = entities().get(entity.getClass());
FieldMetadata field = entityMetadata.id().orElseThrow(() -> IdNotFoundException.newInstance(entity.getClass()));
return isNull(field.read(entity));

}

private <T> Optional<Vertex> vertex(T entity) {
EntityMetadata entityMetadata = entities().get(entity.getClass());
FieldMetadata field = entityMetadata.id().orElseThrow(() -> IdNotFoundException.newInstance(entity.getClass()));
Object id = field.read(entity);
Iterator<Vertex> vertices = vertices(id);
if (vertices.hasNext()) {
return Optional.of(vertices.next());
}
return Optional.empty();
}

protected Iterator<Vertex> vertices(Object id) {
return graph().vertices(id);
}

private Edge getEdge(String label, Vertex outVertex, Vertex inVertex) {
final Edge edge = outVertex.addEdge(label, inVertex);
GraphTransactionUtil.transaction(graph());
return edge;
}

}
@@ -0,0 +1,163 @@
/*
* Copyright (c) 2022 Contributors to the Eclipse Foundation
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Apache License v2.0 which accompanies this distribution.
* The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
* and the Apache License v2.0 is available at http://www.opensource.org/licenses/apache2.0.php.
*
* You may elect to redistribute this code under either of these licenses.
*
* Contributors:
*
* Otavio Santana
*/
package org.eclipse.jnosql.mapping.graph;

import org.apache.tinkerpop.gremlin.structure.Edge;
import org.apache.tinkerpop.gremlin.structure.Property;
import org.eclipse.jnosql.communication.Value;
import org.eclipse.jnosql.communication.graph.CommunicationEntityConverter;
import org.eclipse.jnosql.communication.semistructured.Element;
import org.eclipse.jnosql.mapping.semistructured.EntityConverter;

import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Optional;

import static java.util.Objects.requireNonNull;
import static java.util.stream.Collectors.collectingAndThen;
import static java.util.stream.Collectors.toList;

class DefaultEdgeEntity<O, I> implements EdgeEntity {

private final O outgoing;

private final Edge edge;

private final I incoming;

DefaultEdgeEntity(Edge edge, I incoming, O outgoing) {
this.edge = edge;
this.incoming = incoming;
this.outgoing = outgoing;
}

@Override
public Object id() {
return edge.id();
}

@Override
public <T> T id(Class<T> type) {
Objects.requireNonNull(type, "type is required");
return Value.of(edge.id()).get(type);
}

@Override
public String label() {
return edge.label();
}

@Override
public I incoming() {
return incoming;
}

@Override
public O outgoing() {
return outgoing;
}

@Override
public List<Element> properties() {
return edge.keys()
.stream()
.map(k -> Element.of(k, edge.value(k)))
.collect(collectingAndThen(toList(), Collections::unmodifiableList));
}

@Override
public void add(String key, Object value) {
requireNonNull(key, "key is required");
requireNonNull(value, "value is required");
edge.property(key, value);

}

@Override
public void add(String key, Value value) {
requireNonNull(key, "key is required");
requireNonNull(value, "value is required");
edge.property(key, value.get());
}

@Override
public void remove(String key) {
requireNonNull(key, "key is required");
Property<?> property = edge.property(key);
property.ifPresent(o -> property.remove());
}

@Override
public Optional<Value> get(String key) {
requireNonNull(key, "key is required");
Property<?> property = edge.property(key);
if (property.isPresent()) {
return Optional.of(Value.of(property.value()));
}
return Optional.empty();
}

@Override
public boolean isEmpty() {
return edge.keys().isEmpty();
}

@Override
public int size() {
return edge.keys().size();
}

@Override
public void delete() {
edge.remove();
}

@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof DefaultEdgeEntity)) {
return false;
}
DefaultEdgeEntity<?, ?> that = (DefaultEdgeEntity<?, ?>) o;
return Objects.equals(edge, that.edge) &&
Objects.equals(incoming, that.incoming) &&
Objects.equals(outgoing, that.outgoing);
}

@Override
public int hashCode() {
return Objects.hash(edge, incoming, outgoing);
}

@Override
public String toString() {
return outgoing +
"---" + edge.label() +
" --->" + incoming;
}


public static EdgeEntity of(EntityConverter converter, Edge edge) {
Objects.requireNonNull(converter, "converter is required");
Objects.requireNonNull(edge, "edge is required");
var entityConverter = CommunicationEntityConverter.INSTANCE;
return new DefaultEdgeEntity<>(edge, converter.toEntity(entityConverter.apply(edge.outVertex())),
converter.toEntity(entityConverter.apply(edge.inVertex())));
}

}
Expand Up @@ -3,14 +3,21 @@
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.enterprise.inject.Default;
import jakarta.inject.Inject;
import org.apache.tinkerpop.gremlin.structure.Direction;
import org.apache.tinkerpop.gremlin.structure.Graph;
import org.apache.tinkerpop.gremlin.structure.Transaction;
import org.eclipse.jnosql.communication.graph.GraphDatabaseManager;
import org.eclipse.jnosql.mapping.Database;
import org.eclipse.jnosql.mapping.core.Converters;
import org.eclipse.jnosql.mapping.metadata.EntitiesMetadata;
import org.eclipse.jnosql.mapping.semistructured.EntityConverter;
import org.eclipse.jnosql.mapping.semistructured.EventPersistManager;

import java.util.Collection;
import java.util.Optional;
import java.util.function.Supplier;
import java.util.stream.Stream;

import static org.eclipse.jnosql.mapping.DatabaseType.GRAPH;

@Default
Expand Down

0 comments on commit e1f3942

Please sign in to comment.