Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Signed-off-by: Otavio Santana <otaviopolianasantana@gmail.com>
- Loading branch information
1 parent
a8bb721
commit e1f3942
Showing
7 changed files
with
496 additions
and
43 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
179 changes: 179 additions & 0 deletions
179
...l-mapping-graph/src/main/java/org/eclipse/jnosql/mapping/graph/AbstractGraphTemplate.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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; | ||
} | ||
|
||
} |
163 changes: 163 additions & 0 deletions
163
...nosql-mapping-graph/src/main/java/org/eclipse/jnosql/mapping/graph/DefaultEdgeEntity.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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()))); | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.