use of org.neo4j.driver.v1.Values in project meveo by meveo-org.
the class Neo4jService method deleteEntity.
public void deleteEntity(String neo4jConfiguration, String cetCode, Map<String, Object> values) throws BusinessException {
/* Get entity template */
final CustomEntityTemplate customEntityTemplate = customFieldsCache.getCustomEntityTemplate(cetCode);
/* Extract unique fields values for node */
final Map<String, Object> uniqueFields = getNodeKeys(customEntityTemplate.getAppliesTo(), values);
/* No unique fields has been found */
if (uniqueFields.isEmpty()) {
throw new BusinessException("At least one unique field must be provided for cet to delete");
}
final String uniqueFieldStatement = neo4jDao.getFieldsString(uniqueFields.keySet());
/* Map the variables declared in the statement */
Map<String, Object> valuesMap = new HashMap<>();
valuesMap.put("cetCode", cetCode);
valuesMap.put("uniqueFields", uniqueFieldStatement);
String deleteStatement = getStatement(new StrSubstitutor(valuesMap), Neo4JRequests.deleteCet);
final Transaction transaction = crossStorageTransaction.getNeo4jTransaction(neo4jConfiguration);
InternalNode internalNode = null;
try {
/* Delete the node and all its associated relationships and fire node deletion event */
// Execute query
final StatementResult result = transaction.run(deleteStatement, values);
for (Record record : result.list()) {
// Fire deletion event
// Parse properties
final Map<String, Value> properties = record.get("properties").asMap(e -> e);
// Parse labels
final List<String> labels = record.get("labels").asList(Value::asString);
// Parse id
final long id = record.get("id").asLong();
// Create Node object
internalNode = new InternalNode(id, labels, properties);
}
transaction.success();
} catch (Exception e) {
log.error("Cannot delete node with code {} and values {}", cetCode, values, e);
transaction.failure();
throw new BusinessException(e);
}
if (internalNode != null) {
// Fire notification
nodeRemovedEvent.fire(new Neo4jEntity(internalNode, neo4jConfiguration));
}
}
use of org.neo4j.driver.v1.Values in project meveo by meveo-org.
the class Neo4jService method saveCRT2Neo4j.
/**
* Save CRT to Neo4j
*
* @param neo4JConfiguration Neo4J coordinates
* @param customRelationshipTemplate Template of the CRT
* @param startNodeKeysMap Unique fields values of the start node
* @param endNodeKeysMap Unique fields values of the start node
* @param crtFields Fields values of the relationship
*/
public List<String> saveCRT2Neo4j(String neo4JConfiguration, CustomRelationshipTemplate customRelationshipTemplate, Map<String, Object> startNodeKeysMap, Map<String, Object> endNodeKeysMap, Map<String, Object> crtFields, boolean isTemporaryCET) {
// Alias to use in query
final String relationshipAlias = "relationship";
// Build values map
Map<String, Object> valuesMap = new HashMap<>();
valuesMap.put("startAlias", Neo4JRequests.START_NODE_ALIAS);
valuesMap.put("endAlias", Neo4JRequests.END_NODE_ALIAS);
valuesMap.put("startNode", customRelationshipTemplate.getStartNode().getCode());
valuesMap.put("endNode", customRelationshipTemplate.getEndNode().getCode());
valuesMap.put("relationType", customRelationshipTemplate.getName());
valuesMap.put("starNodeKeys", Values.value(startNodeKeysMap));
valuesMap.put("endNodeKeys", Values.value(endNodeKeysMap));
valuesMap.put("updateDate", isTemporaryCET ? -1 : System.currentTimeMillis());
final String fieldsString = neo4jDao.getFieldsString(crtFields.keySet());
valuesMap.put(FIELDS, fieldsString);
valuesMap.putAll(crtFields);
valuesMap.put(NODE_ID, UUID.randomUUID().toString());
// Build the statement
StringBuffer statement = neo4jDao.appendReturnStatement(Neo4JRequests.crtStatement, relationshipAlias, valuesMap);
StrSubstitutor sub = new StrSubstitutor(valuesMap);
String resolvedStatement = sub.replace(statement);
// Begin Neo4J transaction
final Transaction transaction = crossStorageTransaction.getNeo4jTransaction(neo4JConfiguration);
List<Record> recordList = new ArrayList<>();
try {
/* Execute query and parse result inside a relationship.
If relationship was created fire creation event, fire update event when updated. */
// Execute query
final StatementResult result = transaction.run(resolvedStatement, valuesMap);
// Fire notification for each relation created or updated
recordList = result.list();
// Commit transaction
transaction.success();
} catch (Exception e) {
log.error("Failed to save relationship", e);
transaction.failure();
}
List<String> relationUuids = new ArrayList<>();
for (Record record : recordList) {
// Parse relationship
final Neo4jRelationship relationship = new Neo4jRelationship(record.get(relationshipAlias).asRelationship(), neo4JConfiguration);
if (relationship.containsKey(MEVEO_UUID)) {
relationUuids.add(relationship.get(MEVEO_UUID).asString());
}
if (relationship.containsKey("update_date") || relationship.containsKey("updateDate")) {
// Check if relationship contains the "update_date" key
// Fire update event if contains the key
edgeUpdatedEvent.fire(relationship);
} else {
// Fire creation event if does not contains the key
edgeCreatedEvent.fire(relationship);
}
}
return relationUuids;
}
use of org.neo4j.driver.v1.Values in project meveo by meveo-org.
the class Neo4jService method addSourceNodeUniqueCrt.
/**
* Persist a source node of an unique relationship.
* If a relationship that targets the target node exists, then we merge the fields of the start in parameter to
* the fields of the source node of the relationship.
* If such a relation does not exists, we create the source node with it fields.
*
* @param neo4JConfiguration Neo4J coordinates
* @param crtCode Code of the unique relation
* @param startNodeValues Values to assign to the start node
* @param endNodeValues Filters on the target node values
*/
@JpaAmpNewTx
@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public PersistenceActionResult addSourceNodeUniqueCrt(String neo4JConfiguration, String crtCode, Map<String, Object> startNodeValues, Map<String, Object> endNodeValues) throws BusinessException, ELException {
// Get relationship template
final CustomRelationshipTemplate customRelationshipTemplate = customFieldsCache.getCustomRelationshipTemplate(crtCode);
final CustomEntityTemplate endNode = customRelationshipTemplate.getEndNode();
// Extract unique fields values for the start node
Map<String, CustomFieldTemplate> endNodeCfts = customFieldTemplateService.findByAppliesTo(endNode.getAppliesTo());
Map<String, CustomFieldTemplate> startNodeCfts = customFieldTemplateService.findByAppliesTo(customRelationshipTemplate.getStartNode().getAppliesTo());
final Map<String, Object> endNodeUniqueFields = new HashMap<>();
Map<String, Object> endNodeConvertedValues = validateAndConvertCustomFields(endNodeCfts, endNodeValues, endNodeUniqueFields, true);
Map<String, Object> startNodeConvertedValues = validateAndConvertCustomFields(startNodeCfts, startNodeValues, null, true);
// Map the variables declared in the statement
Map<String, Object> valuesMap = new HashMap<>();
final String cetCode = customRelationshipTemplate.getStartNode().getCode();
valuesMap.put("cetCode", cetCode);
valuesMap.put("crtCode", crtCode);
valuesMap.put("endCetcode", customRelationshipTemplate.getEndNode().getCode());
// Prepare the key maps for unique fields and start node fields
final String uniqueFieldStatements = neo4jDao.getFieldsString(endNodeConvertedValues.keySet());
final String startNodeValuesStatements = neo4jDao.getFieldsString(startNodeConvertedValues.keySet());
// No unique fields has been found
if (endNodeUniqueFields.isEmpty()) {
// If no unique fields are provided / defined, retrieve the meveo_uuid of the target node using unicity rules
Set<String> ids = endNode.getNeo4JStorageConfiguration().getUniqueConstraints().stream().filter(uniqueConstraint -> uniqueConstraint.getTrustScore() == 100).filter(uniqueConstraint -> isApplicableConstraint(endNodeValues, uniqueConstraint)).sorted(Neo4jService.CONSTRAINT_COMPARATOR).map(uniqueConstraint -> neo4jDao.executeUniqueConstraint(neo4JConfiguration, uniqueConstraint, endNodeValues, endNode.getCode())).findFirst().orElse(Set.of());
if (ids.isEmpty()) {
log.error("At least one unique field must be provided for target entity [code = {}, fields = {}]. " + "Unique fields are : {}", customRelationshipTemplate.getEndNode().getCode(), endNodeValues, endNodeUniqueFields);
throw new BusinessException("Unique field must be provided");
}
if (ids.size() > 1) {
throw new BusinessException(String.format("Multiple targets for unique relationship %s : %s.", crtCode, ids));
}
String id = ids.iterator().next();
endNodeValues.put("meveo_uuid", id);
endNodeUniqueFields.put("meveo_uuid", id);
}
// Assign the keys names
valuesMap.put(FIELD_KEYS, uniqueFieldStatements);
valuesMap.put(FIELDS, startNodeValuesStatements);
// Create the substitutor
StrSubstitutor sub = new StrSubstitutor(valuesMap);
// Values of the keys defined in valuesMap
Map<String, Object> parametersValues = new HashMap<>();
parametersValues.putAll(startNodeConvertedValues);
parametersValues.putAll(endNodeConvertedValues);
final Transaction transaction = crossStorageTransaction.getNeo4jTransaction(neo4JConfiguration);
// Try to find the id of the source node
String findStartNodeStatement = getStatement(sub, Neo4JRequests.findStartNodeId);
final StatementResult run = transaction.run(findStartNodeStatement, parametersValues);
Neo4jEntity startNode = null;
try {
try {
/* Update the source node with the found id */
// Alias to use in queries
final String startNodeAlias = "startNode";
// Retrieve ID of the node
final Record idRecord = run.single();
final Value id = idRecord.get(0);
parametersValues.put(NODE_ID, id);
// Create statement
CustomEntityTemplate startCet = customRelationshipTemplate.getStartNode();
List<String> additionalLabels = getAdditionalLabels(startCet);
final Map<String, Object> updatableValues = valuesMap.entrySet().stream().filter(s -> startNodeCfts.get(s.getKey()).isAllowEdit()).collect(Collectors.toMap(Entry::getKey, Entry::getValue));
StringBuffer statement = neo4jDao.appendAdditionalLabels(Neo4JRequests.updateNodeWithId, additionalLabels, startNodeAlias, updatableValues);
statement = neo4jDao.appendReturnStatement(statement, startNodeAlias, valuesMap);
String updateStatement = getStatement(sub, statement);
// Execute query
final StatementResult result = transaction.run(updateStatement, parametersValues);
// Fire node update event
startNode = new Neo4jEntity(result.single().get(startNodeAlias).asNode(), neo4JConfiguration);
} catch (NoSuchRecordException e) {
/* Create the source node */
addCetNode(neo4JConfiguration, customRelationshipTemplate.getStartNode(), startNodeValues, null);
}
transaction.success();
} catch (Exception e) {
transaction.failure();
log.error("Transaction for persisting entity with code {} and fields {} was rolled back", cetCode, startNodeValues, e);
throw new BusinessException(e);
}
if (startNode != null) {
nodeUpdatedEvent.fire(startNode);
return new PersistenceActionResult(startNode.get("meveo_uuid").asString());
} else {
return null;
}
}
use of org.neo4j.driver.v1.Values in project meveo by meveo-org.
the class CrossStorageService method remove.
/**
* Remove an entity from database
*
* @param repository Repository
* @param cet Template of the entity
* @param uuid UUID of the entity
* @throws BusinessException if error happens
*/
public void remove(Repository repository, CustomEntityTemplate cet, String uuid) throws BusinessException {
if (uuid == null) {
throw new IllegalArgumentException("Cannot remove entity by UUID without uuid");
}
CustomEntityInstance cei = new CustomEntityInstance();
cei.setCet(cet);
cei.setCetCode(cet.getCode());
cei.setUuid(uuid);
cei.setRepository(repository);
var listener = customEntityTemplateService.loadCrudEventListener(cei.getCet());
CustomEntity cetClassInstance = null;
transaction.beginTransaction(repository);
try {
if (listener != null) {
var cetClass = listener.getEntityClass();
try {
var values = find(repository, cet, uuid, false);
cei = CEIUtils.fromMap(values, cet);
cetClassInstance = CEIUtils.ceiToPojo(cei, cetClass);
listener.preRemove(cetClassInstance);
} catch (EntityDoesNotExistsException e) {
e.printStackTrace();
}
}
if (cet.getAvailableStorages().contains(DBStorageType.SQL)) {
if (cet.getSqlStorageConfiguration().isStoreAsTable()) {
final String dbTablename = SQLStorageConfiguration.getDbTablename(cet);
customTableService.remove(repository.getSqlConfigurationCode(), cet, uuid);
} else {
final CustomEntityInstance customEntityInstance = customEntityInstanceService.findByUuid(cet.getCode(), uuid);
customEntityInstanceService.remove(customEntityInstance);
}
}
if (cet.getAvailableStorages().contains(DBStorageType.NEO4J)) {
neo4jDao.removeNodeByUUID(repository.getNeo4jConfiguration().getCode(), cet.getCode(), uuid);
}
fileSystemService.delete(repository, cet, uuid);
if (!(cet.getAvailableStorages().contains(DBStorageType.SQL) && !cet.getSqlStorageConfiguration().isStoreAsTable())) {
customEntityInstanceDelete.fire(cei);
}
if (cetClassInstance != null) {
listener.postRemove(cetClassInstance);
}
// Delete binaries
fileSystemService.delete(repository, cet, uuid);
transaction.commitTransaction(repository);
} catch (Exception e) {
transaction.rollbackTransaction(e);
throw e;
}
}
use of org.neo4j.driver.v1.Values in project meveo by meveo-org.
the class CrossStorageService method find.
/**
* Retrieves entity instances
*
* @param repository Repository code
* @param cet Template of the entities to retrieve
* @param paginationConfiguration Pagination and filters
* @return list of matching entities
* @throws EntityDoesNotExistsException if data with given id can't be found
*/
@SuppressWarnings("unchecked")
public List<Map<String, Object>> find(Repository repository, CustomEntityTemplate cet, PaginationConfiguration paginationConfiguration) throws EntityDoesNotExistsException {
final Map<String, CustomFieldTemplate> fields = customFieldTemplateService.getCftsWithInheritedFields(cet);
final Set<String> actualFetchFields;
// If no pagination nor fetch fields are defined, we consider that we must fetch everything
boolean fetchAllFields = paginationConfiguration == null || paginationConfiguration.getFetchFields() == null || paginationConfiguration.getFetchFields().isEmpty();
if (fetchAllFields) {
actualFetchFields = new HashSet<>(fields.keySet());
} else {
actualFetchFields = new HashSet<>(paginationConfiguration.getFetchFields());
}
final Map<String, Set<String>> subFields = extractSubFields(actualFetchFields);
final Map<String, Object> filters = paginationConfiguration == null ? null : paginationConfiguration.getFilters();
final List<Map<String, Object>> valuesList = new ArrayList<>();
// In case where only graphql query is passed, we will only use it so we won't
// fetch sql
boolean dontFetchSql = paginationConfiguration != null && paginationConfiguration.getFilters() == null && paginationConfiguration.getGraphQlQuery() != null;
boolean hasSqlFetchField = paginationConfiguration != null && actualFetchFields != null && actualFetchFields.stream().anyMatch(s -> customTableService.sqlCftFilter(cet, s));
boolean hasSqlFilter = paginationConfiguration != null && paginationConfiguration.getFilters() != null && filters.keySet().stream().anyMatch(s -> customTableService.sqlCftFilter(cet, s));
// Make sure the filters matches the fields
if (filters != null) {
filters.keySet().forEach(key -> {
String[] fieldInfo = key.split(" ");
String fieldName = fieldInfo.length == 1 ? fieldInfo[0] : fieldInfo[1];
if (fields.get(fieldName) == null && !"uuid".equals(fieldName) && !("code".equals(fieldName) && cet.getAvailableStorages().contains(DBStorageType.SQL) && !cet.getSqlStorageConfiguration().isStoreAsTable())) {
throw new IllegalArgumentException("Filter " + key + " does not match fields of " + cet.getCode());
}
});
}
// Collect initial data
if (cet.getAvailableStorages() != null && cet.getAvailableStorages().contains(DBStorageType.SQL) && !dontFetchSql && (fetchAllFields || hasSqlFetchField || hasSqlFilter)) {
PaginationConfiguration sqlPaginationConfiguration = new PaginationConfiguration(paginationConfiguration);
sqlPaginationConfiguration.setFetchFields(List.copyOf(actualFetchFields));
if (cet.getSqlStorageConfiguration().isStoreAsTable()) {
final List<Map<String, Object>> values = customTableService.list(repository.getSqlConfigurationCode(), cet, sqlPaginationConfiguration);
values.forEach(v -> replaceKeys(cet, actualFetchFields, v));
valuesList.addAll(values);
} else {
final List<CustomEntityInstance> ceis = customEntityInstanceService.list(cet.getCode(), cet.isStoreAsTable(), filters, sqlPaginationConfiguration);
final List<Map<String, Object>> values = new ArrayList<>();
for (CustomEntityInstance cei : ceis) {
Map<String, Object> cfValuesAsValues = cei.getCfValuesAsValues();
final Map<String, Object> map = cfValuesAsValues == null ? new HashMap<>() : new HashMap<>(cfValuesAsValues);
map.put("uuid", cei.getUuid());
map.put("code", cei.getCode());
map.put("description", cei.getDescription());
if (!fetchAllFields) {
for (String k : cei.getCfValuesAsValues().keySet()) {
if (!actualFetchFields.contains(k)) {
map.remove(k);
}
}
}
values.add(map);
}
valuesList.addAll(values);
}
}
if (cet.getAvailableStorages() != null && cet.getAvailableStorages().contains(DBStorageType.NEO4J)) {
String graphQlQuery;
Map<String, Object> graphQlVariables = new HashMap<>();
// Find by graphql if query provided
if (paginationConfiguration != null && paginationConfiguration.getGraphQlQuery() != null) {
graphQlQuery = paginationConfiguration.getGraphQlQuery();
graphQlQuery = graphQlQuery.replaceAll("([\\w)]\\s*\\{)(\\s*\\w*)", "$1meveo_uuid,$2");
} else {
graphQlQuery = generateGraphQlFromPagination(cet.getCode(), paginationConfiguration, actualFetchFields, filters, subFields).toString();
}
// Check if filters contains a field not stored in Neo4J
var dontFilterOnNeo4J = filters != null && filters.keySet().stream().anyMatch(f -> fields.get(f) != null && !fields.get(f).getStorages().contains(DBStorageType.NEO4J));
Map<String, Object> result = null;
if (!dontFilterOnNeo4J && repository.getNeo4jConfiguration() != null) {
result = neo4jDao.executeGraphQLQuery(repository.getNeo4jConfiguration().getCode(), graphQlQuery, null, null);
}
if (result != null) {
List<Map<String, Object>> values = (List<Map<String, Object>>) result.get(cet.getCode());
values = values != null ? values : new ArrayList<>();
values.forEach(map -> {
final HashMap<String, Object> resultMap = new HashMap<>(map);
map.forEach((key, mapValue) -> {
if (!key.equals("uuid") && !key.equals("meveo_uuid") && actualFetchFields != null && !actualFetchFields.contains(key)) {
resultMap.remove(key);
}
// and optionally "meveo_uuid" attribute)
if (mapValue instanceof Map && ((Map<?, ?>) mapValue).size() == 1 && ((Map<?, ?>) mapValue).containsKey("value")) {
Object value = ((Map<?, ?>) mapValue).get("value");
resultMap.put(key, value);
} else if (mapValue instanceof Map && ((Map<?, ?>) mapValue).size() == 2 && ((Map<?, ?>) mapValue).containsKey("value") && ((Map<?, ?>) mapValue).containsKey("meveo_uuid")) {
Object value = ((Map<?, ?>) mapValue).get("value");
resultMap.put(key, value);
}
});
// Rewrite "meveo_uuid" to "uuid"
if (resultMap.get("meveo_uuid") != null) {
resultMap.put("uuid", resultMap.remove("meveo_uuid"));
}
// merge the values from sql and neo4j
// valuesList.add(resultMap);
mergeData(valuesList, resultMap);
});
}
}
// Complete missing data
for (Map<String, Object> data : valuesList) {
String uuid = (String) (data.get("uuid") != null ? data.get("uuid") : data.get("meveo_uuid"));
final Map<String, Object> missingData = getMissingData(data, repository, cet, uuid, actualFetchFields, subFields);
if (missingData != null) {
data.putAll(missingData);
}
}
return valuesList.stream().map(values -> deserializeData(values, fields.values())).collect(Collectors.toList());
}
Aggregations