Initial support for associated records (implemented insert, delete).

Include "api" on audit.
This commit is contained in:
2023-03-27 09:52:39 -05:00
parent 17d4c81cc3
commit ba805a4c92
15 changed files with 1052 additions and 85 deletions

View File

@ -31,7 +31,10 @@ 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.query.QCriteriaOperator;
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QFilterCriteria;
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QFilterOrderBy;
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QQueryFilter;
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryInput;
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryOutput;
import com.kingsrook.qqq.backend.core.model.audits.AuditsMetaDataProvider;
import com.kingsrook.qqq.backend.core.model.data.QRecord;
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
@ -149,4 +152,145 @@ class DeleteActionTest extends BaseTest
assertTrue(audits.stream().allMatch(r -> r.getValueString("message").equals("Record was Deleted")));
}
/*******************************************************************************
**
*******************************************************************************/
@Test
void testAssociatedDeletes() throws QException
{
{
InsertInput insertInput = new InsertInput();
insertInput.setTableName(TestUtils.TABLE_NAME_ORDER);
insertInput.setRecords(List.of(
new QRecord().withValue("id", 1),
new QRecord().withValue("id", 2),
new QRecord().withValue("id", 3)
));
new InsertAction().execute(insertInput);
}
{
InsertInput insertInput = new InsertInput();
insertInput.setTableName(TestUtils.TABLE_NAME_ORDER_EXTRINSIC);
insertInput.setRecords(List.of(
new QRecord().withValue("id", 1).withValue("orderId", 1),
new QRecord().withValue("id", 2).withValue("orderId", 1),
new QRecord().withValue("id", 3).withValue("orderId", 1),
new QRecord().withValue("id", 4).withValue("orderId", 1),
new QRecord().withValue("id", 5).withValue("orderId", 3),
new QRecord().withValue("id", 6).withValue("orderId", 3),
new QRecord().withValue("id", 7).withValue("orderId", 3)
));
new InsertAction().execute(insertInput);
}
{
InsertInput insertInput = new InsertInput();
insertInput.setTableName(TestUtils.TABLE_NAME_LINE_ITEM);
insertInput.setRecords(List.of(
new QRecord().withValue("id", 1).withValue("orderId", 1),
new QRecord().withValue("id", 2).withValue("orderId", 1),
new QRecord().withValue("id", 3).withValue("orderId", 2),
new QRecord().withValue("id", 4).withValue("orderId", 3),
new QRecord().withValue("id", 5).withValue("orderId", 3),
new QRecord().withValue("id", 6).withValue("orderId", 3)
));
new InsertAction().execute(insertInput);
}
{
InsertInput insertInput = new InsertInput();
insertInput.setTableName(TestUtils.TABLE_NAME_LINE_ITEM_EXTRINSIC);
insertInput.setRecords(List.of(
new QRecord().withValue("id", 1).withValue("lineItemId", 1), // orderId: 1
new QRecord().withValue("id", 2).withValue("lineItemId", 1), // orderId: 1
new QRecord().withValue("id", 3).withValue("lineItemId", 2), // orderId: 1
new QRecord().withValue("id", 4).withValue("lineItemId", 2), // orderId: 1
new QRecord().withValue("id", 5).withValue("lineItemId", 3), // orderId: 2
new QRecord().withValue("id", 6).withValue("lineItemId", 3), // orderId: 2
new QRecord().withValue("id", 7).withValue("lineItemId", 4), // orderId: 3
new QRecord().withValue("id", 8).withValue("lineItemId", 5), // orderId: 3
new QRecord().withValue("id", 9).withValue("lineItemId", 6) // orderId: 3
));
new InsertAction().execute(insertInput);
}
/////////////////////////////////////////////////////////
// assert about how many things we originally inserted //
/////////////////////////////////////////////////////////
assertEquals(3, queryTable(TestUtils.TABLE_NAME_ORDER).size());
assertEquals(7, queryTable(TestUtils.TABLE_NAME_ORDER_EXTRINSIC).size());
assertEquals(6, queryTable(TestUtils.TABLE_NAME_LINE_ITEM).size());
assertEquals(9, queryTable(TestUtils.TABLE_NAME_LINE_ITEM_EXTRINSIC).size());
////////////////////////////////
// delete (cascading) order 1 //
////////////////////////////////
DeleteInput deleteInput = new DeleteInput();
deleteInput.setTableName(TestUtils.TABLE_NAME_ORDER);
deleteInput.setPrimaryKeys(List.of(1));
new DeleteAction().execute(deleteInput);
//////////////////////////////////////////////////
// assert that the associated data were deleted //
//////////////////////////////////////////////////
assertEquals(2, queryTable(TestUtils.TABLE_NAME_ORDER).size());
assertEquals(3, queryTable(TestUtils.TABLE_NAME_ORDER_EXTRINSIC).size());
assertEquals(4, queryTable(TestUtils.TABLE_NAME_LINE_ITEM).size());
assertEquals(5, queryTable(TestUtils.TABLE_NAME_LINE_ITEM_EXTRINSIC).size());
////////////////////
// delete order 2 //
////////////////////
deleteInput.setPrimaryKeys(List.of(2));
new DeleteAction().execute(deleteInput);
//////////////////////////////////////////////////
// assert that the associated data were deleted //
//////////////////////////////////////////////////
assertEquals(1, queryTable(TestUtils.TABLE_NAME_ORDER).size());
assertEquals(3, queryTable(TestUtils.TABLE_NAME_ORDER_EXTRINSIC).size());
assertEquals(3, queryTable(TestUtils.TABLE_NAME_LINE_ITEM).size());
assertEquals(3, queryTable(TestUtils.TABLE_NAME_LINE_ITEM_EXTRINSIC).size());
////////////////////
// delete order 3 //
////////////////////
deleteInput.setPrimaryKeys(List.of(3));
new DeleteAction().execute(deleteInput);
///////////////////////////////
// everything is deleted now //
///////////////////////////////
assertEquals(0, queryTable(TestUtils.TABLE_NAME_ORDER).size());
assertEquals(0, queryTable(TestUtils.TABLE_NAME_ORDER_EXTRINSIC).size());
assertEquals(0, queryTable(TestUtils.TABLE_NAME_LINE_ITEM).size());
assertEquals(0, queryTable(TestUtils.TABLE_NAME_LINE_ITEM_EXTRINSIC).size());
////////////////////////////////////////////////
// make sure no errors if we try more deletes //
////////////////////////////////////////////////
deleteInput.setPrimaryKeys(List.of(3));
new DeleteAction().execute(deleteInput);
deleteInput.setPrimaryKeys(List.of(1, 2, 3, 4));
new DeleteAction().execute(deleteInput);
}
/*******************************************************************************
**
*******************************************************************************/
private static List<QRecord> queryTable(String tableName) throws QException
{
QueryInput queryInput = new QueryInput();
queryInput.setTableName(tableName);
queryInput.setFilter(new QQueryFilter().withOrderBy(new QFilterOrderBy("id")));
QueryOutput queryOutput = new QueryAction().execute(queryInput);
return (queryOutput.getRecords());
}
}

View File

@ -209,4 +209,78 @@ class InsertActionTest extends BaseTest
assertTrue(CollectionUtils.nullSafeIsEmpty(insertOutput.getRecords().get(1).getErrors()));
}
/*******************************************************************************
**
*******************************************************************************/
@Test
void testInsertAssociations() throws QException
{
QInstance qInstance = QContext.getQInstance();
QContext.getQSession().withSecurityKeyValue("storeId", 1);
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("extrinsics", new QRecord().withValue("key", "YOUR-FIELD-1").withValue("value", "YOUR-VALUE-1"))
));
new InsertAction().execute(insertInput);
List<QRecord> orders = TestUtils.queryTable(qInstance, TestUtils.TABLE_NAME_ORDER);
assertEquals(2, orders.size());
assertEquals(1, orders.get(0).getValueInteger("id"));
assertEquals(2, orders.get(1).getValueInteger("id"));
assertEquals("ORD123", orders.get(0).getValueString("orderNo"));
assertEquals("ORD124", orders.get(1).getValueString("orderNo"));
List<QRecord> orderLines = TestUtils.queryTable(qInstance, TestUtils.TABLE_NAME_LINE_ITEM);
assertEquals(2, orderLines.size());
assertEquals(1, orderLines.get(0).getValueInteger("orderId"));
assertEquals(1, orderLines.get(1).getValueInteger("orderId"));
assertEquals("BASIC1", orderLines.get(0).getValueString("sku"));
assertEquals("BASIC2", orderLines.get(1).getValueString("sku"));
List<QRecord> orderExtrinsics = TestUtils.queryTable(qInstance, TestUtils.TABLE_NAME_ORDER_EXTRINSIC);
assertEquals(4, orderExtrinsics.size());
assertEquals(1, orderExtrinsics.get(0).getValueInteger("orderId"));
assertEquals(1, orderExtrinsics.get(1).getValueInteger("orderId"));
assertEquals(1, orderExtrinsics.get(2).getValueInteger("orderId"));
assertEquals(2, orderExtrinsics.get(3).getValueInteger("orderId"));
assertEquals("MY-FIELD-1", orderExtrinsics.get(0).getValueString("key"));
assertEquals("MY-FIELD-2", orderExtrinsics.get(1).getValueString("key"));
assertEquals("MY-FIELD-3", orderExtrinsics.get(2).getValueString("key"));
assertEquals("YOUR-FIELD-1", orderExtrinsics.get(3).getValueString("key"));
assertEquals("MY-VALUE-1", orderExtrinsics.get(0).getValueString("value"));
assertEquals("MY-VALUE-2", orderExtrinsics.get(1).getValueString("value"));
assertEquals("MY-VALUE-3", orderExtrinsics.get(2).getValueString("value"));
assertEquals("YOUR-VALUE-1", orderExtrinsics.get(3).getValueString("value"));
List<QRecord> lineItemExtrinsics = TestUtils.queryTable(qInstance, TestUtils.TABLE_NAME_LINE_ITEM_EXTRINSIC);
assertEquals(3, lineItemExtrinsics.size());
assertEquals(1, lineItemExtrinsics.get(0).getValueInteger("lineItemId"));
assertEquals(2, lineItemExtrinsics.get(1).getValueInteger("lineItemId"));
assertEquals(2, lineItemExtrinsics.get(2).getValueInteger("lineItemId"));
assertEquals("LINE-EXT-1.1", lineItemExtrinsics.get(0).getValueString("key"));
assertEquals("LINE-EXT-2.1", lineItemExtrinsics.get(1).getValueString("key"));
assertEquals("LINE-EXT-2.2", lineItemExtrinsics.get(2).getValueString("key"));
assertEquals("LINE-VAL-1", lineItemExtrinsics.get(0).getValueString("value"));
assertEquals("LINE-VAL-2", lineItemExtrinsics.get(1).getValueString("value"));
assertEquals("LINE-VAL-3", lineItemExtrinsics.get(2).getValueString("value"));
}
}

View File

@ -91,6 +91,7 @@ import com.kingsrook.qqq.backend.core.model.metadata.reporting.ReportType;
import com.kingsrook.qqq.backend.core.model.metadata.security.FieldSecurityLock;
import com.kingsrook.qqq.backend.core.model.metadata.security.QSecurityKeyType;
import com.kingsrook.qqq.backend.core.model.metadata.security.RecordSecurityLock;
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.model.metadata.tables.UniqueKey;
import com.kingsrook.qqq.backend.core.model.metadata.tables.automation.AutomationStatusTracking;
@ -126,10 +127,12 @@ public class TestUtils
public static final String APP_NAME_PEOPLE = "peopleApp";
public static final String APP_NAME_MISCELLANEOUS = "miscellaneous";
public static final String TABLE_NAME_PERSON = "person";
public static final String TABLE_NAME_SHAPE = "shape";
public static final String TABLE_NAME_ORDER = "order";
public static final String TABLE_NAME_LINE_ITEM = "orderLine";
public static final String TABLE_NAME_PERSON = "person";
public static final String TABLE_NAME_SHAPE = "shape";
public static final String TABLE_NAME_ORDER = "order";
public static final String TABLE_NAME_LINE_ITEM = "orderLine";
public static final String TABLE_NAME_LINE_ITEM_EXTRINSIC = "orderLineExtrinsic";
public static final String TABLE_NAME_ORDER_EXTRINSIC = "orderExtrinsic";
public static final String PROCESS_NAME_GREET_PEOPLE = "greet";
public static final String PROCESS_NAME_GREET_PEOPLE_INTERACTIVE = "greetInteractive";
@ -185,8 +188,12 @@ public class TestUtils
qInstance.addTable(defineTableBasepull());
qInstance.addTable(defineTableOrder());
qInstance.addTable(defineTableLineItem());
qInstance.addTable(defineTableLineItemExtrinsic());
qInstance.addTable(defineTableOrderExtrinsic());
qInstance.addJoin(defineJoinOrderLineItem());
qInstance.addJoin(defineJoinLineItemLineItemExtrinsic());
qInstance.addJoin(defineJoinOrderOrderExtrinsic());
qInstance.addPossibleValueSource(defineAutomationStatusPossibleValueSource());
qInstance.addPossibleValueSource(defineStatesPossibleValueSource());
@ -538,9 +545,12 @@ public class TestUtils
.withRecordSecurityLock(new RecordSecurityLock()
.withSecurityKeyType(SECURITY_KEY_TYPE_STORE)
.withFieldName("storeId"))
.withAssociation(new Association().withName("orderLine").withAssociatedTableName(TABLE_NAME_LINE_ITEM).withJoinName("orderLineItem"))
.withAssociation(new Association().withName("extrinsics").withAssociatedTableName(TABLE_NAME_ORDER_EXTRINSIC).withJoinName("orderOrderExtrinsic"))
.withField(new QFieldMetaData("id", QFieldType.INTEGER).withIsEditable(false))
.withField(new QFieldMetaData("createDate", QFieldType.DATE_TIME).withIsEditable(false))
.withField(new QFieldMetaData("modifyDate", QFieldType.DATE_TIME).withIsEditable(false))
.withField(new QFieldMetaData("orderNo", QFieldType.STRING))
.withField(new QFieldMetaData("orderDate", QFieldType.DATE))
.withField(new QFieldMetaData("storeId", QFieldType.INTEGER))
.withField(new QFieldMetaData("total", QFieldType.DECIMAL).withDisplayFormat(DisplayFormat.CURRENCY).withFieldSecurityLock(new FieldSecurityLock()
@ -561,6 +571,7 @@ public class TestUtils
.withName(TABLE_NAME_LINE_ITEM)
.withBackendName(MEMORY_BACKEND_NAME)
.withPrimaryKeyField("id")
.withAssociation(new Association().withName("extrinsics").withAssociatedTableName(TABLE_NAME_LINE_ITEM_EXTRINSIC).withJoinName("lineItemLineItemExtrinsic"))
.withField(new QFieldMetaData("id", QFieldType.INTEGER).withIsEditable(false))
.withField(new QFieldMetaData("createDate", QFieldType.DATE_TIME).withIsEditable(false))
.withField(new QFieldMetaData("modifyDate", QFieldType.DATE_TIME).withIsEditable(false))
@ -572,6 +583,44 @@ public class TestUtils
/*******************************************************************************
** Define the lineItemExtrinsic table used in standard tests.
*******************************************************************************/
public static QTableMetaData defineTableLineItemExtrinsic()
{
return new QTableMetaData()
.withName(TABLE_NAME_LINE_ITEM_EXTRINSIC)
.withBackendName(MEMORY_BACKEND_NAME)
.withPrimaryKeyField("id")
.withField(new QFieldMetaData("id", QFieldType.INTEGER).withIsEditable(false))
.withField(new QFieldMetaData("createDate", QFieldType.DATE_TIME).withIsEditable(false))
.withField(new QFieldMetaData("modifyDate", QFieldType.DATE_TIME).withIsEditable(false))
.withField(new QFieldMetaData("lineItemId", QFieldType.INTEGER))
.withField(new QFieldMetaData("key", QFieldType.STRING))
.withField(new QFieldMetaData("value", QFieldType.STRING));
}
/*******************************************************************************
** Define the orderExtrinsic table used in standard tests.
*******************************************************************************/
public static QTableMetaData defineTableOrderExtrinsic()
{
return new QTableMetaData()
.withName(TABLE_NAME_ORDER_EXTRINSIC)
.withBackendName(MEMORY_BACKEND_NAME)
.withPrimaryKeyField("id")
.withField(new QFieldMetaData("id", QFieldType.INTEGER).withIsEditable(false))
.withField(new QFieldMetaData("createDate", QFieldType.DATE_TIME).withIsEditable(false))
.withField(new QFieldMetaData("modifyDate", QFieldType.DATE_TIME).withIsEditable(false))
.withField(new QFieldMetaData("orderId", QFieldType.INTEGER))
.withField(new QFieldMetaData("key", QFieldType.STRING))
.withField(new QFieldMetaData("value", QFieldType.STRING));
}
/*******************************************************************************
**
*******************************************************************************/
@ -588,6 +637,38 @@ public class TestUtils
/*******************************************************************************
**
*******************************************************************************/
public static QJoinMetaData defineJoinLineItemLineItemExtrinsic()
{
return new QJoinMetaData()
.withName("lineItemLineItemExtrinsic")
.withType(JoinType.ONE_TO_MANY)
.withLeftTable(TABLE_NAME_LINE_ITEM)
.withRightTable(TABLE_NAME_LINE_ITEM_EXTRINSIC)
.withJoinOn(new JoinOn("id", "lineItemId"))
.withOrderBy(new QFilterOrderBy("key"));
}
/*******************************************************************************
**
*******************************************************************************/
public static QJoinMetaData defineJoinOrderOrderExtrinsic()
{
return new QJoinMetaData()
.withName("orderOrderExtrinsic")
.withType(JoinType.ONE_TO_MANY)
.withLeftTable(TABLE_NAME_ORDER)
.withRightTable(TABLE_NAME_ORDER_EXTRINSIC)
.withJoinOn(new JoinOn("id", "orderId"))
.withOrderBy(new QFilterOrderBy("key"));
}
/*******************************************************************************
**
*******************************************************************************/