Skip to content

Commit

Permalink
Merge pull request #458 from mcneilco/ACAS-710
Browse files Browse the repository at this point in the history
ACAS-710: Code table label text search and short name match query parameters
  • Loading branch information
brianbolt authored Apr 4, 2024
2 parents e5ac8b7 + 69198f2 commit b7a2a0c
Show file tree
Hide file tree
Showing 3 changed files with 101 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
import java.util.Collection;
import java.util.List;

import javax.persistence.TypedQuery;

import com.labsynch.labseer.domain.DDictValue;
import com.labsynch.labseer.dto.CodeTableDTO;
import com.labsynch.labseer.exceptions.ErrorMessage;
Expand Down Expand Up @@ -322,7 +324,10 @@ public ResponseEntity<String> listJson(
public ResponseEntity<java.lang.String> getDDictValuesByTypeKindFormat(
@PathVariable("lsType") String lsType,
@PathVariable("lsKind") String lsKind,
@PathVariable("format") String format) {
@PathVariable("format") String format,
@RequestParam(value = "maxHits", required = false) Integer maxHits,
@RequestParam(value = "shortName", defaultValue = "", required = false) String shortName,
@RequestParam(value = "labelTextSearchTerm", defaultValue = "", required = false) String labelTextSearchTerm) {

HttpHeaders headers = new HttpHeaders();
headers.add("Content-Type", "application/json; charset=utf-8");
Expand All @@ -331,12 +336,37 @@ public ResponseEntity<java.lang.String> getDDictValuesByTypeKindFormat(
return new ResponseEntity<String>(headers, HttpStatus.BAD_REQUEST);
}

List<DDictValue> dDictResults = DDictValue.findDDictValuesByLsTypeEqualsAndLsKindEquals(lsType, lsKind)
.getResultList();
// throw an error if the user tries to search by codeName and label text
if (!shortName.isEmpty() && !labelTextSearchTerm.isEmpty()) {
ErrorMessage errorMessage = new ErrorMessage();
errorMessage.setErrorLevel("error");
errorMessage.setMessage("Cannot search by codeName and labelTextSearchTerm at the same time");
return new ResponseEntity<String>(errorMessage.toJson(), headers, HttpStatus.BAD_REQUEST);
}

List<DDictValue> dDictResults;
if (labelTextSearchTerm.isEmpty() && shortName.isEmpty()) {
TypedQuery<DDictValue> dDictResultsQuery = DDictValue.findDDictValuesByLsTypeEqualsAndLsKindEquals(lsType, lsKind);
if (maxHits != null) {
dDictResultsQuery = dDictResultsQuery.setMaxResults(maxHits);
}
dDictResults = dDictResultsQuery.getResultList();
} else if (!shortName.isEmpty()) {
TypedQuery<DDictValue> dDictResultsQuery = DDictValue.findDDictValuesByLsTypeEqualsAndLsKindEqualsAndShortNameEquals(lsType, lsKind, shortName);
if (maxHits != null) {
dDictResultsQuery = dDictResultsQuery.setMaxResults(maxHits);
}
dDictResults = dDictResultsQuery.getResultList();
} else {
dDictResults = DDictValue.findDDictValuesByLsTypeEqualsAndLsKindEqualsAndLabelTextSearch(lsType, lsKind, labelTextSearchTerm, maxHits);
}

if (format != null && format.equalsIgnoreCase("codeTable")) {
List<CodeTableDTO> codeTables = dataDictionaryService.convertToCodeTables(dDictResults);
codeTables = CodeTableDTO.sortCodeTables(codeTables);
// labelText searches have their own sort order so we don't need to sort them
if (labelTextSearchTerm.isEmpty()) {
codeTables = CodeTableDTO.sortCodeTables(codeTables);
}
return new ResponseEntity<String>(CodeTableDTO.toJsonArray(codeTables), headers, HttpStatus.OK);
} else if (format != null && format.equalsIgnoreCase("csv")) {
String outputString = dataDictionaryService.getCsvList(dDictResults);
Expand Down
40 changes: 40 additions & 0 deletions src/main/java/com/labsynch/labseer/domain/DDictValue.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import javax.persistence.SequenceGenerator;
import javax.persistence.TypedQuery;
import javax.persistence.Version;
Expand Down Expand Up @@ -568,6 +569,45 @@ public static TypedQuery<DDictValue> findDDictValuesByLsTypeEqualsAndLsKindEqual
return q;
}

public static List<DDictValue> findDDictValuesByLsTypeEqualsAndLsKindEqualsAndLabelTextSearch(String lsType, String lsKind, String labelText, Integer maxHits) {
if (lsType == null || lsType.length() == 0)
throw new IllegalArgumentException("The lsType argument is required");
if (lsKind == null || lsKind.length() == 0)
throw new IllegalArgumentException("The lsKind argument is required");
EntityManager em = DDictValue.entityManager();

// Format the search text to match any word in the label text
// e.g. "word1 word2" -> "word1:* & word2:*"
String[] parts = labelText.trim().split("\\s+");
for (int i = 0; i < parts.length; i++) {
parts[i] = parts[i] + ":*";
}
String formattedLabelText = String.join(" & ", parts);

// Native query to use full text search
String sql =
"SELECT * " +
"FROM ddict_value " +
"WHERE ls_type = :lsType " +
"AND ls_kind = :lsKind " +
"AND to_tsvector('english', lower(label_text)) @@ to_tsquery('english', :formattedLabelText) " +
"ORDER BY (lower(label_text) = :labelText) DESC, " +
"ts_rank(to_tsvector('english', lower(label_text)), to_tsquery('english', :formattedLabelText)) DESC";

Query q = em.createNativeQuery(sql, DDictValue.class);
q.setParameter("lsType", lsType);
q.setParameter("lsKind", lsKind);
q.setParameter("labelText", labelText.toLowerCase());
q.setParameter("formattedLabelText", formattedLabelText);
if (maxHits != null) {
q = q.setMaxResults(maxHits);
}

@SuppressWarnings("unchecked")
List<DDictValue> results = q.getResultList();
return results;
}

public static TypedQuery<DDictValue> findDDictValuesByLsTypeEqualsAndLsKindEquals(String lsType, String lsKind,
String sortFieldName, String sortOrder) {
if (lsType == null || lsType.length() == 0)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
DO $$
BEGIN
IF NOT EXISTS (
SELECT 1
FROM pg_class c
JOIN pg_namespace n ON n.oid = c.relnamespace
WHERE c.relname = 'ddict_value_labeltext_tsvector_idx'
)
THEN
CREATE INDEX ddict_value_labeltext_tsvector_idx ON ddict_value USING GIN (to_tsvector('english', label_text));
END IF;
END
$$;

DO $$
BEGIN
IF NOT EXISTS (
SELECT 1
FROM pg_class c
JOIN pg_namespace n ON n.oid = c.relnamespace
WHERE c.relname = 'idx_ddictvalue_labeltext_lower_pattern'
)
THEN
CREATE INDEX idx_ddictvalue_labeltext_lower_pattern ON ddict_value(lower(label_text) varchar_pattern_ops);
END IF;
END
$$;

0 comments on commit b7a2a0c

Please sign in to comment.