src/main/java/de/uapcore/lightpit/dao/postgres/PGIssueDao.java

Sat, 17 Oct 2020 19:56:50 +0200

author
Mike Becker <universe@uap-core.de>
date
Sat, 17 Oct 2020 19:56:50 +0200
changeset 134
f47e82cd6077
parent 128
947d0f6a6a83
child 135
bafc315294fd
permissions
-rw-r--r--

completes feature: project components

     1 /*
     2  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
     3  *
     4  * Copyright 2018 Mike Becker. All rights reserved.
     5  *
     6  * Redistribution and use in source and binary forms, with or without
     7  * modification, are permitted provided that the following conditions are met:
     8  *
     9  *   1. Redistributions of source code must retain the above copyright
    10  *      notice, this list of conditions and the following disclaimer.
    11  *
    12  *   2. Redistributions in binary form must reproduce the above copyright
    13  *      notice, this list of conditions and the following disclaimer in the
    14  *      documentation and/or other materials provided with the distribution.
    15  *
    16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    17  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    19  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
    20  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    25  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    26  * POSSIBILITY OF SUCH DAMAGE.
    27  *
    28  */
    29 package de.uapcore.lightpit.dao.postgres;
    31 import de.uapcore.lightpit.dao.IssueDao;
    32 import de.uapcore.lightpit.entities.*;
    34 import java.sql.*;
    35 import java.util.ArrayList;
    36 import java.util.List;
    37 import java.util.Objects;
    38 import java.util.Optional;
    40 import static de.uapcore.lightpit.dao.Functions.*;
    42 public final class PGIssueDao implements IssueDao {
    44     private final PreparedStatement insert, update, list, listForVersion, find;
    45     private final PreparedStatement affectedVersions, resolvedVersions;
    46     private final PreparedStatement clearAffected, clearResolved;
    47     private final PreparedStatement insertAffected, insertResolved;
    48     private final PreparedStatement insertComment, updateComment, listComments;
    50     public PGIssueDao(Connection connection) throws SQLException {
    51         list = connection.prepareStatement(
    52                 "select issueid, i.project, p.name as projectname, component, c.name as componentname, " +
    53                         "status, category, subject, i.description, " +
    54                         "userid, username, givenname, lastname, mail, " +
    55                         "created, updated, eta " +
    56                         "from lpit_issue i " +
    57                         "join lpit_project p on i.project = projectid " +
    58                         "left join lpit_component c on component = c.id " +
    59                         "left join lpit_user on userid = assignee " +
    60                         "where i.project = ? and coalesce(component, -1) = coalesce(?, component, -1)");
    62         listForVersion = connection.prepareStatement(
    63                 "with issue_version as ( "+
    64                         "select issueid, versionid from lpit_issue_affected_version union "+
    65                         "select issueid, versionid from lpit_issue_resolved_version) "+
    66                         "select issueid, i.project, p.name as projectname, component, c.name as componentname, " +
    67                         "status, category, subject, i.description, " +
    68                         "userid, username, givenname, lastname, mail, " +
    69                         "created, updated, eta " +
    70                         "from lpit_issue i " +
    71                         "join lpit_project p on i.project = projectid " +
    72                         "left join lpit_component c on component = c.id " +
    73                         "left join issue_version using (issueid) "+
    74                         "left join lpit_user on userid = assignee " +
    75                         "where coalesce(versionid,-1) = ? and coalesce(component, -1) = coalesce(?, component, -1)"
    76         );
    78         find = connection.prepareStatement(
    79                 "select issueid, i.project, p.name as projectname, component, c.name as componentname, " +
    80                         "status, category, subject, i.description, " +
    81                         "userid, username, givenname, lastname, mail, " +
    82                         "created, updated, eta " +
    83                         "from lpit_issue i " +
    84                         "join lpit_project p on i.project = projectid " +
    85                         "left join lpit_component c on component = c.id " +
    86                         "left join lpit_user on userid = assignee " +
    87                         "where issueid = ? ");
    89         insert = connection.prepareStatement(
    90                 "insert into lpit_issue (project, component, status, category, subject, description, assignee, eta) " +
    91                         "values (?, ?::issue_status, ?::issue_category, ?, ?, ?, ?) returning issueid"
    92         );
    93         update = connection.prepareStatement(
    94                 "update lpit_issue set " +
    95                         "updated = now(), component = ?, status = ?::issue_status, category = ?::issue_category, " +
    96                         "subject = ?, description = ?, assignee = ?, eta = ? where issueid = ?"
    97         );
    99         affectedVersions = connection.prepareStatement(
   100                 "select versionid, name, status, ordinal " +
   101                         "from lpit_version join lpit_issue_affected_version using (versionid) " +
   102                         "where issueid = ? " +
   103                         "order by ordinal, name"
   104         );
   105         clearAffected = connection.prepareStatement("delete from lpit_issue_affected_version where issueid = ?");
   106         insertAffected = connection.prepareStatement("insert into lpit_issue_affected_version (issueid, versionid) values (?,?)");
   108         resolvedVersions = connection.prepareStatement(
   109                 "select versionid, name, status, ordinal " +
   110                         "from lpit_version v join lpit_issue_resolved_version using (versionid) " +
   111                         "where issueid = ? " +
   112                         "order by ordinal, name"
   113         );
   114         clearResolved = connection.prepareStatement("delete from lpit_issue_resolved_version where issueid = ?");
   115         insertResolved = connection.prepareStatement("insert into lpit_issue_resolved_version (issueid, versionid) values (?,?)");
   117         insertComment = connection.prepareStatement(
   118                 "insert into lpit_issue_comment (issueid, comment, userid) values (?, ? ,?)"
   119         );
   120         updateComment = connection.prepareStatement(
   121                 "update lpit_issue_comment set comment = ?, updated = now(), updatecount = updatecount+1 where commentid = ?"
   122         );
   123         listComments = connection.prepareStatement(
   124                 "select * from lpit_issue_comment left join lpit_user using (userid) where issueid = ? order by created"
   125         );
   126     }
   128     private Issue mapColumns(ResultSet result) throws SQLException {
   129         final var project = new Project(result.getInt("project"));
   130         project.setName(result.getString("projectname"));
   131         var component = new Component(result.getInt("component"));
   132         if (result.wasNull()) {
   133             component = null;
   134         } else {
   135             component.setName(result.getString("componentname"));
   136         }
   137         final var issue = new Issue(result.getInt("issueid"));
   138         issue.setProject(project);
   139         issue.setComponent(component);
   140         issue.setStatus(IssueStatus.valueOf(result.getString("status")));
   141         issue.setCategory(IssueCategory.valueOf(result.getString("category")));
   142         issue.setSubject(result.getString("subject"));
   143         issue.setDescription(result.getString("description"));
   144         issue.setAssignee(PGUserDao.mapColumns(result));
   145         issue.setCreated(result.getTimestamp("created"));
   146         issue.setUpdated(result.getTimestamp("updated"));
   147         issue.setEta(result.getDate("eta"));
   148         return issue;
   149     }
   151     private Version mapVersion(ResultSet result) throws SQLException {
   152         final var version = new Version(result.getInt("versionid"));
   153         version.setName(result.getString("name"));
   154         version.setOrdinal(result.getInt("ordinal"));
   155         version.setStatus(VersionStatus.valueOf(result.getString("status")));
   156         return version;
   157     }
   159     private void updateVersionLists(Issue instance) throws SQLException {
   160         clearAffected.setInt(1, instance.getId());
   161         clearResolved.setInt(1, instance.getId());
   162         insertAffected.setInt(1, instance.getId());
   163         insertResolved.setInt(1, instance.getId());
   164         clearAffected.executeUpdate();
   165         clearResolved.executeUpdate();
   166         for (Version v : instance.getAffectedVersions()) {
   167             insertAffected.setInt(2, v.getId());
   168             insertAffected.executeUpdate();
   169         }
   170         for (Version v : instance.getResolvedVersions()) {
   171             insertResolved.setInt(2, v.getId());
   172             insertResolved.executeUpdate();
   173         }
   174     }
   176     private int setData(PreparedStatement stmt, int column, Issue instance) throws SQLException {
   177         setForeignKeyOrNull(stmt, ++column, instance.getComponent(), Component::getId);
   178         stmt.setString(++column, instance.getStatus().name());
   179         stmt.setString(++column, instance.getCategory().name());
   180         stmt.setString(++column, instance.getSubject());
   181         setStringOrNull(stmt, ++column, instance.getDescription());
   182         setForeignKeyOrNull(stmt, ++column, instance.getAssignee(), User::getId);
   183         setDateOrNull(stmt, ++column, instance.getEta());
   184         return column;
   185     }
   187     @Override
   188     public void save(Issue instance, Project project) throws SQLException {
   189         Objects.requireNonNull(instance.getSubject());
   190         instance.setProject(project);
   191         int column = 0;
   192         insert.setInt(++column, instance.getProject().getId());
   193         setData(insert, column, instance);
   194         // insert and retrieve the ID
   195         final var rs = insert.executeQuery();
   196         rs.next();
   197         instance.setId(rs.getInt(1));
   198         updateVersionLists(instance);
   199     }
   201     @Override
   202     public boolean update(Issue instance) throws SQLException {
   203         if (instance.getId() < 0) return false;
   204         Objects.requireNonNull(instance.getSubject());
   205         int column = setData(update, 0, instance);
   206         update.setInt(++column, instance.getId());
   207         boolean success = update.executeUpdate() > 0;
   208         if (success) {
   209             updateVersionLists(instance);
   210             return true;
   211         } else {
   212             return false;
   213         }
   214     }
   216     private List<Issue> executeQuery(PreparedStatement query) throws SQLException {
   217         List<Issue> issues = new ArrayList<>();
   218         try (var result = query.executeQuery()) {
   219             while (result.next()) {
   220                 issues.add(mapColumns(result));
   221             }
   222         }
   223         return issues;
   224     }
   226     @Override
   227     public List<Issue> list(Project project) throws SQLException {
   228         list.setInt(1, project.getId());
   229         list.setNull(2, Types.INTEGER);
   230         return executeQuery(list);
   231     }
   233     @Override
   234     public List<Issue> list(Project project, Component component, Version version) throws SQLException {
   235         listForVersion.setInt(1, Optional.ofNullable(version).map(Version::getId).orElse(-1));
   236         listForVersion.setInt(2, Optional.ofNullable(component).map(Component::getId).orElse(-1));
   237         return executeQuery(listForVersion);
   238     }
   240     @Override
   241     public List<Issue> list(Project project, Version version) throws SQLException {
   242         listForVersion.setInt(1, Optional.ofNullable(version).map(Version::getId).orElse(-1));
   243         listForVersion.setNull(2, Types.INTEGER);
   244         return executeQuery(listForVersion);
   245     }
   247     @Override
   248     public List<Issue> list(Project project, Component component) throws SQLException {
   249         list.setInt(1, project.getId());
   250         list.setInt(2, Optional.ofNullable(component).map(Component::getId).orElse(-1));
   251         return executeQuery(list);
   252     }
   254     @Override
   255     public Issue find(int id) throws SQLException {
   256         find.setInt(1, id);
   257         try (var result = find.executeQuery()) {
   258             if (result.next()) {
   259                 return mapColumns(result);
   260             } else {
   261                 return null;
   262             }
   263         }
   264     }
   266     private List<Version> listVersions(PreparedStatement stmt, Issue issue) throws SQLException {
   267         stmt.setInt(1, issue.getId());
   268         List<Version> versions = new ArrayList<>();
   269         try (var result = stmt.executeQuery()) {
   270             while (result.next()) {
   271                 versions.add(mapVersion(result));
   272             }
   273         }
   274         return versions;
   275     }
   277     @Override
   278     public void joinVersionInformation(Issue issue) throws SQLException {
   279         Objects.requireNonNull(issue.getProject());
   280         issue.setAffectedVersions(listVersions(affectedVersions, issue));
   281         issue.setResolvedVersions(listVersions(resolvedVersions, issue));
   282     }
   284     @Override
   285     public List<IssueComment> listComments(Issue issue) throws SQLException {
   286         listComments.setInt(1, issue.getId());
   287         List<IssueComment> comments = new ArrayList<>();
   288         try (var result = listComments.executeQuery()) {
   289             while (result.next()) {
   290                 final var comment = new IssueComment(result.getInt("commentid"), issue);
   291                 comment.setCreated(result.getTimestamp("created"));
   292                 comment.setUpdated(result.getTimestamp("updated"));
   293                 comment.setUpdateCount(result.getInt("updatecount"));
   294                 comment.setComment(result.getString("comment"));
   295                 comment.setAuthor(PGUserDao.mapColumns(result));
   296                 comments.add(comment);
   297             }
   298         }
   299         return comments;
   300     }
   302     @Override
   303     public void saveComment(IssueComment comment) throws SQLException {
   304         Objects.requireNonNull(comment.getComment());
   305         Objects.requireNonNull(comment.getIssue());
   306         if (comment.getId() >= 0) {
   307             updateComment.setString(1, comment.getComment());
   308             updateComment.setInt(2, comment.getId());
   309             updateComment.execute();
   310         } else {
   311             insertComment.setInt(1, comment.getIssue().getId());
   312             insertComment.setString(2, comment.getComment());
   313             setForeignKeyOrNull(insertComment, 3, comment.getAuthor(), User::getId);
   314             insertComment.execute();
   315         }
   316     }
   317 }

mercurial