org.eclipse.jnosql.mapping.graph.GraphConverter Maven / Gradle / Ivy
/*
* 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 jakarta.data.exceptions.EmptyResultException;
import jakarta.data.exceptions.MappingException;
import org.apache.tinkerpop.gremlin.structure.Edge;
import org.apache.tinkerpop.gremlin.structure.Graph;
import org.apache.tinkerpop.gremlin.structure.Property;
import org.apache.tinkerpop.gremlin.structure.Vertex;
import org.eclipse.jnosql.mapping.core.Converters;
import org.eclipse.jnosql.mapping.metadata.ConstructorMetadata;
import org.eclipse.jnosql.mapping.metadata.EntitiesMetadata;
import org.eclipse.jnosql.mapping.metadata.EntityMetadata;
import org.eclipse.jnosql.mapping.metadata.FieldMetadata;
import org.eclipse.jnosql.mapping.metadata.InheritanceMetadata;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Collectors;
import static java.util.Objects.requireNonNull;
import static java.util.stream.Collectors.toList;
public abstract class GraphConverter {
protected abstract EntitiesMetadata getEntities();
protected abstract Converters getConverters();
protected abstract GraphEventPersistManager getEventManager();
protected abstract Graph getGraph();
/**
* Converts entity object to TinkerPop Vertex
*
* @param entity the entity
* @param the entity type
* @return the ThinkerPop Vertex with the entity values
* @throws NullPointerException when entity is null
*/
public Vertex toVertex(T entity) {
requireNonNull(entity, "entity is required");
EntityMetadata mapping = getEntities().get(entity.getClass());
String label = mapping.name();
List fields = mapping.fields().stream()
.map(f -> to(f, entity))
.toList();
Optional id = fields.stream().filter(FieldGraph::isId).findFirst();
final Function findVertexOrCreateWithId = p -> {
Iterator vertices = getGraph().vertices(p.value());
return vertices.hasNext() ? vertices.next() :
getGraph().addVertex(org.apache.tinkerpop.gremlin.structure.T.label, label,
org.apache.tinkerpop.gremlin.structure.T.id, p.value());
};
Vertex vertex = id.map(i -> i.toElement(getConverters()))
.map(findVertexOrCreateWithId)
.orElseGet(() -> getGraph().addVertex(label));
fields.stream().filter(FieldGraph::isNotId)
.flatMap(f -> f.toElements(this, getConverters()).stream())
.forEach(p -> vertex.property(p.key(), p.value()));
mapping.inheritance().ifPresent(i ->
vertex.property(i.discriminatorColumn(), i.discriminatorValue()));
return vertex;
}
/**
* List the fields in the entity as property exclude fields annotated with {@link jakarta.nosql.Id}
*
* @param entity the entity
* @param the entity type
* @return the properties of an entity
* @throws NullPointerException when entity is null
*/
public List> getProperties(T entity) {
Objects.requireNonNull(entity, "entity is required");
EntityMetadata mapping = getEntities().get(entity.getClass());
List fields = mapping.fields().stream()
.map(f -> to(f, entity))
.filter(FieldGraph::isNotEmpty).toList();
return fields.stream().filter(FieldGraph::isNotId)
.flatMap(f -> f.toElements(this, getConverters()).stream())
.collect(Collectors.toList());
}
/**
* Converts vertex to an entity
*
* @param vertex the vertex
* @param the entity type
* @return a entity instance
* @throws NullPointerException when vertex is null
*/
public T toEntity(Vertex vertex) {
requireNonNull(vertex, "vertex is required");
EntityMetadata mapping = getEntities().findByName(vertex.label());
List> properties = vertex.keys()
.stream()
.map(k -> DefaultProperty.of(k, vertex.value(k))).collect(toList());
T entity;
if (mapping.isInheritance()) {
entity = mapInheritanceEntity(vertex, properties, mapping.type());
} else {
entity = convert((Class) mapping.type(), properties, vertex);
}
getEventManager().firePostEntity(entity);
return entity;
}
/**
* Converts vertex to an entity
*
* @param type the entity class
* @param vertex the vertex
* @param the entity type
* @return a entity instance
* @throws NullPointerException when vertex or type is null
*/
public T toEntity(Class type, Vertex vertex) {
requireNonNull(type, "type is required");
requireNonNull(vertex, "vertex is required");
List> properties = vertex.keys().stream()
.map(k -> DefaultProperty.of(k, vertex.value(k))).collect(toList());
T entity = convert(type, properties, vertex);
getEventManager().firePostEntity(entity);
return entity;
}
/**
* Converts vertex to an entity
* Instead of creating a new object is uses the instance used in this parameters
*
* @param type the entity class
* @param vertex the vertex
* @param the entity type
* @return a entity instance
* @throws NullPointerException when vertex or type is null
*/
public T toEntity(T type, Vertex vertex) {
requireNonNull(type, "entityInstance is required");
requireNonNull(vertex, "vertex is required");
if (type.getClass().isRecord()) {
return (T) toEntity(type.getClass(), vertex);
}
List> properties = vertex.keys().stream()
.map(k -> DefaultProperty.of(k, vertex.value(k)))
.collect(toList());
EntityMetadata mapping = getEntities().get(type.getClass());
EntityConverterByField converter = EntityConverterByField.of(properties, mapping,
type, vertex, getConverters(), getEntities());
return converter.get();
}
/**
* Converts {@link EdgeEntity} from {@link Edge} Thinkerpop
*
* @param edge the ThinkerPop edge
* @return an EdgeEntity instance
* @throws NullPointerException when Edge is null
*/
public EdgeEntity toEdgeEntity(Edge edge) {
requireNonNull(edge, "vertex is required");
Object out = toEntity(edge.outVertex());
Object in = toEntity(edge.inVertex());
return new DefaultEdgeEntity<>(edge, in, out);
}
/**
* Converts {@link Edge} from {@link EdgeEntity}
*
* @param edge the EdgeEntity instance
* @return a Edge instance
* @throws NullPointerException when edge entity is null
*/
public Edge toEdge(EdgeEntity edge) {
requireNonNull(edge, "vertex is required");
Object id = edge.id();
Iterator edges = getGraph().edges(id);
if (edges.hasNext()) {
return edges.next();
}
throw new EmptyResultException("Edge does not found in the database with id: " + id);
}
private T convert(Class type, List> properties, Vertex vertex) {
EntityMetadata mapping = getEntities().get(type);
ConstructorMetadata constructor = mapping.constructor();
if (constructor.isDefault()) {
EntityConverterByField converter = EntityConverterByField.of(properties, mapping,
mapping.newInstance(), vertex, getConverters(), getEntities());
return converter.get();
} else {
EntityConverterByContructor supplier = EntityConverterByContructor.of(mapping, vertex, getConverters());
return supplier.get();
}
}
protected FieldGraph to(FieldMetadata field, Object entityInstance) {
Object value = field.read(entityInstance);
return FieldGraph.of(value, field);
}
private T mapInheritanceEntity(Vertex vertex,
List> properties, Class> type) {
Map group = getEntities()
.findByParentGroupByDiscriminatorValue(type);
if (group.isEmpty()) {
throw new MappingException("There is no discriminator inheritance to the vertex "
+ vertex.label());
}
String column = group.values()
.stream()
.findFirst()
.map(InheritanceMetadata::discriminatorColumn)
.orElseThrow();
String discriminator = properties.stream().filter(p -> p.key().equals(column))
.map(Property::value).map(Object::toString)
.findFirst()
.orElseThrow(
() -> new MappingException("To inheritance there is the discriminator column missing" +
" on the Vertex, the document name: " + column));
InheritanceMetadata inheritance = Optional.ofNullable(group.get(discriminator))
.orElseThrow(() -> new MappingException("There is no inheritance map to the discriminator" +
" column value " + discriminator));
EntityMetadata mapping = getEntities().get(inheritance.entity());
return convert((Class) mapping.type(), properties, vertex);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy