mirror of
https://github.com/Kingsrook/qqq.git
synced 2025-07-17 20:50:44 +00:00
Update to accept queryJoins in count and query actions
This commit is contained in:
@ -85,6 +85,7 @@ 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.QQueryFilter;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryInput;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryJoin;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryOutput;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.update.UpdateInput;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.update.UpdateOutput;
|
||||
@ -112,6 +113,7 @@ import io.javalin.apibuilder.EndpointGroup;
|
||||
import io.javalin.http.Context;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.eclipse.jetty.http.HttpStatus;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONObject;
|
||||
import static com.kingsrook.qqq.backend.core.logging.LogUtils.logPair;
|
||||
import static com.kingsrook.qqq.backend.javalin.QJavalinAccessLogger.logPairIfSlow;
|
||||
@ -749,6 +751,8 @@ public class QJavalinImplementation
|
||||
countInput.setFilter(JsonUtils.toObject(filter, QQueryFilter.class));
|
||||
}
|
||||
|
||||
countInput.setQueryJoins(processQueryJoinsParam(context));
|
||||
|
||||
CountAction countAction = new CountAction();
|
||||
CountOutput countOutput = countAction.execute(countInput);
|
||||
|
||||
@ -777,6 +781,16 @@ public class QJavalinImplementation
|
||||
* {"fieldName":"age","isAscending":true}
|
||||
* ]}
|
||||
* </pre>
|
||||
*
|
||||
* queryJoins parameter is a JSONArray of objects which represent a QueryJoin object. e.g.,
|
||||
* <pre>
|
||||
* queryJoins=
|
||||
* [
|
||||
* {"joinTable":"orderLine","select":true,"type":"INNER"},
|
||||
* {"joinTable":"customer","select":true,"type":"LEFT"}
|
||||
* }
|
||||
* </pre>
|
||||
* Additional field names in the JSONObjects there are: baseTableOrAlias, alias, joinName.
|
||||
*******************************************************************************/
|
||||
static void dataQuery(Context context)
|
||||
{
|
||||
@ -807,6 +821,8 @@ public class QJavalinImplementation
|
||||
queryInput.setFilter(JsonUtils.toObject(filter, QQueryFilter.class));
|
||||
}
|
||||
|
||||
queryInput.setQueryJoins(processQueryJoinsParam(context));
|
||||
|
||||
QueryAction queryAction = new QueryAction();
|
||||
QueryOutput queryOutput = queryAction.execute(queryInput);
|
||||
|
||||
@ -822,6 +838,56 @@ public class QJavalinImplementation
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
private static List<QueryJoin> processQueryJoinsParam(Context context)
|
||||
{
|
||||
List<QueryJoin> queryJoins = null;
|
||||
|
||||
String queryJoinsParam = stringQueryParam(context, "queryJoins");
|
||||
if(StringUtils.hasContent(queryJoinsParam))
|
||||
{
|
||||
queryJoins = new ArrayList<>();
|
||||
|
||||
JSONArray queryJoinsJSON = new JSONArray(queryJoinsParam);
|
||||
for(int i = 0; i < queryJoinsJSON.length(); i++)
|
||||
{
|
||||
QueryJoin queryJoin = new QueryJoin();
|
||||
queryJoins.add(queryJoin);
|
||||
|
||||
JSONObject jsonObject = queryJoinsJSON.getJSONObject(i);
|
||||
queryJoin.setJoinTable(jsonObject.optString("joinTable"));
|
||||
|
||||
if(jsonObject.has("baseTableOrAlias") && !jsonObject.isNull("baseTableOrAlias"))
|
||||
{
|
||||
queryJoin.setBaseTableOrAlias(jsonObject.optString("baseTableOrAlias"));
|
||||
}
|
||||
|
||||
if(jsonObject.has("alias") && !jsonObject.isNull("alias"))
|
||||
{
|
||||
queryJoin.setAlias(jsonObject.optString("alias"));
|
||||
}
|
||||
|
||||
queryJoin.setSelect(jsonObject.optBoolean("select"));
|
||||
|
||||
if(jsonObject.has("type") && !jsonObject.isNull("type"))
|
||||
{
|
||||
queryJoin.setType(QueryJoin.Type.valueOf(jsonObject.getString("type")));
|
||||
}
|
||||
|
||||
if(jsonObject.has("joinName") && !jsonObject.isNull("joinName"))
|
||||
{
|
||||
queryJoin.setJoinMetaData(QContext.getQInstance().getJoin(jsonObject.getString("joinName")));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (queryJoins);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
|
@ -234,7 +234,7 @@ class QJavalinImplementationTest extends QJavalinTestBase
|
||||
JSONObject jsonObject = JsonUtils.toJSONObject(response.getBody());
|
||||
assertTrue(jsonObject.has("count"));
|
||||
int count = jsonObject.getInt("count");
|
||||
assertEquals(5, count);
|
||||
assertEquals(6, count);
|
||||
}
|
||||
|
||||
|
||||
@ -246,7 +246,7 @@ class QJavalinImplementationTest extends QJavalinTestBase
|
||||
@Test
|
||||
public void test_dataCountWithFilter()
|
||||
{
|
||||
String filterJson = getFirstNameEqualsTimFilterJSON();
|
||||
String filterJson = getFirstNameEqualsFilterJSON("Tim");
|
||||
HttpResponse<String> response = Unirest.get(BASE_URL + "/data/person/count?filter=" + URLEncoder.encode(filterJson, StandardCharsets.UTF_8)).asString();
|
||||
|
||||
assertEquals(200, response.getStatus());
|
||||
@ -266,7 +266,7 @@ class QJavalinImplementationTest extends QJavalinTestBase
|
||||
@Test
|
||||
public void test_dataCountPOST()
|
||||
{
|
||||
String filterJson = getFirstNameEqualsTimFilterJSON();
|
||||
String filterJson = getFirstNameEqualsFilterJSON("Tim");
|
||||
HttpResponse<String> response = Unirest.post(BASE_URL + "/data/person/count")
|
||||
.field("filter", filterJson)
|
||||
.asString();
|
||||
@ -294,7 +294,7 @@ class QJavalinImplementationTest extends QJavalinTestBase
|
||||
JSONObject jsonObject = JsonUtils.toJSONObject(response.getBody());
|
||||
assertTrue(jsonObject.has("records"));
|
||||
JSONArray records = jsonObject.getJSONArray("records");
|
||||
assertEquals(5, records.length());
|
||||
assertEquals(6, records.length());
|
||||
JSONObject record0 = records.getJSONObject(0);
|
||||
assertTrue(record0.has("values"));
|
||||
assertEquals("person", record0.getString("tableName"));
|
||||
@ -312,7 +312,7 @@ class QJavalinImplementationTest extends QJavalinTestBase
|
||||
@Test
|
||||
public void test_dataQueryWithFilter()
|
||||
{
|
||||
String filterJson = getFirstNameEqualsTimFilterJSON();
|
||||
String filterJson = getFirstNameEqualsFilterJSON("Tim");
|
||||
HttpResponse<String> response = Unirest.get(BASE_URL + "/data/person?filter=" + URLEncoder.encode(filterJson, StandardCharsets.UTF_8)).asString();
|
||||
|
||||
assertEquals(200, response.getStatus());
|
||||
@ -327,6 +327,34 @@ class QJavalinImplementationTest extends QJavalinTestBase
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** test a table query using a filter and a queryJoin.
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Test
|
||||
public void test_dataQueryWithFilterAndQueryJoin()
|
||||
{
|
||||
String filterJson = getFirstNameEqualsFilterJSON("Darin");
|
||||
String queryJoinsJson = """
|
||||
[{"joinTable":"person","select":true,"type":"INNER","joinName":"PersonJoinPartnerPerson","alias":"partnerPerson"}]
|
||||
""";
|
||||
|
||||
HttpResponse<String> response = Unirest.get(BASE_URL + "/data/person?filter=" + URLEncoder.encode(filterJson, StandardCharsets.UTF_8)
|
||||
+ "&queryJoins=" + URLEncoder.encode(queryJoinsJson, StandardCharsets.UTF_8)).asString();
|
||||
|
||||
assertEquals(200, response.getStatus());
|
||||
JSONObject jsonObject = JsonUtils.toJSONObject(response.getBody());
|
||||
assertTrue(jsonObject.has("records"));
|
||||
JSONArray records = jsonObject.getJSONArray("records");
|
||||
assertEquals(1, records.length());
|
||||
JSONObject record0 = records.getJSONObject(0);
|
||||
JSONObject values0 = record0.getJSONObject("values");
|
||||
assertEquals("Darin", values0.getString("firstName"));
|
||||
assertEquals("Linda", values0.getString("partnerPerson.firstName"));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** test a table query using an actual filter via POST.
|
||||
**
|
||||
@ -334,7 +362,7 @@ class QJavalinImplementationTest extends QJavalinTestBase
|
||||
@Test
|
||||
public void test_dataQueryWithFilterPOST()
|
||||
{
|
||||
String filterJson = getFirstNameEqualsTimFilterJSON();
|
||||
String filterJson = getFirstNameEqualsFilterJSON("Tim");
|
||||
HttpResponse<String> response = Unirest.post(BASE_URL + "/data/person/query")
|
||||
.field("filter", filterJson)
|
||||
.asString();
|
||||
@ -354,10 +382,10 @@ class QJavalinImplementationTest extends QJavalinTestBase
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
private String getFirstNameEqualsTimFilterJSON()
|
||||
private String getFirstNameEqualsFilterJSON(String name)
|
||||
{
|
||||
return """
|
||||
{"criteria":[{"fieldName":"firstName","operator":"EQUALS","values":["Tim"]}]}""";
|
||||
{"criteria":[{"fieldName":"firstName","operator":"EQUALS","values":["${name}"]}]}""".replaceAll("\\$\\{name}", name);
|
||||
}
|
||||
|
||||
|
||||
@ -391,7 +419,7 @@ class QJavalinImplementationTest extends QJavalinTestBase
|
||||
assertTrue(values0.has("firstName"));
|
||||
assertEquals("Bobby", values0.getString("firstName"));
|
||||
assertTrue(values0.has("id"));
|
||||
assertEquals(6, values0.getInt("id"));
|
||||
assertEquals(7, values0.getInt("id"));
|
||||
}
|
||||
|
||||
|
||||
@ -457,7 +485,7 @@ class QJavalinImplementationTest extends QJavalinTestBase
|
||||
rowsFound++;
|
||||
assertNotEquals(3, rs.getInt(1));
|
||||
}
|
||||
assertEquals(4, rowsFound);
|
||||
assertEquals(5, rowsFound);
|
||||
}));
|
||||
}
|
||||
|
||||
@ -474,7 +502,7 @@ class QJavalinImplementationTest extends QJavalinTestBase
|
||||
assertEquals("text/csv;charset=utf-8", response.getHeaders().get("Content-Type").get(0));
|
||||
assertEquals("filename=MyPersonExport.csv", response.getHeaders().get("Content-Disposition").get(0));
|
||||
String[] csvLines = response.getBody().split("\n");
|
||||
assertEquals(6, csvLines.length);
|
||||
assertEquals(7, csvLines.length);
|
||||
}
|
||||
|
||||
|
||||
@ -512,7 +540,7 @@ class QJavalinImplementationTest extends QJavalinTestBase
|
||||
@Test
|
||||
void testExportFilterQueryParam()
|
||||
{
|
||||
String filterJson = getFirstNameEqualsTimFilterJSON();
|
||||
String filterJson = getFirstNameEqualsFilterJSON("Tim");
|
||||
HttpResponse<String> response = Unirest.get(BASE_URL + "/data/person/export/Favorite People.csv?filter=" + URLEncoder.encode(filterJson, StandardCharsets.UTF_8)).asString();
|
||||
assertEquals("filename=Favorite People.csv", response.getHeaders().get("Content-Disposition").get(0));
|
||||
String[] csvLines = response.getBody().split("\n");
|
||||
@ -576,7 +604,7 @@ class QJavalinImplementationTest extends QJavalinTestBase
|
||||
JSONObject jsonObject = JsonUtils.toJSONObject(response.getBody());
|
||||
assertNotNull(jsonObject);
|
||||
assertNotNull(jsonObject.getJSONArray("options"));
|
||||
assertEquals(5, jsonObject.getJSONArray("options").length());
|
||||
assertEquals(6, jsonObject.getJSONArray("options").length());
|
||||
assertEquals(1, jsonObject.getJSONArray("options").getJSONObject(0).getInt("id"));
|
||||
assertEquals("Darin Kelkhoff (1)", jsonObject.getJSONArray("options").getJSONObject(0).getString("label"));
|
||||
}
|
||||
|
@ -46,6 +46,9 @@ import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeUsage;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.dashboard.QWidgetMetaData;
|
||||
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.joins.JoinOn;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.joins.JoinType;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.joins.QJoinMetaData;
|
||||
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;
|
||||
@ -139,6 +142,7 @@ public class TestUtils
|
||||
qInstance.setAuthentication(defineAuthentication());
|
||||
qInstance.addBackend(defineDefaultH2Backend());
|
||||
qInstance.addTable(defineTablePerson());
|
||||
qInstance.addJoin(definePersonJoinPartnerPerson());
|
||||
qInstance.addProcess(defineProcessGreetPeople());
|
||||
qInstance.addProcess(defineProcessGreetPeopleInteractive());
|
||||
qInstance.addProcess(defineProcessSimpleSleep());
|
||||
@ -249,6 +253,21 @@ public class TestUtils
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public static QJoinMetaData definePersonJoinPartnerPerson()
|
||||
{
|
||||
return (new QJoinMetaData()
|
||||
.withLeftTable(TABLE_NAME_PERSON)
|
||||
.withRightTable(TABLE_NAME_PERSON)
|
||||
.withType(JoinType.MANY_TO_ONE)
|
||||
.withName("PersonJoinPartnerPerson")
|
||||
.withJoinOn(new JoinOn("partnerPersonId", "id")));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Define the 'greet people' process
|
||||
*******************************************************************************/
|
||||
|
@ -34,8 +34,9 @@ CREATE TABLE person
|
||||
test_script_id INT
|
||||
);
|
||||
|
||||
INSERT INTO person (id, first_name, last_name, birth_date, email) VALUES (1, 'Darin', 'Kelkhoff', '1980-05-31', 'darin.kelkhoff@gmail.com');
|
||||
INSERT INTO person (id, first_name, last_name, birth_date, email, partner_person_id) VALUES (1, 'Darin', 'Kelkhoff', '1980-05-31', 'darin.kelkhoff@gmail.com', 6);
|
||||
INSERT INTO person (id, first_name, last_name, birth_date, email) VALUES (2, 'James', 'Maes', '1980-05-15', 'jmaes@mmltholdings.com');
|
||||
INSERT INTO person (id, first_name, last_name, birth_date, email) VALUES (3, 'Tim', 'Chamberlain', '1976-05-28', 'tchamberlain@mmltholdings.com');
|
||||
INSERT INTO person (id, first_name, last_name, birth_date, email) VALUES (4, 'Tyler', 'Samples', '1990-01-01', 'tsamples@mmltholdings.com');
|
||||
INSERT INTO person (id, first_name, last_name, birth_date, email) VALUES (5, 'Garret', 'Richardson', '1981-01-01', 'grichardson@mmltholdings.com');
|
||||
INSERT INTO person (id, first_name, last_name, birth_date, email) VALUES (6, 'Linda', 'Kelkhoff', '1976-01-01', 'not-linda.kelkhoff@gmail.com');
|
||||
|
Reference in New Issue
Block a user