diff --git a/docs/hop-user-manual/modules/ROOT/pages/getting-started/index.adoc b/docs/hop-user-manual/modules/ROOT/pages/getting-started/index.adoc index 99e594e56e3..d0c41d40c73 100644 --- a/docs/hop-user-manual/modules/ROOT/pages/getting-started/index.adoc +++ b/docs/hop-user-manual/modules/ROOT/pages/getting-started/index.adoc @@ -20,7 +20,7 @@ under the License. :page-pagination-no-back: :description: The Apache Hop Getting Started guide walks new Hop users through the Hop concepts and the bare necessities to get started building workflows and pipelines. -== Getting Started += Getting Started This guide walks you through the Hop basics. diff --git a/docs/hop-user-manual/modules/ROOT/pages/pipeline/transforms/formula.adoc b/docs/hop-user-manual/modules/ROOT/pages/pipeline/transforms/formula.adoc index e68b012e7cd..2f1867204f5 100644 --- a/docs/hop-user-manual/modules/ROOT/pages/pipeline/transforms/formula.adoc +++ b/docs/hop-user-manual/modules/ROOT/pages/pipeline/transforms/formula.adoc @@ -92,6 +92,7 @@ TIP: The formula will not evaluate a field unless the field pre-exists. Either s |Length|field length |Precision|field precision |Replace value|select a pipeline field from the dropdown to replace that field's value with the formula result. It is not recommended to pre-create a field with a NULL value in a "Get variables" transform as that is considered a hack and is not supported behavior. +| Set Null to #N/A | By default, Null values will create a blank cell during the calculation. Use this option to insert `#N/A` in the cell |=== == Formula Editor diff --git a/plugins/transforms/formula/src/main/java/org/apache/hop/pipeline/transforms/formula/FormulaDialog.java b/plugins/transforms/formula/src/main/java/org/apache/hop/pipeline/transforms/formula/FormulaDialog.java index d4d4466df2a..62099092aee 100644 --- a/plugins/transforms/formula/src/main/java/org/apache/hop/pipeline/transforms/formula/FormulaDialog.java +++ b/plugins/transforms/formula/src/main/java/org/apache/hop/pipeline/transforms/formula/FormulaDialog.java @@ -53,6 +53,7 @@ public class FormulaDialog extends BaseTransformDialog { private static final Class PKG = FormulaDialog.class; + public static final String SYSTEM_COMBO_YES = "System.Combo.Yes"; private TableView wFields; @@ -151,8 +152,12 @@ public String open() { false), new ColumnInfo( BaseMessages.getString(PKG, "FormulaDialog.Replace.Column"), + ColumnInfo.COLUMN_TYPE_CCOMBO), + new ColumnInfo( + BaseMessages.getString(PKG, "FormulaDialog.NA.Column"), ColumnInfo.COLUMN_TYPE_CCOMBO, - new String[] {}), + BaseMessages.getString(PKG, SYSTEM_COMBO_YES), + BaseMessages.getString(PKG, "System.Combo.No")), }; wFields = @@ -305,6 +310,11 @@ public void getData() { item.setText(5, "" + fn.getValuePrecision()); } item.setText(6, Const.NVL(fn.getReplaceField(), "")); + item.setText( + 7, + Boolean.TRUE.equals(fn.isSetNa()) + ? BaseMessages.getString(PKG, SYSTEM_COMBO_YES) + : BaseMessages.getString(PKG, "System.Combo.No")); } } @@ -340,12 +350,20 @@ private void ok() { int valueLength = Const.toInt(item.getText(4), -1); int valuePrecision = Const.toInt(item.getText(5), -1); String replaceField = item.getText(6); + boolean setNa = + BaseMessages.getString(PKG, SYSTEM_COMBO_YES).equalsIgnoreCase(item.getText(7)); currentMeta .getFormulas() .add( new FormulaMetaFunction( - fieldName, formulaString, valueType, valueLength, valuePrecision, replaceField)); + fieldName, + formulaString, + valueType, + valueLength, + valuePrecision, + replaceField, + setNa)); } if (!originalMeta.equals(currentMeta)) { diff --git a/plugins/transforms/formula/src/main/java/org/apache/hop/pipeline/transforms/formula/FormulaMetaFunction.java b/plugins/transforms/formula/src/main/java/org/apache/hop/pipeline/transforms/formula/FormulaMetaFunction.java index e1a15ad87eb..179c5588eba 100644 --- a/plugins/transforms/formula/src/main/java/org/apache/hop/pipeline/transforms/formula/FormulaMetaFunction.java +++ b/plugins/transforms/formula/src/main/java/org/apache/hop/pipeline/transforms/formula/FormulaMetaFunction.java @@ -18,9 +18,13 @@ package org.apache.hop.pipeline.transforms.formula; import java.util.Objects; +import lombok.Getter; +import lombok.Setter; import org.apache.hop.core.row.value.ValueMetaFactory; import org.apache.hop.metadata.api.HopMetadataProperty; +@Getter +@Setter public class FormulaMetaFunction { public static final String XML_TAG = "formula"; @@ -54,6 +58,9 @@ public class FormulaMetaFunction { injectionKeyDescription = "FormulaMeta.Injection.ReplaceField") private String replaceField; + @HopMetadataProperty(key = "set_na", injectionKeyDescription = "FormulaMeta.Injection.setNa") + private boolean setNa; + /** This value will be discovered on runtime and need not to be persisted into xml or rep. */ @SuppressWarnings("java:S2065") // disable sonar warning on transient private transient boolean needDataConversion = false; @@ -72,13 +79,15 @@ public FormulaMetaFunction( int valueType, int valueLength, int valuePrecision, - String replaceField) { + String replaceField, + boolean setNa) { this.fieldName = fieldName; this.formula = formula; this.valueType = valueType; this.valueLength = valueLength; this.valuePrecision = valuePrecision; this.replaceField = replaceField; + this.setNa = setNa; ValueMetaFactory.getIdForValueMeta("Boolean"); } @@ -90,7 +99,8 @@ public FormulaMetaFunction() { @Override public int hashCode() { - return Objects.hash(fieldName, formula, valueType, valueLength, valuePrecision, replaceField); + return Objects.hash( + fieldName, formula, valueType, valueLength, valuePrecision, replaceField, setNa); } @Override @@ -102,102 +112,4 @@ public Object clone() { return null; } } - - /** - * @return Returns the fieldName. - */ - public String getFieldName() { - return fieldName; - } - - /** - * @param fieldName The fieldName to set. - */ - public void setFieldName(String fieldName) { - this.fieldName = fieldName; - } - - /** - * @return Returns the valueLength. - */ - public int getValueLength() { - return valueLength; - } - - /** - * @param valueLength The valueLength to set. - */ - public void setValueLength(int valueLength) { - this.valueLength = valueLength; - } - - /** - * @return Returns the valuePrecision. - */ - public int getValuePrecision() { - return valuePrecision; - } - - /** - * @param valuePrecision The valuePrecision to set. - */ - public void setValuePrecision(int valuePrecision) { - this.valuePrecision = valuePrecision; - } - - /** - * @return Returns the valueType. - */ - public int getValueType() { - return valueType; - } - - /** - * @param valueType The valueType to set. - */ - public void setValueType(int valueType) { - this.valueType = valueType; - } - - /** - * @return the formula - */ - public String getFormula() { - return formula; - } - - /** - * @param formula the formula to set - */ - public void setFormula(String formula) { - this.formula = formula; - } - - /** - * @return the replaceField - */ - public String getReplaceField() { - return replaceField; - } - - /** - * @param replaceField the replaceField to set - */ - public void setReplaceField(String replaceField) { - this.replaceField = replaceField; - } - - /** - * @return the needDataConversion - */ - public boolean isNeedDataConversion() { - return needDataConversion; - } - - /** - * @param needDataConversion the needDataConversion to set - */ - public void setNeedDataConversion(boolean needDataConversion) { - this.needDataConversion = needDataConversion; - } } diff --git a/plugins/transforms/formula/src/main/java/org/apache/hop/pipeline/transforms/formula/util/FormulaParser.java b/plugins/transforms/formula/src/main/java/org/apache/hop/pipeline/transforms/formula/util/FormulaParser.java index cd3ba88808a..5e5ed93479f 100644 --- a/plugins/transforms/formula/src/main/java/org/apache/hop/pipeline/transforms/formula/util/FormulaParser.java +++ b/plugins/transforms/formula/src/main/java/org/apache/hop/pipeline/transforms/formula/util/FormulaParser.java @@ -121,7 +121,11 @@ public CellValue getFormulaValue() throws HopValueException { cell.setCellValue(rowMeta.getString(dataRow, fieldPosition)); } } else { - cell.setBlank(); + if (formulaMetaFunction.isSetNa()) { + cell.setCellFormula("NA()"); + } else { + cell.setBlank(); + } } fieldIndex++; diff --git a/plugins/transforms/formula/src/main/resources/org/apache/hop/pipeline/transforms/formula/messages/messages_en_US.properties b/plugins/transforms/formula/src/main/resources/org/apache/hop/pipeline/transforms/formula/messages/messages_en_US.properties index 1f0423a6c34..83f071667d3 100644 --- a/plugins/transforms/formula/src/main/resources/org/apache/hop/pipeline/transforms/formula/messages/messages_en_US.properties +++ b/plugins/transforms/formula/src/main/resources/org/apache/hop/pipeline/transforms/formula/messages/messages_en_US.properties @@ -37,6 +37,7 @@ FormulaDialog.NewField.Column = New field FormulaDialog.Precision.Column = Precision FormulaDialog.Remove.Column = Remove FormulaDialog.Replace.Column = Replace value +FormulaDialog.NA.Column = Set Null to #N/A FormulaDialog.SelectCalculationType.Message = Select the calculation type to perform FormulaDialog.SelectCalculationType.Title = Select the calculation type FormulaDialog.Shell.Title=Formula @@ -50,6 +51,7 @@ FormulaMeta.Injection.Formula = Formula FormulaMeta.Injection.Formulas = Formulas FormulaMeta.Injection.FormulaString = Formula FormulaMeta.Injection.ReplaceField = Replace Field +FormulaMeta.Injection.setNa = Convert null to #N/A FormulaMeta.Injection.ValueLength = Value Length FormulaMeta.Injection.ValuePrecision = Value Precision FormulaMeta.Injection.ValueType = Value Type