Commit b74fa364 authored by Valentin Suhnjov's avatar Valentin Suhnjov

Merge branch 'releases/release-0.12.0' into master

parents 6fffa371 f6a50c82
......@@ -5,7 +5,7 @@
<groupId>ee.eesti.riha</groupId>
<artifactId>rest</artifactId>
<version>0.11.0</version>
<version>0.12.0</version>
<packaging>war</packaging>
......
DROP VIEW IF EXISTS riha.main_resource_view CASCADE;
CREATE OR REPLACE VIEW riha.main_resource_view AS
SELECT DISTINCT ON (json_content ->> 'uuid')
*,
((main_resource.json_content #>> '{meta,creation_timestamp}' :: TEXT [])) :: TIMESTAMP WITH TIME ZONE AS j_creation_timestamp,
((main_resource.json_content #>> '{meta,update_timestamp}' :: TEXT [])) :: TIMESTAMP WITH TIME ZONE AS j_update_timestamp
main_resource.*,
((main_resource.json_content #>>
'{meta,creation_timestamp}' :: TEXT [])) :: TIMESTAMP WITH TIME ZONE AS j_creation_timestamp,
((main_resource.json_content #>>
'{meta,update_timestamp}' :: TEXT [])) :: TIMESTAMP WITH TIME ZONE AS j_update_timestamp,
last_positive_approval_request.sub_type AS last_positive_approval_request_type,
last_positive_approval_request.modified_date AS last_positive_approval_request_date
FROM riha.main_resource AS main_resource
LEFT JOIN (SELECT DISTINCT ON (infosystem_uuid)
infosystem_uuid,
sub_type,
modified_date
FROM riha.comment
WHERE
type = 'ISSUE'
AND sub_type IN ('ESTABLISHMENT_REQUEST',
'TAKE_INTO_USE_REQUEST',
'FINALIZATION_REQUEST')
AND status = 'CLOSED'
AND resolution_type = 'POSITIVE'
ORDER BY infosystem_uuid, modified_date DESC) AS last_positive_approval_request
ON (json_content ->> 'uuid') :: UUID = last_positive_approval_request.infosystem_uuid
ORDER BY json_content ->> 'uuid',
j_update_timestamp DESC NULLS LAST,
main_resource_id DESC;
......@@ -22,8 +40,7 @@ CREATE OR REPLACE VIEW riha.main_resource_relation_view AS
LEFT JOIN riha.main_resource_view related_infosystem
ON (related_infosystem.json_content ->> 'uuid') = mrr.related_infosystem_uuid :: TEXT;
-- DROP VIEW riha.comment_type_issue_view;
DROP VIEW IF EXISTS riha.comment_type_issue_view;
CREATE OR REPLACE VIEW riha.comment_type_issue_view AS
SELECT
issue.*,
......
-- Drop main_resource_view and views that depend on it
DROP VIEW IF EXISTS riha.main_resource_view CASCADE;
-- Create main_resource_view with last positive approval request data columns
CREATE OR REPLACE VIEW riha.main_resource_view AS
SELECT DISTINCT ON (json_content ->> 'uuid')
main_resource.*,
((main_resource.json_content #>>
'{meta,creation_timestamp}' :: TEXT [])) :: TIMESTAMP WITH TIME ZONE AS j_creation_timestamp,
((main_resource.json_content #>>
'{meta,update_timestamp}' :: TEXT [])) :: TIMESTAMP WITH TIME ZONE AS j_update_timestamp,
last_positive_approval_request.sub_type AS last_positive_approval_request_type,
last_positive_approval_request.modified_date AS last_positive_approval_request_date
FROM riha.main_resource AS main_resource
LEFT JOIN (SELECT DISTINCT ON (infosystem_uuid)
infosystem_uuid,
sub_type,
modified_date
FROM riha.comment
WHERE
type = 'ISSUE'
AND sub_type IN ('ESTABLISHMENT_REQUEST',
'TAKE_INTO_USE_REQUEST',
'FINALIZATION_REQUEST')
AND status = 'CLOSED'
AND resolution_type = 'POSITIVE'
ORDER BY infosystem_uuid, modified_date DESC) AS last_positive_approval_request
ON (json_content ->> 'uuid') :: UUID = last_positive_approval_request.infosystem_uuid
ORDER BY json_content ->> 'uuid',
j_update_timestamp DESC NULLS LAST,
main_resource_id DESC;
-- Recreate views
DROP VIEW IF EXISTS riha.main_resource_relation_view;
CREATE OR REPLACE VIEW riha.main_resource_relation_view AS
SELECT
mrr.*,
infosystem.json_content ->> 'short_name' AS infosystem_short_name,
infosystem.json_content ->> 'name' AS infosystem_name,
related_infosystem.json_content ->> 'short_name' AS related_infosystem_short_name,
related_infosystem.json_content ->> 'name' AS related_infosystem_name
FROM riha.main_resource_relation mrr
LEFT JOIN riha.main_resource_view infosystem ON (infosystem.json_content ->> 'uuid') = mrr.infosystem_uuid :: TEXT
LEFT JOIN riha.main_resource_view related_infosystem
ON (related_infosystem.json_content ->> 'uuid') = mrr.related_infosystem_uuid :: TEXT;
DROP VIEW IF EXISTS riha.comment_type_issue_view;
CREATE OR REPLACE VIEW riha.comment_type_issue_view AS
SELECT
issue.*,
infosystem.json_content ->> 'short_name' AS infosystem_short_name
FROM riha.comment issue
INNER JOIN riha.main_resource_view infosystem
ON (infosystem.json_content ->> 'uuid') = issue.infosystem_uuid :: TEXT
WHERE issue.type = 'ISSUE'
ORDER BY issue.comment_id;
\ No newline at end of file
......@@ -231,97 +231,88 @@ public class ApiGenericDAOImpl<T, K> implements ApiGenericDAO<T, K> {
// if any of the fields does not exist in model, then query over
// json_content field
boolean allFieldsExistInModel = DaoHelper.allFieldsInFilterAppearInModel(filterComponents, clazz)
&& DaoHelper.isFieldPartOfModel(orderData.getOrderByField(), clazz);
StringBuffer qry = new StringBuffer();
StringBuffer queryString = new StringBuffer();
// next construct where clause separated by AND
String joinedAsOneStr = "";
if (allFieldsExistInModel) {
if (isCount) {
qry.append("SELECT count(*) FROM (SELECT * FROM " + tableName + " item WHERE ");
List<String> allFilters = new ArrayList<>();
//construct HQL query if isCount == false
if (isCount) {
queryString.append("SELECT count(*) FROM (");
}
queryString.append("SELECT * FROM ")
.append(tableName)
.append(" item ");
Map<String, Object> params = new HashMap<>();
for (int i = 0 ; i < filterComponents.size(); i++) {
FilterComponent filterComponent = filterComponents.get(i);
if (DaoHelper.isFieldPartOfModel(filterComponent.getOperandLeft(), clazz)) {
try {
String filter = sqlFilter.constructSqlFilter(filterComponent, clazz, params, i);
allFilters.add(filter);
} catch (NumberFormatException e) {
MyExceptionHandler.numberFormat(e, " filter " + filterComponents);
} catch (ParseException e) {
MyExceptionHandler.dateFormat(e, " filter " + filterComponents);
} catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
// this should never happen, because allFieldsExistInModel
// already tested whether field exists or not
e.printStackTrace();
throw new RuntimeException(e);
}
} else {
// construct HQL query
qry.append("SELECT * FROM " + tableName + " item WHERE ");
}
Map<String, Object> params = null;
try {
// Tuple<String, Map<String, Object>> filterTuple = constructSqlFilter(filterComponents, clazz);
Tuple<String, Map<String, Object>> filterTuple = sqlFilter.constructSqlFilter(filterComponents, clazz);
// joinedAsOneStr = constructSqlFilter(filterComponents, clazz);
joinedAsOneStr = filterTuple.x;
params = filterTuple.y;
} catch (NumberFormatException e) {
MyExceptionHandler.numberFormat(e, " filter " + filterComponents);
} catch (ParseException e) {
MyExceptionHandler.dateFormat(e, " filter " + filterComponents);
} catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
// this should never happen, because allFieldsExistInModel
// already tested whether field exists or not
e.printStackTrace();
throw new RuntimeException(e);
if (jsonFieldExists(session, tableName, filterComponent.getOperandLeft())) {
String filter = sqlFilter.constructSqlOverJsonFilter(filterComponent, clazz, params, i);
allFilters.add(filter);
}
}
}
qry.append(joinedAsOneStr);
// field already checked
qry.append(" ORDER BY " + "item." + orderData.getOrderByField() + (orderData.isAsc() ? " ASC " : " DESC "));
joinedAsOneStr = StringUtils.join(allFilters, " AND ");
if (!allFilters.isEmpty()) {
queryString.append("WHERE ");
}
queryString.append(joinedAsOneStr);
LOG.info("SQL FILTER: " + joinedAsOneStr + " params " + params);
if (isCount) {
qry.append(" LIMIT " + limit + " OFFSET " + offset + ") AS foo;");
query = session.createSQLQuery(qry.toString());
} else {
query = session.createSQLQuery(qry.toString()).addEntity(clazz);
query.setMaxResults(limit);
query.setFirstResult(offset);
}
query.setProperties(params);
if (allFilters.isEmpty()) {
LOG.info("SQL FILTER: No existing filter fields were found.");
} else if (allFilters.size() != filterComponents.size()) {
LOG.info("SQL FILTER: Some filter fields were not taken into account as they exist neither in model nor in JSON content.");
}
if (DaoHelper.isFieldPartOfModel(orderData.getOrderByField(), clazz)) {
queryString.append(" ORDER BY item.")
.append(orderData.getOrderByField())
.append((orderData.isAsc() ? " ASC " : " DESC "));
} else {
// construct postgre SQL query over json_content
if (isCount) {
qry.append("SELECT count(*) FROM (SELECT * FROM " + tableName + " item WHERE ");
} else {
qry.append("SELECT * FROM " + tableName + " item WHERE ");
}
Map<String, Object> params = new HashMap<>();
if (jsonFilterFieldsExist(session, tableName, filterComponents)) {
// Tuple<String, Map<String, Object>> filterTuple = constructSqlOverJsonFilter(filterComponents, clazz);
Tuple<String, Map<String, Object>> filterTuple = sqlFilter
.constructSqlOverJsonFilter(filterComponents, clazz);
joinedAsOneStr = filterTuple.x;
params = filterTuple.y;
} else {
// always false WHERE clause
joinedAsOneStr = "1 = 0";
}
qry.append(joinedAsOneStr);
if (jsonFieldExists(session, tableName, orderData.getOrderByField())) {
String orderByParameterName = "jOrderParameter";
qry.append(" ").append(createJsonQueryClause(orderByParameterName, orderData));
queryString.append(" ").append(createJsonQueryClause(orderByParameterName, orderData));
String jsonOrderByFieldName = "{" + orderData.getOrderByField().replaceAll("\\.", ",") + "}";
params.put(orderByParameterName, jsonOrderByFieldName);
}
if (isCount) {
qry.append(" LIMIT " + limit + " OFFSET " + offset + ") AS foo;");
query = session.createSQLQuery(qry.toString());
} else {
// get object of type clazz in results
query = session.createSQLQuery(qry.toString()).addEntity(clazz);
query.setMaxResults(limit);
query.setFirstResult(offset);
LOG.info("Sorting order field was not taken into account as it exists neither in model nor in JSON content.");
}
query.setProperties(params);
}
if (isCount) {
queryString.append(" LIMIT ")
.append(limit)
.append(" OFFSET ")
.append(offset)
.append(") AS foo;");
query = session.createSQLQuery(queryString.toString());
} else {
// get object of type clazz in results
query = session.createSQLQuery(queryString.toString()).addEntity(clazz);
query.setMaxResults(limit);
query.setFirstResult(offset);
}
query.setProperties(params);
}
return query;
......@@ -511,12 +502,7 @@ public class ApiGenericDAOImpl<T, K> implements ApiGenericDAO<T, K> {
return 0;
}
if (JsonContentBasedTable.isJsonContentBasedTable(clazz)) {
return updateJsonContentEntity(existing, newValue);
} else {
return updateEntity(existing, newValue);
}
}
private int updateJsonContentEntity(T existing, T newValue) throws RihaRestException {
......@@ -965,6 +951,12 @@ public class ApiGenericDAOImpl<T, K> implements ApiGenericDAO<T, K> {
// select count(*) from main_resource
// where (json_content->'test_abc') is not null;
Class classRepresentingTable = Finals.getClassRepresentingTable(tableName) == null ?
Finals.getClassRepresentingTableReadOnly(tableName) : Finals.getClassRepresentingTable(tableName);
if (!JsonContentBasedTable.isJsonContentBasedTable(classRepresentingTable)) {
return false;
}
// Construct SQL query respecting nested keys
String[] keyTokens = StringUtils.split(key, ".");
if (keyTokens.length == 0) {
......
......@@ -105,7 +105,6 @@ public class ChangeLogic<T, K> {
// all = genericDAO.find(classRepresentingTable, limit, offset, filterComponents, sort);
all = secureDAO.find(classRepresentingTable, limit, offset, filterComponents, sort);
replaceContentWithFileUrl(all, appConfigURL.getRestApiBaseUrl());
all = filterByFields(all, fields);
// FileHelper.readDocumentFileToContent(all, classRepresentingTable);
} catch (RihaRestException e) {
......@@ -235,7 +234,6 @@ public class ChangeLogic<T, K> {
// List<T> entityList = genericDAO.findByMainResourceId(classRepresentingTable, id);
List<T> entityList = secureDAO.findByMainResourceId(classRepresentingTable, id);
entityList = tableEntryReadLogic.getAdjustedObjsBasedOnExpectedJson(entityList, null);
// INFO: file content inclusion
// FileHelper.readDocumentFileToContent(entityList, classRepresentingTable);
......@@ -261,7 +259,6 @@ public class ChangeLogic<T, K> {
Validator.noSuchIdInGivenTable(entity, id);
replaceContentWithFileUrl(entity, id, appConfigURL.getRestApiBaseUrl());
entity = filterByFields(entity, fields);
// FileHelper.readDocumentFileToContent(entity, classRepresentingTable);
......@@ -501,12 +498,6 @@ public class ChangeLogic<T, K> {
LOG.info(JsonHelper.GSON.toJson(items));
List<T> itemList = new ArrayList<>(Arrays.asList(items));
// set modifed jsonObject to corresponding item
for (int i = 0; i < itemList.size(); i++) {
JsonObject jsonObject = jsonArray.get(i).getAsJsonObject();
((BaseModel) itemList.get(i)).setJson_content(jsonObject);
}
try {
if (StringHelper.areEqual(idFieldName, Finals.KIND) && classRepresentingTable != Comment.class) {
// kind doesn't exist in database, must be replaced
......@@ -532,7 +523,6 @@ public class ChangeLogic<T, K> {
// create from modified
T item = JsonHelper.GSON.fromJson(jsonObject, classRepresentingTable);
((BaseModel) item).setJson_content(jsonObject);
// id needed to create file path
((BaseModel) item).callSetId(id);
......
......@@ -206,15 +206,6 @@ public class TableEntryCreateLogic<T extends BaseModel> {
entity.callSetId(pkId);
entity.setCreation_date(dt);
// When dealing with json content table, initialize json_content field with source json and check if it was set correctly
if (JsonContentBasedTable.isJsonContentBasedTable(classRepresentingTable)) {
entity.setJson_content(jsonContent);
if (entity.getJson_content() == null) {
throw new IllegalArgumentException("JsonContent can't be null! JsonContent " + jsonContent + " Created object "
+ entity);
}
}
return entity;
}
......
......@@ -9,6 +9,7 @@ import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import com.fasterxml.jackson.annotation.JsonIgnore;
import org.hibernate.annotations.Type;
import org.hibernate.annotations.TypeDef;
import org.hibernate.annotations.TypeDefs;
......@@ -41,9 +42,17 @@ public class Main_resource implements BaseModel {
@Id
@Column(updatable = false)
private Integer main_resource_id;
@JsonIgnore
private String uri;
@JsonIgnore
private String name;
@JsonIgnore
private String short_name;
@JsonIgnore
private String version;
// http://stackoverflow.com/questions/15974474/mapping-postgresql-json-column-to-hibernate-value-type
......@@ -53,35 +62,51 @@ public class Main_resource implements BaseModel {
@Type(type = "JsonObject")
private JsonObject json_content;
@JsonIgnore
private String parent_uri;
@JsonIgnore
private Integer main_resource_parent_id;
@JsonIgnore
private String kind;
@JsonIgnore
private Character state;
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = Finals.DATE_FORMAT)
@JsonIgnore
@Temporal(TemporalType.TIMESTAMP)
private Date start_date;
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = Finals.DATE_FORMAT)
@JsonIgnore
@Temporal(TemporalType.TIMESTAMP)
private Date end_date;
@JsonIgnore
private String creator;
@JsonIgnore
private String modifier;
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = Finals.DATE_FORMAT)
@JsonIgnore
@Temporal(TemporalType.TIMESTAMP)
private Date creation_date;
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = Finals.DATE_FORMAT)
@JsonIgnore
@Temporal(TemporalType.TIMESTAMP)
private Date modified_date;
@JsonIgnore
private Integer old_id;
@JsonIgnore
private String field_name;
@JsonIgnore
private Integer kind_id;
// Needed for indication that this field should not be searched in json content
@JsonIgnore
private String search_content;
/*
......
package ee.eesti.riha.rest.model.readonly;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonRawValue;
import com.fasterxml.jackson.annotation.*;
import com.google.gson.JsonObject;
import ee.eesti.riha.rest.logic.Finals;
import ee.eesti.riha.rest.model.BaseModel;
......@@ -29,31 +27,46 @@ public class Main_resource_view implements BaseModel {
@Id
@Column(updatable = false)
private Integer main_resource_id;
@JsonIgnore
private String uri;
@JsonRawValue
@Type(type = "JsonObject")
private JsonObject json_content;
@JsonIgnore
private String creator;
@JsonIgnore
private String modifier;
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = Finals.DATE_FORMAT)
@JsonIgnore
@Temporal(TemporalType.TIMESTAMP)
private Date creation_date;
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = Finals.DATE_FORMAT)
@JsonIgnore
@Temporal(TemporalType.TIMESTAMP)
private Date modified_date;
@JsonIgnore
private String kind;
// Needed for indication that this field should not be searched in json content
@JsonIgnore
private String search_content;
@JsonIgnore
@Column(name = "j_creation_timestamp")
private Date j_creation_timestamp;
@Column(name = "last_positive_approval_request_type")
private String last_positive_approval_request_type;
@Column(name = "last_positive_approval_request_date")
@Temporal(TemporalType.TIMESTAMP)
private Date last_positive_approval_request_date;
public Integer getMain_resource_id() {
return main_resource_id;
}
......@@ -137,4 +150,20 @@ public class Main_resource_view implements BaseModel {
public void setKind(String kind) {
throw new UnsupportedOperationException();
}
public String getLast_positive_approval_request_type() {
return last_positive_approval_request_type;
}
public void setLast_positive_approval_request_type(String last_positive_approval_request_type) {
this.last_positive_approval_request_type = last_positive_approval_request_type;
}
public Date getLast_positive_approval_request_date() {
return last_positive_approval_request_date;
}
public void setLast_positive_approval_request_date(Date last_positive_approval_request_date) {
this.last_positive_approval_request_date = last_positive_approval_request_date;
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment