From 996579846e7b66b487e20d0a78199c9c910a74fd Mon Sep 17 00:00:00 2001 From: silrenan <75952546+silrenan@users.noreply.github.com> Date: Mon, 2 Jun 2025 11:16:30 -0300 Subject: [PATCH 1/4] refactor MySQLDAO to validate database configuration and credentials before operations Signed-off-by: sirenan <75952546+silrenan@users.noreply.github.com> --- .../br/com/pedr0limpio/services/MySQLDAO.java | 100 +++++++++++------- 1 file changed, 60 insertions(+), 40 deletions(-) diff --git a/src/main/java/br/com/pedr0limpio/services/MySQLDAO.java b/src/main/java/br/com/pedr0limpio/services/MySQLDAO.java index 0a917ba..9f15de2 100644 --- a/src/main/java/br/com/pedr0limpio/services/MySQLDAO.java +++ b/src/main/java/br/com/pedr0limpio/services/MySQLDAO.java @@ -40,8 +40,23 @@ private void loadDatabaseConfig() { } } + private void checkDatabaseConfig() { + if (url == null || url.trim().isEmpty() || + username == null || username.trim().isEmpty() || + password == null || password.trim().isEmpty()) { + throw new RuntimeException("Database configuration is missing or empty. Please check application.properties."); + } + // Try a simple connection to validate credentials + try (Connection conn = DriverManager.getConnection(url, username, password)) { + // Connection successful, do nothing + } catch (SQLException e) { + throw new RuntimeException("Database credentials are invalid or database is unreachable: " + e.getMessage(), e); + } + } + @Override public void writeTask(Task task) { + checkDatabaseConfig(); try (Connection conn = DriverManager.getConnection(url, username, password)) { conn.setAutoCommit(false); @@ -129,62 +144,67 @@ private void insertTaskTag(Connection conn, int taskId, int tagId) throws SQLExc } @Override - public List getAllTasks() { //TODO[#9]: Implement getAllTasks() to fetch in DB for all tasks. + public List getAllTasks() { + checkDatabaseConfig(); return List.of(); } -@Override -public Task getById(int id) { //Implement getById to fetch in DB for a task. - String sql = "SELECT task_id, description, priority, created_at, conclusion_at FROM TASKS WHERE task_id = ?"; - try (Connection conn = DriverManager.getConnection(url, username, password); - PreparedStatement stmt = conn.prepareStatement(sql)) { - stmt.setInt(1, id); - try (ResultSet rs = stmt.executeQuery()) { - if (rs.next()) { - Task task = new Task(rs.getInt("task_id")); - task.setDescription(rs.getString("description")); - task.setPriority(Enum.valueOf(Priority.class, rs.getString("priority"))); - task.setCreation(rs.getTimestamp("created_at")); - Timestamp conclusion = rs.getTimestamp("conclusion_at"); - if (conclusion != null) { - task.setConclusion(conclusion); - } - // Fetch tags for this task - String tagSql = "SELECT t.name FROM TAGS t " + - "JOIN TASK_TAGS tt ON t.tag_id = tt.tag_id " + - "WHERE tt.task_id = ?"; - try (PreparedStatement tagStmt = conn.prepareStatement(tagSql)) { - tagStmt.setInt(1, id); - try (ResultSet tagRs = tagStmt.executeQuery()) { - List tags = new ArrayList<>(); - while (tagRs.next()) { - String tagName = tagRs.getString("name"); - try { - tags.add(Tag.valueOf(tagName)); - } catch (IllegalArgumentException e) { - LOGGER.warn("Unknown tag in DB: " + tagName); + @Override + public Task getById(int id) { + checkDatabaseConfig(); + String sql = "SELECT task_id, description, priority, created_at, conclusion_at FROM TASKS WHERE task_id = ?"; + try (Connection conn = DriverManager.getConnection(url, username, password); + PreparedStatement stmt = conn.prepareStatement(sql)) { + stmt.setInt(1, id); + try (ResultSet rs = stmt.executeQuery()) { + if (rs.next()) { + Task task = new Task(rs.getInt("task_id")); + task.setDescription(rs.getString("description")); + task.setPriority(Enum.valueOf(Priority.class, rs.getString("priority"))); + task.setCreation(rs.getTimestamp("created_at")); + Timestamp conclusion = rs.getTimestamp("conclusion_at"); + if (conclusion != null) { + task.setConclusion(conclusion); + } + // Fetch tags for this task + String tagSql = "SELECT t.name FROM TAGS t " + + "JOIN TASK_TAGS tt ON t.tag_id = tt.tag_id " + + "WHERE tt.task_id = ?"; + try (PreparedStatement tagStmt = conn.prepareStatement(tagSql)) { + tagStmt.setInt(1, id); + try (ResultSet tagRs = tagStmt.executeQuery()) { + List tags = new ArrayList<>(); + while (tagRs.next()) { + String tagName = tagRs.getString("name"); + try { + tags.add(Tag.valueOf(tagName)); + } catch (IllegalArgumentException e) { + LOGGER.warn("Unknown tag in DB: " + tagName); + } } + task.setTagList(tags); } - task.setTagList(tags); } + return task; } - return task; } + } catch (SQLException e) { + LOGGER.error(e.getMessage()); } - } catch (SQLException e) { - LOGGER.error(e.getMessage()); + return null; } - return null; -} @Override - public void update(int idFrom, Task taskFor) { //TODO[#11]: Implement update(int idFrom, Task taskFor) to update a task in DB. + public void update(int idFrom, Task taskFor) { + checkDatabaseConfig(); + //TODO[#11]: Implement update(int idFrom, Task taskFor) to update a task in DB. } @Override - public void removeById(int id) { //TODO[#12]: Implement removeById(int id) to delete a task by id in DB. + public void removeById(int id) { + checkDatabaseConfig(); + //TODO[#12]: Implement removeById(int id) to delete a task by id in DB. } } - From 228ab20fa89283cb8024cf826533958fd3f690a2 Mon Sep 17 00:00:00 2001 From: silrenan <75952546+silrenan@users.noreply.github.com> Date: Wed, 11 Jun 2025 11:58:25 -0300 Subject: [PATCH 2/4] change writeTask method to return the created task ID Signed-off-by: silrenan <75952546+silrenan@users.noreply.github.com> --- src/main/java/br/com/pedr0limpio/services/MySQLDAO.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/br/com/pedr0limpio/services/MySQLDAO.java b/src/main/java/br/com/pedr0limpio/services/MySQLDAO.java index 2ee01d5..78954e3 100644 --- a/src/main/java/br/com/pedr0limpio/services/MySQLDAO.java +++ b/src/main/java/br/com/pedr0limpio/services/MySQLDAO.java @@ -55,7 +55,7 @@ private void checkDatabaseConfig() { } @Override - public void writeTask(Task task) { + public int writeTask(Task task) { checkDatabaseConfig(); int taskId = -1; From 62008e426dbad63cafdfd5a28bd6f8c26ba9473d Mon Sep 17 00:00:00 2001 From: silrenan <75952546+silrenan@users.noreply.github.com> Date: Wed, 11 Jun 2025 11:20:02 -0300 Subject: [PATCH 3/4] add instructions for using the GraphQL API with Insomnia Signed-off-by: silrenan <75952546+silrenan@users.noreply.github.com> --- README.md | 54 ++++++++- doc/insomnia/insomnia.json | 221 +++++++++++++++++++++++++++++++++++++ 2 files changed, 274 insertions(+), 1 deletion(-) create mode 100644 doc/insomnia/insomnia.json diff --git a/README.md b/README.md index ec42fc0..b33aba5 100644 --- a/README.md +++ b/README.md @@ -43,4 +43,56 @@ If you want to learn more about building native executables, please consult **Import/Export** > **Import Data** > **From File**. + - Select the `doc/insomnia/insomnia.json` file. + - This will import all relevant requests for Tasky. + +3. **Manual Setup (Optional)** + + - Alternatively, you can create a new request manually: + - Click on the **Create** button and select **Request**. + - Choose **GraphQL Query** as the request type. + - Set the request URL to `http://localhost:8080/graphql`. + - Run the app in dev mode using: + ```shell + ./mvnw quarkus:dev # if on linux + .\mvnw.cmd quarkus:dev # if on windows powershell + ``` + - Paste your GraphQL query (for example, to list all tasks): + + ```graphql + query { + listAll { + taskId + title + description + tags { + name + } + } + } + ``` + + - Click **Send** to execute the query and see the results. + +4. **Tip:** + You can save your requests in a collection for easy access later. \ No newline at end of file diff --git a/doc/insomnia/insomnia.json b/doc/insomnia/insomnia.json new file mode 100644 index 0000000..0d2cfd4 --- /dev/null +++ b/doc/insomnia/insomnia.json @@ -0,0 +1,221 @@ +{ + "_type": "export", + "__export_format": 4, + "__export_date": "2025-06-11T14:07:47.005Z", + "__export_source": "insomnia.desktop.app:v10.3.1", + "resources": [ + { + "_id": "req_890f0fcd88c547caa3f21524c28bd167", + "parentId": "wrk_3d521749d9754acc9979a11ac55e42a1", + "modified": 1748453651349, + "created": 1748443055314, + "url": "http://localhost:8080/graphql", + "name": "newTask", + "description": "", + "method": "POST", + "body": { + "mimeType": "application/graphql", + "text": "{\"query\":\"mutation {\\n\\tnewTask(\\n\\t\\ttask: {\\n\\t\\tdescription: \\\"deleteme\\\",\\n\\t\\tpriority: Info,\\n\\t\\ttagList: [Personal, Work],\\n\\t\\tcreation: \\\"2025-05-28T11:00:00Z\\\",\\n\\t\\tconclusion: null\\n\\t\\n\\t\\t})\\n\\t{\\n\\t\\tid\\n\\t\\tdescription\\n\\t\\tpriority\\n\\t\\ttagList\\n\\t\\tcreation\\n\\t\\tconclusion\\n\\t}\\n}\\n\\t\"}" + }, + "parameters": [], + "headers": [ + { + "name": "User-Agent", + "value": "insomnia/10.3.1" + }, + { + "name": "Content-Type", + "value": "application/json" + } + ], + "authentication": {}, + "metaSortKey": -1748443055314, + "isPrivate": false, + "pathParameters": [], + "settingStoreCookies": true, + "settingSendCookies": true, + "settingDisableRenderRequestBody": false, + "settingEncodeUrl": true, + "settingRebuildPath": true, + "settingFollowRedirects": "global", + "_type": "request" + }, + { + "_id": "wrk_3d521749d9754acc9979a11ac55e42a1", + "parentId": null, + "modified": 1748441235305, + "created": 1741269754962, + "name": "tasky", + "description": "", + "scope": "collection", + "_type": "workspace" + }, + { + "_id": "req_37e6e6f5c32e495a850a4872150d34d5", + "parentId": "wrk_3d521749d9754acc9979a11ac55e42a1", + "modified": 1748873650402, + "created": 1748443359584, + "url": "http://localhost:8080/graphql", + "name": "getTaskId", + "description": "", + "method": "POST", + "body": { + "mimeType": "application/graphql", + "text": "{\"query\":\"query {\\n\\tsearchById(id: 1) {\\n\\t\\tid\\n\\t\\tdescription\\n\\t\\tpriority\\n\\t\\ttagList\\n\\t\\tcreation\\n\\t\\tconclusion\\n\\t}\\n}\\n\"}" + }, + "parameters": [], + "headers": [ + { + "name": "User-Agent", + "value": "insomnia/10.3.1" + }, + { + "name": "Content-Type", + "value": "application/json" + } + ], + "authentication": {}, + "metaSortKey": -1748443055264, + "isPrivate": false, + "pathParameters": [], + "settingStoreCookies": true, + "settingSendCookies": true, + "settingDisableRenderRequestBody": false, + "settingEncodeUrl": true, + "settingRebuildPath": true, + "settingFollowRedirects": "global", + "_type": "request" + }, + { + "_id": "req_17c2a41c6d064f9a98b0d8afdb653e9f", + "parentId": "wrk_3d521749d9754acc9979a11ac55e42a1", + "modified": 1748454896283, + "created": 1748453240683, + "url": "http://localhost:8080/graphql", + "name": "deleteTaskId", + "description": "", + "method": "POST", + "body": { + "mimeType": "application/graphql", + "text": "{\"query\":\"mutation {\\n deleteById(id: 5)\\n}\"}" + }, + "parameters": [], + "headers": [ + { + "name": "User-Agent", + "value": "insomnia/10.3.1" + }, + { + "name": "Content-Type", + "value": "application/json" + } + ], + "authentication": {}, + "metaSortKey": -1748443055214, + "isPrivate": false, + "pathParameters": [], + "settingStoreCookies": true, + "settingSendCookies": true, + "settingDisableRenderRequestBody": false, + "settingEncodeUrl": true, + "settingRebuildPath": true, + "settingFollowRedirects": "global", + "_type": "request" + }, + { + "_id": "req_b394fd4e6b0b4f059d3a8d70c22506aa", + "parentId": "wrk_3d521749d9754acc9979a11ac55e42a1", + "modified": 1748869202698, + "created": 1748868351221, + "url": "http://localhost:8080/graphql", + "name": "editTaskId", + "description": "", + "method": "POST", + "body": { + "mimeType": "application/graphql", + "text": "{\"query\":\"mutation {\\n editById(\\n id: 1,\\n updatedTask: {\\n description: \\\"Updated description\\\"\\n priority: High\\n tagList: [Personal]\\n creation: \\\"2024-06-01T12:00:00Z\\\"\\n conclusion: \\\"2024-06-02T12:00:00Z\\\"\\n }\\n ) {\\n description\\n priority\\n tagList\\n creation\\n conclusion\\n }\\n}\"}" + }, + "parameters": [], + "headers": [ + { + "name": "User-Agent", + "value": "insomnia/10.3.1" + }, + { + "name": "Content-Type", + "value": "application/json" + } + ], + "authentication": {}, + "metaSortKey": -1748443055164, + "isPrivate": false, + "pathParameters": [], + "settingStoreCookies": true, + "settingSendCookies": true, + "settingDisableRenderRequestBody": false, + "settingEncodeUrl": true, + "settingRebuildPath": true, + "settingFollowRedirects": "global", + "_type": "request" + }, + { + "_id": "req_b78a363cdf8c4f98833251aeb074b6c3", + "parentId": "wrk_3d521749d9754acc9979a11ac55e42a1", + "modified": 1749051097383, + "created": 1749051081703, + "url": "http://localhost:8080/graphql", + "name": "listAll", + "description": "", + "method": "POST", + "body": { + "mimeType": "application/graphql", + "text": "{\"query\":\"query {\\n listAll {\\n description\\n priority\\n tagList\\n creation\\n conclusion\\n }\\n}\"}" + }, + "parameters": [], + "headers": [ + { + "name": "User-Agent", + "value": "insomnia/10.3.1" + }, + { + "name": "Content-Type", + "value": "application/json" + } + ], + "authentication": {}, + "metaSortKey": -1748443055114, + "isPrivate": false, + "pathParameters": [], + "settingStoreCookies": true, + "settingSendCookies": true, + "settingDisableRenderRequestBody": false, + "settingEncodeUrl": true, + "settingRebuildPath": true, + "settingFollowRedirects": "global", + "_type": "request" + }, + { + "_id": "env_d76da4c90990988c348bc28a0f33427c80a290a0", + "parentId": "wrk_3d521749d9754acc9979a11ac55e42a1", + "modified": 1748441235304, + "created": 1741269754966, + "name": "Base Environment", + "data": {}, + "dataPropertyOrder": null, + "color": null, + "isPrivate": false, + "metaSortKey": 1741269754966, + "environmentType": "kv", + "_type": "environment" + }, + { + "_id": "jar_d76da4c90990988c348bc28a0f33427c80a290a0", + "parentId": "wrk_3d521749d9754acc9979a11ac55e42a1", + "modified": 1748441235351, + "created": 1748441235351, + "name": "Default Jar", + "cookies": [], + "_type": "cookie_jar" + } + ] +} From 63e381f9f8410b57596e809a2f8813ef0078ac36 Mon Sep 17 00:00:00 2001 From: silrenan <75952546+silrenan@users.noreply.github.com> Date: Wed, 11 Jun 2025 12:10:16 -0300 Subject: [PATCH 4/4] update Insomnia JSON to reflect changes in GraphQL queries and timestamps Signed-off-by: silrenan <75952546+silrenan@users.noreply.github.com> --- doc/insomnia/insomnia.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/doc/insomnia/insomnia.json b/doc/insomnia/insomnia.json index 0d2cfd4..bf2bbc9 100644 --- a/doc/insomnia/insomnia.json +++ b/doc/insomnia/insomnia.json @@ -1,13 +1,13 @@ { "_type": "export", "__export_format": 4, - "__export_date": "2025-06-11T14:07:47.005Z", + "__export_date": "2025-06-11T15:07:31.764Z", "__export_source": "insomnia.desktop.app:v10.3.1", "resources": [ { "_id": "req_890f0fcd88c547caa3f21524c28bd167", "parentId": "wrk_3d521749d9754acc9979a11ac55e42a1", - "modified": 1748453651349, + "modified": 1749654422099, "created": 1748443055314, "url": "http://localhost:8080/graphql", "name": "newTask", @@ -15,7 +15,7 @@ "method": "POST", "body": { "mimeType": "application/graphql", - "text": "{\"query\":\"mutation {\\n\\tnewTask(\\n\\t\\ttask: {\\n\\t\\tdescription: \\\"deleteme\\\",\\n\\t\\tpriority: Info,\\n\\t\\ttagList: [Personal, Work],\\n\\t\\tcreation: \\\"2025-05-28T11:00:00Z\\\",\\n\\t\\tconclusion: null\\n\\t\\n\\t\\t})\\n\\t{\\n\\t\\tid\\n\\t\\tdescription\\n\\t\\tpriority\\n\\t\\ttagList\\n\\t\\tcreation\\n\\t\\tconclusion\\n\\t}\\n}\\n\\t\"}" + "text": "{\"query\":\"mutation {\\n newTask(\\n task: {\\n description: \\\"deleteme\\\"\\n priority: Info\\n tagList: [Personal, Work]\\n creation: \\\"2025-05-28T11:00:00Z\\\"\\n conclusion: null\\n }\\n )\\n}\"}" }, "parameters": [], "headers": [ @@ -53,7 +53,7 @@ { "_id": "req_37e6e6f5c32e495a850a4872150d34d5", "parentId": "wrk_3d521749d9754acc9979a11ac55e42a1", - "modified": 1748873650402, + "modified": 1749653836448, "created": 1748443359584, "url": "http://localhost:8080/graphql", "name": "getTaskId", @@ -61,7 +61,7 @@ "method": "POST", "body": { "mimeType": "application/graphql", - "text": "{\"query\":\"query {\\n\\tsearchById(id: 1) {\\n\\t\\tid\\n\\t\\tdescription\\n\\t\\tpriority\\n\\t\\ttagList\\n\\t\\tcreation\\n\\t\\tconclusion\\n\\t}\\n}\\n\"}" + "text": "{\"query\":\"query {\\n\\tsearchById(id: 7) {\\n\\t\\tid\\n\\t\\tdescription\\n\\t\\tpriority\\n\\t\\ttagList\\n\\t\\tcreation\\n\\t\\tconclusion\\n\\t}\\n}\\n\"}" }, "parameters": [], "headers": [ @@ -218,4 +218,4 @@ "_type": "cookie_jar" } ] -} +} \ No newline at end of file