[jdbc] Implement 'ModifiablePersistenceService' interface (#11922)
Signed-off-by: Christoph Weitkamp <github@christophweitkamp.de>
This commit is contained in:
parent
344a4ceae3
commit
bb2e4c7c65
@ -13,7 +13,6 @@
|
||||
package org.openhab.persistence.jdbc.db;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.sql.Timestamp;
|
||||
import java.time.Instant;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZonedDateTime;
|
||||
@ -327,8 +326,8 @@ public class JdbcBaseDAO {
|
||||
Yank.execute(sql, null);
|
||||
}
|
||||
|
||||
public void doStoreItemValue(Item item, ItemVO vo) {
|
||||
ItemVO storedVO = storeItemValueProvider(item, vo);
|
||||
public void doStoreItemValue(Item item, State itemState, ItemVO vo) {
|
||||
ItemVO storedVO = storeItemValueProvider(item, itemState, vo);
|
||||
String sql = StringUtilsExt.replaceArrayMerge(sqlInsertItemValue,
|
||||
new String[] { "#tableName#", "#tablePrimaryValue#" },
|
||||
new String[] { storedVO.getTableName(), sqlTypes.get("tablePrimaryValue") });
|
||||
@ -337,6 +336,16 @@ public class JdbcBaseDAO {
|
||||
Yank.execute(sql, params);
|
||||
}
|
||||
|
||||
public void doStoreItemValue(Item item, State itemState, ItemVO vo, ZonedDateTime date) {
|
||||
ItemVO storedVO = storeItemValueProvider(item, itemState, vo);
|
||||
String sql = StringUtilsExt.replaceArrayMerge(sqlInsertItemValue,
|
||||
new String[] { "#tableName#", "#tablePrimaryValue#" }, new String[] { storedVO.getTableName(), "?" });
|
||||
java.sql.Timestamp timestamp = new java.sql.Timestamp(date.toInstant().toEpochMilli());
|
||||
Object[] params = new Object[] { storedVO.getValue(), timestamp, storedVO.getValue() };
|
||||
logger.debug("JDBC::doStoreItemValue sql={} timestamp={} value='{}'", sql, timestamp, storedVO.getValue());
|
||||
Yank.execute(sql, params);
|
||||
}
|
||||
|
||||
public List<HistoricItem> doGetHistItemFilterQuery(Item item, FilterCriteria filter, int numberDecimalcount,
|
||||
String table, String name, ZoneId timeZone) {
|
||||
String sql = histItemFilterQueryProvider(filter, numberDecimalcount, table, name, timeZone);
|
||||
@ -353,6 +362,12 @@ public class JdbcBaseDAO {
|
||||
.collect(Collectors.<HistoricItem> toList());
|
||||
}
|
||||
|
||||
public void doDeleteItemValues(Item item, FilterCriteria filter, String table, ZoneId timeZone) {
|
||||
String sql = histItemFilterDeleteProvider(filter, table, timeZone);
|
||||
logger.debug("JDBC::doDeleteItemValues sql={}", sql);
|
||||
Yank.execute(sql, null);
|
||||
}
|
||||
|
||||
/*************
|
||||
* Providers *
|
||||
*************/
|
||||
@ -364,19 +379,9 @@ public class JdbcBaseDAO {
|
||||
"JDBC::getHistItemFilterQueryProvider filter = {}, numberDecimalcount = {}, table = {}, simpleName = {}",
|
||||
filter, numberDecimalcount, table, simpleName);
|
||||
|
||||
String filterString = "";
|
||||
if (filter.getBeginDate() != null) {
|
||||
filterString += filterString.isEmpty() ? " WHERE" : " AND";
|
||||
filterString += " TIME>'" + JDBC_DATE_FORMAT.format(filter.getBeginDate().withZoneSameInstant(timeZone))
|
||||
+ "'";
|
||||
}
|
||||
if (filter.getEndDate() != null) {
|
||||
filterString += filterString.isEmpty() ? " WHERE" : " AND";
|
||||
filterString += " TIME<'" + JDBC_DATE_FORMAT.format(filter.getEndDate().withZoneSameInstant(timeZone))
|
||||
+ "'";
|
||||
}
|
||||
filterString += (filter.getOrdering() == Ordering.ASCENDING) ? " ORDER BY time ASC" : " ORDER BY time DESC ";
|
||||
if (filter.getPageSize() != 0x7fffffff) {
|
||||
String filterString = resolveTimeFilter(filter, timeZone);
|
||||
filterString += (filter.getOrdering() == Ordering.ASCENDING) ? " ORDER BY time ASC" : " ORDER BY time DESC";
|
||||
if (filter.getPageSize() != Integer.MAX_VALUE) {
|
||||
filterString += " LIMIT " + filter.getPageNumber() * filter.getPageSize() + "," + filter.getPageSize();
|
||||
}
|
||||
// SELECT time, ROUND(value,3) FROM number_item_0114 ORDER BY time DESC LIMIT 0,1
|
||||
@ -391,6 +396,33 @@ public class JdbcBaseDAO {
|
||||
return queryString;
|
||||
}
|
||||
|
||||
protected String histItemFilterDeleteProvider(FilterCriteria filter, String table, ZoneId timeZone) {
|
||||
logger.debug("JDBC::histItemFilterDeleteProvider filter = {}, table = {}", filter, table);
|
||||
|
||||
String filterString = resolveTimeFilter(filter, timeZone);
|
||||
String deleteString = "DELETE FROM " + table;
|
||||
if (!filterString.isEmpty()) {
|
||||
deleteString += filterString;
|
||||
}
|
||||
logger.debug("JDBC::delete deleteString = {}", deleteString);
|
||||
return deleteString;
|
||||
}
|
||||
|
||||
protected String resolveTimeFilter(FilterCriteria filter, ZoneId timeZone) {
|
||||
String filterString = "";
|
||||
if (filter.getBeginDate() != null) {
|
||||
filterString += filterString.isEmpty() ? " WHERE" : " AND";
|
||||
filterString += " TIME>'" + JDBC_DATE_FORMAT.format(filter.getBeginDate().withZoneSameInstant(timeZone))
|
||||
+ "'";
|
||||
}
|
||||
if (filter.getEndDate() != null) {
|
||||
filterString += filterString.isEmpty() ? " WHERE" : " AND";
|
||||
filterString += " TIME<'" + JDBC_DATE_FORMAT.format(filter.getEndDate().withZoneSameInstant(timeZone))
|
||||
+ "'";
|
||||
}
|
||||
return filterString;
|
||||
}
|
||||
|
||||
private String updateItemTableNamesProvider(List<ItemVO> namesList) {
|
||||
logger.debug("JDBC::updateItemTableNamesProvider namesList.size = {}", namesList.size());
|
||||
String queryString = "";
|
||||
@ -402,14 +434,14 @@ public class JdbcBaseDAO {
|
||||
return queryString;
|
||||
}
|
||||
|
||||
protected ItemVO storeItemValueProvider(Item item, ItemVO vo) {
|
||||
protected ItemVO storeItemValueProvider(Item item, State itemState, ItemVO vo) {
|
||||
String itemType = getItemType(item);
|
||||
|
||||
logger.debug("JDBC::storeItemValueProvider: item '{}' as Type '{}' in '{}' with state '{}'", item.getName(),
|
||||
itemType, vo.getTableName(), item.getState());
|
||||
itemType, vo.getTableName(), itemState);
|
||||
|
||||
// insertItemValue
|
||||
logger.debug("JDBC::storeItemValueProvider: getState: '{}'", item.getState());
|
||||
logger.debug("JDBC::storeItemValueProvider: itemState: '{}'", itemState);
|
||||
/*
|
||||
* !!ATTENTION!!
|
||||
*
|
||||
@ -427,20 +459,19 @@ public class JdbcBaseDAO {
|
||||
switch (itemType) {
|
||||
case "COLORITEM":
|
||||
vo.setValueTypes(getSqlTypes().get(itemType), java.lang.String.class);
|
||||
vo.setValue(item.getState().toString());
|
||||
vo.setValue(itemState.toString());
|
||||
break;
|
||||
case "NUMBERITEM":
|
||||
State state = item.getState();
|
||||
State convertedState = state;
|
||||
if (item instanceof NumberItem && state instanceof QuantityType) {
|
||||
State convertedState = itemState;
|
||||
if (item instanceof NumberItem && itemState instanceof QuantityType) {
|
||||
Unit<? extends Quantity<?>> unit = ((NumberItem) item).getUnit();
|
||||
if (unit != null && !Units.ONE.equals(unit)) {
|
||||
convertedState = ((QuantityType<?>) state).toUnit(unit);
|
||||
convertedState = ((QuantityType<?>) itemState).toUnit(unit);
|
||||
if (convertedState == null) {
|
||||
logger.warn(
|
||||
"JDBC::storeItemValueProvider: Failed to convert state '{}' to unit '{}'. Please check your item definition for correctness.",
|
||||
state, unit);
|
||||
convertedState = state;
|
||||
itemState, unit);
|
||||
convertedState = itemState;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -462,21 +493,21 @@ public class JdbcBaseDAO {
|
||||
vo.setValue(value);
|
||||
} else {// fall back to String
|
||||
vo.setValueTypes(it, java.lang.String.class);
|
||||
logger.warn("JDBC::storeItemValueProvider: item.getState().toString(): '{}'", convertedState);
|
||||
logger.warn("JDBC::storeItemValueProvider: itemState: '{}'", convertedState);
|
||||
vo.setValue(convertedState.toString());
|
||||
}
|
||||
break;
|
||||
case "ROLLERSHUTTERITEM":
|
||||
case "DIMMERITEM":
|
||||
vo.setValueTypes(getSqlTypes().get(itemType), java.lang.Integer.class);
|
||||
int value = ((DecimalType) item.getState()).intValue();
|
||||
int value = ((DecimalType) itemState).intValue();
|
||||
logger.debug("JDBC::storeItemValueProvider: newVal.intValue: '{}'", value);
|
||||
vo.setValue(value);
|
||||
break;
|
||||
case "DATETIMEITEM":
|
||||
vo.setValueTypes(getSqlTypes().get(itemType), java.sql.Timestamp.class);
|
||||
java.sql.Timestamp d = new java.sql.Timestamp(
|
||||
((DateTimeType) item.getState()).getZonedDateTime().toInstant().toEpochMilli());
|
||||
((DateTimeType) itemState).getZonedDateTime().toInstant().toEpochMilli());
|
||||
logger.debug("JDBC::storeItemValueProvider: DateTimeItem: '{}'", d);
|
||||
vo.setValue(d);
|
||||
break;
|
||||
@ -489,8 +520,8 @@ public class JdbcBaseDAO {
|
||||
default:
|
||||
// All other items should return the best format by default
|
||||
vo.setValueTypes(getSqlTypes().get(itemType), java.lang.String.class);
|
||||
logger.debug("JDBC::storeItemValueProvider: other: item.getState().toString(): '{}'", item.getState());
|
||||
vo.setValue(item.getState().toString());
|
||||
logger.debug("JDBC::storeItemValueProvider: other: itemState: '{}'", itemState);
|
||||
vo.setValue(itemState.toString());
|
||||
break;
|
||||
}
|
||||
return vo;
|
||||
@ -533,9 +564,10 @@ public class JdbcBaseDAO {
|
||||
|
||||
protected ZonedDateTime objectAsDate(Object v) {
|
||||
if (v instanceof java.lang.String) {
|
||||
return ZonedDateTime.ofInstant(Timestamp.valueOf(v.toString()).toInstant(), ZoneId.systemDefault());
|
||||
return ZonedDateTime.ofInstant(java.sql.Timestamp.valueOf(v.toString()).toInstant(),
|
||||
ZoneId.systemDefault());
|
||||
}
|
||||
return ZonedDateTime.ofInstant(((Timestamp) v).toInstant(), ZoneId.systemDefault());
|
||||
return ZonedDateTime.ofInstant(((java.sql.Timestamp) v).toInstant(), ZoneId.systemDefault());
|
||||
}
|
||||
|
||||
protected Long objectAsLong(Object v) {
|
||||
|
||||
@ -25,6 +25,7 @@ import org.openhab.core.library.items.NumberItem;
|
||||
import org.openhab.core.persistence.FilterCriteria;
|
||||
import org.openhab.core.persistence.FilterCriteria.Ordering;
|
||||
import org.openhab.core.persistence.HistoricItem;
|
||||
import org.openhab.core.types.State;
|
||||
import org.openhab.persistence.jdbc.dto.ItemVO;
|
||||
import org.openhab.persistence.jdbc.dto.ItemsVO;
|
||||
import org.openhab.persistence.jdbc.dto.JdbcHistoricItem;
|
||||
@ -148,13 +149,14 @@ public class JdbcDerbyDAO extends JdbcBaseDAO {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doStoreItemValue(Item item, ItemVO vo) {
|
||||
vo = storeItemValueProvider(item, vo);
|
||||
public void doStoreItemValue(Item item, State itemState, ItemVO vo) {
|
||||
ItemVO storedVO = storeItemValueProvider(item, itemState, vo);
|
||||
String sql = StringUtilsExt.replaceArrayMerge(sqlInsertItemValue,
|
||||
new String[] { "#tableName#", "#dbType#", "#tablePrimaryValue#" },
|
||||
new String[] { vo.getTableName().toUpperCase(), vo.getDbType(), sqlTypes.get("tablePrimaryValue") });
|
||||
Object[] params = new Object[] { vo.getValue() };
|
||||
logger.debug("JDBC::doStoreItemValue sql={} value='{}'", sql, vo.getValue());
|
||||
new String[] { storedVO.getTableName().toUpperCase(), storedVO.getDbType(),
|
||||
sqlTypes.get("tablePrimaryValue") });
|
||||
Object[] params = new Object[] { storedVO.getValue() };
|
||||
logger.debug("JDBC::doStoreItemValue sql={} value='{}'", sql, storedVO.getValue());
|
||||
Yank.execute(sql, params);
|
||||
}
|
||||
|
||||
|
||||
@ -14,6 +14,7 @@ package org.openhab.persistence.jdbc.db;
|
||||
|
||||
import org.knowm.yank.Yank;
|
||||
import org.openhab.core.items.Item;
|
||||
import org.openhab.core.types.State;
|
||||
import org.openhab.persistence.jdbc.dto.ItemVO;
|
||||
import org.openhab.persistence.jdbc.utils.StringUtilsExt;
|
||||
import org.slf4j.Logger;
|
||||
@ -71,13 +72,13 @@ public class JdbcH2DAO extends JdbcBaseDAO {
|
||||
* ITEM DAOs *
|
||||
*************/
|
||||
@Override
|
||||
public void doStoreItemValue(Item item, ItemVO vo) {
|
||||
vo = storeItemValueProvider(item, vo);
|
||||
public void doStoreItemValue(Item item, State itemState, ItemVO vo) {
|
||||
ItemVO storedVO = storeItemValueProvider(item, itemState, vo);
|
||||
String sql = StringUtilsExt.replaceArrayMerge(sqlInsertItemValue,
|
||||
new String[] { "#tableName#", "#dbType#", "#tablePrimaryValue#" },
|
||||
new String[] { vo.getTableName(), vo.getDbType(), sqlTypes.get("tablePrimaryValue") });
|
||||
Object[] params = new Object[] { vo.getValue() };
|
||||
logger.debug("JDBC::doStoreItemValue sql={} value='{}'", sql, vo.getValue());
|
||||
new String[] { storedVO.getTableName(), storedVO.getDbType(), sqlTypes.get("tablePrimaryValue") });
|
||||
Object[] params = new Object[] { storedVO.getValue() };
|
||||
logger.debug("JDBC::doStoreItemValue sql={} value='{}'", sql, storedVO.getValue());
|
||||
Yank.execute(sql, params);
|
||||
}
|
||||
|
||||
|
||||
@ -14,6 +14,7 @@ package org.openhab.persistence.jdbc.db;
|
||||
|
||||
import org.knowm.yank.Yank;
|
||||
import org.openhab.core.items.Item;
|
||||
import org.openhab.core.types.State;
|
||||
import org.openhab.persistence.jdbc.dto.ItemVO;
|
||||
import org.openhab.persistence.jdbc.dto.ItemsVO;
|
||||
import org.openhab.persistence.jdbc.utils.StringUtilsExt;
|
||||
@ -101,13 +102,14 @@ public class JdbcHsqldbDAO extends JdbcBaseDAO {
|
||||
* ITEM DAOs *
|
||||
*************/
|
||||
@Override
|
||||
public void doStoreItemValue(Item item, ItemVO vo) {
|
||||
vo = storeItemValueProvider(item, vo);
|
||||
public void doStoreItemValue(Item item, State itemState, ItemVO vo) {
|
||||
ItemVO storedVO = storeItemValueProvider(item, itemState, vo);
|
||||
String sql = StringUtilsExt.replaceArrayMerge(sqlInsertItemValue,
|
||||
new String[] { "#tableName#", "#dbType#", "#tableName#", "#tablePrimaryValue#" }, new String[] {
|
||||
vo.getTableName(), vo.getDbType(), vo.getTableName(), sqlTypes.get("tablePrimaryValue") });
|
||||
Object[] params = new Object[] { vo.getValue() };
|
||||
logger.debug("JDBC::doStoreItemValue sql={} value='{}'", sql, vo.getValue());
|
||||
new String[] { "#tableName#", "#dbType#", "#tableName#", "#tablePrimaryValue#" },
|
||||
new String[] { storedVO.getTableName(), storedVO.getDbType(), storedVO.getTableName(),
|
||||
sqlTypes.get("tablePrimaryValue") });
|
||||
Object[] params = new Object[] { storedVO.getValue() };
|
||||
logger.debug("JDBC::doStoreItemValue sql={} value='{}'", sql, storedVO.getValue());
|
||||
Yank.execute(sql, params);
|
||||
}
|
||||
|
||||
|
||||
@ -19,6 +19,7 @@ import org.knowm.yank.Yank;
|
||||
import org.openhab.core.items.Item;
|
||||
import org.openhab.core.persistence.FilterCriteria;
|
||||
import org.openhab.core.persistence.FilterCriteria.Ordering;
|
||||
import org.openhab.core.types.State;
|
||||
import org.openhab.persistence.jdbc.dto.ItemVO;
|
||||
import org.openhab.persistence.jdbc.dto.ItemsVO;
|
||||
import org.openhab.persistence.jdbc.utils.StringUtilsExt;
|
||||
@ -133,13 +134,13 @@ public class JdbcPostgresqlDAO extends JdbcBaseDAO {
|
||||
* ITEM DAOs *
|
||||
*************/
|
||||
@Override
|
||||
public void doStoreItemValue(Item item, ItemVO vo) {
|
||||
vo = storeItemValueProvider(item, vo);
|
||||
public void doStoreItemValue(Item item, State itemState, ItemVO vo) {
|
||||
ItemVO storedVO = storeItemValueProvider(item, itemState, vo);
|
||||
String sql = StringUtilsExt.replaceArrayMerge(sqlInsertItemValue,
|
||||
new String[] { "#tableName#", "#dbType#", "#tablePrimaryValue#" },
|
||||
new String[] { vo.getTableName(), vo.getDbType(), sqlTypes.get("tablePrimaryValue") });
|
||||
Object[] params = new Object[] { vo.getValue() };
|
||||
logger.debug("JDBC::doStoreItemValue sql={} value='{}'", sql, vo.getValue());
|
||||
new String[] { storedVO.getTableName(), storedVO.getDbType(), sqlTypes.get("tablePrimaryValue") });
|
||||
Object[] params = new Object[] { storedVO.getValue() };
|
||||
logger.debug("JDBC::doStoreItemValue sql={} value='{}'", sql, storedVO.getValue());
|
||||
Yank.execute(sql, params);
|
||||
}
|
||||
|
||||
|
||||
@ -14,6 +14,7 @@ package org.openhab.persistence.jdbc.db;
|
||||
|
||||
import org.knowm.yank.Yank;
|
||||
import org.openhab.core.items.Item;
|
||||
import org.openhab.core.types.State;
|
||||
import org.openhab.persistence.jdbc.dto.ItemVO;
|
||||
import org.openhab.persistence.jdbc.dto.ItemsVO;
|
||||
import org.openhab.persistence.jdbc.utils.StringUtilsExt;
|
||||
@ -90,13 +91,13 @@ public class JdbcSqliteDAO extends JdbcBaseDAO {
|
||||
* ITEM DAOs *
|
||||
*************/
|
||||
@Override
|
||||
public void doStoreItemValue(Item item, ItemVO vo) {
|
||||
vo = storeItemValueProvider(item, vo);
|
||||
public void doStoreItemValue(Item item, State itemState, ItemVO vo) {
|
||||
ItemVO storedVO = storeItemValueProvider(item, itemState, vo);
|
||||
String sql = StringUtilsExt.replaceArrayMerge(sqlInsertItemValue,
|
||||
new String[] { "#tableName#", "#dbType#", "#tablePrimaryValue#" },
|
||||
new String[] { vo.getTableName(), vo.getDbType(), sqlTypes.get("tablePrimaryValue") });
|
||||
Object[] params = new Object[] { vo.getValue() };
|
||||
logger.debug("JDBC::doStoreItemValue sql={} value='{}'", sql, vo.getValue());
|
||||
new String[] { storedVO.getTableName(), storedVO.getDbType(), sqlTypes.get("tablePrimaryValue") });
|
||||
Object[] params = new Object[] { storedVO.getValue() };
|
||||
logger.debug("JDBC::doStoreItemValue sql={} value='{}'", sql, storedVO.getValue());
|
||||
Yank.execute(sql, params);
|
||||
}
|
||||
|
||||
|
||||
@ -16,6 +16,7 @@ import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
import java.util.Objects;
|
||||
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@ -30,7 +31,7 @@ public class ItemVO implements Serializable {
|
||||
private static final long serialVersionUID = 1871441039821454890L;
|
||||
|
||||
private String tableName;
|
||||
private String newTableName;
|
||||
private @Nullable String newTableName;
|
||||
private String dbType;
|
||||
private String jdbcType;
|
||||
private String itemType;
|
||||
@ -38,7 +39,7 @@ public class ItemVO implements Serializable {
|
||||
private Date time;
|
||||
private Object value;
|
||||
|
||||
public ItemVO(String tableName, String newTableName) {
|
||||
public ItemVO(String tableName, @Nullable String newTableName) {
|
||||
logger.debug("JDBC:ItemVO tableName={}; newTableName={}; ", tableName, newTableName);
|
||||
this.tableName = tableName;
|
||||
this.newTableName = newTableName;
|
||||
@ -61,7 +62,7 @@ public class ItemVO implements Serializable {
|
||||
this.tableName = tableName;
|
||||
}
|
||||
|
||||
public String getNewTableName() {
|
||||
public @Nullable String getNewTableName() {
|
||||
return newTableName;
|
||||
}
|
||||
|
||||
@ -117,11 +118,6 @@ public class ItemVO implements Serializable {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see java.lang.Object#equals(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
@ -146,20 +142,8 @@ public class ItemVO implements Serializable {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append("ItemVO [tableName=");
|
||||
builder.append(tableName);
|
||||
builder.append(", newTableName=");
|
||||
builder.append(newTableName);
|
||||
builder.append(", dbType=");
|
||||
builder.append(dbType);
|
||||
builder.append(", javaType=");
|
||||
builder.append(javaType);
|
||||
builder.append(", time=");
|
||||
builder.append(time);
|
||||
builder.append(", value=");
|
||||
builder.append(value);
|
||||
builder.append("]");
|
||||
return builder.toString();
|
||||
return new StringBuilder("ItemVO [tableName=").append(tableName).append(", newTableName=").append(newTableName)
|
||||
.append(", dbType=").append(dbType).append(", javaType=").append(javaType).append(", time=")
|
||||
.append(time).append(", value=").append(value).append("]").toString();
|
||||
}
|
||||
}
|
||||
|
||||
@ -12,6 +12,7 @@
|
||||
*/
|
||||
package org.openhab.persistence.jdbc.internal;
|
||||
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
@ -19,12 +20,14 @@ import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.knowm.yank.Yank;
|
||||
import org.openhab.core.i18n.TimeZoneProvider;
|
||||
import org.openhab.core.items.Item;
|
||||
import org.openhab.core.persistence.FilterCriteria;
|
||||
import org.openhab.core.persistence.HistoricItem;
|
||||
import org.openhab.core.persistence.PersistenceItemInfo;
|
||||
import org.openhab.core.types.State;
|
||||
import org.openhab.persistence.jdbc.dto.ItemVO;
|
||||
import org.openhab.persistence.jdbc.dto.ItemsVO;
|
||||
import org.openhab.persistence.jdbc.dto.JdbcPersistenceItemInfo;
|
||||
@ -145,15 +148,19 @@ public class JdbcMapper {
|
||||
return vo;
|
||||
}
|
||||
|
||||
public Item storeItemValue(Item item) {
|
||||
logger.debug("JDBC::storeItemValue: item={}", item);
|
||||
public Item storeItemValue(Item item, State itemState, @Nullable ZonedDateTime date) {
|
||||
logger.debug("JDBC::storeItemValue: item={} state={} date={}", item, itemState, date);
|
||||
String tableName = getTable(item);
|
||||
if (tableName == null) {
|
||||
logger.error("JDBC::store: Unable to store item '{}'.", item.getName());
|
||||
return item;
|
||||
}
|
||||
long timerStart = System.currentTimeMillis();
|
||||
conf.getDBDAO().doStoreItemValue(item, new ItemVO(tableName, null));
|
||||
if (date == null) {
|
||||
conf.getDBDAO().doStoreItemValue(item, itemState, new ItemVO(tableName, null));
|
||||
} else {
|
||||
conf.getDBDAO().doStoreItemValue(item, itemState, new ItemVO(tableName, null), date);
|
||||
}
|
||||
logTime("storeItemValue", timerStart, System.currentTimeMillis());
|
||||
errCnt = 0;
|
||||
return item;
|
||||
@ -177,6 +184,21 @@ public class JdbcMapper {
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean deleteItemValues(FilterCriteria filter, String table, Item item) {
|
||||
logger.debug("JDBC::deleteItemValues filter='{}' table='{}' item='{}' itemName='{}'", (filter != null), table,
|
||||
item, item.getName());
|
||||
if (table != null) {
|
||||
long timerStart = System.currentTimeMillis();
|
||||
conf.getDBDAO().doDeleteItemValues(item, filter, table, timeZoneProvider.getTimeZone());
|
||||
logTime("deleteItemValues", timerStart, System.currentTimeMillis());
|
||||
errCnt = 0;
|
||||
return true;
|
||||
} else {
|
||||
logger.error("JDBC::deleteItemValues: TABLE is NULL; cannot delete data from non-existent table.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/***********************
|
||||
* DATABASE CONNECTION *
|
||||
***********************/
|
||||
|
||||
@ -12,6 +12,8 @@
|
||||
*/
|
||||
package org.openhab.persistence.jdbc.internal;
|
||||
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
@ -27,10 +29,12 @@ import org.openhab.core.items.ItemNotFoundException;
|
||||
import org.openhab.core.items.ItemRegistry;
|
||||
import org.openhab.core.persistence.FilterCriteria;
|
||||
import org.openhab.core.persistence.HistoricItem;
|
||||
import org.openhab.core.persistence.ModifiablePersistenceService;
|
||||
import org.openhab.core.persistence.PersistenceItemInfo;
|
||||
import org.openhab.core.persistence.PersistenceService;
|
||||
import org.openhab.core.persistence.QueryablePersistenceService;
|
||||
import org.openhab.core.persistence.strategy.PersistenceStrategy;
|
||||
import org.openhab.core.types.State;
|
||||
import org.openhab.core.types.UnDefType;
|
||||
import org.osgi.framework.BundleContext;
|
||||
import org.osgi.framework.Constants;
|
||||
@ -52,8 +56,10 @@ import org.slf4j.LoggerFactory;
|
||||
QueryablePersistenceService.class }, configurationPid = "org.openhab.jdbc", //
|
||||
property = Constants.SERVICE_PID + "=org.openhab.jdbc")
|
||||
@ConfigurableService(category = "persistence", label = "JDBC Persistence Service", description_uri = JdbcPersistenceService.CONFIG_URI)
|
||||
public class JdbcPersistenceService extends JdbcMapper implements QueryablePersistenceService {
|
||||
public class JdbcPersistenceService extends JdbcMapper implements ModifiablePersistenceService {
|
||||
|
||||
private static final String SERVICE_ID = "jdbc";
|
||||
private static final String SERVICE_LABEL = "JDBC";
|
||||
protected static final String CONFIG_URI = "persistence:jdbc";
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(JdbcPersistenceService.class);
|
||||
@ -110,39 +116,48 @@ public class JdbcPersistenceService extends JdbcMapper implements QueryablePersi
|
||||
@Override
|
||||
public String getId() {
|
||||
logger.debug("JDBC::getName: returning name 'jdbc' for queryable persistence service.");
|
||||
return "jdbc";
|
||||
return SERVICE_ID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLabel(@Nullable Locale locale) {
|
||||
return "JDBC";
|
||||
return SERVICE_LABEL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void store(Item item) {
|
||||
store(item, null);
|
||||
internalStore(item, null, item.getState());
|
||||
}
|
||||
|
||||
/**
|
||||
* @{inheritDoc
|
||||
*/
|
||||
@Override
|
||||
public void store(Item item, @Nullable String alias) {
|
||||
// alias is not supported
|
||||
internalStore(item, null, item.getState());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void store(Item item, ZonedDateTime date, State state) {
|
||||
internalStore(item, date, state);
|
||||
}
|
||||
|
||||
private void internalStore(Item item, @Nullable ZonedDateTime date, State state) {
|
||||
// Do not store undefined/uninitialized data
|
||||
if (item.getState() instanceof UnDefType) {
|
||||
if (state instanceof UnDefType) {
|
||||
logger.debug("JDBC::store: ignore Item '{}' because it is UnDefType", item.getName());
|
||||
return;
|
||||
}
|
||||
if (!checkDBAccessability()) {
|
||||
logger.warn(
|
||||
"JDBC::store: No connection to database. Cannot persist item '{}'! Will retry connecting to database when error count:{} equals errReconnectThreshold:{}",
|
||||
item, errCnt, conf.getErrReconnectThreshold());
|
||||
"JDBC::store: No connection to database. Cannot persist state '{}' for item '{}'! Will retry connecting to database when error count:{} equals errReconnectThreshold:{}",
|
||||
state, item, errCnt, conf.getErrReconnectThreshold());
|
||||
return;
|
||||
}
|
||||
long timerStart = System.currentTimeMillis();
|
||||
storeItemValue(item);
|
||||
logger.debug("JDBC: Stored item '{}' as '{}' in SQL database at {} in {} ms.", item.getName(), item.getState(),
|
||||
new java.util.Date(), System.currentTimeMillis() - timerStart);
|
||||
storeItemValue(item, state, date);
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("JDBC: Stored item '{}' as '{}' in SQL database at {} in {} ms.", item.getName(), state,
|
||||
new Date(), System.currentTimeMillis() - timerStart);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -228,4 +243,42 @@ public class JdbcPersistenceService extends JdbcMapper implements QueryablePersi
|
||||
public List<PersistenceStrategy> getDefaultStrategies() {
|
||||
return List.of(PersistenceStrategy.Globals.CHANGE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean remove(FilterCriteria filter) throws IllegalArgumentException {
|
||||
if (!checkDBAccessability()) {
|
||||
logger.warn("JDBC::remove: database not connected, remove aborted for item '{}'", filter.getItemName());
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get the item name from the filter
|
||||
// Also get the Item object so we can determine the type
|
||||
Item item = null;
|
||||
String itemName = filter.getItemName();
|
||||
logger.debug("JDBC::remove: item is {}", itemName);
|
||||
if (itemName == null) {
|
||||
throw new IllegalArgumentException("Item name must not be null");
|
||||
}
|
||||
try {
|
||||
item = itemRegistry.getItem(itemName);
|
||||
} catch (ItemNotFoundException e) {
|
||||
logger.error("JDBC::remove: unable to get item for itemName: '{}'. Ignore and give up!", itemName);
|
||||
return false;
|
||||
}
|
||||
|
||||
String table = sqlTables.get(itemName);
|
||||
if (table == null) {
|
||||
logger.debug("JDBC::remove: unable to find table for item with name: '{}', no data in database.", itemName);
|
||||
return false;
|
||||
}
|
||||
|
||||
long timerStart = System.currentTimeMillis();
|
||||
boolean result = deleteItemValues(filter, table, item);
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("JDBC: Deleted values for item '{}' in SQL database at {} in {} ms.", item.getName(),
|
||||
new Date(), System.currentTimeMillis() - timerStart);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,135 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2022 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.persistence.jdbc.db;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.openhab.core.persistence.FilterCriteria;
|
||||
import org.openhab.core.persistence.FilterCriteria.Ordering;
|
||||
|
||||
/**
|
||||
* Tests the {@link JdbcBaseDAO}.
|
||||
*
|
||||
* @author Christoph Weitkamp - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class JdbcBaseDAOTest {
|
||||
|
||||
private static final String DATE_PATTERN = "yyyy-MM-dd'T'HH:mm:ss";
|
||||
private static final DateTimeFormatter DATE_PARSER = DateTimeFormatter.ofPattern(DATE_PATTERN);
|
||||
private static final ZoneId UTC_ZONE_ID = ZoneId.of("UTC");
|
||||
private static final String DB_TABLE_NAME = "testitem";
|
||||
|
||||
private final JdbcBaseDAO jdbcBaseDAO = new JdbcBaseDAO();
|
||||
private @NonNullByDefault({}) FilterCriteria filter;
|
||||
|
||||
@BeforeEach
|
||||
public void setup() {
|
||||
filter = new FilterCriteria();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHistItemFilterQueryProviderReturnsSelectQueryWithoutWhereClauseDescendingOrder() {
|
||||
String sql = jdbcBaseDAO.histItemFilterQueryProvider(filter, 0, DB_TABLE_NAME, "TEST", UTC_ZONE_ID);
|
||||
assertThat(sql, is("SELECT time, value FROM " + DB_TABLE_NAME + " ORDER BY time DESC"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHistItemFilterQueryProviderReturnsSelectQueryWithoutWhereClauseAscendingOrder() {
|
||||
filter.setOrdering(Ordering.ASCENDING);
|
||||
|
||||
String sql = jdbcBaseDAO.histItemFilterQueryProvider(filter, 0, DB_TABLE_NAME, "TEST", UTC_ZONE_ID);
|
||||
assertThat(sql, is("SELECT time, value FROM " + DB_TABLE_NAME + " ORDER BY time ASC"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHistItemFilterQueryProviderWithStartAndEndDateReturnsDeleteQueryWithWhereClauseDescendingOrder() {
|
||||
filter.setBeginDate(parseDateTimeString("2022-01-10T15:01:44"));
|
||||
filter.setEndDate(parseDateTimeString("2022-01-15T15:01:44"));
|
||||
|
||||
String sql = jdbcBaseDAO.histItemFilterQueryProvider(filter, 0, DB_TABLE_NAME, "TEST", UTC_ZONE_ID);
|
||||
assertThat(sql, is("SELECT time, value FROM " + DB_TABLE_NAME + " WHERE TIME>'" //
|
||||
+ JdbcBaseDAO.JDBC_DATE_FORMAT.format(filter.getBeginDate()) + "'" //
|
||||
+ " AND TIME<'" + JdbcBaseDAO.JDBC_DATE_FORMAT.format(filter.getEndDate()) + "' ORDER BY time DESC"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHistItemFilterQueryProviderReturnsSelectQueryWithoutWhereClauseDescendingOrderAndLimit() {
|
||||
filter.setPageSize(1);
|
||||
|
||||
String sql = jdbcBaseDAO.histItemFilterQueryProvider(filter, 0, DB_TABLE_NAME, "TEST", UTC_ZONE_ID);
|
||||
assertThat(sql, is("SELECT time, value FROM " + DB_TABLE_NAME + " ORDER BY time DESC LIMIT 0,1"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHistItemFilterDeleteProviderReturnsDeleteQueryWithoutWhereClause() {
|
||||
String sql = jdbcBaseDAO.histItemFilterDeleteProvider(filter, DB_TABLE_NAME, UTC_ZONE_ID);
|
||||
assertThat(sql, is("DELETE FROM " + DB_TABLE_NAME));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHistItemFilterDeleteProviderWithStartAndEndDateReturnsDeleteQueryWithWhereClause() {
|
||||
filter.setBeginDate(parseDateTimeString("2022-01-10T15:01:44"));
|
||||
filter.setEndDate(parseDateTimeString("2022-01-15T15:01:44"));
|
||||
|
||||
String sql = jdbcBaseDAO.histItemFilterDeleteProvider(filter, DB_TABLE_NAME, UTC_ZONE_ID);
|
||||
assertThat(sql, is("DELETE FROM " + DB_TABLE_NAME + " WHERE TIME>'" //
|
||||
+ JdbcBaseDAO.JDBC_DATE_FORMAT.format(filter.getBeginDate()) + "'" //
|
||||
+ " AND TIME<'" + JdbcBaseDAO.JDBC_DATE_FORMAT.format(filter.getEndDate()) + "'"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testResolveTimeFilterWithNoDatesReturnsEmptyString() {
|
||||
String sql = jdbcBaseDAO.resolveTimeFilter(filter, UTC_ZONE_ID);
|
||||
assertThat(sql, is(""));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testResolveTimeFilterWithStartDateOnlyReturnsWhereClause() {
|
||||
filter.setBeginDate(parseDateTimeString("2022-01-10T15:01:44"));
|
||||
|
||||
String sql = jdbcBaseDAO.resolveTimeFilter(filter, UTC_ZONE_ID);
|
||||
assertThat(sql, is(" WHERE TIME>'" + JdbcBaseDAO.JDBC_DATE_FORMAT.format(filter.getBeginDate()) + "'"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testResolveTimeFilterWithEndDateOnlyReturnsWhereClause() {
|
||||
filter.setEndDate(parseDateTimeString("2022-01-15T15:01:44"));
|
||||
|
||||
String sql = jdbcBaseDAO.resolveTimeFilter(filter, UTC_ZONE_ID);
|
||||
assertThat(sql, is(" WHERE TIME<'" + JdbcBaseDAO.JDBC_DATE_FORMAT.format(filter.getEndDate()) + "'"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testResolveTimeFilterWithStartAndEndDateReturnsWhereClauseWithTwoConditions() {
|
||||
filter.setBeginDate(parseDateTimeString("2022-01-10T15:01:44"));
|
||||
filter.setEndDate(parseDateTimeString("2022-01-15T15:01:44"));
|
||||
|
||||
String sql = jdbcBaseDAO.resolveTimeFilter(filter, UTC_ZONE_ID);
|
||||
assertThat(sql, is(" WHERE TIME>'" + JdbcBaseDAO.JDBC_DATE_FORMAT.format(filter.getBeginDate()) + "'" //
|
||||
+ " AND TIME<'" + JdbcBaseDAO.JDBC_DATE_FORMAT.format(filter.getEndDate()) + "'"));
|
||||
}
|
||||
|
||||
private ZonedDateTime parseDateTimeString(String dts) {
|
||||
return ZonedDateTime.of(LocalDateTime.parse(dts, DATE_PARSER), UTC_ZONE_ID);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,51 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2022 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.persistence.jdbc.internal;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.openhab.core.i18n.TimeZoneProvider;
|
||||
import org.openhab.core.items.ItemRegistry;
|
||||
import org.openhab.core.persistence.FilterCriteria;
|
||||
|
||||
/**
|
||||
* Tests the {@link JdbcPersistenceService}.
|
||||
*
|
||||
* @author Christoph Weitkamp - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class JdbcPersistenceServiceTest {
|
||||
|
||||
private final JdbcPersistenceService jdbcPersistenceService = new JdbcPersistenceService(mock(ItemRegistry.class),
|
||||
mock(TimeZoneProvider.class)) {
|
||||
@Override
|
||||
protected boolean checkDBAccessability() {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
private @NonNullByDefault({}) FilterCriteria filter;
|
||||
|
||||
@BeforeEach
|
||||
public void setup() {
|
||||
filter = new FilterCriteria();
|
||||
}
|
||||
|
||||
@Test
|
||||
void removeThrowsIllegalArgumentExceptionIfItemNameOfFilterIsNull() {
|
||||
assertThrows(IllegalArgumentException.class, () -> jdbcPersistenceService.remove(filter));
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user