diff --git a/CoreAnalyticSchema/src/au/gov/asd/tac/constellation/graph/schema/analytic/attribute/objects/ContractedCompositeNodeState.java b/CoreAnalyticSchema/src/au/gov/asd/tac/constellation/graph/schema/analytic/attribute/objects/ContractedCompositeNodeState.java index e73379fc52..4dec73c5ad 100644 --- a/CoreAnalyticSchema/src/au/gov/asd/tac/constellation/graph/schema/analytic/attribute/objects/ContractedCompositeNodeState.java +++ b/CoreAnalyticSchema/src/au/gov/asd/tac/constellation/graph/schema/analytic/attribute/objects/ContractedCompositeNodeState.java @@ -130,7 +130,7 @@ public List expand(final GraphWriteMethods wg, final int vxId) { // Add the now complete expanded composite node store to the graph (do not initialise or complete with schema) final Map vertexMap = new HashMap<>(); - final List expandedVerts = GraphRecordStoreUtilities.addRecordStoreToGraph(wg, addToGraphStore, false, false, null, vertexMap, null); + final List expandedVerts = GraphRecordStoreUtilities.addRecordStoreToGraph(wg, addToGraphStore, false, false, null, vertexMap, null, true); // Create the expanded composite state for each expanded node and add it to those nodes. vertexMap.entrySet().forEach(entry -> { diff --git a/CoreAnalyticSchema/src/au/gov/asd/tac/constellation/graph/schema/analytic/attribute/objects/ExpandedCompositeNodeState.java b/CoreAnalyticSchema/src/au/gov/asd/tac/constellation/graph/schema/analytic/attribute/objects/ExpandedCompositeNodeState.java index 63d0083cbb..c34272a4a5 100644 --- a/CoreAnalyticSchema/src/au/gov/asd/tac/constellation/graph/schema/analytic/attribute/objects/ExpandedCompositeNodeState.java +++ b/CoreAnalyticSchema/src/au/gov/asd/tac/constellation/graph/schema/analytic/attribute/objects/ExpandedCompositeNodeState.java @@ -189,7 +189,7 @@ public int contract(final GraphWriteMethods wg) { // Add all the transactions between the expanded nodes to the expansion record store // Add the contraction record store to the graph, which creates the composite node and all its relevant transactions - int contractedVert = GraphRecordStoreUtilities.addRecordStoreToGraph(wg, addToGraphStore, false, false, null).get(0); + int contractedVert = GraphRecordStoreUtilities.addRecordStoreToGraph(wg, addToGraphStore, false, false, null, true).get(0); // Set the x,y,z and composite node state for the newly added composite node. wg.setFloatValue(xAttr, contractedVert, x); diff --git a/CoreArrangementPlugins/src/au/gov/asd/tac/constellation/plugins/arrangements/subgraph/ComponentSubgraph.java b/CoreArrangementPlugins/src/au/gov/asd/tac/constellation/plugins/arrangements/subgraph/ComponentSubgraph.java index 4e49ca5150..044cb09e58 100644 --- a/CoreArrangementPlugins/src/au/gov/asd/tac/constellation/plugins/arrangements/subgraph/ComponentSubgraph.java +++ b/CoreArrangementPlugins/src/au/gov/asd/tac/constellation/plugins/arrangements/subgraph/ComponentSubgraph.java @@ -809,4 +809,14 @@ public Class getAttributeDataType(final int attr public Object getAttributeDefaultValue(final int attribute) { return proxy.getAttributeDefaultValue(attribute); } + + @Override + public int addTransaction(int sourceVertex, int destinationVertex, boolean directed, boolean isFromComposite) { + throw new UnsupportedOperationException("Not supported yet."); // Generated from nbfs://nbhost/SystemFileSystem/Templates/Classes/Code/GeneratedMethodBody + } + + @Override + public int addTransaction(int transaction, int sourceVertex, int destinationVertex, boolean directed, boolean isFromComposite) { + throw new UnsupportedOperationException("Not supported yet."); // Generated from nbfs://nbhost/SystemFileSystem/Templates/Classes/Code/GeneratedMethodBody + } } diff --git a/CoreDataAccessView/src/au/gov/asd/tac/constellation/views/dataaccess/templates/WorkflowQueryPlugin.java b/CoreDataAccessView/src/au/gov/asd/tac/constellation/views/dataaccess/templates/WorkflowQueryPlugin.java index 375fc517cb..5baaa9774b 100644 --- a/CoreDataAccessView/src/au/gov/asd/tac/constellation/views/dataaccess/templates/WorkflowQueryPlugin.java +++ b/CoreDataAccessView/src/au/gov/asd/tac/constellation/views/dataaccess/templates/WorkflowQueryPlugin.java @@ -128,7 +128,7 @@ protected void execute(final PluginGraphs pluginGraphs, final PluginInteraction } } - GraphRecordStoreUtilities.addRecordStoreToGraph(batchGraph, batch, true, true, null, vertexMap, transactionMap); + GraphRecordStoreUtilities.addRecordStoreToGraph(batchGraph, batch, true, true, null, vertexMap, transactionMap, false); final WorkerQueryPlugin worker = new WorkerQueryPlugin(getWorkflow(), batchGraph, exceptions, getErrorHandlingPlugin(), addPartialResults()); workerPlugins.add(workflowExecutor.submit(() -> { final ThreadConstraints workerConstraints = ThreadConstraints.getConstraints(); diff --git a/CoreGraphFramework/src/au/gov/asd/tac/constellation/graph/GraphWriteMethods.java b/CoreGraphFramework/src/au/gov/asd/tac/constellation/graph/GraphWriteMethods.java index 244aa415a9..34a2f7a19d 100644 --- a/CoreGraphFramework/src/au/gov/asd/tac/constellation/graph/GraphWriteMethods.java +++ b/CoreGraphFramework/src/au/gov/asd/tac/constellation/graph/GraphWriteMethods.java @@ -214,6 +214,46 @@ public interface GraphWriteMethods extends GraphReadMethods { */ int addTransaction(final int transaction, final int sourceVertex, final int destinationVertex, final boolean directed); + + int addTransaction(final int sourceVertex, final int destinationVertex, final boolean directed, final boolean isFromComposite); + + /** + * Adds a new transaction to the graph. + *

+ * The new transaction will be given a new id that is both currently unused + * and also less than the graph's transaction capacity. If the graph's + * transaction capacity is exhausted then the capacity will be increased so + * that the new transaction can be accommodated. + *

+ * If this is the first transaction to be added between these two vertices + * then a new link will also be created to hold the transaction. If the + * transaction is the first in its link with this direction then a new edge + * will also be created to represent the transaction. + *

+ * If the new transaction is a loop (source and destination vertices the + * same), then a directed transaction will have an uphill edge but not a + * downhill edge. + *

+ * If the transaction is undirected, the source and destination vertices may + * be swapped to ensure that the source vertex id is not greater than the + * destination vertex id. This ensures that all undirected transactions are + * represented by the uphill edge. + *

+ * If a primary key has been set on transaction in the graph, it is + * important that this new transaction be allocated unique primary key + * attribute values before the changes are committed to the graph or + * automatic transaction merging may occur. + * + * @param transaction the id to be given to the transaction + * @param sourceVertex the vertex from which the transaction originates. + * @param destinationVertex the vertex at which the transaction terminates. + * @param directed specifies whether or not the transaction is directed or + * undirected. + * @param isFromComposite + * @return the id of the new transaction. + */ + int addTransaction(final int transaction, final int sourceVertex, final int destinationVertex, final boolean directed, final boolean isFromComposite); + /** * Removes the specified transaction from the graph. If this is the last * transaction represented by an edge then the edge will also be removed. diff --git a/CoreGraphFramework/src/au/gov/asd/tac/constellation/graph/StoreGraph.java b/CoreGraphFramework/src/au/gov/asd/tac/constellation/graph/StoreGraph.java index 8d2710160c..ea4abe5a32 100644 --- a/CoreGraphFramework/src/au/gov/asd/tac/constellation/graph/StoreGraph.java +++ b/CoreGraphFramework/src/au/gov/asd/tac/constellation/graph/StoreGraph.java @@ -778,13 +778,23 @@ private int calculateHash(final int lowVertex, final int highVertex) { return (lowVertex * 11 + highVertex * 117) & linkHashMask; } + @Override + public int addTransaction(int transaction, int sourceVertex, int destinationVertex, final boolean directed) { + return addTransaction(transaction, sourceVertex, destinationVertex, directed, false); + } + @Override public int addTransaction(final int sourceVertex, final int destinationVertex, final boolean directed) { - return addTransaction(-1, sourceVertex, destinationVertex, directed); + return addTransaction(-1, sourceVertex, destinationVertex, directed, false); + } + + @Override + public int addTransaction(final int sourceVertex, final int destinationVertex, final boolean directed, final boolean isFromComposite) { + return addTransaction(-1, sourceVertex, destinationVertex, directed, isFromComposite); } @Override - public int addTransaction(int transaction, int sourceVertex, int destinationVertex, final boolean directed) { + public int addTransaction(int transaction, int sourceVertex, int destinationVertex, final boolean directed, final boolean isFromComposite) { // Ensure that the source vertex exists if (!vStore.elementExists(sourceVertex)) { throw new IllegalArgumentException("Attempt to create transaction from source vertex that does not exist: " + sourceVertex); @@ -822,7 +832,7 @@ public int addTransaction(int transaction, int sourceVertex, int destinationVert final int destinationDirection; if (sourceVertex <= destinationVertex) { lowVertex = sourceVertex; - highVertex = destinationVertex; + highVertex = destinationVertex; if (directed) { lowDirection = OUTGOING; highDirection = INCOMING; @@ -843,8 +853,10 @@ public int addTransaction(int transaction, int sourceVertex, int destinationVert } else { lowDirection = highDirection = UNDIRECTED; sourceDirection = destinationDirection = UNDIRECTED; - sourceVertex = lowVertex; - destinationVertex = highVertex; + if (!isFromComposite) { + sourceVertex = lowVertex; + destinationVertex = highVertex; + } } } @@ -919,7 +931,8 @@ public int addTransaction(int transaction, int sourceVertex, int destinationVert addElementToIndices(GraphElementType.TRANSACTION, transaction); if (graphEdit != null) { - graphEdit.addTransaction(sourceVertex, destinationVertex, directed, transaction); + final boolean newDirected = isFromComposite ? true : directed; + graphEdit.addTransaction(sourceVertex, destinationVertex, newDirected, transaction); } return transaction; diff --git a/CoreGraphFramework/src/au/gov/asd/tac/constellation/graph/processing/GraphRecordStoreUtilities.java b/CoreGraphFramework/src/au/gov/asd/tac/constellation/graph/processing/GraphRecordStoreUtilities.java index d2c2dfe8af..ab77e185df 100644 --- a/CoreGraphFramework/src/au/gov/asd/tac/constellation/graph/processing/GraphRecordStoreUtilities.java +++ b/CoreGraphFramework/src/au/gov/asd/tac/constellation/graph/processing/GraphRecordStoreUtilities.java @@ -212,7 +212,7 @@ private static int getVertex(final GraphWriteMethods graph, final String id, fin private static int addTransaction(final GraphWriteMethods graph, final int source, final int destination, final Map values, final Map transactionMap, - final boolean initializeWithSchema, boolean completeWithSchema) { + final boolean initializeWithSchema, boolean completeWithSchema, boolean isFromComposite) { final String type = values.get(TYPE_KEY); final String directedValue = values.get(DIRECTED_KEY); boolean directed = true; @@ -237,7 +237,7 @@ private static int addTransaction(final GraphWriteMethods graph, final int sourc } final String idValue = values.remove(ID); - final int transaction = getTransaction(graph, idValue, source, destination, directed, transactionMap, initializeWithSchema); + final int transaction = getTransaction(graph, idValue, source, destination, directed, transactionMap, initializeWithSchema, isFromComposite); if (values.remove(DELETE_KEY) != null) { graph.removeTransaction(transaction); @@ -259,7 +259,7 @@ private static int addTransaction(final GraphWriteMethods graph, final int sourc private static int getTransaction(final GraphWriteMethods graph, final String id, final int source, final int destination, final boolean directed, final Map transactionMap, - final boolean initializeWithSchema) { + final boolean initializeWithSchema, final boolean isFromComposite) { if (StringUtils.isNotBlank(id)) { try { final Integer transaction = Integer.valueOf(id); @@ -269,7 +269,7 @@ private static int getTransaction(final GraphWriteMethods graph, final String id } catch (final NumberFormatException ex) { // it's a non-integer id being passed but that's ok, continue on } - + // using earlier created transactions map to check if transaction has been created Integer transaction = transactionMap.get(id); if (transaction != null) { if (graph.transactionExists(transaction)) { @@ -279,11 +279,12 @@ private static int getTransaction(final GraphWriteMethods graph, final String id } // if we hit here, we are likely trying to copy a transaction from another graph including its original id // calling addTransaction ensures the graph has capacity to handle the id + // Set to directed, then restore it after addTransaction transaction = graph.addTransaction(transaction, source, destination, directed); } else if (source == NO_ELEMENT || destination == NO_ELEMENT) { return NO_ELEMENT; } else { - transaction = graph.addTransaction(source, destination, directed); + transaction = graph.addTransaction(source, destination, directed, isFromComposite); transactionMap.put(id, transaction); } @@ -372,7 +373,12 @@ private static void copyValues(final GraphWriteMethods graph, final GraphElement */ public static List addRecordStoreToGraph(final GraphWriteMethods graph, final RecordStore recordStore, final boolean initializeWithSchema, final boolean completeWithSchema, final List vertexIdAttributes) { - return addRecordStoreToGraph(graph, recordStore, initializeWithSchema, completeWithSchema, vertexIdAttributes, null, null); + return addRecordStoreToGraph(graph, recordStore, initializeWithSchema, completeWithSchema, vertexIdAttributes, null, null, false); + } + + public static List addRecordStoreToGraph(final GraphWriteMethods graph, final RecordStore recordStore, + final boolean initializeWithSchema, final boolean completeWithSchema, final List vertexIdAttributes, final boolean isFromComposite) { + return addRecordStoreToGraph(graph, recordStore, initializeWithSchema, completeWithSchema, vertexIdAttributes, null, null, isFromComposite); } /** @@ -391,11 +397,12 @@ public static List addRecordStoreToGraph(final GraphWriteMethods graph, * @param transactionMap A map which will be populated with the mappings from transaction id in the * {@link RecordStore} (or created transaction id if no id was provided in the {@link RecordStore}) to transaction * id on the graph. + * @param isFromComposite An indicator that this function was called when compositing is happening. * @return A {@link List} of {@link Integer} objects representing the vertex id's of the newly added vertices. */ public static List addRecordStoreToGraph(final GraphWriteMethods graph, final RecordStore recordStore, final boolean initializeWithSchema, final boolean completeWithSchema, final List vertexIdAttributes, - Map vertexMap, Map transactionMap) { + Map vertexMap, Map transactionMap, final boolean isFromComposite) { final List newVertices = new ArrayList<>(); final Set ghostVertices = new HashSet<>(); @@ -446,11 +453,11 @@ public static List addRecordStoreToGraph(final GraphWriteMethods graph, if (sourceValues.isEmpty() && destinationValues.isEmpty() && transactionValues.containsKey(ID)) { // This will not add a new transaction to the graph (as source and destination are both -1), but if the transaction exists already it will be returned allowing it to be selected. - addTransaction(graph, NO_ELEMENT, NO_ELEMENT, transactionValues, transactionMap, initializeWithSchema, completeWithSchema); + addTransaction(graph, NO_ELEMENT, NO_ELEMENT, transactionValues, transactionMap, initializeWithSchema, completeWithSchema, isFromComposite); } else if (!sourceValues.isEmpty() && !destinationValues.isEmpty()) { final int source = addVertex(graph, sourceValues, vertexMap, initializeWithSchema, completeWithSchema, newVertices, ghostVertices, vertexIdAttributes); final int destination = addVertex(graph, destinationValues, vertexMap, initializeWithSchema, completeWithSchema, newVertices, ghostVertices, vertexIdAttributes); - addTransaction(graph, source, destination, transactionValues, transactionMap, initializeWithSchema, completeWithSchema); + addTransaction(graph, source, destination, transactionValues, transactionMap, initializeWithSchema, completeWithSchema, isFromComposite); } else if (!sourceValues.isEmpty()) { addVertex(graph, sourceValues, vertexMap, initializeWithSchema, completeWithSchema, newVertices, ghostVertices, vertexIdAttributes); } else if (!destinationValues.isEmpty()) { diff --git a/CoreGraphFramework/test/unit/src/au/gov/asd/tac/constellation/graph/StoreGraphValidator.java b/CoreGraphFramework/test/unit/src/au/gov/asd/tac/constellation/graph/StoreGraphValidator.java index c228777324..f77db2c0aa 100644 --- a/CoreGraphFramework/test/unit/src/au/gov/asd/tac/constellation/graph/StoreGraphValidator.java +++ b/CoreGraphFramework/test/unit/src/au/gov/asd/tac/constellation/graph/StoreGraphValidator.java @@ -352,6 +352,16 @@ public Object getAttributeDefaultValue(int attribute) { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } + @Override + public int addTransaction(int sourceVertex, int destinationVertex, boolean directed, boolean isFromComposite) { + throw new UnsupportedOperationException("Not supported yet."); // Generated from nbfs://nbhost/SystemFileSystem/Templates/Classes/Code/GeneratedMethodBody + } + + @Override + public int addTransaction(int transaction, int sourceVertex, int destinationVertex, boolean directed, boolean isFromComposite) { + throw new UnsupportedOperationException("Not supported yet."); // Generated from nbfs://nbhost/SystemFileSystem/Templates/Classes/Code/GeneratedMethodBody + } + private class Vertex { private int id; diff --git a/CoreGraphFramework/test/unit/src/au/gov/asd/tac/constellation/graph/processing/GraphRecordStoreUtilitiesNGTest.java b/CoreGraphFramework/test/unit/src/au/gov/asd/tac/constellation/graph/processing/GraphRecordStoreUtilitiesNGTest.java index 2356979599..f2513c1a4c 100644 --- a/CoreGraphFramework/test/unit/src/au/gov/asd/tac/constellation/graph/processing/GraphRecordStoreUtilitiesNGTest.java +++ b/CoreGraphFramework/test/unit/src/au/gov/asd/tac/constellation/graph/processing/GraphRecordStoreUtilitiesNGTest.java @@ -242,7 +242,7 @@ public void addRecordStoreToGraphWithAnEmptyRecordStore() { final Map vertexMap = new HashMap<>(); final Map transactionMap = new HashMap<>(); - final List veritices = GraphRecordStoreUtilities.addRecordStoreToGraph(newGraph, recordStore, initializeWithSchema, completeWithSchema, vertexIdAttributes, vertexMap, transactionMap); + final List veritices = GraphRecordStoreUtilities.addRecordStoreToGraph(newGraph, recordStore, initializeWithSchema, completeWithSchema, vertexIdAttributes, vertexMap, transactionMap, false); assertEquals(veritices.size(), 0); } @@ -263,7 +263,7 @@ public void addRecordStoreToGraphWithTransactionsInBothDirections() { final Map vertexMap = new HashMap<>(); final Map transactionMap = new HashMap<>(); - final List veritices = GraphRecordStoreUtilities.addRecordStoreToGraph(newGraph, recordStore, initializeWithSchema, completeWithSchema, vertexIdAttributes, vertexMap, transactionMap); + final List veritices = GraphRecordStoreUtilities.addRecordStoreToGraph(newGraph, recordStore, initializeWithSchema, completeWithSchema, vertexIdAttributes, vertexMap, transactionMap, false); assertEquals(2, veritices.size()); assertEquals(2, newGraph.getVertexCount()); assertEquals(2, newGraph.getTransactionCount());