diff --git a/bundles/org.openhab.persistence.jdbc/README.md b/bundles/org.openhab.persistence.jdbc/README.md
index 0a828875f..1cf0ef8f6 100644
--- a/bundles/org.openhab.persistence.jdbc/README.md
+++ b/bundles/org.openhab.persistence.jdbc/README.md
@@ -38,38 +38,39 @@ The following databases are currently supported and tested:
This service can be configured in the file `services/jdbc.cfg`.
-| Property | Default | Required | Description |
-| ------------------------- | ------------------------------------------------------------ | :-------: | ------------------------------------------------------------ |
-| url | | Yes | JDBC URL to establish a connection to your database. Examples:
If no database is available it will be created; for example the url `jdbc:h2:./testH2` creates a new H2 database in openHAB folder. Example to create your own MySQL database directly:
`CREATE DATABASE 'yourDB' CHARACTER SET utf8 COLLATE utf8_general_ci;` |
-| user | | if needed | database user name |
-| password | | if needed | database user password |
-| errReconnectThreshold | 0 | No | when the service is deactivated (0 means ignore) |
-| sqltype.CALL | `VARCHAR(200)` | No | All `sqlType` options allow you to change the SQL data type used to store values for different openHAB item states. See the following links for further information: [mybatis](https://mybatis.github.io/mybatis-3/apidocs/reference/org/apache/ibatis/type/JdbcType.html) [H2](https://www.h2database.com/html/datatypes.html) [PostgresSQL](https://www.postgresql.org/docs/9.3/static/datatype.html) |
-| sqltype.COLOR | `VARCHAR(70)` | No | see above |
-| sqltype.CONTACT | `VARCHAR(6)` | No | see above |
-| sqltype.DATETIME | `DATETIME` | No | see above |
-| sqltype.DIMMER | `TINYINT` | No | see above |
-| sqltype.IMAGE | `VARCHAR(65500)` | No | see above |
-| sqltype.LOCATION | `VARCHAR(50)` | No | see above |
-| sqltype.NUMBER | `DOUBLE` | No | see above |
-| sqltype.PLAYER | `VARCHAR(20)` | No | see above |
-| sqltype.ROLLERSHUTTER | `TINYINT` | No | see above |
-| sqltype.STRING | `VARCHAR(65500)` | No | see above |
-| sqltype.SWITCH | `VARCHAR(6)` | No | see above |
-| sqltype.tablePrimaryKey | `TIMESTAMP` | No | type of `time` column for newly created item tables |
-| sqltype.tablePrimaryValue | `NOW()` | No | value of `time` column for newly inserted rows |
-| numberDecimalcount | 3 | No | for Itemtype "Number" default decimal digit count |
-| tableNamePrefix | `item` | No | table name prefix. For Migration from MySQL Persistence, set to `Item`. |
-| tableUseRealItemNames | `false` | No | table name prefix generation. When set to `true`, real item names are used for table names and `tableNamePrefix` is ignored. When set to `false`, the `tableNamePrefix` is used to generate table names with sequential numbers. |
-| tableIdDigitCount | 4 | No | when `tableUseRealItemNames` is `false` and thus table names are generated sequentially, this controls how many zero-padded digits are used in the table name. With the default of 4, the first table name will end with `0001`. For migration from the MySQL persistence service, set this to 0. |
-| rebuildTableNames | false | No | rename existing tables using `tableUseRealItemNames` and `tableIdDigitCount`. USE WITH CARE! Deactivate after Renaming is done! |
-| jdbc.maximumPoolSize | configured per database in package `org.openhab.persistence.jdbc.db.*` | No | Some embedded databases can handle only one connection. See [this link](https://github.com/brettwooldridge/HikariCP/issues/256) for more information |
-| jdbc.minimumIdle | see above | No | see above |
-| enableLogTime | `false` | No | timekeeping |
+| Property | Default | Required | Description |
+| --------------------------- | ------------------------------------------------------------ | :-------: | ------------------------------------------------------------ |
+| url | | Yes | JDBC URL to establish a connection to your database. Examples:
If no database is available it will be created; for example the url `jdbc:h2:./testH2` creates a new H2 database in openHAB folder. Example to create your own MySQL database directly:
`CREATE DATABASE 'yourDB' CHARACTER SET utf8 COLLATE utf8_general_ci;` |
+| user | | if needed | database user name |
+| password | | if needed | database user password |
+| errReconnectThreshold | 0 | No | when the service is deactivated (0 means ignore) |
+| sqltype.CALL | `VARCHAR(200)` | No | All `sqlType` options allow you to change the SQL data type used to store values for different openHAB item states. See the following links for further information: [mybatis](https://mybatis.github.io/mybatis-3/apidocs/reference/org/apache/ibatis/type/JdbcType.html) [H2](https://www.h2database.com/html/datatypes.html) [PostgresSQL](https://www.postgresql.org/docs/9.3/static/datatype.html) |
+| sqltype.COLOR | `VARCHAR(70)` | No | see above |
+| sqltype.CONTACT | `VARCHAR(6)` | No | see above |
+| sqltype.DATETIME | `DATETIME` | No | see above |
+| sqltype.DIMMER | `TINYINT` | No | see above |
+| sqltype.IMAGE | `VARCHAR(65500)` | No | see above |
+| sqltype.LOCATION | `VARCHAR(50)` | No | see above |
+| sqltype.NUMBER | `DOUBLE` | No | see above |
+| sqltype.PLAYER | `VARCHAR(20)` | No | see above |
+| sqltype.ROLLERSHUTTER | `TINYINT` | No | see above |
+| sqltype.STRING | `VARCHAR(65500)` | No | see above |
+| sqltype.SWITCH | `VARCHAR(6)` | No | see above |
+| sqltype.tablePrimaryKey | `TIMESTAMP` | No | type of `time` column for newly created item tables |
+| sqltype.tablePrimaryValue | `NOW()` | No | value of `time` column for newly inserted rows |
+| numberDecimalcount | 3 | No | for Itemtype "Number" default decimal digit count |
+| tableNamePrefix | `item` | No | table name prefix. For Migration from MySQL Persistence, set to `Item`. |
+| tableUseRealItemNames | `false` | No | table name prefix generation. When set to `true`, real item names are used for table names and `tableNamePrefix` is ignored. When set to `false`, the `tableNamePrefix` is used to generate table names with sequential numbers. |
+| tableCaseSensitiveItemNames | `false` | No | table name case when `tableUseRealItemNames` is `true`. When set to `true`, item name case is preserved in table names and no suffix is used. When set to `false`, table names are lower cased and a numeric suffix is added. Please read [this](#case-sensitive-item-names) before enabling. |
+| tableIdDigitCount | 4 | No | when `tableUseRealItemNames` is `false` and thus table names are generated sequentially, this controls how many zero-padded digits are used in the table name. With the default of 4, the first table name will end with `0001`. For migration from the MySQL persistence service, set this to 0. |
+| rebuildTableNames | false | No | rename existing tables using `tableUseRealItemNames` and `tableIdDigitCount`. USE WITH CARE! Deactivate after Renaming is done! |
+| jdbc.maximumPoolSize | configured per database in package `org.openhab.persistence.jdbc.db.*` | No | Some embedded databases can handle only one connection. See [this link](https://github.com/brettwooldridge/HikariCP/issues/256) for more information |
+| jdbc.minimumIdle | see above | No | see above |
+| enableLogTime | `false` | No | timekeeping |
All item- and event-related configuration is done in the file `persistence/jdbc.persist`.
-To configure this service as the default persistence service for openHAB 2, add or change the line
+To configure this service as the default persistence service for openHAB, add or change the line
```
org.openhab.core.persistence:default=jdbc
@@ -85,6 +86,13 @@ services/jdbc.cfg
url=jdbc:postgresql://192.168.0.1:5432/testPostgresql
```
+### Case Sensitive Item Names
+
+To avoid numbered suffixes entirely, `tableUseRealItemNames` and `tableCaseSensitiveItemNames` must both be enabled.
+With this configuration, tables are named exactly like their corresponding items.
+In order for this to work correctly, the underlying operating system, database server and configuration must support case sensitive table names.
+For MySQL, see [MySQL: Identifier Case Sensitivity](https://dev.mysql.com/doc/refman/8.0/en/identifier-case-sensitivity.html) for more information.
+
### Migration from MySQL to JDBC Persistence Services
The JDBC Persistence service can act as a replacement for the MySQL Persistence service.
diff --git a/bundles/org.openhab.persistence.jdbc/src/main/java/org/openhab/persistence/jdbc/db/JdbcBaseDAO.java b/bundles/org.openhab.persistence.jdbc/src/main/java/org/openhab/persistence/jdbc/db/JdbcBaseDAO.java
index 63ed87172..074530b95 100644
--- a/bundles/org.openhab.persistence.jdbc/src/main/java/org/openhab/persistence/jdbc/db/JdbcBaseDAO.java
+++ b/bundles/org.openhab.persistence.jdbc/src/main/java/org/openhab/persistence/jdbc/db/JdbcBaseDAO.java
@@ -84,8 +84,9 @@ public class JdbcBaseDAO {
protected String sqlIfTableExists = "SHOW TABLES LIKE '#searchTable#'";
protected String sqlCreateNewEntryInItemsTable = "INSERT INTO #itemsManageTable# (ItemName) VALUES ('#itemname#')";
protected String sqlCreateItemsTableIfNot = "CREATE TABLE IF NOT EXISTS #itemsManageTable# (ItemId INT NOT NULL AUTO_INCREMENT,#colname# #coltype# NOT NULL,PRIMARY KEY (ItemId))";
+ protected String sqlDropItemsTableIfExists = "DROP TABLE IF EXISTS #itemsManageTable#";
protected String sqlDeleteItemsEntry = "DELETE FROM items WHERE ItemName=#itemname#";
- protected String sqlGetItemIDTableNames = "SELECT itemid, itemname FROM #itemsManageTable#";
+ protected String sqlGetItemIDTableNames = "SELECT ItemId, ItemName FROM #itemsManageTable#";
protected String sqlGetItemTables = "SELECT table_name FROM information_schema.tables WHERE table_type='BASE TABLE' AND table_schema='#jdbcUriDatabaseName#' AND NOT table_name='#itemsManageTable#'";
protected String sqlCreateItemTable = "CREATE TABLE IF NOT EXISTS #tableName# (time #tablePrimaryKey# NOT NULL, value #dbType#, PRIMARY KEY(time))";
protected String sqlInsertItemValue = "INSERT INTO #tableName# (TIME, VALUE) VALUES( #tablePrimaryValue#, ? ) ON DUPLICATE KEY UPDATE VALUE= ?";
@@ -266,7 +267,7 @@ public class JdbcBaseDAO {
public Long doCreateNewEntryInItemsTable(ItemsVO vo) {
String sql = StringUtilsExt.replaceArrayMerge(sqlCreateNewEntryInItemsTable,
new String[] { "#itemsManageTable#", "#itemname#" },
- new String[] { vo.getItemsManageTable(), vo.getItemname() });
+ new String[] { vo.getItemsManageTable(), vo.getItemName() });
logger.debug("JDBC::doCreateNewEntryInItemsTable sql={}", sql);
return Yank.insert(sql, null);
}
@@ -280,9 +281,17 @@ public class JdbcBaseDAO {
return vo;
}
+ public ItemsVO doDropItemsTableIfExists(ItemsVO vo) {
+ String sql = StringUtilsExt.replaceArrayMerge(sqlDropItemsTableIfExists, new String[] { "#itemsManageTable#" },
+ new String[] { vo.getItemsManageTable() });
+ logger.debug("JDBC::doDropItemsTableIfExists sql={}", sql);
+ Yank.execute(sql, null);
+ return vo;
+ }
+
public void doDeleteItemsEntry(ItemsVO vo) {
String sql = StringUtilsExt.replaceArrayMerge(sqlDeleteItemsEntry, new String[] { "#itemname#" },
- new String[] { vo.getItemname() });
+ new String[] { vo.getItemName() });
logger.debug("JDBC::doDeleteItemsEntry sql={}", sql);
Yank.execute(sql, null);
}
@@ -306,8 +315,9 @@ public class JdbcBaseDAO {
* ITEM DAOs *
*************/
public void doUpdateItemTableNames(List vol) {
- if (!vol.isEmpty()) {
- String sql = updateItemTableNamesProvider(vol);
+ logger.debug("JDBC::doUpdateItemTableNames vol.size = {}", vol.size());
+ for (ItemVO itemTable : vol) {
+ String sql = updateItemTableNamesProvider(itemTable);
Yank.execute(sql, null);
}
}
@@ -416,13 +426,8 @@ public class JdbcBaseDAO {
return filterString;
}
- private String updateItemTableNamesProvider(List namesList) {
- logger.debug("JDBC::updateItemTableNamesProvider namesList.size = {}", namesList.size());
- String queryString = "";
- for (int i = 0; i < namesList.size(); i++) {
- ItemVO it = namesList.get(i);
- queryString += "ALTER TABLE " + it.getTableName() + " RENAME TO " + it.getNewTableName() + ";";
- }
+ private String updateItemTableNamesProvider(ItemVO itemTable) {
+ String queryString = "ALTER TABLE " + itemTable.getTableName() + " RENAME TO " + itemTable.getNewTableName();
logger.debug("JDBC::query queryString = {}", queryString);
return queryString;
}
diff --git a/bundles/org.openhab.persistence.jdbc/src/main/java/org/openhab/persistence/jdbc/db/JdbcDerbyDAO.java b/bundles/org.openhab.persistence.jdbc/src/main/java/org/openhab/persistence/jdbc/db/JdbcDerbyDAO.java
index 4ee6c2d4c..f0d12bff0 100644
--- a/bundles/org.openhab.persistence.jdbc/src/main/java/org/openhab/persistence/jdbc/db/JdbcDerbyDAO.java
+++ b/bundles/org.openhab.persistence.jdbc/src/main/java/org/openhab/persistence/jdbc/db/JdbcDerbyDAO.java
@@ -123,7 +123,7 @@ public class JdbcDerbyDAO extends JdbcBaseDAO {
public Long doCreateNewEntryInItemsTable(ItemsVO vo) {
String sql = StringUtilsExt.replaceArrayMerge(sqlCreateNewEntryInItemsTable,
new String[] { "#itemsManageTable#", "#itemname#" },
- new String[] { vo.getItemsManageTable().toUpperCase(), vo.getItemname() });
+ new String[] { vo.getItemsManageTable().toUpperCase(), vo.getItemName() });
logger.debug("JDBC::doCreateNewEntryInItemsTable sql={}", sql);
return Yank.insert(sql, null);
}
diff --git a/bundles/org.openhab.persistence.jdbc/src/main/java/org/openhab/persistence/jdbc/db/JdbcHsqldbDAO.java b/bundles/org.openhab.persistence.jdbc/src/main/java/org/openhab/persistence/jdbc/db/JdbcHsqldbDAO.java
index 2fd77b4c7..fe9eb8f78 100644
--- a/bundles/org.openhab.persistence.jdbc/src/main/java/org/openhab/persistence/jdbc/db/JdbcHsqldbDAO.java
+++ b/bundles/org.openhab.persistence.jdbc/src/main/java/org/openhab/persistence/jdbc/db/JdbcHsqldbDAO.java
@@ -101,7 +101,7 @@ public class JdbcHsqldbDAO extends JdbcBaseDAO {
public Long doCreateNewEntryInItemsTable(ItemsVO vo) {
String sql = StringUtilsExt.replaceArrayMerge(sqlCreateNewEntryInItemsTable,
new String[] { "#itemsManageTable#", "#itemname#" },
- new String[] { vo.getItemsManageTable(), vo.getItemname() });
+ new String[] { vo.getItemsManageTable(), vo.getItemName() });
logger.debug("JDBC::doCreateNewEntryInItemsTable sql={}", sql);
return Yank.insert(sql, null);
}
diff --git a/bundles/org.openhab.persistence.jdbc/src/main/java/org/openhab/persistence/jdbc/db/JdbcPostgresqlDAO.java b/bundles/org.openhab.persistence.jdbc/src/main/java/org/openhab/persistence/jdbc/db/JdbcPostgresqlDAO.java
index 9c419af8c..974fd8fd0 100644
--- a/bundles/org.openhab.persistence.jdbc/src/main/java/org/openhab/persistence/jdbc/db/JdbcPostgresqlDAO.java
+++ b/bundles/org.openhab.persistence.jdbc/src/main/java/org/openhab/persistence/jdbc/db/JdbcPostgresqlDAO.java
@@ -121,7 +121,7 @@ public class JdbcPostgresqlDAO extends JdbcBaseDAO {
public Long doCreateNewEntryInItemsTable(ItemsVO vo) {
String sql = StringUtilsExt.replaceArrayMerge(sqlCreateNewEntryInItemsTable,
new String[] { "#itemsManageTable#", "#itemname#" },
- new String[] { vo.getItemsManageTable(), vo.getItemname() });
+ new String[] { vo.getItemsManageTable(), vo.getItemName() });
logger.debug("JDBC::doCreateNewEntryInItemsTable sql={}", sql);
return Yank.insert(sql, null);
}
diff --git a/bundles/org.openhab.persistence.jdbc/src/main/java/org/openhab/persistence/jdbc/dto/ItemsVO.java b/bundles/org.openhab.persistence.jdbc/src/main/java/org/openhab/persistence/jdbc/dto/ItemsVO.java
index 37ecc22b3..0e203f598 100644
--- a/bundles/org.openhab.persistence.jdbc/src/main/java/org/openhab/persistence/jdbc/dto/ItemsVO.java
+++ b/bundles/org.openhab.persistence.jdbc/src/main/java/org/openhab/persistence/jdbc/dto/ItemsVO.java
@@ -28,9 +28,9 @@ public class ItemsVO implements Serializable {
private String coltype = "VARCHAR(500)";
private String colname = "itemname";
private String itemsManageTable = "items";
- private int itemid;
- private String itemname;
- private String table_name;
+ private int itemId;
+ private String itemName;
+ private String tableName;
private String jdbcUriDatabaseName;
public String getColtype() {
@@ -57,28 +57,28 @@ public class ItemsVO implements Serializable {
this.itemsManageTable = itemsManageTable.replaceAll(STR_FILTER, "");
}
- public int getItemid() {
- return itemid;
+ public int getItemId() {
+ return itemId;
}
- public void setItemid(int itemid) {
- this.itemid = itemid;
+ public void setItemId(int itemId) {
+ this.itemId = itemId;
}
- public String getItemname() {
- return itemname;
+ public String getItemName() {
+ return itemName;
}
- public void setItemname(String itemname) {
- this.itemname = itemname;
+ public void setItemName(String itemName) {
+ this.itemName = itemName;
}
- public String getTable_name() {
- return table_name;
+ public String getTableName() {
+ return tableName;
}
- public void setTable_name(String table_name) {
- this.table_name = table_name;
+ public void setTableName(String tableName) {
+ this.tableName = tableName;
}
public String getJdbcUriDatabaseName() {
@@ -98,8 +98,8 @@ public class ItemsVO implements Serializable {
public int hashCode() {
final int prime = 31;
int result = 1;
- result = prime * result + ((itemname == null) ? 0 : itemname.hashCode());
- result = prime * result + (itemid ^ (itemid >>> 32));
+ result = prime * result + ((itemName == null) ? 0 : itemName.hashCode());
+ result = prime * result + (itemId ^ (itemId >>> 32));
return result;
}
@@ -120,14 +120,14 @@ public class ItemsVO implements Serializable {
return false;
}
ItemsVO other = (ItemsVO) obj;
- if (itemname == null) {
- if (other.itemname != null) {
+ if (itemName == null) {
+ if (other.itemName != null) {
return false;
}
- } else if (!itemname.equals(other.itemname)) {
+ } else if (!itemName.equals(other.itemName)) {
return false;
}
- return itemid == other.itemid;
+ return itemId == other.itemId;
}
@Override
@@ -140,11 +140,11 @@ public class ItemsVO implements Serializable {
builder.append(", itemsManageTable=");
builder.append(itemsManageTable);
builder.append(", itemid=");
- builder.append(itemid);
+ builder.append(itemId);
builder.append(", itemname=");
- builder.append(itemname);
+ builder.append(itemName);
builder.append(", table_name=");
- builder.append(table_name);
+ builder.append(tableName);
builder.append("]");
return builder.toString();
}
diff --git a/bundles/org.openhab.persistence.jdbc/src/main/java/org/openhab/persistence/jdbc/internal/JdbcConfiguration.java b/bundles/org.openhab.persistence.jdbc/src/main/java/org/openhab/persistence/jdbc/internal/JdbcConfiguration.java
index a2342050c..56f76d745 100644
--- a/bundles/org.openhab.persistence.jdbc/src/main/java/org/openhab/persistence/jdbc/internal/JdbcConfiguration.java
+++ b/bundles/org.openhab.persistence.jdbc/src/main/java/org/openhab/persistence/jdbc/internal/JdbcConfiguration.java
@@ -57,6 +57,7 @@ public class JdbcConfiguration {
// private String password;
private int numberDecimalcount = 3;
private boolean tableUseRealItemNames = false;
+ private boolean tableCaseSensitiveItemNames = false;
private String tableNamePrefix = "item";
private int tableIdDigitCount = 4;
private boolean rebuildTableNames = false;
@@ -163,6 +164,12 @@ public class JdbcConfiguration {
logger.debug("JDBC::updateConfig: tableUseRealItemNames={}", tableUseRealItemNames);
}
+ String lc = (String) configuration.get("tableCaseSensitiveItemNames");
+ if (lc != null && !lc.isBlank()) {
+ tableCaseSensitiveItemNames = Boolean.parseBoolean(lc);
+ logger.debug("JDBC::updateConfig: tableCaseSensitiveItemNames={}", tableCaseSensitiveItemNames);
+ }
+
String td = (String) configuration.get("tableIdDigitCount");
if (td != null && !td.isBlank() && isNumericPattern.matcher(td).matches()) {
tableIdDigitCount = Integer.parseInt(td);
@@ -363,6 +370,19 @@ public class JdbcConfiguration {
return tableUseRealItemNames;
}
+ public boolean getTableCaseSensitiveItemNames() {
+ return tableCaseSensitiveItemNames;
+ }
+
+ /**
+ * Checks if real item names (without number suffix) is enabled.
+ *
+ * @return true if both tableUseRealItemNames and tableCaseSensitiveItemNames are enabled.
+ */
+ public boolean getTableUseRealCaseSensitiveItemNames() {
+ return tableUseRealItemNames && tableCaseSensitiveItemNames;
+ }
+
public int getTableIdDigitCount() {
return tableIdDigitCount;
}
diff --git a/bundles/org.openhab.persistence.jdbc/src/main/java/org/openhab/persistence/jdbc/internal/JdbcMapper.java b/bundles/org.openhab.persistence.jdbc/src/main/java/org/openhab/persistence/jdbc/internal/JdbcMapper.java
index f3aa81a4d..f59e7c8b6 100644
--- a/bundles/org.openhab.persistence.jdbc/src/main/java/org/openhab/persistence/jdbc/internal/JdbcMapper.java
+++ b/bundles/org.openhab.persistence.jdbc/src/main/java/org/openhab/persistence/jdbc/internal/JdbcMapper.java
@@ -18,6 +18,7 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
@@ -53,10 +54,10 @@ public class JdbcMapper {
protected int errCnt;
protected boolean initialized = false;
protected @NonNullByDefault({}) JdbcConfiguration conf;
- protected final Map sqlTables = new HashMap<>();
+ protected final Map itemNameToTableNameMap = new HashMap<>();
+ protected @NonNullByDefault({}) NamingStrategy namingStrategy;
private long afterAccessMin = 10000;
private long afterAccessMax = 0;
- private static final String ITEM_NAME_PATTERN = "[^a-zA-Z_0-9\\-]";
public JdbcMapper(TimeZoneProvider timeZoneProvider) {
this.timeZoneProvider = timeZoneProvider;
@@ -97,11 +98,19 @@ public class JdbcMapper {
return res != null ? res : "";
}
+ public boolean ifItemsTableExists() {
+ logger.debug("JDBC::ifItemsTableExists");
+ long timerStart = System.currentTimeMillis();
+ boolean res = conf.getDBDAO().doIfTableExists(new ItemsVO());
+ logTime("doIfTableExists", timerStart, System.currentTimeMillis());
+ return res;
+ }
+
public ItemsVO createNewEntryInItemsTable(ItemsVO vo) {
logger.debug("JDBC::createNewEntryInItemsTable");
long timerStart = System.currentTimeMillis();
Long i = conf.getDBDAO().doCreateNewEntryInItemsTable(vo);
- vo.setItemid(i.intValue());
+ vo.setItemId(i.intValue());
logTime("doCreateNewEntryInItemsTable", timerStart, System.currentTimeMillis());
return vo;
}
@@ -114,6 +123,14 @@ public class JdbcMapper {
return true;
}
+ public boolean dropItemsTableIfExists(ItemsVO vo) {
+ logger.debug("JDBC::dropItemsTableIfExists");
+ long timerStart = System.currentTimeMillis();
+ conf.getDBDAO().doDropItemsTableIfExists(vo);
+ logTime("doDropItemsTableIfExists", timerStart, System.currentTimeMillis());
+ return true;
+ }
+
public ItemsVO deleteItemsEntry(ItemsVO vo) {
logger.debug("JDBC::deleteItemsEntry");
long timerStart = System.currentTimeMillis();
@@ -252,47 +269,66 @@ public class JdbcMapper {
* DATABASE TABLEHANDLING *
**************************/
protected void checkDBSchema() {
- // Create Items Table if does not exist
- createItemsTableIfNot(new ItemsVO());
+ if (!conf.getTableUseRealCaseSensitiveItemNames()) {
+ createItemsTableIfNot(new ItemsVO());
+ }
if (conf.getRebuildTableNames()) {
formatTableNames();
+
+ if (conf.getTableUseRealCaseSensitiveItemNames()) {
+ dropItemsTableIfExists(new ItemsVO());
+ }
logger.info(
"JDBC::checkDBSchema: Rebuild complete, configure the 'rebuildTableNames' setting to 'false' to stop rebuilds on startup");
- } else {
// Reset the error counter
errCnt = 0;
+ }
+ populateItemNameToTableNameMap();
+ }
+
+ private void populateItemNameToTableNameMap() {
+ itemNameToTableNameMap.clear();
+ if (conf.getTableUseRealCaseSensitiveItemNames()) {
+ for (String itemName : getItemTables().stream().map(t -> t.getTableName()).collect(Collectors.toList())) {
+ itemNameToTableNameMap.put(itemName, itemName);
+ }
+ } else {
for (ItemsVO vo : getItemIDTableNames()) {
- sqlTables.put(vo.getItemname(), getTableName(vo.getItemid(), vo.getItemname()));
+ itemNameToTableNameMap.put(vo.getItemName(),
+ namingStrategy.getTableName(vo.getItemId(), vo.getItemName()));
}
}
}
protected String getTable(Item item) {
- int rowId = 0;
+ int itemId = 0;
ItemsVO isvo;
ItemVO ivo;
String itemName = item.getName();
- String tableName = sqlTables.get(itemName);
+ String tableName = itemNameToTableNameMap.get(itemName);
// Table already exists - return the name
- if (tableName != null) {
+ if (!Objects.isNull(tableName)) {
return tableName;
}
logger.debug("JDBC::getTable: no table found for item '{}' in sqlTables", itemName);
- // Create a new entry in items table
- isvo = new ItemsVO();
- isvo.setItemname(itemName);
- isvo = createNewEntryInItemsTable(isvo);
- rowId = isvo.getItemid();
- if (rowId == 0) {
- logger.error("JDBC::getTable: Creating table for item '{}' failed.", itemName);
+ if (!conf.getTableUseRealCaseSensitiveItemNames()) {
+ // Create a new entry in items table
+ isvo = new ItemsVO();
+ isvo.setItemName(itemName);
+ isvo = createNewEntryInItemsTable(isvo);
+ itemId = isvo.getItemId();
+ if (itemId == 0) {
+ logger.error("JDBC::getTable: Creating items entry for item '{}' failed.", itemName);
+ }
}
+
// Create the table name
- logger.debug("JDBC::getTable: getTableName with rowId={} itemName={}", rowId, itemName);
- tableName = getTableName(rowId, itemName);
+ logger.debug("JDBC::getTable: getTableName with rowId={} itemName={}", itemId, itemName);
+ tableName = namingStrategy.getTableName(itemId, itemName);
// Create table for item
String dataType = conf.getDBDAO().getDataType(item);
@@ -301,18 +337,8 @@ public class JdbcMapper {
ivo = createItemTable(ivo);
logger.debug("JDBC::getTable: Table created for item '{}' with dataType {} in SQL database.", itemName,
dataType);
- sqlTables.put(itemName, tableName);
- // Check if the new entry is in the table list
- // If it's not in the list, then there was an error and we need to do
- // some tidying up
- // The item needs to be removed from the index table to avoid duplicates
- if (sqlTables.get(itemName) == null) {
- logger.error("JDBC::getTable: Item '{}' was not added to the table - removing index", itemName);
- isvo = new ItemsVO();
- isvo.setItemname(itemName);
- deleteItemsEntry(isvo);
- }
+ itemNameToTableNameMap.put(itemName, tableName);
return tableName;
}
@@ -323,93 +349,57 @@ public class JdbcMapper {
initialized = false;
}
- Map tableIds = new HashMap<>();
+ List itemIdTableNames = ifItemsTableExists() ? getItemIDTableNames() : new ArrayList();
+ List itemTables = getItemTables().stream().map(t -> t.getTableName()).collect(Collectors.toList());
+ List oldNewTableNames;
- //
- for (ItemsVO vo : getItemIDTableNames()) {
- String t = getTableName(vo.getItemid(), vo.getItemname());
- sqlTables.put(vo.getItemname(), t);
- tableIds.put(vo.getItemid(), t);
- }
-
- //
- List al = getItemTables();
-
- String oldName = "";
- String newName = "";
- List oldNewTablenames = new ArrayList<>();
- for (int i = 0; i < al.size(); i++) {
- int id = -1;
- oldName = al.get(i).getTable_name();
- logger.info("JDBC::formatTableNames: found Table Name= {}", oldName);
-
- if (oldName.startsWith(conf.getTableNamePrefix()) && !oldName.contains("_")) {
- id = Integer.parseInt(oldName.substring(conf.getTableNamePrefix().length()));
- logger.info("JDBC::formatTableNames: found Table with Prefix '{}' Name= {} id= {}",
- conf.getTableNamePrefix(), oldName, (id));
- } else if (oldName.contains("_")) {
- id = Integer.parseInt(oldName.substring(oldName.lastIndexOf("_") + 1));
- logger.info("JDBC::formatTableNames: found Table Name= {} id= {}", oldName, (id));
+ if (itemIdTableNames.isEmpty()) {
+ // Without mappings we can only migrate from direct item name to numeric mapping.
+ if (conf.getTableUseRealCaseSensitiveItemNames()) {
+ logger.info("JDBC::formatTableNames: Nothing to migrate.");
+ initialized = tmpinit;
+ return;
}
- logger.info("JDBC::formatTableNames: found Table id= {}", id);
-
- newName = tableIds.get(id);
- logger.info("JDBC::formatTableNames: found Table newName= {}", newName);
-
- if (newName != null) {
- if (!oldName.equalsIgnoreCase(newName)) {
- oldNewTablenames.add(new ItemVO(oldName, newName));
- logger.info("JDBC::formatTableNames: Table '{}' will be renamed to '{}'", oldName, newName);
+ oldNewTableNames = new ArrayList<>();
+ for (String itemName : itemTables) {
+ ItemsVO isvo = new ItemsVO();
+ isvo.setItemName(itemName);
+ isvo = createNewEntryInItemsTable(isvo);
+ int itemId = isvo.getItemId();
+ if (itemId == 0) {
+ logger.error("JDBC::formatTableNames: Creating items entry for item '{}' failed.", itemName);
} else {
- logger.info("JDBC::formatTableNames: Table oldName='{}' newName='{}' nothing to rename", oldName,
- newName);
+ String newTableName = namingStrategy.getTableName(itemId, itemName);
+ oldNewTableNames.add(new ItemVO(itemName, newTableName));
+ logger.info("JDBC::formatTableNames: Table '{}' will be renamed to '{}'", itemName, newTableName);
}
- } else {
- logger.error("JDBC::formatTableNames: Table '{}' could NOT be renamed to '{}'", oldName, newName);
- break;
}
+ } else {
+ String itemsManageTable = new ItemsVO().getItemsManageTable();
+ Map itemIdToItemNameMap = new HashMap<>();
+
+ for (ItemsVO vo : itemIdTableNames) {
+ int itemId = vo.getItemId();
+ String itemName = vo.getItemName();
+ itemIdToItemNameMap.put(itemId, itemName);
+ }
+
+ oldNewTableNames = namingStrategy.prepareMigration(itemTables, itemIdToItemNameMap, itemsManageTable);
}
- updateItemTableNames(oldNewTablenames);
- logger.info("JDBC::formatTableNames: Finished updating {} item table names", oldNewTablenames.size());
+ updateItemTableNames(oldNewTableNames);
+ logger.info("JDBC::formatTableNames: Finished updating {} item table names", oldNewTableNames.size());
initialized = tmpinit;
}
- private String getTableName(int rowId, String itemName) {
- return getTableNamePrefix(itemName) + formatRight(rowId, conf.getTableIdDigitCount());
- }
-
- private String getTableNamePrefix(String itemName) {
- String name = conf.getTableNamePrefix();
- if (conf.getTableUseRealItemNames()) {
- // Create the table name with real Item Names
- name = (itemName.replaceAll(ITEM_NAME_PATTERN, "") + "_").toLowerCase();
- }
- return name;
- }
-
public Set getItems() {
// TODO: in general it would be possible to query the count, earliest and latest values for each item too but it
// would be a very costly operation
- return sqlTables.keySet().stream().map(itemName -> new JdbcPersistenceItemInfo(itemName))
+ return itemNameToTableNameMap.keySet().stream().map(itemName -> new JdbcPersistenceItemInfo(itemName))
.collect(Collectors. toSet());
}
- private static String formatRight(final Object value, final int len) {
- final String valueAsString = String.valueOf(value);
- if (valueAsString.length() < len) {
- final StringBuffer result = new StringBuffer(len);
- for (int i = len - valueAsString.length(); i > 0; i--) {
- result.append('0');
- }
- result.append(valueAsString);
- return result.toString();
- } else {
- return valueAsString;
- }
- }
-
/*****************
* H E L P E R S *
*****************/
diff --git a/bundles/org.openhab.persistence.jdbc/src/main/java/org/openhab/persistence/jdbc/internal/JdbcPersistenceService.java b/bundles/org.openhab.persistence.jdbc/src/main/java/org/openhab/persistence/jdbc/internal/JdbcPersistenceService.java
index 20a0fff89..bac25c3e5 100644
--- a/bundles/org.openhab.persistence.jdbc/src/main/java/org/openhab/persistence/jdbc/internal/JdbcPersistenceService.java
+++ b/bundles/org.openhab.persistence.jdbc/src/main/java/org/openhab/persistence/jdbc/internal/JdbcPersistenceService.java
@@ -206,7 +206,7 @@ public class JdbcPersistenceService extends JdbcMapper implements ModifiablePers
}
}
- String table = sqlTables.get(itemName);
+ String table = itemNameToTableNameMap.get(itemName);
if (table == null) {
logger.debug("JDBC::query: unable to find table for item with name: '{}', no data in database.", itemName);
return List.of();
@@ -229,6 +229,7 @@ public class JdbcPersistenceService extends JdbcMapper implements ModifiablePers
conf = new JdbcConfiguration(configuration);
if (conf.valid && checkDBAccessability()) {
+ namingStrategy = new NamingStrategy(conf);
checkDBSchema();
// connection has been established ... initialization completed!
initialized = true;
@@ -259,7 +260,7 @@ public class JdbcPersistenceService extends JdbcMapper implements ModifiablePers
throw new IllegalArgumentException("Item name must not be null");
}
- String table = sqlTables.get(itemName);
+ String table = itemNameToTableNameMap.get(itemName);
if (table == null) {
logger.debug("JDBC::remove: unable to find table for item with name: '{}', no data in database.", itemName);
return false;
diff --git a/bundles/org.openhab.persistence.jdbc/src/main/java/org/openhab/persistence/jdbc/internal/NamingStrategy.java b/bundles/org.openhab.persistence.jdbc/src/main/java/org/openhab/persistence/jdbc/internal/NamingStrategy.java
new file mode 100644
index 000000000..3fcf9f065
--- /dev/null
+++ b/bundles/org.openhab.persistence.jdbc/src/main/java/org/openhab/persistence/jdbc/internal/NamingStrategy.java
@@ -0,0 +1,120 @@
+/**
+ * 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 java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Objects;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.openhab.core.items.ItemUtil;
+import org.openhab.persistence.jdbc.dto.ItemVO;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This class manages strategy for table names.
+ *
+ * @author Jacob Laursen - Initial contribution
+ */
+@NonNullByDefault
+public class NamingStrategy {
+
+ private final Logger logger = LoggerFactory.getLogger(NamingStrategy.class);
+
+ private JdbcConfiguration configuration;
+
+ public NamingStrategy(JdbcConfiguration configuration) {
+ this.configuration = configuration;
+ }
+
+ public String getTableName(int itemId, String itemName) {
+ if (!ItemUtil.isValidItemName(itemName)) {
+ throw new IllegalArgumentException(itemName + " is not a valid item name");
+ }
+ if (configuration.getTableUseRealItemNames()) {
+ return formatTableName(itemName, itemId);
+ } else {
+ return configuration.getTableNamePrefix() + getSuffix(itemId);
+ }
+ }
+
+ private String formatTableName(String itemName, int itemId) {
+ if (configuration.getTableCaseSensitiveItemNames()) {
+ return itemName;
+ } else {
+ return itemName.toLowerCase() + "_" + getSuffix(itemId);
+ }
+ }
+
+ private String getSuffix(int itemId) {
+ int digits = configuration.getTableIdDigitCount();
+ if (digits > 0) {
+ return String.format("%0" + configuration.getTableIdDigitCount() + "d", itemId);
+ } else {
+ return String.valueOf(itemId);
+ }
+ }
+
+ public List prepareMigration(List itemTables, Map itemIdToItemNameMap,
+ String itemsManageTable) {
+ List oldNewTableNames = new ArrayList<>();
+ Map tableNameToItemIdMap = new HashMap<>();
+
+ for (Entry entry : itemIdToItemNameMap.entrySet()) {
+ String itemName = entry.getValue();
+ tableNameToItemIdMap.put(itemName, entry.getKey());
+ }
+
+ for (String oldName : itemTables) {
+ Integer itemIdBoxed = tableNameToItemIdMap.get(oldName);
+ int itemId = -1;
+
+ if (Objects.nonNull(itemIdBoxed)) {
+ itemId = itemIdBoxed;
+ logger.info("JDBC::formatTableNames: found by name; table name= {} id= {}", oldName, itemId);
+ } else {
+ try {
+ itemId = Integer.parseInt(oldName.replaceFirst("^.*\\D", ""));
+ logger.info("JDBC::formatTableNames: found by id; table name= {} id= {}", oldName, itemId);
+ } catch (NumberFormatException e) {
+ // Fall through.
+ }
+ }
+
+ String itemName = itemIdToItemNameMap.get(itemId);
+
+ if (!Objects.isNull(itemName)) {
+ String newName = getTableName(itemId, itemName);
+ if (newName.equalsIgnoreCase(itemsManageTable)) {
+ logger.error(
+ "JDBC::formatTableNames: Table '{}' could NOT be renamed to '{}' since it conflicts with manage table",
+ oldName, newName);
+ } else if (!oldName.equals(newName)) {
+ oldNewTableNames.add(new ItemVO(oldName, newName));
+ logger.info("JDBC::formatTableNames: Table '{}' will be renamed to '{}'", oldName, newName);
+ } else {
+ logger.info("JDBC::formatTableNames: Table oldName='{}' newName='{}' nothing to rename", oldName,
+ newName);
+ }
+ } else {
+ logger.error("JDBC::formatTableNames: Table '{}' could NOT be renamed for id '{}'", oldName, itemId);
+ }
+ }
+
+ return oldNewTableNames;
+ }
+}
diff --git a/bundles/org.openhab.persistence.jdbc/src/main/resources/OH-INF/config/config.xml b/bundles/org.openhab.persistence.jdbc/src/main/resources/OH-INF/config/config.xml
index 31d16a61b..cc8411376 100644
--- a/bundles/org.openhab.persistence.jdbc/src/main/resources/OH-INF/config/config.xml
+++ b/bundles/org.openhab.persistence.jdbc/src/main/resources/OH-INF/config/config.xml
@@ -143,6 +143,11 @@
#tableUseRealItemNames=
tableUseRealItemNames=true
+ # Tablename Prefix generation, using case sensitive item names (optional, default: disabled -> table names are lower cased
+ # with numeric suffix appended).
+ # If true, no suffix is used.
+ #tableCaseSensitiveItemNames=true
+
# Tablename Suffix length (optional, default: 4 -> 0001-9999)
# for Migration from MYSQL-Bundle set to 0.
#tableIdDigitCount=
@@ -165,6 +170,15 @@
+
+
+
+ If true, no suffix is used. (optional, default: disabled -> table names are lower cased with numeric suffix appended).]]>
+
+
+
+
+ (optional, default: 4 -> 0001-9999).
@@ -172,7 +186,8 @@
-
+
USE WITH CARE! Deactivate after renaming is done!]]>
diff --git a/bundles/org.openhab.persistence.jdbc/src/main/resources/OH-INF/i18n/jdbc.properties b/bundles/org.openhab.persistence.jdbc/src/main/resources/OH-INF/i18n/jdbc.properties
index 110e4b8d9..670c072cc 100644
--- a/bundles/org.openhab.persistence.jdbc/src/main/resources/OH-INF/i18n/jdbc.properties
+++ b/bundles/org.openhab.persistence.jdbc/src/main/resources/OH-INF/i18n/jdbc.properties
@@ -9,7 +9,7 @@ persistence.config.jdbc.minimumIdle.description = Overrides min idle database co
persistence.config.jdbc.password.label = Database Password
persistence.config.jdbc.password.description = Defines the database password.
persistence.config.jdbc.rebuildTableNames.label = Tablename Rebuild
-persistence.config.jdbc.rebuildTableNames.description = Rename existing tables using 'Tablename Realname Generation' and 'Tablename Suffix ID Count', (optional, default: disabled). USE WITH CARE! Deactivate after renaming is done!
+persistence.config.jdbc.rebuildTableNames.description = Rename existing tables using 'Tablename Prefix String', 'Tablename Realname Generation', 'Tablename Case Sensitive' and 'Tablename Suffix ID Count'. (optional, default: disabled). USE WITH CARE! Deactivate after renaming is done!
persistence.config.jdbc.rebuildTableNames.option.true = Enable
persistence.config.jdbc.rebuildTableNames.option.false = Disable
persistence.config.jdbc.sqltype.CALL.label = SqlType CALL
@@ -36,6 +36,10 @@ persistence.config.jdbc.sqltype.STRING.label = SqlType STRING
persistence.config.jdbc.sqltype.STRING.description = Overrides used JDBC/SQL datatype for STRING (optional, default: "VARCHAR(65500)").
persistence.config.jdbc.sqltype.SWITCH.label = SqlType SWITCH
persistence.config.jdbc.sqltype.SWITCH.description = Overrides used JDBC/SQL datatype for SWITCH (optional, default: "VARCHAR(6)").
+persistence.config.jdbc.tableCaseSensitiveItemNames.label = Tablename Case Sensitive
+persistence.config.jdbc.tableCaseSensitiveItemNames.description = Enables Tablename generation with case sensitive item names case when "Tablename Realname Generation" is enabled If true, no suffix is used. (optional, default: disabled -> table names are lower cased with numeric suffix appended).
+persistence.config.jdbc.tableCaseSensitiveItemNames.option.true = Enable
+persistence.config.jdbc.tableCaseSensitiveItemNames.option.false = Disable
persistence.config.jdbc.tableIdDigitCount.label = Tablename Suffix ID Count
persistence.config.jdbc.tableIdDigitCount.description = Tablename Suffix ID Count (optional, default: 4 -> 0001-9999). For migration from MYSQL-Bundle set to 0.
persistence.config.jdbc.tableNamePrefix.label = Tablename Prefix String
diff --git a/bundles/org.openhab.persistence.jdbc/src/test/java/org/openhab/persistence/jdbc/internal/NamingStrategyTest.java b/bundles/org.openhab.persistence.jdbc/src/test/java/org/openhab/persistence/jdbc/internal/NamingStrategyTest.java
new file mode 100644
index 000000000..257bf97ac
--- /dev/null
+++ b/bundles/org.openhab.persistence.jdbc/src/test/java/org/openhab/persistence/jdbc/internal/NamingStrategyTest.java
@@ -0,0 +1,444 @@
+/**
+ * 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.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.core.Is.is;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.mockito.junit.jupiter.MockitoSettings;
+import org.mockito.quality.Strictness;
+import org.openhab.persistence.jdbc.dto.ItemVO;
+import org.slf4j.LoggerFactory;
+
+import ch.qos.logback.classic.Level;
+import ch.qos.logback.classic.Logger;
+
+/**
+ * Tests the {@link NamingStrategy} class.
+ *
+ * @author Jacob Laursen - Initial contribution
+ */
+@ExtendWith(MockitoExtension.class)
+@MockitoSettings(strictness = Strictness.LENIENT)
+@NonNullByDefault
+public class NamingStrategyTest {
+ private static final String ITEMS_MANAGE_TABLE_NAME = "items";
+
+ private @Mock @NonNullByDefault({}) JdbcConfiguration configurationMock;
+ private NamingStrategy namingStrategy = new NamingStrategy(configurationMock);
+
+ @BeforeEach
+ public void initialize() {
+ final Logger logger = (Logger) LoggerFactory.getLogger(NamingStrategy.class);
+ logger.setLevel(Level.OFF);
+ namingStrategy = new NamingStrategy(configurationMock);
+ }
+
+ @Test
+ public void getTableNameWhenInvalidItemNameThrows() {
+ Assertions.assertThrows(IllegalArgumentException.class, () -> {
+ namingStrategy.getTableName(1, "4Two");
+ });
+ }
+
+ @Test
+ public void getTableNameWhenUseRealItemNamesNameIsLowerCaseAndNumbered() {
+ Mockito.doReturn(true).when(configurationMock).getTableUseRealItemNames();
+ Mockito.doReturn(false).when(configurationMock).getTableCaseSensitiveItemNames();
+ assertThat(namingStrategy.getTableName(1, "Test"), is("test_1"));
+ }
+
+ @Test
+ public void getTableNameWhenUseRealCaseSensitiveItemNamesNameIsSameCase() {
+ Mockito.doReturn(true).when(configurationMock).getTableUseRealItemNames();
+ Mockito.doReturn(true).when(configurationMock).getTableCaseSensitiveItemNames();
+ assertThat(namingStrategy.getTableName(1, "Camel"), is("Camel"));
+ }
+
+ @Test
+ public void getTableNameWhenUseRealCaseSensitiveItemNamesNameIsSameCaseLower() {
+ Mockito.doReturn(true).when(configurationMock).getTableUseRealItemNames();
+ Mockito.doReturn(true).when(configurationMock).getTableCaseSensitiveItemNames();
+ assertThat(namingStrategy.getTableName(1, "lower"), is("lower"));
+ }
+
+ @Test
+ public void getTableNameWhenNotUseRealItemNamesAndCount4NameHasLeavingZeros() {
+ Mockito.doReturn(false).when(configurationMock).getTableUseRealItemNames();
+ Mockito.doReturn(4).when(configurationMock).getTableIdDigitCount();
+ Mockito.doReturn("Item").when(configurationMock).getTableNamePrefix();
+ assertThat(namingStrategy.getTableName(2, "Test"), is("Item0002"));
+ }
+
+ @Test
+ public void getTableNameWhenNotUseRealItemNamesAndCount0() {
+ Mockito.doReturn(false).when(configurationMock).getTableUseRealItemNames();
+ Mockito.doReturn(0).when(configurationMock).getTableIdDigitCount();
+ Mockito.doReturn("Item").when(configurationMock).getTableNamePrefix();
+ assertThat(namingStrategy.getTableName(12345, "Test"), is("Item12345"));
+ }
+
+ @Test
+ public void prepareMigrationFromNumberedToRealNames() {
+ final int itemId = 1;
+ final String itemName = "Test";
+ final String tableName = "Item1";
+
+ List actual = prepareMigrationRealItemNames(itemId, itemName, tableName);
+
+ assertTableName(actual, "Test");
+ }
+
+ @Test
+ public void prepareMigrationWithChangedPrefix() {
+ Mockito.doReturn(0).when(configurationMock).getTableIdDigitCount();
+ Mockito.doReturn(false).when(configurationMock).getTableUseRealItemNames();
+
+ final int itemId = 1;
+ final String itemName = "Test";
+ final String tableName = "Item1";
+
+ List actual = prepareMigration(itemId, itemName, tableName, "item");
+
+ assertTableName(actual, "item1");
+ }
+
+ @Test
+ public void prepareMigrationShouldNotStopWhenEncounteringUnknownItem() {
+ Mockito.doReturn(true).when(configurationMock).getTableUseRealItemNames();
+ Mockito.doReturn(true).when(configurationMock).getTableCaseSensitiveItemNames();
+ Mockito.doReturn("Item").when(configurationMock).getTableNamePrefix();
+
+ Map itemIdToItemNameMap = new HashMap<>(2);
+ itemIdToItemNameMap.put(1, "First");
+ itemIdToItemNameMap.put(3, "Third");
+
+ List itemTables = new ArrayList(3);
+ itemTables.add("Item1");
+ itemTables.add("Item2");
+ itemTables.add("Item3");
+
+ List actual = namingStrategy.prepareMigration(itemTables, itemIdToItemNameMap, ITEMS_MANAGE_TABLE_NAME);
+
+ assertThat(actual.size(), is(2));
+ assertThat(actual.get(0).getNewTableName(), is("First"));
+ assertThat(actual.get(1).getNewTableName(), is("Third"));
+ }
+
+ @Test
+ public void prepareMigrationFromMixedNumberedToNumberedRealNames() {
+ Mockito.doReturn(true).when(configurationMock).getTableUseRealItemNames();
+ Mockito.doReturn(false).when(configurationMock).getTableCaseSensitiveItemNames();
+ Mockito.doReturn("Item").when(configurationMock).getTableNamePrefix();
+
+ Map itemIdToItemNameMap = new HashMap<>(3);
+ itemIdToItemNameMap.put(1, "First");
+ itemIdToItemNameMap.put(2, "Second");
+ itemIdToItemNameMap.put(3, "Third");
+
+ List itemTables = new ArrayList(3);
+ itemTables.add("Item1");
+ itemTables.add("Item002");
+ itemTables.add("third_0003");
+
+ List actual = namingStrategy.prepareMigration(itemTables, itemIdToItemNameMap, ITEMS_MANAGE_TABLE_NAME);
+
+ assertThat(actual.size(), is(3));
+ assertThat(actual.get(0).getNewTableName(), is("first_1"));
+ assertThat(actual.get(1).getNewTableName(), is("second_2"));
+ assertThat(actual.get(2).getNewTableName(), is("third_3"));
+ }
+
+ @Test
+ public void prepareMigrationFromMixedNumberedToCaseSensitiveRealNames() {
+ Mockito.doReturn(true).when(configurationMock).getTableUseRealItemNames();
+ Mockito.doReturn(true).when(configurationMock).getTableCaseSensitiveItemNames();
+ Mockito.doReturn("Item").when(configurationMock).getTableNamePrefix();
+
+ Map itemIdToItemNameMap = new HashMap<>(3);
+ itemIdToItemNameMap.put(1, "First");
+ itemIdToItemNameMap.put(2, "Second");
+ itemIdToItemNameMap.put(3, "Third");
+
+ List itemTables = new ArrayList(3);
+ itemTables.add("Item1");
+ itemTables.add("Item002");
+ itemTables.add("third_0003");
+
+ List actual = namingStrategy.prepareMigration(itemTables, itemIdToItemNameMap, ITEMS_MANAGE_TABLE_NAME);
+
+ assertThat(actual.size(), is(3));
+ assertThat(actual.get(0).getNewTableName(), is("First"));
+ assertThat(actual.get(1).getNewTableName(), is("Second"));
+ assertThat(actual.get(2).getNewTableName(), is("Third"));
+ }
+
+ @Test
+ public void prepareMigrationFromNumberedRealNamesToCaseSensitiveRealNames() {
+ final int itemId = 1;
+ final String itemName = "Test";
+ final String tableName = "test_0001";
+
+ List actual = prepareMigrationRealItemNames(itemId, itemName, tableName, true);
+
+ assertTableName(actual, "Test");
+ }
+
+ @Test
+ public void prepareMigrationFromCaseSensitiveRealNamesToNumberedRealNames() {
+ final int itemId = 1;
+ final String itemName = "Test";
+ final String tableName = "Test";
+
+ List actual = prepareMigrationRealItemNames(itemId, itemName, tableName, false);
+
+ assertTableName(actual, "test_0001");
+ }
+
+ @Test
+ public void prepareMigrationRealNamesWithTwoItemsWithDifferentCaseToNumbered() {
+ Mockito.doReturn(false).when(configurationMock).getTableUseRealItemNames();
+ Mockito.doReturn("Item").when(configurationMock).getTableNamePrefix();
+ Mockito.doReturn(1).when(configurationMock).getTableIdDigitCount();
+
+ Map itemIdToItemNameMap = new HashMap<>(2);
+ itemIdToItemNameMap.put(1, "MyItem");
+ itemIdToItemNameMap.put(2, "myItem");
+
+ List itemTables = new ArrayList(2);
+ itemTables.add("MyItem");
+ itemTables.add("myItem");
+
+ List actual = namingStrategy.prepareMigration(itemTables, itemIdToItemNameMap, ITEMS_MANAGE_TABLE_NAME);
+
+ assertThat(actual.size(), is(2));
+ assertThat(actual.get(0).getNewTableName(), is("Item1"));
+ assertThat(actual.get(1).getNewTableName(), is("Item2"));
+ }
+
+ @Test
+ public void prepareMigrationNumberedWithTwoItemsWithDifferentCaseToNumberedRealNames() {
+ Mockito.doReturn(true).when(configurationMock).getTableUseRealItemNames();
+ Mockito.doReturn("Item").when(configurationMock).getTableNamePrefix();
+ Mockito.doReturn(false).when(configurationMock).getTableCaseSensitiveItemNames();
+
+ Map itemIdToItemNameMap = new HashMap<>(2);
+ itemIdToItemNameMap.put(1, "MyItem");
+ itemIdToItemNameMap.put(2, "myItem");
+
+ List itemTables = new ArrayList(2);
+ itemTables.add("Item1");
+ itemTables.add("Item2");
+
+ List actual = namingStrategy.prepareMigration(itemTables, itemIdToItemNameMap, ITEMS_MANAGE_TABLE_NAME);
+
+ assertThat(actual.size(), is(2));
+ assertThat(actual.get(0).getNewTableName(), is("myitem_1"));
+ assertThat(actual.get(1).getNewTableName(), is("myitem_2"));
+ }
+
+ @Test
+ public void prepareMigrationNumberedWithTwoItemsWithDifferentCaseToCaseSensitiveRealNames() {
+ Mockito.doReturn(true).when(configurationMock).getTableUseRealItemNames();
+ Mockito.doReturn("Item").when(configurationMock).getTableNamePrefix();
+ Mockito.doReturn(true).when(configurationMock).getTableCaseSensitiveItemNames();
+
+ Map itemIdToItemNameMap = new HashMap<>(2);
+ itemIdToItemNameMap.put(1, "MyItem");
+ itemIdToItemNameMap.put(2, "myItem");
+
+ List itemTables = new ArrayList(2);
+ itemTables.add("Item1");
+ itemTables.add("Item2");
+
+ List actual = namingStrategy.prepareMigration(itemTables, itemIdToItemNameMap, ITEMS_MANAGE_TABLE_NAME);
+
+ assertThat(actual.size(), is(2));
+ assertThat(actual.get(0).getNewTableName(), is("MyItem"));
+ assertThat(actual.get(1).getNewTableName(), is("myItem"));
+ }
+
+ @Test
+ public void prepareMigrationFromNumberedRealNamesToCaseSensitiveRealNamesWhenUnknownItemIdThenSkip() {
+ final int itemId = 2;
+ final String itemName = "Test";
+ final String tableName = "test_0001";
+
+ List actual = prepareMigrationRealItemNames(itemId, itemName, tableName);
+
+ assertThat(actual.size(), is(0));
+ }
+
+ @Test
+ public void prepareMigrationFromNumberedRealNamesToNumbered() {
+ final int itemId = 1;
+ final String itemName = "Test";
+ final String tableName = "test_0001";
+
+ List actual = prepareMigrationNumbered(itemId, itemName, tableName);
+
+ assertTableName(actual, "Item0001");
+ }
+
+ @Test
+ public void prepareMigrationFromNumberedToNumberedWithCorrectPadding() {
+ final int itemId = 1;
+ final String itemName = "Test";
+ final String tableName = "Item1";
+
+ List actual = prepareMigrationNumbered(itemId, itemName, tableName, 2);
+
+ assertTableName(actual, "Item01");
+ }
+
+ @Test
+ public void prepareMigrationFromNumberedToNumberedExceedingPadding() {
+ final int itemId = 101;
+ final String itemName = "Test";
+ final String tableName = "Item0101";
+
+ List actual = prepareMigrationNumbered(itemId, itemName, tableName, 2);
+
+ assertTableName(actual, "Item101");
+ }
+
+ @Test
+ public void prepareMigrationFromCaseSensitiveRealNamesToNumbered() {
+ final int itemId = 1;
+ final String itemName = "Test";
+ final String tableName = "Test";
+
+ List actual = prepareMigrationNumbered(itemId, itemName, tableName);
+
+ assertTableName(actual, "Item0001");
+ }
+
+ @Test
+ public void prepareMigrationFromCaseSensitiveRealNamesToNumberedHavingUnderscore() {
+ final int itemId = 1;
+ final String itemName = "My_Test";
+ final String tableName = "My_Test";
+
+ List actual = prepareMigrationNumbered(itemId, itemName, tableName);
+
+ assertTableName(actual, "Item0001");
+ }
+
+ @Test
+ public void prepareMigrationFromCaseSensitiveRealNamesHavingUnderscoreAndNumberToNumbered() {
+ final int itemId = 2;
+ final String itemName = "My_Test_1";
+ final String tableName = "My_Test_1";
+
+ List actual = prepareMigrationNumbered(itemId, itemName, tableName);
+
+ assertTableName(actual, "Item0002");
+ }
+
+ @Test
+ public void prepareMigrationFromCaseSensitiveRealNamesToNumberedShouldSwap() {
+ Mockito.doReturn(false).when(configurationMock).getTableUseRealItemNames();
+ Mockito.doReturn("Item").when(configurationMock).getTableNamePrefix();
+
+ Map itemIdToItemNameMap = new HashMap<>(2);
+ itemIdToItemNameMap.put(1, "Item2");
+ itemIdToItemNameMap.put(2, "Item1");
+
+ List itemTables = new ArrayList(2);
+ itemTables.add("Item2");
+ itemTables.add("Item1");
+
+ List actual = namingStrategy.prepareMigration(itemTables, itemIdToItemNameMap, ITEMS_MANAGE_TABLE_NAME);
+
+ assertThat(actual.size(), is(2));
+ assertThat(actual.get(0).getNewTableName(), is("Item1"));
+ assertThat(actual.get(1).getNewTableName(), is("Item2"));
+ }
+
+ @Test
+ public void prepareMigrationWhenConflictWithItemsManageTableThenSkip() {
+ final int itemId = 1;
+ final String itemName = "items";
+ final String tableName = "Item1";
+
+ List actual = prepareMigrationRealItemNames(itemId, itemName, tableName);
+
+ assertThat(actual.size(), is(0));
+ }
+
+ private List prepareMigrationNumbered(int itemId, String itemName, String tableName) {
+ return prepareMigrationNumbered(itemId, itemName, tableName, 4);
+ }
+
+ private List prepareMigrationNumbered(int itemId, String itemName, String tableName,
+ int tableIdDigitCount) {
+ Mockito.doReturn(tableIdDigitCount).when(configurationMock).getTableIdDigitCount();
+ Mockito.doReturn(false).when(configurationMock).getTableUseRealItemNames();
+ return prepareMigration(itemId, itemName, tableName);
+ }
+
+ private List prepareMigrationRealItemNames(int itemId, String itemName, String tableName) {
+ return prepareMigrationRealItemNames(itemId, itemName, tableName, true);
+ }
+
+ private List prepareMigrationRealItemNames(int itemId, String itemName, String tableName,
+ boolean caseSensitive) {
+ Mockito.doReturn(4).when(configurationMock).getTableIdDigitCount();
+ Mockito.doReturn(true).when(configurationMock).getTableUseRealItemNames();
+ Mockito.doReturn(caseSensitive).when(configurationMock).getTableCaseSensitiveItemNames();
+ return prepareMigration(itemId, itemName, tableName);
+ }
+
+ private List prepareMigration(int itemId, String itemName, String tableName) {
+ return prepareMigration(itemId, itemName, tableName, "Item");
+ }
+
+ private List prepareMigration(int itemId, String itemName, String tableName, String prefix) {
+ Mockito.doReturn(prefix).when(configurationMock).getTableNamePrefix();
+
+ Map itemIdToItemNameMap = getItemIdToItemNameMap(itemId, itemName);
+ List itemTables = getItemTables(tableName);
+
+ return namingStrategy.prepareMigration(itemTables, itemIdToItemNameMap, ITEMS_MANAGE_TABLE_NAME);
+ }
+
+ private Map getItemIdToItemNameMap(int itemId, String itemName) {
+ Map itemIdToItemNameMap = new HashMap<>(1);
+ itemIdToItemNameMap.put(itemId, itemName);
+ return itemIdToItemNameMap;
+ }
+
+ private List getItemTables(String tableName) {
+ List itemTables = new ArrayList(1);
+ itemTables.add(tableName);
+ return itemTables;
+ }
+
+ private void assertTableName(List actual, String expected) {
+ assertThat(actual.size(), is(1));
+ assertThat(actual.get(0).getNewTableName(), is(expected));
+ }
+}