mirror of
https://github.com/Kingsrook/qqq.git
synced 2025-07-19 05:30:43 +00:00
Merge branch 'feature/sprint-9-support-updates' into feature/QQQ-37-streamed-processes
This commit is contained in:
@ -22,6 +22,8 @@
|
||||
package com.kingsrook.qqq.backend.core.actions.tables;
|
||||
|
||||
|
||||
import java.util.List;
|
||||
import com.kingsrook.qqq.backend.core.actions.reporting.RecordPipe;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryInput;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryOutput;
|
||||
@ -76,4 +78,50 @@ class QueryActionTest
|
||||
assertThat(record.getDisplayValues()).isNotEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Test running with a recordPipe - using the shape table, which uses the memory
|
||||
** backend, which is known to do an addAll to the query output.
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Test
|
||||
public void testRecordPipeShapeTable() throws QException
|
||||
{
|
||||
TestUtils.insertDefaultShapes(TestUtils.defineInstance());
|
||||
|
||||
RecordPipe pipe = new RecordPipe();
|
||||
QueryInput queryInput = new QueryInput(TestUtils.defineInstance());
|
||||
queryInput.setSession(TestUtils.getMockSession());
|
||||
queryInput.setTableName(TestUtils.TABLE_NAME_SHAPE);
|
||||
queryInput.setRecordPipe(pipe);
|
||||
QueryOutput queryOutput = new QueryAction().execute(queryInput);
|
||||
assertNotNull(queryOutput);
|
||||
|
||||
List<QRecord> records = pipe.consumeAvailableRecords();
|
||||
assertThat(records).isNotEmpty();
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Test running with a recordPipe - using the person table, which uses the mock
|
||||
** backend, which is known to do a single-add (not addAll) to the query output.
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Test
|
||||
public void testRecordPipePersonTable() throws QException
|
||||
{
|
||||
RecordPipe pipe = new RecordPipe();
|
||||
QueryInput queryInput = new QueryInput(TestUtils.defineInstance());
|
||||
queryInput.setSession(TestUtils.getMockSession());
|
||||
queryInput.setTableName(TestUtils.TABLE_NAME_PERSON);
|
||||
queryInput.setRecordPipe(pipe);
|
||||
QueryOutput queryOutput = new QueryAction().execute(queryInput);
|
||||
assertNotNull(queryOutput);
|
||||
|
||||
List<QRecord> records = pipe.consumeAvailableRecords();
|
||||
assertThat(records).isNotEmpty();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -25,30 +25,42 @@ package com.kingsrook.qqq.backend.core.actions.values;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import com.kingsrook.qqq.backend.core.actions.tables.InsertAction;
|
||||
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.data.QRecord;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.DisplayFormat;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldType;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.possiblevalues.PVSValueFormatAndFields;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.possiblevalues.QPossibleValueSource;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.possiblevalues.QPossibleValueSourceType;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.session.QSession;
|
||||
import com.kingsrook.qqq.backend.core.modules.backend.implementations.memory.MemoryRecordStore;
|
||||
import com.kingsrook.qqq.backend.core.utils.TestUtils;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Unit test for QPossibleValueTranslator
|
||||
*******************************************************************************/
|
||||
public class QPossibleValueTranslatorTest
|
||||
{
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@BeforeEach
|
||||
void beforeEach()
|
||||
{
|
||||
MemoryRecordStore.getInstance().reset();
|
||||
MemoryRecordStore.resetStatistics();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@ -90,22 +102,20 @@ public class QPossibleValueTranslatorTest
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// assert the LABEL_ONLY format (when called out specifically) //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
possibleValueSource.setValueFormat(QPossibleValueSource.ValueFormat.LABEL_ONLY);
|
||||
possibleValueSource.setValueFields(QPossibleValueSource.ValueFields.LABEL_ONLY);
|
||||
possibleValueSource.setValueFormatAndFields(PVSValueFormatAndFields.LABEL_ONLY);
|
||||
assertEquals("IL", possibleValueTranslator.translatePossibleValue(stateField, 1));
|
||||
|
||||
///////////////////////////////////////
|
||||
// assert the LABEL_PARAMS_ID format //
|
||||
///////////////////////////////////////
|
||||
possibleValueSource.setValueFormat(QPossibleValueSource.ValueFormat.LABEL_PARENS_ID);
|
||||
possibleValueSource.setValueFields(QPossibleValueSource.ValueFields.LABEL_PARENS_ID);
|
||||
possibleValueSource.setValueFormatAndFields(PVSValueFormatAndFields.LABEL_PARENS_ID);
|
||||
assertEquals("IL (1)", possibleValueTranslator.translatePossibleValue(stateField, 1));
|
||||
|
||||
//////////////////////////////////////
|
||||
// assert the ID_COLON_LABEL format //
|
||||
//////////////////////////////////////
|
||||
possibleValueSource.setValueFormat(QPossibleValueSource.ValueFormat.ID_COLON_LABEL);
|
||||
possibleValueSource.setValueFields(QPossibleValueSource.ValueFields.ID_COLON_LABEL);
|
||||
possibleValueSource.setValueFormat(PVSValueFormatAndFields.ID_COLON_LABEL.getFormat());
|
||||
possibleValueSource.setValueFields(PVSValueFormatAndFields.ID_COLON_LABEL.getFields());
|
||||
assertEquals("1: IL", possibleValueTranslator.translatePossibleValue(stateField, 1));
|
||||
}
|
||||
|
||||
@ -123,16 +133,7 @@ public class QPossibleValueTranslatorTest
|
||||
QFieldMetaData shapeField = qInstance.getTable(TestUtils.TABLE_NAME_PERSON).getField("favoriteShapeId");
|
||||
QPossibleValueSource possibleValueSource = qInstance.getPossibleValueSource(shapeField.getPossibleValueSourceName());
|
||||
|
||||
List<QRecord> shapeRecords = List.of(
|
||||
new QRecord().withTableName(shapeTable.getName()).withValue("id", 1).withValue("name", "Triangle"),
|
||||
new QRecord().withTableName(shapeTable.getName()).withValue("id", 2).withValue("name", "Square"),
|
||||
new QRecord().withTableName(shapeTable.getName()).withValue("id", 3).withValue("name", "Circle"));
|
||||
|
||||
InsertInput insertInput = new InsertInput(qInstance);
|
||||
insertInput.setSession(new QSession());
|
||||
insertInput.setTableName(shapeTable.getName());
|
||||
insertInput.setRecords(shapeRecords);
|
||||
new InsertAction().execute(insertInput);
|
||||
TestUtils.insertDefaultShapes(qInstance);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// assert the default formatting for a not-found value is a null string //
|
||||
@ -156,8 +157,7 @@ public class QPossibleValueTranslatorTest
|
||||
///////////////////////////////////////
|
||||
// assert the LABEL_PARAMS_ID format //
|
||||
///////////////////////////////////////
|
||||
possibleValueSource.setValueFormat(QPossibleValueSource.ValueFormat.LABEL_PARENS_ID);
|
||||
possibleValueSource.setValueFields(QPossibleValueSource.ValueFields.LABEL_PARENS_ID);
|
||||
possibleValueSource.setValueFormatAndFields(PVSValueFormatAndFields.LABEL_PARENS_ID);
|
||||
assertEquals("Circle (3)", possibleValueTranslator.translatePossibleValue(shapeField, 3));
|
||||
|
||||
///////////////////////////////////////////////////////////
|
||||
@ -195,19 +195,113 @@ public class QPossibleValueTranslatorTest
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Make sure that if we have 2 different PVS's pointed at the same 1 table,
|
||||
** that we avoid re-doing queries, and that we actually get different (formatted) values.
|
||||
*******************************************************************************/
|
||||
@Test
|
||||
void testPossibleValueTableMultiplePvsForATable() throws QException
|
||||
{
|
||||
QInstance qInstance = TestUtils.defineInstance();
|
||||
QTableMetaData shapeTable = qInstance.getTable(TestUtils.TABLE_NAME_SHAPE);
|
||||
QTableMetaData personTable = qInstance.getTable(TestUtils.TABLE_NAME_PERSON);
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// define a second version of the Shape PVS, with a unique format //
|
||||
////////////////////////////////////////////////////////////////////
|
||||
qInstance.addPossibleValueSource(new QPossibleValueSource()
|
||||
.withName("shapeV2")
|
||||
.withType(QPossibleValueSourceType.TABLE)
|
||||
.withTableName(TestUtils.TABLE_NAME_SHAPE)
|
||||
.withValueFormat("%d: %s")
|
||||
.withValueFields(List.of("id", "label"))
|
||||
);
|
||||
|
||||
//////////////////////////////////////////////////////
|
||||
// use that PVS in a new column on the person table //
|
||||
//////////////////////////////////////////////////////
|
||||
personTable.addField(new QFieldMetaData("currentShapeId", QFieldType.INTEGER)
|
||||
.withPossibleValueSourceName("shapeV2")
|
||||
);
|
||||
|
||||
TestUtils.insertDefaultShapes(qInstance);
|
||||
|
||||
///////////////////////////////////////////////////////
|
||||
// define a list of persons pointing at those shapes //
|
||||
///////////////////////////////////////////////////////
|
||||
List<QRecord> personRecords = List.of(
|
||||
new QRecord().withTableName(TestUtils.TABLE_NAME_PERSON).withValue("favoriteShapeId", 1).withValue("currentShapeId", 2),
|
||||
new QRecord().withTableName(TestUtils.TABLE_NAME_PERSON).withValue("favoriteShapeId", 1).withValue("currentShapeId", 3),
|
||||
new QRecord().withTableName(TestUtils.TABLE_NAME_PERSON).withValue("favoriteShapeId", 2).withValue("currentShapeId", 3),
|
||||
new QRecord().withTableName(TestUtils.TABLE_NAME_PERSON).withValue("favoriteShapeId", 2).withValue("currentShapeId", 3)
|
||||
);
|
||||
|
||||
/////////////////////////
|
||||
// translate the PVS's //
|
||||
/////////////////////////
|
||||
MemoryRecordStore.setCollectStatistics(true);
|
||||
new QPossibleValueTranslator(qInstance, new QSession()).translatePossibleValuesInRecords(personTable, personRecords);
|
||||
|
||||
/////////////////////////////////
|
||||
// assert only 1 query was ran //
|
||||
/////////////////////////////////
|
||||
assertEquals(1, MemoryRecordStore.getStatistics().get(MemoryRecordStore.STAT_QUERIES_RAN), "Should only run 1 query");
|
||||
|
||||
////////////////////////////////////////
|
||||
// assert expected values and formats //
|
||||
////////////////////////////////////////
|
||||
assertEquals("Triangle", personRecords.get(0).getDisplayValue("favoriteShapeId"));
|
||||
assertEquals("2: Square", personRecords.get(0).getDisplayValue("currentShapeId"));
|
||||
assertEquals("Triangle", personRecords.get(1).getDisplayValue("favoriteShapeId"));
|
||||
assertEquals("3: Circle", personRecords.get(1).getDisplayValue("currentShapeId"));
|
||||
assertEquals("Square", personRecords.get(2).getDisplayValue("favoriteShapeId"));
|
||||
assertEquals("3: Circle", personRecords.get(2).getDisplayValue("currentShapeId"));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Make sure that if we have 2 different PVS's pointed at the same 1 table,
|
||||
** that we avoid re-doing queries, and that we actually get different (formatted) values.
|
||||
*******************************************************************************/
|
||||
@Test
|
||||
void testCustomPossibleValue() throws QException
|
||||
{
|
||||
QInstance qInstance = TestUtils.defineInstance();
|
||||
QTableMetaData personTable = qInstance.getTable(TestUtils.TABLE_NAME_PERSON);
|
||||
String fieldName = "customValue";
|
||||
|
||||
//////////////////////////////////////////////////////////////
|
||||
// define a list of persons with values in the custom field //
|
||||
//////////////////////////////////////////////////////////////
|
||||
List<QRecord> personRecords = List.of(
|
||||
new QRecord().withTableName(TestUtils.TABLE_NAME_PERSON).withValue(fieldName, 1),
|
||||
new QRecord().withTableName(TestUtils.TABLE_NAME_PERSON).withValue(fieldName, 2),
|
||||
new QRecord().withTableName(TestUtils.TABLE_NAME_PERSON).withValue(fieldName, "Buckle my shoe")
|
||||
);
|
||||
|
||||
/////////////////////////
|
||||
// translate the PVS's //
|
||||
/////////////////////////
|
||||
new QPossibleValueTranslator(qInstance, new QSession()).translatePossibleValuesInRecords(personTable, personRecords);
|
||||
|
||||
////////////////////////////////////////
|
||||
// assert expected values and formats //
|
||||
////////////////////////////////////////
|
||||
assertEquals("Custom[1]", personRecords.get(0).getDisplayValue(fieldName));
|
||||
assertEquals("Custom[2]", personRecords.get(1).getDisplayValue(fieldName));
|
||||
assertEquals("Custom[Buckle my shoe]", personRecords.get(2).getDisplayValue(fieldName));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Test
|
||||
void testSetDisplayValuesInRecords()
|
||||
{
|
||||
QTableMetaData table = new QTableMetaData()
|
||||
.withRecordLabelFormat("%s %s")
|
||||
.withRecordLabelFields("firstName", "lastName")
|
||||
.withField(new QFieldMetaData("firstName", QFieldType.STRING))
|
||||
.withField(new QFieldMetaData("lastName", QFieldType.STRING))
|
||||
.withField(new QFieldMetaData("price", QFieldType.DECIMAL).withDisplayFormat(DisplayFormat.CURRENCY))
|
||||
.withField(new QFieldMetaData("homeStateId", QFieldType.INTEGER).withPossibleValueSourceName(TestUtils.POSSIBLE_VALUE_SOURCE_STATE));
|
||||
QTableMetaData table = TestUtils.defineTablePerson();
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// first, make sure it doesn't crash with null or empty inputs //
|
||||
|
@ -292,6 +292,11 @@ class CsvToQRecordAdapterTest
|
||||
void testByteOrderMarker()
|
||||
{
|
||||
CsvToQRecordAdapter csvToQRecordAdapter = new CsvToQRecordAdapter();
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// note - there's a zero-width non-breaking-space character (0xFEFF or some-such) //
|
||||
// at the start of this string!! You may not be able to see it, depending on where you view this file. //
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
List<QRecord> records = csvToQRecordAdapter.buildRecordsFromCsv("""
|
||||
id,firstName
|
||||
1,John""", TestUtils.defineTablePerson(), null);
|
||||
|
@ -140,6 +140,7 @@ class QInstanceEnricherTest
|
||||
assertEquals("Field 20", QInstanceEnricher.nameToLabel("field20"));
|
||||
assertEquals("Something USA", QInstanceEnricher.nameToLabel("somethingUSA"));
|
||||
assertEquals("Number 1 Dad", QInstanceEnricher.nameToLabel("number1Dad"));
|
||||
assertEquals("Number 417 Dad", QInstanceEnricher.nameToLabel("number417Dad"));
|
||||
}
|
||||
|
||||
|
||||
|
@ -27,9 +27,14 @@ import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import com.kingsrook.qqq.backend.core.actions.customizers.TableCustomizers;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QInstanceValidationException;
|
||||
import com.kingsrook.qqq.backend.core.model.data.QRecord;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeReference;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeType;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeUsage;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldType;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.layout.QAppMetaData;
|
||||
@ -114,12 +119,13 @@ class QInstanceValidatorTest
|
||||
@Test
|
||||
public void test_validateNullTables()
|
||||
{
|
||||
assertValidationFailureReasonsAllowingExtraReasons((qInstance) ->
|
||||
assertValidationFailureReasons((qInstance) ->
|
||||
{
|
||||
qInstance.setTables(null);
|
||||
qInstance.setProcesses(null);
|
||||
},
|
||||
"At least 1 table must be defined");
|
||||
"At least 1 table must be defined",
|
||||
"Unrecognized table shape for possibleValueSource shape");
|
||||
}
|
||||
|
||||
|
||||
@ -131,12 +137,13 @@ class QInstanceValidatorTest
|
||||
@Test
|
||||
public void test_validateEmptyTables()
|
||||
{
|
||||
assertValidationFailureReasonsAllowingExtraReasons((qInstance) ->
|
||||
assertValidationFailureReasons((qInstance) ->
|
||||
{
|
||||
qInstance.setTables(new HashMap<>());
|
||||
qInstance.setProcesses(new HashMap<>());
|
||||
},
|
||||
"At least 1 table must be defined");
|
||||
"At least 1 table must be defined",
|
||||
"Unrecognized table shape for possibleValueSource shape");
|
||||
}
|
||||
|
||||
|
||||
@ -191,7 +198,6 @@ class QInstanceValidatorTest
|
||||
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@ -265,6 +271,138 @@ class QInstanceValidatorTest
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Test
|
||||
void testTableCustomizers()
|
||||
{
|
||||
assertValidationFailureReasons((qInstance) -> qInstance.getTable("person").withCustomizer(TableCustomizers.POST_QUERY_RECORD.getRole(), new QCodeReference()),
|
||||
"missing a code reference name", "missing a code type");
|
||||
|
||||
assertValidationFailureReasons((qInstance) -> qInstance.getTable("person").withCustomizer(TableCustomizers.POST_QUERY_RECORD.getRole(), new QCodeReference(null, QCodeType.JAVA, null)),
|
||||
"missing a code reference name");
|
||||
|
||||
assertValidationFailureReasons((qInstance) -> qInstance.getTable("person").withCustomizer(TableCustomizers.POST_QUERY_RECORD.getRole(), new QCodeReference("", QCodeType.JAVA, null)),
|
||||
"missing a code reference name");
|
||||
|
||||
assertValidationFailureReasons((qInstance) -> qInstance.getTable("person").withCustomizer(TableCustomizers.POST_QUERY_RECORD.getRole(), new QCodeReference("Test", null, null)),
|
||||
"missing a code type");
|
||||
|
||||
assertValidationFailureReasons((qInstance) -> qInstance.getTable("person").withCustomizer(TableCustomizers.POST_QUERY_RECORD.getRole(), new QCodeReference("Test", QCodeType.JAVA, QCodeUsage.CUSTOMIZER)),
|
||||
"Class for CodeReference could not be found");
|
||||
|
||||
assertValidationFailureReasons((qInstance) -> qInstance.getTable("person").withCustomizer(TableCustomizers.POST_QUERY_RECORD.getRole(), new QCodeReference(CustomizerWithNoVoidConstructor.class, QCodeUsage.CUSTOMIZER)),
|
||||
"Instance of CodeReference could not be created");
|
||||
|
||||
assertValidationFailureReasons((qInstance) -> qInstance.getTable("person").withCustomizer(TableCustomizers.POST_QUERY_RECORD.getRole(), new QCodeReference(CustomizerThatIsNotAFunction.class, QCodeUsage.CUSTOMIZER)),
|
||||
"CodeReference could not be casted");
|
||||
|
||||
assertValidationFailureReasons((qInstance) -> qInstance.getTable("person").withCustomizer(TableCustomizers.POST_QUERY_RECORD.getRole(), new QCodeReference(CustomizerFunctionWithIncorrectTypeParameters.class, QCodeUsage.CUSTOMIZER)),
|
||||
"Error validating customizer type parameters");
|
||||
|
||||
assertValidationFailureReasons((qInstance) -> qInstance.getTable("person").withCustomizer(TableCustomizers.POST_QUERY_RECORD.getRole(), new QCodeReference(CustomizerFunctionWithIncorrectTypeParameter1.class, QCodeUsage.CUSTOMIZER)),
|
||||
"Error validating customizer type parameters");
|
||||
|
||||
assertValidationFailureReasons((qInstance) -> qInstance.getTable("person").withCustomizer(TableCustomizers.POST_QUERY_RECORD.getRole(), new QCodeReference(CustomizerFunctionWithIncorrectTypeParameter2.class, QCodeUsage.CUSTOMIZER)),
|
||||
"Error validating customizer type parameters");
|
||||
|
||||
assertValidationSuccess((qInstance) -> qInstance.getTable("person").withCustomizer(TableCustomizers.POST_QUERY_RECORD.getRole(), new QCodeReference(CustomizerValid.class, QCodeUsage.CUSTOMIZER)));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public static class CustomizerWithNoVoidConstructor
|
||||
{
|
||||
public CustomizerWithNoVoidConstructor(boolean b)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public static class CustomizerWithOnlyPrivateConstructor
|
||||
{
|
||||
private CustomizerWithOnlyPrivateConstructor()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public static class CustomizerThatIsNotAFunction
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public static class CustomizerFunctionWithIncorrectTypeParameters implements Function<String, String>
|
||||
{
|
||||
@Override
|
||||
public String apply(String s)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public static class CustomizerFunctionWithIncorrectTypeParameter1 implements Function<String, QRecord>
|
||||
{
|
||||
@Override
|
||||
public QRecord apply(String s)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public static class CustomizerFunctionWithIncorrectTypeParameter2 implements Function<QRecord, String>
|
||||
{
|
||||
@Override
|
||||
public String apply(QRecord s)
|
||||
{
|
||||
return "Test";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public static class CustomizerValid implements Function<QRecord, QRecord>
|
||||
{
|
||||
@Override
|
||||
public QRecord apply(QRecord record)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Test that if a field specifies a backend that doesn't exist, that it fails.
|
||||
**
|
||||
@ -443,18 +581,6 @@ class QInstanceValidatorTest
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Test
|
||||
void testPossibleValueSourceMissingIdType()
|
||||
{
|
||||
assertValidationFailureReasons((qInstance) -> qInstance.getPossibleValueSource(TestUtils.POSSIBLE_VALUE_SOURCE_STATE).setIdType(null),
|
||||
"Missing an idType for possibleValueSource");
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@ -516,7 +642,9 @@ class QInstanceValidatorTest
|
||||
"is missing a customCodeReference");
|
||||
|
||||
assertValidationFailureReasons((qInstance) -> qInstance.getPossibleValueSource(TestUtils.POSSIBLE_VALUE_SOURCE_CUSTOM).setCustomCodeReference(new QCodeReference()),
|
||||
"not a possibleValueProvider");
|
||||
"not a possibleValueProvider",
|
||||
"missing a code reference name",
|
||||
"missing a code type");
|
||||
}
|
||||
|
||||
|
||||
@ -561,7 +689,8 @@ class QInstanceValidatorTest
|
||||
{
|
||||
if(!allowExtraReasons)
|
||||
{
|
||||
assertEquals(reasons.length, e.getReasons().size(), "Expected number of validation failure reasons\nExpected: " + String.join(",", reasons) + "\nActual: " + e.getReasons());
|
||||
int noOfReasons = e.getReasons() == null ? 0 : e.getReasons().size();
|
||||
assertEquals(reasons.length, noOfReasons, "Expected number of validation failure reasons.\nExpected reasons: " + String.join(",", reasons) + "\nActual reasons: " + e.getReasons());
|
||||
}
|
||||
|
||||
for(String reason : reasons)
|
||||
@ -573,6 +702,25 @@ class QInstanceValidatorTest
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Assert that an instance is valid!
|
||||
*******************************************************************************/
|
||||
private void assertValidationSuccess(Consumer<QInstance> setup)
|
||||
{
|
||||
try
|
||||
{
|
||||
QInstance qInstance = TestUtils.defineInstance();
|
||||
setup.accept(qInstance);
|
||||
new QInstanceValidator().validate(qInstance);
|
||||
}
|
||||
catch(QInstanceValidationException e)
|
||||
{
|
||||
fail("Expected no validation errors, but received: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** utility method for asserting that a specific reason string is found within
|
||||
** the list of reasons in the QInstanceValidationException.
|
||||
|
@ -24,7 +24,7 @@ package com.kingsrook.qqq.backend.core.modules.backend.implementations.memory;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
import com.kingsrook.qqq.backend.core.actions.customizers.Customizers;
|
||||
import com.kingsrook.qqq.backend.core.actions.customizers.TableCustomizers;
|
||||
import com.kingsrook.qqq.backend.core.actions.tables.CountAction;
|
||||
import com.kingsrook.qqq.backend.core.actions.tables.DeleteAction;
|
||||
import com.kingsrook.qqq.backend.core.actions.tables.InsertAction;
|
||||
@ -36,6 +36,9 @@ 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.QFilterCriteria;
|
||||
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.actions.tables.update.UpdateInput;
|
||||
@ -68,6 +71,7 @@ class MemoryBackendModuleTest
|
||||
void beforeAndAfter()
|
||||
{
|
||||
MemoryRecordStore.getInstance().reset();
|
||||
MemoryRecordStore.resetStatistics();
|
||||
}
|
||||
|
||||
|
||||
@ -122,8 +126,6 @@ class MemoryBackendModuleTest
|
||||
|
||||
assertEquals(3, new CountAction().execute(countInput).getCount());
|
||||
|
||||
// todo - filters in query
|
||||
|
||||
//////////////////
|
||||
// do an update //
|
||||
//////////////////
|
||||
@ -152,6 +154,24 @@ class MemoryBackendModuleTest
|
||||
|
||||
assertEquals(3, new CountAction().execute(countInput).getCount());
|
||||
|
||||
/////////////////////////
|
||||
// do a filtered query //
|
||||
/////////////////////////
|
||||
queryInput = new QueryInput(qInstance);
|
||||
queryInput.setSession(session);
|
||||
queryInput.setTableName(table.getName());
|
||||
queryInput.setFilter(new QQueryFilter().withCriteria(new QFilterCriteria("id", QCriteriaOperator.IN, List.of(1, 3))));
|
||||
queryOutput = new QueryAction().execute(queryInput);
|
||||
assertEquals(2, queryOutput.getRecords().size());
|
||||
assertTrue(queryOutput.getRecords().stream().anyMatch(r -> r.getValueInteger("id").equals(1)));
|
||||
assertTrue(queryOutput.getRecords().stream().anyMatch(r -> r.getValueInteger("id").equals(3)));
|
||||
|
||||
/////////////////////////
|
||||
// do a filtered count //
|
||||
/////////////////////////
|
||||
countInput.setFilter(queryInput.getFilter());
|
||||
assertEquals(2, new CountAction().execute(countInput).getCount());
|
||||
|
||||
/////////////////
|
||||
// do a delete //
|
||||
/////////////////
|
||||
@ -173,6 +193,57 @@ class MemoryBackendModuleTest
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Test
|
||||
void testSerials() throws QException
|
||||
{
|
||||
QInstance qInstance = TestUtils.defineInstance();
|
||||
QTableMetaData table = qInstance.getTable(TestUtils.TABLE_NAME_SHAPE);
|
||||
QSession session = new QSession();
|
||||
|
||||
//////////////////
|
||||
// do an insert //
|
||||
//////////////////
|
||||
InsertInput insertInput = new InsertInput(qInstance);
|
||||
insertInput.setSession(session);
|
||||
insertInput.setTableName(table.getName());
|
||||
insertInput.setRecords(List.of(new QRecord().withTableName(table.getName()).withValue("name", "Shape 1")));
|
||||
new InsertAction().execute(insertInput);
|
||||
|
||||
insertInput.setRecords(List.of(new QRecord().withTableName(table.getName()).withValue("name", "Shape 2")));
|
||||
new InsertAction().execute(insertInput);
|
||||
|
||||
insertInput.setRecords(List.of(new QRecord().withTableName(table.getName()).withValue("name", "Shape 3")));
|
||||
new InsertAction().execute(insertInput);
|
||||
|
||||
QueryInput queryInput = new QueryInput(qInstance);
|
||||
queryInput.setSession(new QSession());
|
||||
queryInput.setTableName(table.getName());
|
||||
QueryOutput queryOutput = new QueryAction().execute(queryInput);
|
||||
assertTrue(queryOutput.getRecords().stream().anyMatch(r -> r.getValueInteger("id").equals(1)));
|
||||
assertTrue(queryOutput.getRecords().stream().anyMatch(r -> r.getValueInteger("id").equals(2)));
|
||||
assertTrue(queryOutput.getRecords().stream().anyMatch(r -> r.getValueInteger("id").equals(3)));
|
||||
|
||||
insertInput.setRecords(List.of(new QRecord().withTableName(table.getName()).withValue("id", 4).withValue("name", "Shape 4")));
|
||||
new InsertAction().execute(insertInput);
|
||||
queryOutput = new QueryAction().execute(queryInput);
|
||||
assertTrue(queryOutput.getRecords().stream().anyMatch(r -> r.getValueInteger("id").equals(4)));
|
||||
|
||||
insertInput.setRecords(List.of(new QRecord().withTableName(table.getName()).withValue("id", 6).withValue("name", "Shape 6")));
|
||||
new InsertAction().execute(insertInput);
|
||||
queryOutput = new QueryAction().execute(queryInput);
|
||||
assertTrue(queryOutput.getRecords().stream().anyMatch(r -> r.getValueInteger("id").equals(6)));
|
||||
|
||||
insertInput.setRecords(List.of(new QRecord().withTableName(table.getName()).withValue("name", "Shape 7")));
|
||||
new InsertAction().execute(insertInput);
|
||||
queryOutput = new QueryAction().execute(queryInput);
|
||||
assertTrue(queryOutput.getRecords().stream().anyMatch(r -> r.getValueInteger("id").equals(7)));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@ -215,7 +286,7 @@ class MemoryBackendModuleTest
|
||||
///////////////////////////////////
|
||||
// add a customizer to the table //
|
||||
///////////////////////////////////
|
||||
table.withCustomizer(Customizers.POST_QUERY_RECORD, new QCodeReference(ShapeTestCustomizer.class, QCodeUsage.CUSTOMIZER));
|
||||
table.withCustomizer(TableCustomizers.POST_QUERY_RECORD.getRole(), new QCodeReference(ShapeTestCustomizer.class, QCodeUsage.CUSTOMIZER));
|
||||
|
||||
//////////////////
|
||||
// do an insert //
|
||||
|
@ -26,9 +26,11 @@ import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import com.kingsrook.qqq.backend.core.actions.processes.person.addtopeoplesage.AddAge;
|
||||
import com.kingsrook.qqq.backend.core.actions.processes.person.addtopeoplesage.GetAgeStatistics;
|
||||
import com.kingsrook.qqq.backend.core.actions.tables.InsertAction;
|
||||
import com.kingsrook.qqq.backend.core.actions.tables.QueryAction;
|
||||
import com.kingsrook.qqq.backend.core.actions.values.QCustomPossibleValueProvider;
|
||||
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.query.QueryInput;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryOutput;
|
||||
import com.kingsrook.qqq.backend.core.model.data.QRecord;
|
||||
@ -447,6 +449,25 @@ public class TestUtils
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public static void insertDefaultShapes(QInstance qInstance) throws QException
|
||||
{
|
||||
List<QRecord> shapeRecords = List.of(
|
||||
new QRecord().withTableName(TABLE_NAME_SHAPE).withValue("id", 1).withValue("name", "Triangle"),
|
||||
new QRecord().withTableName(TABLE_NAME_SHAPE).withValue("id", 2).withValue("name", "Square"),
|
||||
new QRecord().withTableName(TABLE_NAME_SHAPE).withValue("id", 3).withValue("name", "Circle"));
|
||||
|
||||
InsertInput insertInput = new InsertInput(qInstance);
|
||||
insertInput.setSession(new QSession());
|
||||
insertInput.setTableName(TABLE_NAME_SHAPE);
|
||||
insertInput.setRecords(shapeRecords);
|
||||
new InsertAction().execute(insertInput);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
|
Reference in New Issue
Block a user