From d6557daa42bcb028883287bb707bd0e788308c38 Mon Sep 17 00:00:00 2001 From: Darin Kelkhoff Date: Tue, 1 Mar 2022 18:29:09 -0600 Subject: [PATCH] Checkpoint: Added Update (edit) action --- .../javalin/QJavalinImplementation.java | 60 ++++++++++++++++--- .../javalin/QJavalinImplementationTest.java | 42 +++++++++++-- 2 files changed, 90 insertions(+), 12 deletions(-) diff --git a/src/main/java/com/kingsrook/qqq/backend/javalin/QJavalinImplementation.java b/src/main/java/com/kingsrook/qqq/backend/javalin/QJavalinImplementation.java index ccaefc50..e4f53aad 100644 --- a/src/main/java/com/kingsrook/qqq/backend/javalin/QJavalinImplementation.java +++ b/src/main/java/com/kingsrook/qqq/backend/javalin/QJavalinImplementation.java @@ -5,6 +5,8 @@ package com.kingsrook.qqq.backend.javalin; +import java.io.File; +import java.io.IOException; import java.io.Serializable; import java.util.ArrayList; 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.QueryAction; 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.QUserFacingException; 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.QueryRequest; 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.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.modules.QAuthenticationModuleDispatcher; 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.apibuilder.EndpointGroup; import io.javalin.http.Context; +import org.apache.commons.io.FileUtils; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; 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.path; 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", () -> { get("/", QJavalinImplementation::dataQuery); - post("/", QJavalinImplementation::dataInsert); - path("/:id", () -> + post("/", QJavalinImplementation::dataInsert); // todo - internal to that method, if input is a list, do a bulk - else, single. + // 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); patch("", QJavalinImplementation::dataUpdate); + put("", QJavalinImplementation::dataUpdate); // todo - want different semantics?? delete("", QJavalinImplementation::dataDelete); }); }); @@ -176,7 +188,7 @@ public class QJavalinImplementation { String table = context.pathParam("table"); List primaryKeys = new ArrayList<>(); - primaryKeys.add(context.pathParam("id")); + primaryKeys.add(context.pathParam("primaryKey")); DeleteRequest deleteRequest = new DeleteRequest(qInstance); setupSession(context, deleteRequest); @@ -201,7 +213,41 @@ public class QJavalinImplementation *******************************************************************************/ private static void dataUpdate(Context context) { - context.result("{\"todo\":\"not-done\",\"updateResult\":{}}"); + try + { + String table = context.pathParam("table"); + List 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); + } } diff --git a/src/test/java/com/kingsrook/qqq/backend/javalin/QJavalinImplementationTest.java b/src/test/java/com/kingsrook/qqq/backend/javalin/QJavalinImplementationTest.java index b2266896..3d2a4ac6 100644 --- a/src/test/java/com/kingsrook/qqq/backend/javalin/QJavalinImplementationTest.java +++ b/src/test/java/com/kingsrook/qqq/backend/javalin/QJavalinImplementationTest.java @@ -20,7 +20,7 @@ import org.junit.jupiter.api.BeforeAll; 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.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -147,9 +147,9 @@ class QJavalinImplementationTest JSONObject record0 = records.getJSONObject(0); assertTrue(record0.has("values")); assertEquals("person", record0.getString("tableName")); - assertTrue(record0.has("primaryKey")); JSONObject values0 = record0.getJSONObject("values"); assertTrue(values0.has("firstName")); + assertTrue(values0.has("id")); } @@ -200,10 +200,42 @@ class QJavalinImplementationTest JSONObject record0 = records.getJSONObject(0); assertTrue(record0.has("values")); assertEquals("person", record0.getString("tableName")); - assertTrue(record0.has("primaryKey")); JSONObject values0 = record0.getJSONObject("values"); assertTrue(values0.has("firstName")); assertEquals("Bobby", values0.getString("firstName")); + assertTrue(values0.has("id")); + assertEquals(6, values0.getInt("id")); + } + + + /******************************************************************************* + ** test an update + ** + *******************************************************************************/ + @Test + public void test_dataUpdate() + { + Map body = new HashMap<>(); + body.put("firstName", "Free"); + //? body.put("id", 4); + + HttpResponse 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()); assertNotNull(jsonObject); 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 -> { int rowsFound = 0; while(rs.next()) { rowsFound++; - assertFalse(rs.getInt(1) == 3); + assertNotEquals(3, rs.getInt(1)); } assertEquals(4, rowsFound); }));