diff --git a/packages/nocodb-sdk/src/lib/formulaHelpers.ts b/packages/nocodb-sdk/src/lib/formulaHelpers.ts index f2281c89f1..6bdabf0dcc 100644 --- a/packages/nocodb-sdk/src/lib/formulaHelpers.ts +++ b/packages/nocodb-sdk/src/lib/formulaHelpers.ts @@ -664,16 +664,28 @@ const formulas: Record = { 'IF(5 > 1, "YES", "NO") => "YES"', 'IF({column} > 1, "YES", "NO")', ], - returnType: (argsTypes: FormulaDataTypes[]) => { - if (argsTypes.slice(1).includes(FormulaDataTypes.STRING)) { + returnType: (argTypes: FormulaDataTypes[]) => { + // extract all return types except NULL, since null can be returned by any type + const returnValueTypes = new Set( + argTypes.slice(1).filter((type) => type !== FormulaDataTypes.NULL) + ); + // if there are more than one return types or if there is a string return type + // return type as string else return the type + if ( + returnValueTypes.size > 1 || + returnValueTypes.has(FormulaDataTypes.STRING) + ) { return FormulaDataTypes.STRING; - } else if (argsTypes.slice(1).includes(FormulaDataTypes.NUMERIC)) { + } else if (returnValueTypes.has(FormulaDataTypes.NUMERIC)) { return FormulaDataTypes.NUMERIC; - } else if (argsTypes.slice(1).includes(FormulaDataTypes.BOOLEAN)) { + } else if (returnValueTypes.has(FormulaDataTypes.BOOLEAN)) { return FormulaDataTypes.BOOLEAN; + } else if (returnValueTypes.has(FormulaDataTypes.DATE)) { + return FormulaDataTypes.DATE; } - return argsTypes[1]; + // if none of the above conditions are met, return the first return argument type + return argTypes[1]; }, }, SWITCH: { @@ -681,7 +693,7 @@ const formulas: Record = { validation: { args: { min: 3, - }, + } }, description: 'Switch case value based on expr output', syntax: 'SWITCH(expr, [pattern, value, ..., default])', @@ -691,19 +703,29 @@ const formulas: Record = { 'SWITCH(3, 1, "One", 2, "Two", "N/A") => "N/A"', 'SWITCH({column1}, 1, "One", 2, "Two", "N/A")', ], - // todo: resolve return type based on the args returnType: (argTypes: FormulaDataTypes[]) => { - const returnArgTypes = argTypes.slice(2).filter((_, i) => i % 2 === 0); + // extract all return types except NULL, since null can be returned by any type + const returnValueTypes = new Set( + argTypes.slice(2).filter((_, i) => i % 2 === 0) + ); - if (returnArgTypes.includes(FormulaDataTypes.STRING)) { + // if there are more than one return types or if there is a string return type + // return type as string else return the type + if ( + returnValueTypes.size > 1 || + returnValueTypes.has(FormulaDataTypes.STRING) + ) { return FormulaDataTypes.STRING; - } else if (returnArgTypes.includes(FormulaDataTypes.NUMERIC)) { + } else if (returnValueTypes.has(FormulaDataTypes.NUMERIC)) { return FormulaDataTypes.NUMERIC; - } else if (returnArgTypes.includes(FormulaDataTypes.BOOLEAN)) { + } else if (returnValueTypes.has(FormulaDataTypes.BOOLEAN)) { return FormulaDataTypes.BOOLEAN; + } else if (returnValueTypes.has(FormulaDataTypes.DATE)) { + return FormulaDataTypes.DATE; } - return returnArgTypes[0]; + // if none of the above conditions are met, return the first return argument type + return argTypes[1]; }, }, URL: { @@ -965,13 +987,13 @@ const formulas: Record = { enum FormulaErrorType { NOT_AVAILABLE = 'NOT_AVAILABLE', NOT_SUPPORTED = 'NOT_SUPPORTED', - 'MIN_ARG' = 'MIN_ARG', - 'MAX_ARG' = 'MAX_ARG', - 'TYPE_MISMATCH' = 'TYPE_MISMATCH', - 'INVALID_ARG' = 'INVALID_ARG', - 'INVALID_ARG_TYPE' = 'INVALID_ARG_TYPE', - 'INVALID_ARG_VALUE' = 'INVALID_ARG_VALUE', - 'INVALID_ARG_COUNT' = 'INVALID_ARG_COUNT', + MIN_ARG = 'MIN_ARG', + MAX_ARG = 'MAX_ARG', + TYPE_MISMATCH = 'TYPE_MISMATCH', + INVALID_ARG = 'INVALID_ARG', + INVALID_ARG_TYPE = 'INVALID_ARG_TYPE', + INVALID_ARG_VALUE = 'INVALID_ARG_VALUE', + INVALID_ARG_COUNT = 'INVALID_ARG_COUNT', CIRCULAR_REFERENCE = 'CIRCULAR_REFERENCE', INVALID_FUNCTION_NAME = 'INVALID_FUNCTION_NAME', } @@ -1075,11 +1097,11 @@ export function validateFormulaAndExtractTreeWithType( } )); - const argsTypes = validateResult.map((v: any) => v.dataType); + const argTypes = validateResult.map((v: any) => v.dataType); if (typeof formulas[calleeName].returnType === 'function') { res.dataType = (formulas[calleeName].returnType as any)?.( - argsTypes + argTypes ) as FormulaDataTypes; } else if (formulas[calleeName].returnType) { res.dataType = formulas[calleeName].returnType as FormulaDataTypes;