mirror of
https://github.com/Kingsrook/qqq.git
synced 2025-07-18 05:01:07 +00:00
Adding associated records to Get, Query.
This commit is contained in:
@ -329,6 +329,8 @@ public class GetAction
|
|||||||
}
|
}
|
||||||
|
|
||||||
queryInput.setFilter(filter);
|
queryInput.setFilter(filter);
|
||||||
|
queryInput.setIncludeAssociations(getInput.getIncludeAssociations());
|
||||||
|
queryInput.setAssociationNamesToInclude(getInput.getAssociationNamesToInclude());
|
||||||
queryInput.setShouldFetchHeavyFields(getInput.getShouldFetchHeavyFields());
|
queryInput.setShouldFetchHeavyFields(getInput.getShouldFetchHeavyFields());
|
||||||
|
|
||||||
QueryOutput queryOutput = new QueryAction().execute(queryInput);
|
QueryOutput queryOutput = new QueryAction().execute(queryInput);
|
||||||
|
@ -22,8 +22,13 @@
|
|||||||
package com.kingsrook.qqq.backend.core.actions.tables;
|
package com.kingsrook.qqq.backend.core.actions.tables;
|
||||||
|
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
import java.util.Set;
|
||||||
import com.kingsrook.qqq.backend.core.actions.ActionHelper;
|
import com.kingsrook.qqq.backend.core.actions.ActionHelper;
|
||||||
import com.kingsrook.qqq.backend.core.actions.customizers.AbstractPostQueryCustomizer;
|
import com.kingsrook.qqq.backend.core.actions.customizers.AbstractPostQueryCustomizer;
|
||||||
import com.kingsrook.qqq.backend.core.actions.customizers.QCodeLoader;
|
import com.kingsrook.qqq.backend.core.actions.customizers.QCodeLoader;
|
||||||
@ -31,13 +36,23 @@ import com.kingsrook.qqq.backend.core.actions.customizers.TableCustomizers;
|
|||||||
import com.kingsrook.qqq.backend.core.actions.reporting.BufferedRecordPipe;
|
import com.kingsrook.qqq.backend.core.actions.reporting.BufferedRecordPipe;
|
||||||
import com.kingsrook.qqq.backend.core.actions.values.QPossibleValueTranslator;
|
import com.kingsrook.qqq.backend.core.actions.values.QPossibleValueTranslator;
|
||||||
import com.kingsrook.qqq.backend.core.actions.values.QValueFormatter;
|
import com.kingsrook.qqq.backend.core.actions.values.QValueFormatter;
|
||||||
|
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.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.QueryInput;
|
||||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryOutput;
|
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryOutput;
|
||||||
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.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 com.kingsrook.qqq.backend.core.utils.ListingHash;
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
@ -70,6 +85,14 @@ public class QueryAction
|
|||||||
queryInput.getRecordPipe().setPostRecordActions(this::postRecordActions);
|
queryInput.getRecordPipe().setPostRecordActions(this::postRecordActions);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(queryInput.getIncludeAssociations() && queryInput.getRecordPipe() != null)
|
||||||
|
{
|
||||||
|
//////////////////////////////////////////////
|
||||||
|
// todo - support this in the future maybe? //
|
||||||
|
//////////////////////////////////////////////
|
||||||
|
throw (new QException("Associations may not be fetched into a RecordPipe."));
|
||||||
|
}
|
||||||
|
|
||||||
QBackendModuleDispatcher qBackendModuleDispatcher = new QBackendModuleDispatcher();
|
QBackendModuleDispatcher qBackendModuleDispatcher = new QBackendModuleDispatcher();
|
||||||
QBackendModuleInterface qModule = qBackendModuleDispatcher.getQBackendModule(queryInput.getBackend());
|
QBackendModuleInterface qModule = qBackendModuleDispatcher.getQBackendModule(queryInput.getBackend());
|
||||||
// todo pre-customization - just get to modify the request?
|
// todo pre-customization - just get to modify the request?
|
||||||
@ -86,11 +109,119 @@ public class QueryAction
|
|||||||
postRecordActions(queryOutput.getRecords());
|
postRecordActions(queryOutput.getRecords());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(queryInput.getIncludeAssociations())
|
||||||
|
{
|
||||||
|
manageAssociations(queryInput, queryOutput);
|
||||||
|
}
|
||||||
|
|
||||||
return queryOutput;
|
return queryOutput;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
private void manageAssociations(QueryInput queryInput, QueryOutput queryOutput) throws QException
|
||||||
|
{
|
||||||
|
QTableMetaData table = queryInput.getTable();
|
||||||
|
for(Association association : CollectionUtils.nonNullList(table.getAssociations()))
|
||||||
|
{
|
||||||
|
if(queryInput.getAssociationNamesToInclude() == null || queryInput.getAssociationNamesToInclude().contains(association.getName()))
|
||||||
|
{
|
||||||
|
// e.g., order -> orderLine
|
||||||
|
QJoinMetaData join = QContext.getQInstance().getJoin(association.getJoinName()); // todo ... ever need to flip?
|
||||||
|
// just assume this, at least for now... if(BooleanUtils.isTrue(association.getDoInserts()))
|
||||||
|
|
||||||
|
QueryInput nextLevelQueryInput = new QueryInput();
|
||||||
|
nextLevelQueryInput.setTableName(association.getAssociatedTableName());
|
||||||
|
nextLevelQueryInput.setIncludeAssociations(true);
|
||||||
|
nextLevelQueryInput.setAssociationNamesToInclude(buildNextLevelAssociationNamesToInclude(association.getName(), queryInput.getAssociationNamesToInclude()));
|
||||||
|
|
||||||
|
QQueryFilter filter = new QQueryFilter();
|
||||||
|
nextLevelQueryInput.setFilter(filter);
|
||||||
|
|
||||||
|
ListingHash<List<Serializable>, QRecord> outerResultMap = new ListingHash<>();
|
||||||
|
|
||||||
|
if(join.getJoinOns().size() == 1)
|
||||||
|
{
|
||||||
|
JoinOn joinOn = join.getJoinOns().get(0);
|
||||||
|
Set<Serializable> values = new HashSet<>();
|
||||||
|
for(QRecord record : queryOutput.getRecords())
|
||||||
|
{
|
||||||
|
Serializable value = record.getValue(joinOn.getLeftField());
|
||||||
|
values.add(value);
|
||||||
|
outerResultMap.add(List.of(value), record);
|
||||||
|
}
|
||||||
|
filter.addCriteria(new QFilterCriteria(joinOn.getRightField(), QCriteriaOperator.IN, new ArrayList<>(values)));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
filter.setBooleanOperator(QQueryFilter.BooleanOperator.OR);
|
||||||
|
|
||||||
|
for(QRecord record : queryOutput.getRecords())
|
||||||
|
{
|
||||||
|
QQueryFilter subFilter = new QQueryFilter();
|
||||||
|
filter.addSubFilter(subFilter);
|
||||||
|
List<Serializable> values = new ArrayList<>();
|
||||||
|
for(JoinOn joinOn : join.getJoinOns())
|
||||||
|
{
|
||||||
|
Serializable value = record.getValue(joinOn.getLeftField());
|
||||||
|
values.add(value);
|
||||||
|
subFilter.addCriteria(new QFilterCriteria(joinOn.getRightField(), QCriteriaOperator.EQUALS, value));
|
||||||
|
}
|
||||||
|
outerResultMap.add(values, record);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryOutput nextLevelQueryOutput = new QueryAction().execute(nextLevelQueryInput);
|
||||||
|
for(QRecord record : nextLevelQueryOutput.getRecords())
|
||||||
|
{
|
||||||
|
List<Serializable> values = new ArrayList<>();
|
||||||
|
for(JoinOn joinOn : join.getJoinOns())
|
||||||
|
{
|
||||||
|
Serializable value = record.getValue(joinOn.getRightField());
|
||||||
|
values.add(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(outerResultMap.containsKey(values))
|
||||||
|
{
|
||||||
|
for(QRecord outerRecord : outerResultMap.get(values))
|
||||||
|
{
|
||||||
|
outerRecord.withAssociatedRecord(association.getName(), record);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
private Collection<String> buildNextLevelAssociationNamesToInclude(String name, Collection<String> associationNamesToInclude)
|
||||||
|
{
|
||||||
|
if(associationNamesToInclude == null)
|
||||||
|
{
|
||||||
|
return (associationNamesToInclude);
|
||||||
|
}
|
||||||
|
|
||||||
|
Set<String> rs = new HashSet<>();
|
||||||
|
for(String nextLevelCandidateName : associationNamesToInclude)
|
||||||
|
{
|
||||||
|
if(nextLevelCandidateName.startsWith(name + "."))
|
||||||
|
{
|
||||||
|
rs.add(nextLevelCandidateName.replaceFirst(name + ".", ""));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (rs);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
** Run the necessary actions on a list of records (which must be a mutable list - e.g.,
|
** Run the necessary actions on a list of records (which must be a mutable list - e.g.,
|
||||||
** not one created via List.of()). This may include setting display values,
|
** not one created via List.of()). This may include setting display values,
|
||||||
|
@ -23,6 +23,7 @@ package com.kingsrook.qqq.backend.core.model.actions.tables.get;
|
|||||||
|
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import com.kingsrook.qqq.backend.core.actions.QBackendTransaction;
|
import com.kingsrook.qqq.backend.core.actions.QBackendTransaction;
|
||||||
import com.kingsrook.qqq.backend.core.model.actions.AbstractTableActionInput;
|
import com.kingsrook.qqq.backend.core.model.actions.AbstractTableActionInput;
|
||||||
@ -44,6 +45,15 @@ public class GetInput extends AbstractTableActionInput
|
|||||||
private boolean shouldFetchHeavyFields = true;
|
private boolean shouldFetchHeavyFields = true;
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// if you say you want to includeAssociations, you can limit which ones by passing them in associationNamesToInclude. //
|
||||||
|
// if you leave it null, you get all associations defined on the table. if you pass it as empty, you get none. //
|
||||||
|
// to go to a recursive level of associations, you need to dot-qualify the names. e.g., A, B, A.C, A.D, A.C.E //
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
private boolean includeAssociations = false;
|
||||||
|
private Collection<String> associationNamesToInclude = null;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
**
|
**
|
||||||
@ -229,4 +239,66 @@ public class GetInput extends AbstractTableActionInput
|
|||||||
return (this);
|
return (this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for includeAssociations
|
||||||
|
*******************************************************************************/
|
||||||
|
public boolean getIncludeAssociations()
|
||||||
|
{
|
||||||
|
return (this.includeAssociations);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for includeAssociations
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setIncludeAssociations(boolean includeAssociations)
|
||||||
|
{
|
||||||
|
this.includeAssociations = includeAssociations;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for includeAssociations
|
||||||
|
*******************************************************************************/
|
||||||
|
public GetInput withIncludeAssociations(boolean includeAssociations)
|
||||||
|
{
|
||||||
|
this.includeAssociations = includeAssociations;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for associationNamesToInclude
|
||||||
|
*******************************************************************************/
|
||||||
|
public Collection<String> getAssociationNamesToInclude()
|
||||||
|
{
|
||||||
|
return (this.associationNamesToInclude);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for associationNamesToInclude
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setAssociationNamesToInclude(Collection<String> associationNamesToInclude)
|
||||||
|
{
|
||||||
|
this.associationNamesToInclude = associationNamesToInclude;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for associationNamesToInclude
|
||||||
|
*******************************************************************************/
|
||||||
|
public GetInput withAssociationNamesToInclude(Collection<String> associationNamesToInclude)
|
||||||
|
{
|
||||||
|
this.associationNamesToInclude = associationNamesToInclude;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,7 @@ package com.kingsrook.qqq.backend.core.model.actions.tables.query;
|
|||||||
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import com.kingsrook.qqq.backend.core.actions.QBackendTransaction;
|
import com.kingsrook.qqq.backend.core.actions.QBackendTransaction;
|
||||||
@ -56,6 +57,14 @@ public class QueryInput extends AbstractTableActionInput
|
|||||||
|
|
||||||
private List<QueryJoin> queryJoins = null;
|
private List<QueryJoin> queryJoins = null;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// if you say you want to includeAssociations, you can limit which ones by passing them in associationNamesToInclude. //
|
||||||
|
// if you leave it null, you get all associations defined on the table. if you pass it as empty, you get none. //
|
||||||
|
// to go to a recursive level of associations, you need to dot-qualify the names. e.g., A, B, A.C, A.D, A.C.E //
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
private boolean includeAssociations = false;
|
||||||
|
private Collection<String> associationNamesToInclude = null;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
@ -425,4 +434,67 @@ public class QueryInput extends AbstractTableActionInput
|
|||||||
super.withTableName(tableName);
|
super.withTableName(tableName);
|
||||||
return (this);
|
return (this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for includeAssociations
|
||||||
|
*******************************************************************************/
|
||||||
|
public boolean getIncludeAssociations()
|
||||||
|
{
|
||||||
|
return (this.includeAssociations);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for includeAssociations
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setIncludeAssociations(boolean includeAssociations)
|
||||||
|
{
|
||||||
|
this.includeAssociations = includeAssociations;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for includeAssociations
|
||||||
|
*******************************************************************************/
|
||||||
|
public QueryInput withIncludeAssociations(boolean includeAssociations)
|
||||||
|
{
|
||||||
|
this.includeAssociations = includeAssociations;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for associationNamesToInclude
|
||||||
|
*******************************************************************************/
|
||||||
|
public Collection<String> getAssociationNamesToInclude()
|
||||||
|
{
|
||||||
|
return (this.associationNamesToInclude);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for associationNamesToInclude
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setAssociationNamesToInclude(Collection<String> associationNamesToInclude)
|
||||||
|
{
|
||||||
|
this.associationNamesToInclude = associationNamesToInclude;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for associationNamesToInclude
|
||||||
|
*******************************************************************************/
|
||||||
|
public QueryInput withAssociationNamesToInclude(Collection<String> associationNamesToInclude)
|
||||||
|
{
|
||||||
|
this.associationNamesToInclude = associationNamesToInclude;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -170,6 +170,10 @@ public class MemoryRecordStore
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// make sure we're not giving back records that are all full of associations... //
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////
|
||||||
|
qRecord.setAssociatedRecords(new HashMap<>());
|
||||||
records.add(qRecord);
|
records.add(qRecord);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,18 +22,25 @@
|
|||||||
package com.kingsrook.qqq.backend.core.actions.tables;
|
package com.kingsrook.qqq.backend.core.actions.tables;
|
||||||
|
|
||||||
|
|
||||||
|
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.actions.reporting.RecordPipe;
|
import com.kingsrook.qqq.backend.core.actions.reporting.RecordPipe;
|
||||||
import com.kingsrook.qqq.backend.core.context.QContext;
|
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.query.QQueryFilter;
|
||||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryInput;
|
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.query.QueryOutput;
|
||||||
import com.kingsrook.qqq.backend.core.model.data.QRecord;
|
import com.kingsrook.qqq.backend.core.model.data.QRecord;
|
||||||
|
import com.kingsrook.qqq.backend.core.utils.CollectionUtils;
|
||||||
import com.kingsrook.qqq.backend.core.utils.TestUtils;
|
import com.kingsrook.qqq.backend.core.utils.TestUtils;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
@ -124,4 +131,193 @@ class QueryActionTest extends BaseTest
|
|||||||
assertThat(records).isNotEmpty();
|
assertThat(records).isNotEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Test
|
||||||
|
void testQueryAssociations() throws QException
|
||||||
|
{
|
||||||
|
QContext.getQSession().withSecurityKeyValue(TestUtils.SECURITY_KEY_TYPE_STORE_ALL_ACCESS, true);
|
||||||
|
insert2OrdersWith3Lines3LineExtrinsicsAnd4OrderExtrinsicAssociations();
|
||||||
|
|
||||||
|
QueryInput queryInput = new QueryInput();
|
||||||
|
queryInput.setTableName(TestUtils.TABLE_NAME_ORDER);
|
||||||
|
queryInput.setFilter(new QQueryFilter());
|
||||||
|
queryInput.setIncludeAssociations(true);
|
||||||
|
QueryOutput queryOutput = new QueryAction().execute(queryInput);
|
||||||
|
|
||||||
|
QRecord order0 = queryOutput.getRecords().get(0);
|
||||||
|
assertEquals(2, order0.getAssociatedRecords().get("orderLine").size());
|
||||||
|
assertEquals(3, order0.getAssociatedRecords().get("extrinsics").size());
|
||||||
|
|
||||||
|
QRecord orderLine00 = order0.getAssociatedRecords().get("orderLine").get(0);
|
||||||
|
assertEquals(1, orderLine00.getAssociatedRecords().get("extrinsics").size());
|
||||||
|
QRecord orderLine01 = order0.getAssociatedRecords().get("orderLine").get(1);
|
||||||
|
assertEquals(2, orderLine01.getAssociatedRecords().get("extrinsics").size());
|
||||||
|
|
||||||
|
QRecord order1 = queryOutput.getRecords().get(1);
|
||||||
|
assertEquals(1, order1.getAssociatedRecords().get("orderLine").size());
|
||||||
|
assertEquals(1, order1.getAssociatedRecords().get("extrinsics").size());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Test
|
||||||
|
void testQueryAssociationsNoAssociationNamesToInclude() throws QException
|
||||||
|
{
|
||||||
|
QContext.getQSession().withSecurityKeyValue(TestUtils.SECURITY_KEY_TYPE_STORE_ALL_ACCESS, true);
|
||||||
|
insert2OrdersWith3Lines3LineExtrinsicsAnd4OrderExtrinsicAssociations();
|
||||||
|
|
||||||
|
QueryInput queryInput = new QueryInput();
|
||||||
|
queryInput.setTableName(TestUtils.TABLE_NAME_ORDER);
|
||||||
|
queryInput.setFilter(new QQueryFilter());
|
||||||
|
queryInput.setIncludeAssociations(true);
|
||||||
|
queryInput.setAssociationNamesToInclude(new ArrayList<>());
|
||||||
|
QueryOutput queryOutput = new QueryAction().execute(queryInput);
|
||||||
|
|
||||||
|
QRecord order0 = queryOutput.getRecords().get(0);
|
||||||
|
assertTrue(CollectionUtils.nullSafeIsEmpty(order0.getAssociatedRecords()));
|
||||||
|
QRecord order1 = queryOutput.getRecords().get(1);
|
||||||
|
assertTrue(CollectionUtils.nullSafeIsEmpty(order1.getAssociatedRecords()));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Test
|
||||||
|
void testQueryAssociationsLimitedAssociationNamesToInclude() throws QException
|
||||||
|
{
|
||||||
|
QContext.getQSession().withSecurityKeyValue(TestUtils.SECURITY_KEY_TYPE_STORE_ALL_ACCESS, true);
|
||||||
|
insert2OrdersWith3Lines3LineExtrinsicsAnd4OrderExtrinsicAssociations();
|
||||||
|
|
||||||
|
QueryInput queryInput = new QueryInput();
|
||||||
|
queryInput.setTableName(TestUtils.TABLE_NAME_ORDER);
|
||||||
|
queryInput.setFilter(new QQueryFilter());
|
||||||
|
queryInput.setIncludeAssociations(true);
|
||||||
|
queryInput.setAssociationNamesToInclude(List.of("orderLine"));
|
||||||
|
QueryOutput queryOutput = new QueryAction().execute(queryInput);
|
||||||
|
|
||||||
|
QRecord order0 = queryOutput.getRecords().get(0);
|
||||||
|
assertEquals(2, order0.getAssociatedRecords().get("orderLine").size());
|
||||||
|
assertTrue(CollectionUtils.nullSafeIsEmpty(CollectionUtils.nonNullCollection(order0.getAssociatedRecords().get("extrinsics"))));
|
||||||
|
|
||||||
|
QRecord orderLine00 = order0.getAssociatedRecords().get("orderLine").get(0);
|
||||||
|
assertTrue(CollectionUtils.nullSafeIsEmpty(CollectionUtils.nonNullCollection(orderLine00.getAssociatedRecords().get("extrinsics"))));
|
||||||
|
QRecord orderLine01 = order0.getAssociatedRecords().get("orderLine").get(1);
|
||||||
|
assertTrue(CollectionUtils.nullSafeIsEmpty(CollectionUtils.nonNullCollection(orderLine01.getAssociatedRecords().get("extrinsics"))));
|
||||||
|
|
||||||
|
QRecord order1 = queryOutput.getRecords().get(1);
|
||||||
|
assertEquals(1, order1.getAssociatedRecords().get("orderLine").size());
|
||||||
|
assertTrue(CollectionUtils.nullSafeIsEmpty(CollectionUtils.nonNullCollection(order1.getAssociatedRecords().get("extrinsics"))));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Test
|
||||||
|
void testQueryAssociationsLimitedAssociationNamesToIncludeChildTableDuplicatedAssociationNameExcluded() throws QException
|
||||||
|
{
|
||||||
|
QContext.getQSession().withSecurityKeyValue(TestUtils.SECURITY_KEY_TYPE_STORE_ALL_ACCESS, true);
|
||||||
|
insert2OrdersWith3Lines3LineExtrinsicsAnd4OrderExtrinsicAssociations();
|
||||||
|
|
||||||
|
QueryInput queryInput = new QueryInput();
|
||||||
|
queryInput.setTableName(TestUtils.TABLE_NAME_ORDER);
|
||||||
|
queryInput.setFilter(new QQueryFilter());
|
||||||
|
queryInput.setIncludeAssociations(true);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// say that we want extrinsics - but that should only get them from the top-level -- to get them from the child, we need orderLine.extrinsics //
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
queryInput.setAssociationNamesToInclude(List.of("orderLine", "extrinsics"));
|
||||||
|
QueryOutput queryOutput = new QueryAction().execute(queryInput);
|
||||||
|
|
||||||
|
QRecord order0 = queryOutput.getRecords().get(0);
|
||||||
|
assertEquals(2, order0.getAssociatedRecords().get("orderLine").size());
|
||||||
|
assertEquals(3, order0.getAssociatedRecords().get("extrinsics").size());
|
||||||
|
|
||||||
|
QRecord orderLine00 = order0.getAssociatedRecords().get("orderLine").get(0);
|
||||||
|
assertTrue(CollectionUtils.nullSafeIsEmpty(CollectionUtils.nonNullCollection(orderLine00.getAssociatedRecords().get("extrinsics"))));
|
||||||
|
QRecord orderLine01 = order0.getAssociatedRecords().get("orderLine").get(1);
|
||||||
|
assertTrue(CollectionUtils.nullSafeIsEmpty(CollectionUtils.nonNullCollection(orderLine01.getAssociatedRecords().get("extrinsics"))));
|
||||||
|
|
||||||
|
QRecord order1 = queryOutput.getRecords().get(1);
|
||||||
|
assertEquals(1, order1.getAssociatedRecords().get("orderLine").size());
|
||||||
|
assertEquals(1, order1.getAssociatedRecords().get("extrinsics").size());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Test
|
||||||
|
void testQueryAssociationsLimitedAssociationNamesToIncludeChildTableDuplicatedAssociationNameIncluded() throws QException
|
||||||
|
{
|
||||||
|
QContext.getQSession().withSecurityKeyValue(TestUtils.SECURITY_KEY_TYPE_STORE_ALL_ACCESS, true);
|
||||||
|
insert2OrdersWith3Lines3LineExtrinsicsAnd4OrderExtrinsicAssociations();
|
||||||
|
|
||||||
|
QueryInput queryInput = new QueryInput();
|
||||||
|
queryInput.setTableName(TestUtils.TABLE_NAME_ORDER);
|
||||||
|
queryInput.setFilter(new QQueryFilter());
|
||||||
|
queryInput.setIncludeAssociations(true);
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
// this time say we want the orderLine.extrinsics - not the top-level ones //
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
queryInput.setAssociationNamesToInclude(List.of("orderLine", "orderLine.extrinsics"));
|
||||||
|
QueryOutput queryOutput = new QueryAction().execute(queryInput);
|
||||||
|
|
||||||
|
QRecord order0 = queryOutput.getRecords().get(0);
|
||||||
|
assertEquals(2, order0.getAssociatedRecords().get("orderLine").size());
|
||||||
|
assertTrue(CollectionUtils.nullSafeIsEmpty(CollectionUtils.nonNullCollection(order0.getAssociatedRecords().get("extrinsics"))));
|
||||||
|
|
||||||
|
QRecord orderLine00 = order0.getAssociatedRecords().get("orderLine").get(0);
|
||||||
|
assertFalse(CollectionUtils.nullSafeIsEmpty(CollectionUtils.nonNullCollection(orderLine00.getAssociatedRecords().get("extrinsics"))));
|
||||||
|
QRecord orderLine01 = order0.getAssociatedRecords().get("orderLine").get(1);
|
||||||
|
assertFalse(CollectionUtils.nullSafeIsEmpty(CollectionUtils.nonNullCollection(orderLine01.getAssociatedRecords().get("extrinsics"))));
|
||||||
|
|
||||||
|
QRecord order1 = queryOutput.getRecords().get(1);
|
||||||
|
assertEquals(1, order1.getAssociatedRecords().get("orderLine").size());
|
||||||
|
assertTrue(CollectionUtils.nullSafeIsEmpty(CollectionUtils.nonNullCollection(order1.getAssociatedRecords().get("extrinsics"))));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -70,8 +70,6 @@ public class QRecordApiAdapter
|
|||||||
{
|
{
|
||||||
ApiFieldMetaData apiFieldMetaData = ApiFieldMetaData.of(field);
|
ApiFieldMetaData apiFieldMetaData = ApiFieldMetaData.of(field);
|
||||||
|
|
||||||
// todo - what about display values / possible values?
|
|
||||||
|
|
||||||
String apiFieldName = ApiFieldMetaData.getEffectiveApiFieldName(field);
|
String apiFieldName = ApiFieldMetaData.getEffectiveApiFieldName(field);
|
||||||
if(StringUtils.hasContent(apiFieldMetaData.getReplacedByFieldName()))
|
if(StringUtils.hasContent(apiFieldMetaData.getReplacedByFieldName()))
|
||||||
{
|
{
|
||||||
@ -82,6 +80,23 @@ public class QRecordApiAdapter
|
|||||||
outputRecord.put(apiFieldName, record.getValue(field.getName()));
|
outputRecord.put(apiFieldName, record.getValue(field.getName()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// todo - should probably define in meta-data if an association is included in the api or not!! //
|
||||||
|
// and what its name is too... //
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
QTableMetaData table = QContext.getQInstance().getTable(tableName);
|
||||||
|
for(Association association : CollectionUtils.nonNullList(table.getAssociations()))
|
||||||
|
{
|
||||||
|
ArrayList<Map<String, Serializable>> associationList = new ArrayList<>();
|
||||||
|
outputRecord.put(association.getName(), associationList);
|
||||||
|
|
||||||
|
for(QRecord associatedRecord : CollectionUtils.nonNullList(CollectionUtils.nonNullMap(record.getAssociatedRecords()).get(association.getName())))
|
||||||
|
{
|
||||||
|
associationList.add(qRecordToApiMap(associatedRecord, association.getAssociatedTableName(), apiVersion));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return (outputRecord);
|
return (outputRecord);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -567,6 +567,7 @@ public class QJavalinApiHandler
|
|||||||
// and throw a 400-series error (tell the user bad-request), rather than, we're doing a 500 (server error)
|
// and throw a 400-series error (tell the user bad-request), rather than, we're doing a 500 (server error)
|
||||||
|
|
||||||
getInput.setPrimaryKey(primaryKey);
|
getInput.setPrimaryKey(primaryKey);
|
||||||
|
getInput.setIncludeAssociations(true);
|
||||||
|
|
||||||
GetAction getAction = new GetAction();
|
GetAction getAction = new GetAction();
|
||||||
GetOutput getOutput = getAction.execute(getInput);
|
GetOutput getOutput = getAction.execute(getInput);
|
||||||
@ -616,6 +617,7 @@ public class QJavalinApiHandler
|
|||||||
QJavalinAccessLogger.logStart("apiQuery", logPair("table", tableName));
|
QJavalinAccessLogger.logStart("apiQuery", logPair("table", tableName));
|
||||||
|
|
||||||
queryInput.setTableName(tableName);
|
queryInput.setTableName(tableName);
|
||||||
|
queryInput.setIncludeAssociations(true);
|
||||||
|
|
||||||
PermissionsHelper.checkTablePermissionThrowing(queryInput, TablePermissionSubType.READ);
|
PermissionsHelper.checkTablePermissionThrowing(queryInput, TablePermissionSubType.READ);
|
||||||
|
|
||||||
@ -795,6 +797,16 @@ public class QJavalinApiHandler
|
|||||||
output.put("pageNo", pageNo);
|
output.put("pageNo", pageNo);
|
||||||
output.put("pageSize", pageSize);
|
output.put("pageSize", pageSize);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// map record fields for api //
|
||||||
|
// note - don't put them in the output until after the count, just because that looks a little nicer, i think //
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
ArrayList<Map<String, Serializable>> records = new ArrayList<>();
|
||||||
|
for(QRecord record : queryOutput.getRecords())
|
||||||
|
{
|
||||||
|
records.add(QRecordApiAdapter.qRecordToApiMap(record, tableName, version));
|
||||||
|
}
|
||||||
|
|
||||||
/////////////////////////////
|
/////////////////////////////
|
||||||
// optionally do the count //
|
// optionally do the count //
|
||||||
/////////////////////////////
|
/////////////////////////////
|
||||||
@ -807,14 +819,6 @@ public class QJavalinApiHandler
|
|||||||
output.put("count", countOutput.getCount());
|
output.put("count", countOutput.getCount());
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////
|
|
||||||
// map record fields for api //
|
|
||||||
///////////////////////////////
|
|
||||||
ArrayList<Map<String, Serializable>> records = new ArrayList<>();
|
|
||||||
for(QRecord record : queryOutput.getRecords())
|
|
||||||
{
|
|
||||||
records.add(QRecordApiAdapter.qRecordToApiMap(record, tableName, version));
|
|
||||||
}
|
|
||||||
output.put("records", records);
|
output.put("records", records);
|
||||||
|
|
||||||
QJavalinAccessLogger.logEndSuccess(logPair("recordCount", queryOutput.getRecords().size()), QJavalinAccessLogger.logPairIfSlow("filter", filter, SLOW_LOG_THRESHOLD_MS));
|
QJavalinAccessLogger.logEndSuccess(logPair("recordCount", queryOutput.getRecords().size()), QJavalinAccessLogger.logPairIfSlow("filter", filter, SLOW_LOG_THRESHOLD_MS));
|
||||||
|
@ -195,6 +195,29 @@ class QJavalinApiHandlerTest extends BaseTest
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Test
|
||||||
|
void testGetAssociations() throws QException
|
||||||
|
{
|
||||||
|
insert1Order3Lines4LineExtrinsicsAnd1OrderExtrinsic();
|
||||||
|
|
||||||
|
HttpResponse<String> response = Unirest.get(BASE_URL + "/api/" + VERSION + "/order/1").asString();
|
||||||
|
assertEquals(HttpStatus.OK_200, response.getStatus());
|
||||||
|
JSONObject jsonObject = new JSONObject(response.getBody());
|
||||||
|
System.out.println(jsonObject.toString(3));
|
||||||
|
JSONArray orderLines = jsonObject.getJSONArray("orderLines");
|
||||||
|
assertEquals(3, orderLines.length());
|
||||||
|
JSONObject orderLine0 = orderLines.getJSONObject(0);
|
||||||
|
JSONArray lineExtrinsics = orderLine0.getJSONArray("extrinsics");
|
||||||
|
assertEquals(3, lineExtrinsics.length());
|
||||||
|
assertEquals("Size", lineExtrinsics.getJSONObject(0).getString("key"));
|
||||||
|
assertEquals("Medium", lineExtrinsics.getJSONObject(0).getString("value"));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
**
|
**
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
@ -406,6 +429,30 @@ class QJavalinApiHandlerTest extends BaseTest
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Test
|
||||||
|
void testQueryAssociations() throws QException
|
||||||
|
{
|
||||||
|
insert1Order3Lines4LineExtrinsicsAnd1OrderExtrinsic();
|
||||||
|
|
||||||
|
HttpResponse<String> response = Unirest.get(BASE_URL + "/api/" + VERSION + "/order/query?id=1").asString();
|
||||||
|
assertEquals(HttpStatus.OK_200, response.getStatus());
|
||||||
|
JSONObject jsonObject = new JSONObject(response.getBody());
|
||||||
|
System.out.println(jsonObject.toString(3));
|
||||||
|
JSONObject order0 = jsonObject.getJSONArray("records").getJSONObject(0);
|
||||||
|
JSONArray orderLines = order0.getJSONArray("orderLines");
|
||||||
|
assertEquals(3, orderLines.length());
|
||||||
|
JSONObject orderLine0 = orderLines.getJSONObject(0);
|
||||||
|
JSONArray lineExtrinsics = orderLine0.getJSONArray("extrinsics");
|
||||||
|
assertEquals(3, lineExtrinsics.length());
|
||||||
|
assertEquals("Size", lineExtrinsics.getJSONObject(0).getString("key"));
|
||||||
|
assertEquals("Medium", lineExtrinsics.getJSONObject(0).getString("value"));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
**
|
**
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
@ -958,19 +1005,7 @@ class QJavalinApiHandlerTest extends BaseTest
|
|||||||
@Test
|
@Test
|
||||||
void testDeleteAssociations() throws QException
|
void testDeleteAssociations() throws QException
|
||||||
{
|
{
|
||||||
InsertInput insertInput = new InsertInput();
|
insert1Order3Lines4LineExtrinsicsAnd1OrderExtrinsic();
|
||||||
insertInput.setTableName(TestUtils.TABLE_NAME_ORDER);
|
|
||||||
insertInput.setRecords(List.of(new QRecord().withValue("id", 1).withValue("orderNo", "ORD123").withValue("storeId", 47)
|
|
||||||
.withAssociatedRecord("orderLines", new QRecord().withValue("lineNumber", 1).withValue("sku", "BASIC1").withValue("quantity", 42)
|
|
||||||
.withAssociatedRecord("extrinsics", new QRecord().withValue("key", "Size").withValue("value", "Medium"))
|
|
||||||
.withAssociatedRecord("extrinsics", new QRecord().withValue("key", "Discount").withValue("value", "3.50"))
|
|
||||||
.withAssociatedRecord("extrinsics", new QRecord().withValue("key", "Color").withValue("value", "Red")))
|
|
||||||
.withAssociatedRecord("orderLines", new QRecord().withValue("lineNumber", 2).withValue("sku", "BASIC2").withValue("quantity", 42)
|
|
||||||
.withAssociatedRecord("extrinsics", new QRecord().withValue("key", "Size").withValue("value", "Medium")))
|
|
||||||
.withAssociatedRecord("orderLines", new QRecord().withValue("lineNumber", 3).withValue("sku", "BASIC3").withValue("quantity", 42))
|
|
||||||
.withAssociatedRecord("extrinsics", new QRecord().withValue("key", "shopifyOrderNo").withValue("value", "#1032"))
|
|
||||||
));
|
|
||||||
new InsertAction().execute(insertInput);
|
|
||||||
|
|
||||||
assertEquals(1, queryTable(TestUtils.TABLE_NAME_ORDER).size());
|
assertEquals(1, queryTable(TestUtils.TABLE_NAME_ORDER).size());
|
||||||
assertEquals(4, queryTable(TestUtils.TABLE_NAME_LINE_ITEM_EXTRINSIC).size());
|
assertEquals(4, queryTable(TestUtils.TABLE_NAME_LINE_ITEM_EXTRINSIC).size());
|
||||||
@ -989,6 +1024,28 @@ class QJavalinApiHandlerTest extends BaseTest
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
private static void insert1Order3Lines4LineExtrinsicsAnd1OrderExtrinsic() throws QException
|
||||||
|
{
|
||||||
|
InsertInput insertInput = new InsertInput();
|
||||||
|
insertInput.setTableName(TestUtils.TABLE_NAME_ORDER);
|
||||||
|
insertInput.setRecords(List.of(new QRecord().withValue("id", 1).withValue("orderNo", "ORD123").withValue("storeId", 47)
|
||||||
|
.withAssociatedRecord("orderLines", new QRecord().withValue("lineNumber", 1).withValue("sku", "BASIC1").withValue("quantity", 42)
|
||||||
|
.withAssociatedRecord("extrinsics", new QRecord().withValue("key", "Size").withValue("value", "Medium"))
|
||||||
|
.withAssociatedRecord("extrinsics", new QRecord().withValue("key", "Discount").withValue("value", "3.50"))
|
||||||
|
.withAssociatedRecord("extrinsics", new QRecord().withValue("key", "Color").withValue("value", "Red")))
|
||||||
|
.withAssociatedRecord("orderLines", new QRecord().withValue("lineNumber", 2).withValue("sku", "BASIC2").withValue("quantity", 42)
|
||||||
|
.withAssociatedRecord("extrinsics", new QRecord().withValue("key", "Size").withValue("value", "Medium")))
|
||||||
|
.withAssociatedRecord("orderLines", new QRecord().withValue("lineNumber", 3).withValue("sku", "BASIC3").withValue("quantity", 42))
|
||||||
|
.withAssociatedRecord("extrinsics", new QRecord().withValue("key", "shopifyOrderNo").withValue("value", "#1032"))
|
||||||
|
));
|
||||||
|
new InsertAction().execute(insertInput);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
**
|
**
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
|
Reference in New Issue
Block a user