Checkpoint: Added Update (edit) action

This commit is contained in:
Darin Kelkhoff
2022-03-01 18:29:09 -06:00
parent e7c2cf9b94
commit d6557daa42
2 changed files with 90 additions and 12 deletions

View File

@ -5,6 +5,8 @@
package com.kingsrook.qqq.backend.javalin; package com.kingsrook.qqq.backend.javalin;
import java.io.File;
import java.io.IOException;
import java.io.Serializable; import java.io.Serializable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
@ -15,6 +17,8 @@ import com.kingsrook.qqq.backend.core.actions.InsertAction;
import com.kingsrook.qqq.backend.core.actions.MetaDataAction; import com.kingsrook.qqq.backend.core.actions.MetaDataAction;
import com.kingsrook.qqq.backend.core.actions.QueryAction; import com.kingsrook.qqq.backend.core.actions.QueryAction;
import com.kingsrook.qqq.backend.core.actions.TableMetaDataAction; import com.kingsrook.qqq.backend.core.actions.TableMetaDataAction;
import com.kingsrook.qqq.backend.core.actions.UpdateAction;
import com.kingsrook.qqq.backend.core.adapters.QInstanceAdapter;
import com.kingsrook.qqq.backend.core.exceptions.QModuleDispatchException; import com.kingsrook.qqq.backend.core.exceptions.QModuleDispatchException;
import com.kingsrook.qqq.backend.core.exceptions.QUserFacingException; import com.kingsrook.qqq.backend.core.exceptions.QUserFacingException;
import com.kingsrook.qqq.backend.core.model.actions.AbstractQRequest; import com.kingsrook.qqq.backend.core.model.actions.AbstractQRequest;
@ -29,8 +33,11 @@ import com.kingsrook.qqq.backend.core.model.actions.metadata.table.TableMetaData
import com.kingsrook.qqq.backend.core.model.actions.query.QQueryFilter; import com.kingsrook.qqq.backend.core.model.actions.query.QQueryFilter;
import com.kingsrook.qqq.backend.core.model.actions.query.QueryRequest; import com.kingsrook.qqq.backend.core.model.actions.query.QueryRequest;
import com.kingsrook.qqq.backend.core.model.actions.query.QueryResult; import com.kingsrook.qqq.backend.core.model.actions.query.QueryResult;
import com.kingsrook.qqq.backend.core.model.actions.update.UpdateRequest;
import com.kingsrook.qqq.backend.core.model.actions.update.UpdateResult;
import com.kingsrook.qqq.backend.core.model.data.QRecord; import com.kingsrook.qqq.backend.core.model.data.QRecord;
import com.kingsrook.qqq.backend.core.model.metadata.QInstance; import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
import com.kingsrook.qqq.backend.core.model.metadata.QTableMetaData;
import com.kingsrook.qqq.backend.core.model.session.QSession; import com.kingsrook.qqq.backend.core.model.session.QSession;
import com.kingsrook.qqq.backend.core.modules.QAuthenticationModuleDispatcher; import com.kingsrook.qqq.backend.core.modules.QAuthenticationModuleDispatcher;
import com.kingsrook.qqq.backend.core.modules.interfaces.QAuthenticationModuleInterface; import com.kingsrook.qqq.backend.core.modules.interfaces.QAuthenticationModuleInterface;
@ -40,6 +47,7 @@ import com.kingsrook.qqq.backend.core.utils.StringUtils;
import io.javalin.Javalin; import io.javalin.Javalin;
import io.javalin.apibuilder.EndpointGroup; import io.javalin.apibuilder.EndpointGroup;
import io.javalin.http.Context; import io.javalin.http.Context;
import org.apache.commons.io.FileUtils;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.eclipse.jetty.http.HttpStatus; import org.eclipse.jetty.http.HttpStatus;
@ -48,6 +56,7 @@ import static io.javalin.apibuilder.ApiBuilder.get;
import static io.javalin.apibuilder.ApiBuilder.patch; import static io.javalin.apibuilder.ApiBuilder.patch;
import static io.javalin.apibuilder.ApiBuilder.path; import static io.javalin.apibuilder.ApiBuilder.path;
import static io.javalin.apibuilder.ApiBuilder.post; import static io.javalin.apibuilder.ApiBuilder.post;
import static io.javalin.apibuilder.ApiBuilder.put;
/******************************************************************************* /*******************************************************************************
@ -91,12 +100,13 @@ public class QJavalinImplementation
/******************************************************************************* /*******************************************************************************
** Setter for qInstance
** **
*******************************************************************************/ *******************************************************************************/
public static void setQInstance(QInstance qInstance) public QJavalinImplementation(String qInstanceFilePath) throws IOException
{ {
QJavalinImplementation.qInstance = qInstance; LOG.info("Loading qInstance from file (assuming json): " + qInstanceFilePath);
String qInstanceJson = FileUtils.readFileToString(new File(qInstanceFilePath));
QJavalinImplementation.qInstance = new QInstanceAdapter().jsonToQInstanceIncludingBackends(qInstanceJson);
} }
@ -134,11 +144,13 @@ public class QJavalinImplementation
path("/:table", () -> path("/:table", () ->
{ {
get("/", QJavalinImplementation::dataQuery); get("/", QJavalinImplementation::dataQuery);
post("/", QJavalinImplementation::dataInsert); post("/", QJavalinImplementation::dataInsert); // todo - internal to that method, if input is a list, do a bulk - else, single.
path("/:id", () -> // todo - add put and/or patch at this level (without a primaryKey) to do a bulk update based on primaryKeys in the records.
path("/:primaryKey", () ->
{ {
get("", QJavalinImplementation::dataGet); get("", QJavalinImplementation::dataGet);
patch("", QJavalinImplementation::dataUpdate); patch("", QJavalinImplementation::dataUpdate);
put("", QJavalinImplementation::dataUpdate); // todo - want different semantics??
delete("", QJavalinImplementation::dataDelete); delete("", QJavalinImplementation::dataDelete);
}); });
}); });
@ -176,7 +188,7 @@ public class QJavalinImplementation
{ {
String table = context.pathParam("table"); String table = context.pathParam("table");
List<Serializable> primaryKeys = new ArrayList<>(); List<Serializable> primaryKeys = new ArrayList<>();
primaryKeys.add(context.pathParam("id")); primaryKeys.add(context.pathParam("primaryKey"));
DeleteRequest deleteRequest = new DeleteRequest(qInstance); DeleteRequest deleteRequest = new DeleteRequest(qInstance);
setupSession(context, deleteRequest); setupSession(context, deleteRequest);
@ -201,7 +213,41 @@ public class QJavalinImplementation
*******************************************************************************/ *******************************************************************************/
private static void dataUpdate(Context context) private static void dataUpdate(Context context)
{ {
context.result("{\"todo\":\"not-done\",\"updateResult\":{}}"); try
{
String table = context.pathParam("table");
List<QRecord> recordList = new ArrayList<>();
QRecord record = new QRecord();
record.setTableName(table);
recordList.add(record);
Map<?, ?> map = context.bodyAsClass(Map.class);
for(Map.Entry<?, ?> entry : map.entrySet())
{
if(StringUtils.hasContent(String.valueOf(entry.getValue())))
{
record.setValue(String.valueOf(entry.getKey()), (Serializable) entry.getValue());
}
}
QTableMetaData tableMetaData = qInstance.getTable(table);
record.setValue(tableMetaData.getPrimaryKeyField(), context.pathParam("primaryKey"));
UpdateRequest updateRequest = new UpdateRequest(qInstance);
setupSession(context, updateRequest);
updateRequest.setTableName(table);
updateRequest.setRecords(recordList);
UpdateAction updateAction = new UpdateAction();
UpdateResult updateResult = updateAction.execute(updateRequest);
context.result(JsonUtils.toJson(updateResult));
}
catch(Exception e)
{
handleException(context, e);
}
} }

View File

@ -20,7 +20,7 @@ import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.assertTrue;
@ -147,9 +147,9 @@ class QJavalinImplementationTest
JSONObject record0 = records.getJSONObject(0); JSONObject record0 = records.getJSONObject(0);
assertTrue(record0.has("values")); assertTrue(record0.has("values"));
assertEquals("person", record0.getString("tableName")); assertEquals("person", record0.getString("tableName"));
assertTrue(record0.has("primaryKey"));
JSONObject values0 = record0.getJSONObject("values"); JSONObject values0 = record0.getJSONObject("values");
assertTrue(values0.has("firstName")); assertTrue(values0.has("firstName"));
assertTrue(values0.has("id"));
} }
@ -200,10 +200,42 @@ class QJavalinImplementationTest
JSONObject record0 = records.getJSONObject(0); JSONObject record0 = records.getJSONObject(0);
assertTrue(record0.has("values")); assertTrue(record0.has("values"));
assertEquals("person", record0.getString("tableName")); assertEquals("person", record0.getString("tableName"));
assertTrue(record0.has("primaryKey"));
JSONObject values0 = record0.getJSONObject("values"); JSONObject values0 = record0.getJSONObject("values");
assertTrue(values0.has("firstName")); assertTrue(values0.has("firstName"));
assertEquals("Bobby", values0.getString("firstName")); assertEquals("Bobby", values0.getString("firstName"));
assertTrue(values0.has("id"));
assertEquals(6, values0.getInt("id"));
}
/*******************************************************************************
** test an update
**
*******************************************************************************/
@Test
public void test_dataUpdate()
{
Map<String, Serializable> body = new HashMap<>();
body.put("firstName", "Free");
//? body.put("id", 4);
HttpResponse<String> response = Unirest.patch(BASE_URL + "/data/person/4")
.header("Content-Type", "application/json")
.body(body)
.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);
assertTrue(record0.has("values"));
assertEquals("person", record0.getString("tableName"));
JSONObject values0 = record0.getJSONObject("values");
assertEquals(4, values0.getInt("id"));
assertEquals("Free", values0.getString("firstName"));
// mmm, whole record isn't loaded. should it be? assertEquals("Samples", values0.getString("lastName"));
} }
@ -224,13 +256,13 @@ class QJavalinImplementationTest
JSONObject jsonObject = JsonUtils.toJSONObject(response.getBody()); JSONObject jsonObject = JsonUtils.toJSONObject(response.getBody());
assertNotNull(jsonObject); assertNotNull(jsonObject);
assertEquals(1, jsonObject.getJSONArray("records").length()); assertEquals(1, jsonObject.getJSONArray("records").length());
assertEquals(3, jsonObject.getJSONArray("records").getJSONObject(0).getInt("primaryKey")); assertEquals(3, jsonObject.getJSONArray("records").getJSONObject(0).getJSONObject("values").getInt("id"));
TestUtils.runTestSql("SELECT id FROM person", (rs -> { TestUtils.runTestSql("SELECT id FROM person", (rs -> {
int rowsFound = 0; int rowsFound = 0;
while(rs.next()) while(rs.next())
{ {
rowsFound++; rowsFound++;
assertFalse(rs.getInt(1) == 3); assertNotEquals(3, rs.getInt(1));
} }
assertEquals(4, rowsFound); assertEquals(4, rowsFound);
})); }));