Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions backend/src/baserow/core/apps.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,11 @@ def ready(self):
from baserow.core.formula.runtime_formula_types import (
RuntimeAdd,
RuntimeAnd,
RuntimeAt,
RuntimeAvg,
RuntimeCapitalize,
RuntimeConcat,
RuntimeContains,
RuntimeDateTimeFormat,
RuntimeDay,
RuntimeDivide,
Expand All @@ -51,8 +54,11 @@ def ready(self):
RuntimeGreaterThanOrEqual,
RuntimeHour,
RuntimeIf,
RuntimeIsEmpty,
RuntimeIsEven,
RuntimeIsOdd,
RuntimeJoin,
RuntimeLength,
RuntimeLessThan,
RuntimeLessThanOrEqual,
RuntimeLower,
Expand All @@ -66,8 +72,14 @@ def ready(self):
RuntimeRandomBool,
RuntimeRandomFloat,
RuntimeRandomInt,
RuntimeReplace,
RuntimeReverse,
RuntimeRound,
RuntimeSecond,
RuntimeSplit,
RuntimeStrip,
RuntimeSum,
RuntimeToArray,
RuntimeToday,
RuntimeUpper,
RuntimeYear,
Expand Down Expand Up @@ -108,6 +120,18 @@ def ready(self):
formula_runtime_function_registry.register(RuntimeIf())
formula_runtime_function_registry.register(RuntimeAnd())
formula_runtime_function_registry.register(RuntimeOr())
formula_runtime_function_registry.register(RuntimeReplace())
formula_runtime_function_registry.register(RuntimeLength())
formula_runtime_function_registry.register(RuntimeContains())
formula_runtime_function_registry.register(RuntimeReverse())
formula_runtime_function_registry.register(RuntimeJoin())
formula_runtime_function_registry.register(RuntimeSplit())
formula_runtime_function_registry.register(RuntimeIsEmpty())
formula_runtime_function_registry.register(RuntimeStrip())
formula_runtime_function_registry.register(RuntimeSum())
formula_runtime_function_registry.register(RuntimeAvg())
formula_runtime_function_registry.register(RuntimeAt())
formula_runtime_function_registry.register(RuntimeToArray())

from baserow.core.permission_manager import (
AllowIfTemplatePermissionManagerType,
Expand Down
23 changes: 23 additions & 0 deletions backend/src/baserow/core/formula/argument_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import pytz

from baserow.core.formula.validator import (
ensure_array,
ensure_boolean,
ensure_datetime,
ensure_numeric,
Expand Down Expand Up @@ -112,3 +113,25 @@ def test(self, value):

def parse(self, value):
return value


class ArrayOfNumbersBaserowRuntimeFormulaArgumentType(
BaserowRuntimeFormulaArgumentType
):
def test(self, value):
try:
value = ensure_array(value)
except ValidationError:
return False

for item in value:
try:
ensure_numeric(item)
except ValidationError:
return False

return True

def parse(self, value):
value = ensure_array(value)
return [ensure_numeric(item) for item in value]
4 changes: 4 additions & 0 deletions backend/src/baserow/core/formula/parser/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,3 +57,7 @@ def __init__(self, operatorText):

class BaserowFormulaSyntaxError(BaserowFormulaException):
pass


class BaserowFormulaExecuteError(BaserowFormulaException):
pass
162 changes: 161 additions & 1 deletion backend/src/baserow/core/formula/runtime_formula_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

from baserow.core.formula.argument_types import (
AnyBaserowRuntimeFormulaArgumentType,
ArrayOfNumbersBaserowRuntimeFormulaArgumentType,
BooleanBaserowRuntimeFormulaArgumentType,
DateTimeBaserowRuntimeFormulaArgumentType,
DictBaserowRuntimeFormulaArgumentType,
Expand All @@ -17,7 +18,7 @@
from baserow.core.formula.registries import RuntimeFormulaFunction
from baserow.core.formula.types import FormulaArg, FormulaArgs, FormulaContext
from baserow.core.formula.utils.date import convert_date_format_moment_to_python
from baserow.core.formula.validator import ensure_string
from baserow.core.formula.validator import ensure_array, ensure_string


class RuntimeConcat(RuntimeFormulaFunction):
Expand Down Expand Up @@ -418,3 +419,162 @@ class RuntimeOr(RuntimeFormulaFunction):

def execute(self, context: FormulaContext, args: FormulaArgs):
return args[0] or args[1]


class RuntimeReplace(RuntimeFormulaFunction):
type = "replace"

args = [
TextBaserowRuntimeFormulaArgumentType(),
TextBaserowRuntimeFormulaArgumentType(),
TextBaserowRuntimeFormulaArgumentType(),
]

def execute(self, context: FormulaContext, args: FormulaArgs):
return args[0].replace(args[1], args[2])


class RuntimeLength(RuntimeFormulaFunction):
type = "length"

args = [
AnyBaserowRuntimeFormulaArgumentType(),
]

def execute(self, context: FormulaContext, args: FormulaArgs):
return len(args[0])


class RuntimeContains(RuntimeFormulaFunction):
type = "contains"

args = [
AnyBaserowRuntimeFormulaArgumentType(),
AnyBaserowRuntimeFormulaArgumentType(),
]

def execute(self, context: FormulaContext, args: FormulaArgs):
return args[1] in args[0]


class RuntimeReverse(RuntimeFormulaFunction):
type = "reverse"

args = [
AnyBaserowRuntimeFormulaArgumentType(),
]

def execute(self, context: FormulaContext, args: FormulaArgs):
value = args[0]

if isinstance(value, list):
return list(reversed(value))

if isinstance(value, str):
return "".join(list(reversed(value)))

raise TypeError(f"Cannot reverse {value}")


class RuntimeJoin(RuntimeFormulaFunction):
type = "join"

args = [
AnyBaserowRuntimeFormulaArgumentType(),
TextBaserowRuntimeFormulaArgumentType(optional=True),
]

def execute(self, context: FormulaContext, args: FormulaArgs):
value = args[0]
separator = args[1] if len(args) == 2 else ","
return separator.join(value)


class RuntimeSplit(RuntimeFormulaFunction):
type = "split"

args = [
TextBaserowRuntimeFormulaArgumentType(),
TextBaserowRuntimeFormulaArgumentType(optional=True),
]

def execute(self, context: FormulaContext, args: FormulaArgs):
separator = args[1] if len(args) == 2 else None
return args[0].split(separator)


class RuntimeIsEmpty(RuntimeFormulaFunction):
type = "is_empty"

args = [
AnyBaserowRuntimeFormulaArgumentType(),
]

def execute(self, context: FormulaContext, args: FormulaArgs):
value = args[0]

if value is None:
return True

if isinstance(value, (list, str, dict)):
if isinstance(value, str):
value = value.strip()
return len(value) == 0

return False


class RuntimeStrip(RuntimeFormulaFunction):
type = "strip"

args = [
TextBaserowRuntimeFormulaArgumentType(),
]

def execute(self, context: FormulaContext, args: FormulaArgs):
return args[0].strip()


class RuntimeSum(RuntimeFormulaFunction):
type = "sum"

args = [
ArrayOfNumbersBaserowRuntimeFormulaArgumentType(),
]

def execute(self, context: FormulaContext, args: FormulaArgs):
return sum(args[0])


class RuntimeAvg(RuntimeFormulaFunction):
type = "avg"

args = [
ArrayOfNumbersBaserowRuntimeFormulaArgumentType(),
]

def execute(self, context: FormulaContext, args: FormulaArgs):
return sum(args[0]) / len(args[0])


class RuntimeAt(RuntimeFormulaFunction):
type = "at"

args = [
AnyBaserowRuntimeFormulaArgumentType(),
NumberBaserowRuntimeFormulaArgumentType(cast_to_int=True),
]

def execute(self, context: FormulaContext, args: FormulaArgs):
value = args[0]
index = args[1]
return value[index]


class RuntimeToArray(RuntimeFormulaFunction):
type = "to_array"

args = [TextBaserowRuntimeFormulaArgumentType()]

def execute(self, context: FormulaContext, args: FormulaArgs):
return ensure_array(args[0])
Loading
Loading