mirror of
https://github.com/Kingsrook/qqq.git
synced 2025-07-18 13:10:44 +00:00
Manage associations in UpdateAction
This commit is contained in:
@ -23,15 +23,22 @@ package com.kingsrook.qqq.backend.core.actions.tables;
|
|||||||
|
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
import com.kingsrook.qqq.backend.core.actions.ActionHelper;
|
import com.kingsrook.qqq.backend.core.actions.ActionHelper;
|
||||||
import com.kingsrook.qqq.backend.core.actions.audits.DMLAuditAction;
|
import com.kingsrook.qqq.backend.core.actions.audits.DMLAuditAction;
|
||||||
import com.kingsrook.qqq.backend.core.actions.automation.AutomationStatus;
|
import com.kingsrook.qqq.backend.core.actions.automation.AutomationStatus;
|
||||||
import com.kingsrook.qqq.backend.core.actions.automation.RecordAutomationStatusUpdater;
|
import com.kingsrook.qqq.backend.core.actions.automation.RecordAutomationStatusUpdater;
|
||||||
import com.kingsrook.qqq.backend.core.actions.values.ValueBehaviorApplier;
|
import com.kingsrook.qqq.backend.core.actions.values.ValueBehaviorApplier;
|
||||||
|
import com.kingsrook.qqq.backend.core.context.QContext;
|
||||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||||
import com.kingsrook.qqq.backend.core.logging.QLogger;
|
import com.kingsrook.qqq.backend.core.logging.QLogger;
|
||||||
import com.kingsrook.qqq.backend.core.model.actions.audits.DMLAuditInput;
|
import com.kingsrook.qqq.backend.core.model.actions.audits.DMLAuditInput;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.actions.tables.delete.DeleteInput;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.actions.tables.delete.DeleteOutput;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.actions.tables.insert.InsertInput;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.actions.tables.insert.InsertOutput;
|
||||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QCriteriaOperator;
|
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QCriteriaOperator;
|
||||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QFilterCriteria;
|
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QFilterCriteria;
|
||||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QQueryFilter;
|
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QQueryFilter;
|
||||||
@ -41,8 +48,13 @@ import com.kingsrook.qqq.backend.core.model.actions.tables.update.UpdateInput;
|
|||||||
import com.kingsrook.qqq.backend.core.model.actions.tables.update.UpdateOutput;
|
import com.kingsrook.qqq.backend.core.model.actions.tables.update.UpdateOutput;
|
||||||
import com.kingsrook.qqq.backend.core.model.data.QRecord;
|
import com.kingsrook.qqq.backend.core.model.data.QRecord;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.audits.AuditLevel;
|
import com.kingsrook.qqq.backend.core.model.metadata.audits.AuditLevel;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.joins.JoinOn;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.joins.QJoinMetaData;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.tables.Association;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
|
||||||
import com.kingsrook.qqq.backend.core.modules.backend.QBackendModuleDispatcher;
|
import com.kingsrook.qqq.backend.core.modules.backend.QBackendModuleDispatcher;
|
||||||
import com.kingsrook.qqq.backend.core.modules.backend.QBackendModuleInterface;
|
import com.kingsrook.qqq.backend.core.modules.backend.QBackendModuleInterface;
|
||||||
|
import com.kingsrook.qqq.backend.core.utils.CollectionUtils;
|
||||||
import static com.kingsrook.qqq.backend.core.logging.LogUtils.logPair;
|
import static com.kingsrook.qqq.backend.core.logging.LogUtils.logPair;
|
||||||
|
|
||||||
|
|
||||||
@ -75,6 +87,8 @@ public class UpdateAction
|
|||||||
UpdateOutput updateResult = qModule.getUpdateInterface().execute(updateInput);
|
UpdateOutput updateResult = qModule.getUpdateInterface().execute(updateInput);
|
||||||
// todo post-customization - can do whatever w/ the result if you want
|
// todo post-customization - can do whatever w/ the result if you want
|
||||||
|
|
||||||
|
manageAssociations(updateInput);
|
||||||
|
|
||||||
if(updateInput.getOmitDmlAudit())
|
if(updateInput.getOmitDmlAudit())
|
||||||
{
|
{
|
||||||
LOG.debug("Requested to omit DML audit");
|
LOG.debug("Requested to omit DML audit");
|
||||||
@ -89,6 +103,121 @@ public class UpdateAction
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
private void manageAssociations(UpdateInput updateInput) throws QException
|
||||||
|
{
|
||||||
|
QTableMetaData table = updateInput.getTable();
|
||||||
|
for(Association association : CollectionUtils.nonNullList(table.getAssociations()))
|
||||||
|
{
|
||||||
|
// e.g., order -> orderLine
|
||||||
|
QTableMetaData associatedTable = QContext.getQInstance().getTable(association.getAssociatedTableName());
|
||||||
|
QJoinMetaData join = QContext.getQInstance().getJoin(association.getJoinName()); // todo ... ever need to flip?
|
||||||
|
// just assume this, at least for now... if(BooleanUtils.isTrue(association.getDoInserts()))
|
||||||
|
|
||||||
|
for(List<QRecord> page : CollectionUtils.getPages(updateInput.getRecords(), 500))
|
||||||
|
{
|
||||||
|
List<QRecord> nextLevelUpdates = new ArrayList<>();
|
||||||
|
List<QRecord> nextLevelInserts = new ArrayList<>();
|
||||||
|
QQueryFilter findDeletesFilter = new QQueryFilter().withBooleanOperator(QQueryFilter.BooleanOperator.OR);
|
||||||
|
boolean lookForDeletes = false;
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////
|
||||||
|
// for each updated record, look at as associations //
|
||||||
|
//////////////////////////////////////////////////////
|
||||||
|
for(QRecord record : page)
|
||||||
|
{
|
||||||
|
if(record.getAssociatedRecords() != null && record.getAssociatedRecords().containsKey(association.getName()))
|
||||||
|
{
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// build a sub-query to find the children of this record - and we'll exclude (below) any whose ids are given //
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
QQueryFilter subFilter = new QQueryFilter();
|
||||||
|
findDeletesFilter.addSubFilter(subFilter);
|
||||||
|
lookForDeletes = true;
|
||||||
|
List<Serializable> idsBeingUpdated = new ArrayList<>();
|
||||||
|
for(JoinOn joinOn : join.getJoinOns())
|
||||||
|
{
|
||||||
|
subFilter.addCriteria(new QFilterCriteria(joinOn.getRightField(), QCriteriaOperator.EQUALS, record.getValue(joinOn.getLeftField())));
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// for any associated records present here, figure out if they're being inserted (no primaryKey) or updated //
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
for(QRecord associatedRecord : CollectionUtils.nonNullList(record.getAssociatedRecords().get(association.getName())))
|
||||||
|
{
|
||||||
|
Serializable associatedId = associatedRecord.getValue(associatedTable.getPrimaryKeyField());
|
||||||
|
if(associatedId == null)
|
||||||
|
{
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// if inserting, add to the inserts list, and propagate values from the header record down to the child //
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
for(JoinOn joinOn : join.getJoinOns())
|
||||||
|
{
|
||||||
|
associatedRecord.setValue(joinOn.getRightField(), record.getValue(joinOn.getLeftField()));
|
||||||
|
}
|
||||||
|
nextLevelInserts.add(associatedRecord);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// if updating, add to the updates list, and add the id as one to not delete //
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
idsBeingUpdated.add(associatedId);
|
||||||
|
nextLevelUpdates.add(associatedRecord);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!idsBeingUpdated.isEmpty())
|
||||||
|
{
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// if any records are being updated, add them to the query to NOT be deleted //
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
subFilter.addCriteria(new QFilterCriteria(associatedTable.getPrimaryKeyField(), QCriteriaOperator.NOT_IN, idsBeingUpdated));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(lookForDeletes)
|
||||||
|
{
|
||||||
|
QueryInput queryInput = new QueryInput();
|
||||||
|
queryInput.setTableName(associatedTable.getName());
|
||||||
|
queryInput.setFilter(findDeletesFilter);
|
||||||
|
QueryOutput queryOutput = new QueryAction().execute(queryInput);
|
||||||
|
if(!queryOutput.getRecords().isEmpty())
|
||||||
|
{
|
||||||
|
LOG.debug("Deleting associatedRecords", logPair("associatedTable", associatedTable.getName()), logPair("noOfRecords", queryOutput.getRecords().size()));
|
||||||
|
DeleteInput deleteInput = new DeleteInput();
|
||||||
|
deleteInput.setTableName(association.getAssociatedTableName());
|
||||||
|
deleteInput.setPrimaryKeys(queryOutput.getRecords().stream().map(r -> r.getValue(associatedTable.getPrimaryKeyField())).collect(Collectors.toList()));
|
||||||
|
DeleteOutput deleteOutput = new DeleteAction().execute(deleteInput);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(CollectionUtils.nullSafeHasContents(nextLevelUpdates))
|
||||||
|
{
|
||||||
|
LOG.debug("Updating associatedRecords", logPair("associatedTable", associatedTable.getName()), logPair("noOfRecords", nextLevelUpdates.size()));
|
||||||
|
UpdateInput nextLevelUpdateInput = new UpdateInput();
|
||||||
|
nextLevelUpdateInput.setTableName(association.getAssociatedTableName());
|
||||||
|
nextLevelUpdateInput.setRecords(nextLevelUpdates);
|
||||||
|
UpdateOutput nextLevelUpdateOutput = new UpdateAction().execute(nextLevelUpdateInput);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(CollectionUtils.nullSafeHasContents(nextLevelInserts))
|
||||||
|
{
|
||||||
|
LOG.debug("Inserting associatedRecords", logPair("associatedTable", associatedTable.getName()), logPair("noOfRecords", nextLevelUpdates.size()));
|
||||||
|
InsertInput nextLevelInsertInput = new InsertInput();
|
||||||
|
nextLevelInsertInput.setTableName(association.getAssociatedTableName());
|
||||||
|
nextLevelInsertInput.setRecords(nextLevelInserts);
|
||||||
|
InsertOutput nextLevelInsertOutput = new InsertAction().execute(nextLevelInsertInput);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
**
|
**
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
|
@ -25,12 +25,18 @@ package com.kingsrook.qqq.backend.core.actions.tables;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import com.kingsrook.qqq.backend.core.BaseTest;
|
import com.kingsrook.qqq.backend.core.BaseTest;
|
||||||
|
import com.kingsrook.qqq.backend.core.context.QContext;
|
||||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.actions.tables.insert.InsertInput;
|
||||||
import com.kingsrook.qqq.backend.core.model.actions.tables.update.UpdateInput;
|
import com.kingsrook.qqq.backend.core.model.actions.tables.update.UpdateInput;
|
||||||
import com.kingsrook.qqq.backend.core.model.actions.tables.update.UpdateOutput;
|
import com.kingsrook.qqq.backend.core.model.actions.tables.update.UpdateOutput;
|
||||||
import com.kingsrook.qqq.backend.core.model.data.QRecord;
|
import com.kingsrook.qqq.backend.core.model.data.QRecord;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
||||||
|
import com.kingsrook.qqq.backend.core.utils.TestUtils;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
@ -60,4 +66,271 @@ class UpdateActionTest extends BaseTest
|
|||||||
assertNotNull(result);
|
assertNotNull(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Test
|
||||||
|
void testUpdateAssociationsUpdateOneChild() throws QException
|
||||||
|
{
|
||||||
|
QInstance qInstance = QContext.getQInstance();
|
||||||
|
QContext.getQSession().withSecurityKeyValue("storeId", 1);
|
||||||
|
|
||||||
|
insert2OrdersWith3Lines3LineExtrinsicsAnd4OrderExtrinsicAssociations();
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
// update the order's orderNo, and the quantity on one of the lines //
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
UpdateInput updateInput = new UpdateInput();
|
||||||
|
updateInput.setTableName(TestUtils.TABLE_NAME_ORDER);
|
||||||
|
updateInput.setRecords(List.of(
|
||||||
|
new QRecord().withValue("id", 1).withValue("orderNo", "ORD123-b")
|
||||||
|
.withAssociatedRecord("orderLine", new QRecord().withValue("id", 1).withValue("quantity", 17))
|
||||||
|
.withAssociatedRecord("orderLine", new QRecord().withValue("id", 2))
|
||||||
|
));
|
||||||
|
new UpdateAction().execute(updateInput);
|
||||||
|
|
||||||
|
List<QRecord> orders = TestUtils.queryTable(qInstance, TestUtils.TABLE_NAME_ORDER);
|
||||||
|
assertEquals(2, orders.size());
|
||||||
|
assertEquals("ORD123-b", orders.get(0).getValueString("orderNo"));
|
||||||
|
|
||||||
|
List<QRecord> orderLines = TestUtils.queryTable(qInstance, TestUtils.TABLE_NAME_LINE_ITEM);
|
||||||
|
assertEquals(3, orderLines.size());
|
||||||
|
assertEquals(17, orderLines.get(0).getValueInteger("quantity"));
|
||||||
|
|
||||||
|
List<QRecord> lineItemExtrinsics = TestUtils.queryTable(qInstance, TestUtils.TABLE_NAME_LINE_ITEM_EXTRINSIC);
|
||||||
|
assertEquals(3, lineItemExtrinsics.size());
|
||||||
|
|
||||||
|
List<QRecord> orderExtrinsics = TestUtils.queryTable(qInstance, TestUtils.TABLE_NAME_ORDER_EXTRINSIC);
|
||||||
|
assertEquals(4, orderExtrinsics.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Test
|
||||||
|
void testUpdateAssociationsUpdateOneGrandChild() throws QException
|
||||||
|
{
|
||||||
|
QInstance qInstance = QContext.getQInstance();
|
||||||
|
QContext.getQSession().withSecurityKeyValue("storeId", 1);
|
||||||
|
|
||||||
|
insert2OrdersWith3Lines3LineExtrinsicsAnd4OrderExtrinsicAssociations();
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
// update the order's orderNo, and the quantity on one of the lines //
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
UpdateInput updateInput = new UpdateInput();
|
||||||
|
updateInput.setTableName(TestUtils.TABLE_NAME_ORDER);
|
||||||
|
updateInput.setRecords(List.of(
|
||||||
|
new QRecord().withValue("id", 1).withValue("orderNo", "ORD123-b")
|
||||||
|
.withAssociatedRecord("orderLine", new QRecord().withValue("id", 1)
|
||||||
|
.withAssociatedRecord("extrinsics", new QRecord().withValue("id", 1).withValue("value", "LINE-VAL-1-updated")))
|
||||||
|
.withAssociatedRecord("orderLine", new QRecord().withValue("id", 2))
|
||||||
|
));
|
||||||
|
new UpdateAction().execute(updateInput);
|
||||||
|
|
||||||
|
List<QRecord> orders = TestUtils.queryTable(qInstance, TestUtils.TABLE_NAME_ORDER);
|
||||||
|
assertEquals(2, orders.size());
|
||||||
|
assertEquals("ORD123-b", orders.get(0).getValueString("orderNo"));
|
||||||
|
|
||||||
|
List<QRecord> orderLines = TestUtils.queryTable(qInstance, TestUtils.TABLE_NAME_LINE_ITEM);
|
||||||
|
assertEquals(3, orderLines.size());
|
||||||
|
|
||||||
|
List<QRecord> lineItemExtrinsics = TestUtils.queryTable(qInstance, TestUtils.TABLE_NAME_LINE_ITEM_EXTRINSIC);
|
||||||
|
assertEquals(3, lineItemExtrinsics.size());
|
||||||
|
assertEquals("LINE-VAL-1-updated", lineItemExtrinsics.get(0).getValueString("value"));
|
||||||
|
|
||||||
|
List<QRecord> orderExtrinsics = TestUtils.queryTable(qInstance, TestUtils.TABLE_NAME_ORDER_EXTRINSIC);
|
||||||
|
assertEquals(4, orderExtrinsics.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Test
|
||||||
|
void testUpdateAssociationsDeleteOneChild() throws QException
|
||||||
|
{
|
||||||
|
QInstance qInstance = QContext.getQInstance();
|
||||||
|
QContext.getQSession().withSecurityKeyValue("storeId", 1);
|
||||||
|
|
||||||
|
insert2OrdersWith3Lines3LineExtrinsicsAnd4OrderExtrinsicAssociations();
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
// update the order's orderNo, and the quantity on one of the lines //
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
UpdateInput updateInput = new UpdateInput();
|
||||||
|
updateInput.setTableName(TestUtils.TABLE_NAME_ORDER);
|
||||||
|
updateInput.setRecords(List.of(
|
||||||
|
new QRecord().withValue("id", 1).withValue("orderNo", "ORD123-b")
|
||||||
|
.withAssociatedRecord("orderLine", new QRecord().withValue("id", 2))
|
||||||
|
));
|
||||||
|
new UpdateAction().execute(updateInput);
|
||||||
|
|
||||||
|
List<QRecord> orders = TestUtils.queryTable(qInstance, TestUtils.TABLE_NAME_ORDER);
|
||||||
|
assertEquals(2, orders.size());
|
||||||
|
assertEquals("ORD123-b", orders.get(0).getValueString("orderNo"));
|
||||||
|
|
||||||
|
List<QRecord> orderLines = TestUtils.queryTable(qInstance, TestUtils.TABLE_NAME_LINE_ITEM);
|
||||||
|
assertEquals(2, orderLines.size());
|
||||||
|
assertTrue(orderLines.stream().noneMatch(r -> r.getValueInteger("id").equals(1))); // id=1 should be deleted
|
||||||
|
|
||||||
|
List<QRecord> lineItemExtrinsics = TestUtils.queryTable(qInstance, TestUtils.TABLE_NAME_LINE_ITEM_EXTRINSIC);
|
||||||
|
assertEquals(2, lineItemExtrinsics.size()); // one was deleted (when its parent was deleted)
|
||||||
|
|
||||||
|
List<QRecord> orderExtrinsics = TestUtils.queryTable(qInstance, TestUtils.TABLE_NAME_ORDER_EXTRINSIC);
|
||||||
|
assertEquals(4, orderExtrinsics.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Test
|
||||||
|
void testUpdateAssociationsDeleteGrandchildren() throws QException
|
||||||
|
{
|
||||||
|
QInstance qInstance = QContext.getQInstance();
|
||||||
|
QContext.getQSession().withSecurityKeyValue("storeId", 1);
|
||||||
|
|
||||||
|
insert2OrdersWith3Lines3LineExtrinsicsAnd4OrderExtrinsicAssociations();
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
// update the order's orderNo, and the quantity on one of the lines //
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
UpdateInput updateInput = new UpdateInput();
|
||||||
|
updateInput.setTableName(TestUtils.TABLE_NAME_ORDER);
|
||||||
|
updateInput.setRecords(List.of(
|
||||||
|
new QRecord().withValue("id", 1).withValue("orderNo", "ORD123-b")
|
||||||
|
.withAssociatedRecord("orderLine", new QRecord().withValue("id", 1))
|
||||||
|
.withAssociatedRecord("orderLine", new QRecord().withValue("id", 2).withAssociatedRecords("extrinsics", new ArrayList<>()))
|
||||||
|
));
|
||||||
|
new UpdateAction().execute(updateInput);
|
||||||
|
|
||||||
|
List<QRecord> orders = TestUtils.queryTable(qInstance, TestUtils.TABLE_NAME_ORDER);
|
||||||
|
assertEquals(2, orders.size());
|
||||||
|
assertEquals("ORD123-b", orders.get(0).getValueString("orderNo"));
|
||||||
|
|
||||||
|
List<QRecord> orderLines = TestUtils.queryTable(qInstance, TestUtils.TABLE_NAME_LINE_ITEM);
|
||||||
|
assertEquals(3, orderLines.size());
|
||||||
|
|
||||||
|
List<QRecord> lineItemExtrinsics = TestUtils.queryTable(qInstance, TestUtils.TABLE_NAME_LINE_ITEM_EXTRINSIC);
|
||||||
|
assertEquals(1, lineItemExtrinsics.size()); // deleted the two beneath line item id=2
|
||||||
|
|
||||||
|
List<QRecord> orderExtrinsics = TestUtils.queryTable(qInstance, TestUtils.TABLE_NAME_ORDER_EXTRINSIC);
|
||||||
|
assertEquals(4, orderExtrinsics.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Test
|
||||||
|
void testUpdateAssociationsInsertOneChild() throws QException
|
||||||
|
{
|
||||||
|
QInstance qInstance = QContext.getQInstance();
|
||||||
|
QContext.getQSession().withSecurityKeyValue("storeId", 1);
|
||||||
|
|
||||||
|
insert2OrdersWith3Lines3LineExtrinsicsAnd4OrderExtrinsicAssociations();
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
// update the order's orderNo, and the quantity on one of the lines //
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
UpdateInput updateInput = new UpdateInput();
|
||||||
|
updateInput.setTableName(TestUtils.TABLE_NAME_ORDER);
|
||||||
|
updateInput.setRecords(List.of(
|
||||||
|
new QRecord().withValue("id", 1).withValue("orderNo", "ORD123-b")
|
||||||
|
.withAssociatedRecord("orderLine", new QRecord().withValue("id", 1))
|
||||||
|
.withAssociatedRecord("orderLine", new QRecord().withValue("id", 2))
|
||||||
|
.withAssociatedRecord("orderLine", new QRecord().withValue("sku", "BASIC4").withValue("quantity", 47))
|
||||||
|
));
|
||||||
|
new UpdateAction().execute(updateInput);
|
||||||
|
|
||||||
|
List<QRecord> orders = TestUtils.queryTable(qInstance, TestUtils.TABLE_NAME_ORDER);
|
||||||
|
assertEquals(2, orders.size());
|
||||||
|
assertEquals("ORD123-b", orders.get(0).getValueString("orderNo"));
|
||||||
|
|
||||||
|
List<QRecord> orderLines = TestUtils.queryTable(qInstance, TestUtils.TABLE_NAME_LINE_ITEM);
|
||||||
|
assertEquals(4, orderLines.size());
|
||||||
|
assertEquals("BASIC4", orderLines.get(3).getValueString("sku"));
|
||||||
|
assertEquals(47, orderLines.get(3).getValueInteger("quantity"));
|
||||||
|
|
||||||
|
List<QRecord> lineItemExtrinsics = TestUtils.queryTable(qInstance, TestUtils.TABLE_NAME_LINE_ITEM_EXTRINSIC);
|
||||||
|
assertEquals(3, lineItemExtrinsics.size());
|
||||||
|
|
||||||
|
List<QRecord> orderExtrinsics = TestUtils.queryTable(qInstance, TestUtils.TABLE_NAME_ORDER_EXTRINSIC);
|
||||||
|
assertEquals(4, orderExtrinsics.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Test
|
||||||
|
void testUpdateAssociationsDeleteAllChildren() throws QException
|
||||||
|
{
|
||||||
|
QInstance qInstance = QContext.getQInstance();
|
||||||
|
QContext.getQSession().withSecurityKeyValue("storeId", 1);
|
||||||
|
|
||||||
|
insert2OrdersWith3Lines3LineExtrinsicsAnd4OrderExtrinsicAssociations();
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
// update the order's orderNo, and the quantity on one of the lines //
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
UpdateInput updateInput = new UpdateInput();
|
||||||
|
updateInput.setTableName(TestUtils.TABLE_NAME_ORDER);
|
||||||
|
updateInput.setRecords(List.of(
|
||||||
|
new QRecord().withValue("id", 1).withAssociatedRecords("orderLine", new ArrayList<>()),
|
||||||
|
new QRecord().withValue("id", 2).withAssociatedRecords("orderLine", new ArrayList<>())
|
||||||
|
));
|
||||||
|
new UpdateAction().execute(updateInput);
|
||||||
|
|
||||||
|
List<QRecord> orders = TestUtils.queryTable(qInstance, TestUtils.TABLE_NAME_ORDER);
|
||||||
|
assertEquals(2, orders.size());
|
||||||
|
|
||||||
|
List<QRecord> lineItemExtrinsics = TestUtils.queryTable(qInstance, TestUtils.TABLE_NAME_LINE_ITEM_EXTRINSIC);
|
||||||
|
assertEquals(0, lineItemExtrinsics.size());
|
||||||
|
|
||||||
|
List<QRecord> orderLines = TestUtils.queryTable(qInstance, TestUtils.TABLE_NAME_LINE_ITEM);
|
||||||
|
assertEquals(0, orderLines.size()); // all of these got deleted too.
|
||||||
|
|
||||||
|
List<QRecord> orderExtrinsics = TestUtils.queryTable(qInstance, TestUtils.TABLE_NAME_ORDER_EXTRINSIC);
|
||||||
|
assertEquals(4, orderExtrinsics.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
private static void insert2OrdersWith3Lines3LineExtrinsicsAnd4OrderExtrinsicAssociations() throws QException
|
||||||
|
{
|
||||||
|
InsertInput insertInput = new InsertInput();
|
||||||
|
insertInput.setTableName(TestUtils.TABLE_NAME_ORDER);
|
||||||
|
insertInput.setRecords(List.of(
|
||||||
|
new QRecord().withValue("storeId", 1).withValue("orderNo", "ORD123")
|
||||||
|
|
||||||
|
.withAssociatedRecord("orderLine", new QRecord().withValue("sku", "BASIC1").withValue("quantity", 1)
|
||||||
|
.withAssociatedRecord("extrinsics", new QRecord().withValue("key", "LINE-EXT-1.1").withValue("value", "LINE-VAL-1")))
|
||||||
|
|
||||||
|
.withAssociatedRecord("orderLine", new QRecord().withValue("sku", "BASIC2").withValue("quantity", 2)
|
||||||
|
.withAssociatedRecord("extrinsics", new QRecord().withValue("key", "LINE-EXT-2.1").withValue("value", "LINE-VAL-2"))
|
||||||
|
.withAssociatedRecord("extrinsics", new QRecord().withValue("key", "LINE-EXT-2.2").withValue("value", "LINE-VAL-3")))
|
||||||
|
|
||||||
|
.withAssociatedRecord("extrinsics", new QRecord().withValue("key", "MY-FIELD-1").withValue("value", "MY-VALUE-1"))
|
||||||
|
.withAssociatedRecord("extrinsics", new QRecord().withValue("key", "MY-FIELD-2").withValue("value", "MY-VALUE-2"))
|
||||||
|
.withAssociatedRecord("extrinsics", new QRecord().withValue("key", "MY-FIELD-3").withValue("value", "MY-VALUE-3")),
|
||||||
|
|
||||||
|
new QRecord().withValue("storeId", 1).withValue("orderNo", "ORD124")
|
||||||
|
.withAssociatedRecord("orderLine", new QRecord().withValue("sku", "BASIC3").withValue("quantity", 3))
|
||||||
|
.withAssociatedRecord("extrinsics", new QRecord().withValue("key", "YOUR-FIELD-1").withValue("value", "YOUR-VALUE-1"))
|
||||||
|
));
|
||||||
|
new InsertAction().execute(insertInput);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user