Skip to content

feat: Add Runtime Formula for formatting numbers#5262

Open
paljort wants to merge 29 commits into
developfrom
4974-add-number-formatting-expressions
Open

feat: Add Runtime Formula for formatting numbers#5262
paljort wants to merge 29 commits into
developfrom
4974-add-number-formatting-expressions

Conversation

@paljort
Copy link
Copy Markdown
Collaborator

@paljort paljort commented Apr 23, 2026

What is in this PR

This PR implements four new runtime formulas: number_format(), abs(), null(), date_interval(), and to_datetime().

It also adds support for better human-readable error messages by adding a new getErrorMessage() method to the BaserowRuntimeFormulaArgumentType class, as well as refactoring the RuntimeFormulaFunction::validateArgs() to raise the error message if available. The backend has been similarly refactored.

Finally, a new skill create-update-runtime-formula AI skill has been added. This will make it easier to use an LLM to add/update a runtime formula with a simple prompt. For instance, to create the null() runtime formula, I just prompted:

I want you to create a runtime formula named null() that should simply return null in the frontend or None in the backend.

Closes #4974

How to test this PR

1. abs()

This simply returns the absolute value of a number, e.g. abs(-100) should return 100.

Create a Builder element, e.g. Heading, and using expert mode type in abs(-100). You should see 100 rendered.

2. null()

This returns a null (or None in the backend). This is useful when you need a null value to be used, e.g. when upserting a null to a row or evaluating it in a Router node, e.g.:

if(get('previous_node.40.0.field_2918') = null(), true, false)

Create a Date field in your database table and fill the field with a date value. Then in Builder or Automation, create an workflow action or a node that updates that row's field to use null() in the service. You should observe that the row's field is correctly set to null.

3. number_format()

This formats a number with the option to specify:

  • Decimal places (defaults to 0)
  • Thousand separator (defaults to ,)
  • Decimal separator (default to .)

E.g. using number_format(12345, 2, '.', ',') should return 12.345,00.

4. date_interval()

This returns a timedelta that can be used by the existing add or minus formulas to operate on a date.

E.g. now() + date_format('1 day') should add a day to the current datetime.

5. to_datetime()

This takes a Moment.js datetime string with an optional date format, and converts it to a datetime objeect.

E.g. to_datetime('2026-06-04') returns datetime(2026, 06, 04, 0, 0, 0).

Checklist

  • A changelog entry has been added to changelog/entries/unreleased using changelog/src/changelog.py
  • New/updated Premium/Enterprise features are separated correctly in the premium or enterprise folder
  • The latest Chrome and Firefox have been used to test any new frontend features
  • Documentation has been updated
  • Quality Standards are met
  • Performance: tables are still fast with 100k+ rows, 100+ field tables
  • The redoc API pages have been updated for any REST API changes
  • Our custom API docs are updated for changes to endpoints accessed via API tokens
  • The UI/UX has been updated following the UI Style Guide
  • Security impact of change has been considered

@paljort paljort added this to the v2.3 milestone Apr 23, 2026
@paljort paljort self-assigned this Apr 23, 2026
@paljort paljort added the core 🔩 Only core code is affected and no other expertise is needed label Apr 23, 2026
@paljort paljort marked this pull request as draft April 23, 2026 10:03
@paljort paljort force-pushed the 4974-add-number-formatting-expressions branch from 01f7c82 to dde88d3 Compare April 24, 2026 10:33
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 24, 2026

Coverage report

Click to see where and how coverage changed

FileStatementsMissingCoverageCoverage
(new stmts)
Lines missing
  backend/src/baserow/core
  apps.py 37-38, 106-112, 138-146
  backend/src/baserow/core/formula
  argument_types.py 1-26, 32-47, 124-136, 160-237
  registries.py 4-5, 83-90, 104-124
  runtime_formula_types.py 1-45, 95-118, 129-150, 286-299, 319, 668-767
  validator.py 1-6, 15-19, 100-108, 129-138, 214-274
  backend/src/baserow/core/formula/utils
  date.py 1-73, 81-84
Project Total  

This report was generated by python-coverage-comment-action

@paljort paljort force-pushed the 4974-add-number-formatting-expressions branch 3 times, most recently from 9e6a4a4 to 51d9d2d Compare April 28, 2026 10:05
Comment thread web-frontend/modules/core/components/formula/FormulaInputField.vue
@paljort paljort marked this pull request as ready for review April 28, 2026 10:20
@paljort paljort force-pushed the 4974-add-number-formatting-expressions branch 3 times, most recently from bc9a233 to d265c3f Compare May 4, 2026 06:17
@paljort paljort marked this pull request as draft May 4, 2026 06:44
@paljort paljort marked this pull request as ready for review May 4, 2026 07:08
Copy link
Copy Markdown
Collaborator

@jrmi jrmi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey Tsering, thanks for this PR and the new skill, it will be really usefull.

In this PR we introduce the new "time interval" data type but we don't have an ensurer for that. What do you think about adding the ensurer and support this new type in other ensurer, I thinks mainly to the "ensureString" that could return something more human friendly than {"ms":172800000}. It could be the best string representation (bay be moment has something like that?). Even the ensureInteger could return something like the number of seconds or something like that. What do you think?

More generally I left multiple comments about using the ensurer when possible. I think it could be something we add in the skill to make sure next PR use them.

Could you give an example with different separators here:

Image

There is no ways to know what are the other parameters.

The return value here is too technical, may be it could be the number of seconds?

Image

For the null() function may be we can be a bit more precise and say it allows to set null as value or something like that?

Image

Comment thread backend/src/baserow/core/formula/argument_types.py Outdated
Comment thread backend/src/baserow/core/formula/registries.py Outdated
Comment thread backend/src/baserow/core/formula/runtime_formula_types.py
Comment thread backend/src/baserow/core/formula/argument_types.py Outdated
Comment thread web-frontend/modules/core/runtimeFormulaTypes.js
Comment thread web-frontend/modules/core/runtimeFormulaTypes.js
Comment thread web-frontend/modules/core/runtimeFormulaTypes.js Outdated
@paljort paljort force-pushed the 4974-add-number-formatting-expressions branch from 13d279e to 8006010 Compare May 5, 2026 10:04
@paljort paljort marked this pull request as draft May 5, 2026 10:05
@paljort paljort force-pushed the 4974-add-number-formatting-expressions branch from 8006010 to 9206379 Compare May 6, 2026 10:29
@paljort
Copy link
Copy Markdown
Collaborator Author

paljort commented May 6, 2026

Thanks for your review @jrmi - I believe it's ready for another round.

@paljort paljort marked this pull request as ready for review May 6, 2026 11:10
@paljort paljort requested a review from jrmi May 6, 2026 11:10
Copy link
Copy Markdown
Collaborator

@jrmi jrmi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey Tsering, almost there. I suggested two improvments, let me know what you think.

if isinstance(value, timedelta):
total = int(value.total_seconds())
if total == 0:
return "0 seconds"
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We either:

  • Want to translate that
  • Just return a number so the user can make the conversion themselves with a convoluted advanced formula.

Second option is easier for us and first is better for user.

WDYT?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point, I've refactored it to just return the total seconds as a string. Done in 5203b52

if isinstance(value, timedelta):
return value

if isinstance(value, str):
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it's a string I would try to match a duration and if it doesn't work ensure a number and fall in the next case if it's possible. WDYT?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense, done in aef2621

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of converting to float could you use ensure_integar as I suggested to support potentially more values?

Comment thread web-frontend/modules/core/runtimeFormulaTypes.js
@jrmi jrmi marked this pull request as draft May 7, 2026 14:56
@paljort paljort force-pushed the 4974-add-number-formatting-expressions branch from 9206379 to aef2621 Compare May 8, 2026 06:08
@paljort
Copy link
Copy Markdown
Collaborator Author

paljort commented May 8, 2026

@jrmi it's ready for another round 😄

@paljort paljort marked this pull request as ready for review May 8, 2026 06:08
@paljort paljort requested a review from jrmi May 8, 2026 06:09
@paljort paljort force-pushed the 4974-add-number-formatting-expressions branch from f5b813c to 82dc9ac Compare May 18, 2026 05:51
@paljort
Copy link
Copy Markdown
Collaborator Author

paljort commented May 18, 2026

Instead of converting to float could you use ensure_integar as I suggested to support potentially more values?

Done in 4d4dd6f. This means we won't support fractional seconds, but I guess that should be fine since most users won't want to do millisecond level intervals.

@paljort paljort marked this pull request as ready for review May 18, 2026 06:07
@paljort paljort requested a review from jrmi May 18, 2026 06:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

core 🔩 Only core code is affected and no other expertise is needed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add missing expression functions

2 participants