TableFieldValue.java
/*
* Copyright (C) 2000 - 2024 Silverpeas
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* As a special exception to the terms and conditions of version 3.0 of
* the GPL, you may redistribute this Program in connection with Free/Libre
* Open Source Software ("FLOSS") applications as described in Silverpeas's
* FLOSS exception. You should have received a copy of the text describing
* the FLOSS exception, and it is also available here:
* "https://www.silverpeas.org/legal/floss_exception.html"
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package org.silverpeas.components.mydb.model;
import org.silverpeas.components.mydb.service.MyDBRuntimeException;
import org.silverpeas.kernel.util.StringUtil;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.sql.Date;
import java.sql.JDBCType;
import java.sql.Time;
import java.sql.Timestamp;
import java.util.Objects;
/**
* The value of a field in a table row with its type (and associated type name) in the database.
* @author mmoquillon
*/
public class TableFieldValue implements Comparable<TableFieldValue> {
private Object value;
private final int type;
/**
* Constructs a {@link TableFieldValue} instance from the specified value represented as a
* {@link String} object and according to the specified SQL type (a value among
* {@link java.sql.Types}). If the specified value
* doesn't match the SQL type of this field value, then an {@link IllegalArgumentException}
* exception is thrown.
* @param value the {@link String} representation of a value. Null value shouldn't be null but the
* String "null".
* @param sqlType the SQL type as defined in {@link java.sql.Types}.
* @return a {@link TableFieldValue} instance.
*/
public static TableFieldValue fromString(final String value, int sqlType) {
TableFieldValue tableFieldValue = new TableFieldValue(null, sqlType);
tableFieldValue.update(value);
return tableFieldValue;
}
/**
* Constructs a new value of a field in a database table.
* @see java.sql.Types for SQL type of the value.
* @param value the value of the field
* @param type the SQL type of the value
*/
TableFieldValue(final Object value, final int type) {
this.value = value;
this.type = type;
}
/**
* Gets the code of the SQL type of this value.
* @see java.sql.Types for the available possible codes.
* @return the SQL type of this value as defined in {@link java.sql.Types}.
*/
public int getType() {
return type;
}
/**
* Is this value a text?
* @return true if the type of this value is a text, false otherwise.
*/
public boolean isText() {
return SqlTypes.isText(this.type);
}
/**
* Is this value an empty text?
* @return true if this value is a text and it is empty. False otherwise.
*/
public boolean isEmpty() {
return isText() && toString().isEmpty();
}
/**
* Updates this value with the textual representation of the new value. If the specified value
* doesn't match the SQL type of this field value, then an {@link IllegalArgumentException}
* exception is thrown.
* @param value a {@link String} representation of the value. Null value shouldn't be null but the
* String "null".
*/
public void update(final String value) {
if (value == null || value.equals("null")) {
this.value = null;
} else if (SqlTypes.isText(this.type)) {
this.value = value;
} else if (SqlTypes.isDate(this.type)) {
try {
this.value = Date.valueOf(value);
} catch (IllegalArgumentException e) {
throw new IllegalArgumentException("The date '" + value +
"' is not in the database date escape format (yyyy-[m]m-[d]d)");
}
} else if (SqlTypes.isTime(this.type)) {
this.value = Time.valueOf(value);
} else if (SqlTypes.isTimestamp(this.type)) {
this.value = Timestamp.valueOf(value);
} else if (SqlTypes.isBoolean(this.type)) {
this.value = StringUtil.getBooleanValue(value);
} else if (SqlTypes.isBigInteger(this.type)) {
this.value = BigInteger.valueOf(Long.parseLong(value));
} else if (SqlTypes.isDecimal(this.type)) {
this.value = BigDecimal.valueOf(Double.parseDouble(value));
} else if (SqlTypes.isInteger(this.type)) {
this.value = Integer.valueOf(value);
} else if (SqlTypes.isFloat(this.type)) {
this.value = Float.valueOf(value);
} else if (SqlTypes.isDouble(this.type)) {
this.value = Double.valueOf(value);
}
}
@Override
public boolean equals(final Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
final TableFieldValue that = (TableFieldValue) o;
return Objects.equals(value, that.value) && Objects.equals(type, that.type);
}
@Override
public int hashCode() {
return Objects.hash(value, type);
}
/**
* Compares this {@link TableFieldValue} with the specified one. The comparing is actually done
* on the wrapped values themselves. If the wrapped values satisfy the {@link Comparable}
* interface then the {@link Comparable#compareTo(Object)} method is used, otherwise both of them
* are converted in {@link String} objects and these {@link String} instances are then compared
* between themselves.
* @param o another {@link TableFieldValue} with which this one is compared.
* @return the comparing distance between the two {@link TableFieldValue} instances.
*/
@Override
public int compareTo(final TableFieldValue o) {
if (this.type != o.type) {
final String typeName = JDBCType.valueOf(this.type).getName();
throw new MyDBRuntimeException(
"The two table field values aren't of the same type: this is of type " + typeName +
" whereas other if of type " + typeName);
}
final int compare;
if (o.value == null && this.value == null) {
compare = 0;
} else if (o.value != null && this.value instanceof Comparable) {
//noinspection unchecked,rawtypes
compare = ((Comparable) this.value).compareTo(o.value);
} else if (o.value == null) {
return 1;
} else if (this.value == null) {
return -1;
} else {
compare = toString().compareTo(o.toString());
}
return compare;
}
/**
* Converts this table field value to an SQL object as defined by its SQL type.
* @return this value as an SQL object.
*/
Object toSQLObject() {
return value;
}
@Override
public String toString() {
return value == null ? "null" : value.toString();
}
public TableFieldValue getCopy() {
return new TableFieldValue(value, type);
}
}