Skip to content

[IMP] export: reduce JSON size#7756

Closed
VincentSchippefilt wants to merge 3 commits intomasterfrom
master-squish-vsc
Closed

[IMP] export: reduce JSON size#7756
VincentSchippefilt wants to merge 3 commits intomasterfrom
master-squish-vsc

Conversation

@VincentSchippefilt
Copy link
Copy Markdown
Collaborator

@VincentSchippefilt VincentSchippefilt commented Jan 13, 2026

Description:

Reduce the JSON file size of spreadsheets by storing only changes to formulae and, in a second pass,
collecting all the formulae or changes that are the same and storing them under one single key in the JSON file.

Task: 5489478

API changes:

compiler.ts/compile(formula: string) --> CompiledFormula.Compile(formula: string, sheetId: UID, getters: CoreGetters)
fomulas/helpers.ts/getFunctionsFromTokens(tokens: Tokens[], functionNames: string[]) --> fomulas/helpers.ts/getFunctionsFromTokens(compiledFormula: CompiledFormula, functionNames: string[])
removed RangeCompiledFormula --> CompiledFormula
model.ts/export() --> export(shouldSquish?: boolean = false)
cell.ts/getTranslatedFormulaCell(sheetId: UID, offsetX: number, offsetY: number, tokens: Token[]) --> getTranslatedFormulaCell(sheetId: UID,offsetX: number,offsetY: number,compiledFormula: CompiledFormula | SerializedCompiledFormula )
removed plugins/core/cell.ts/ReferenceToken class --> it is implemented in CompiledFormula formulas/helper.ts/isExportableToExcel&getFunctionsFromTokens --> CompiledFormula.areAllFunctionsExportableToExcel&getFunctionsFromTokens`
removed FormulaCellWithDependencies and ReferenceToken

Observed performance gains on large dashboard:

importing sheets:
~2300ms --> ~680 ms
1560 MB ram --> 580 MB

JSON Size:
40 MB -> 147 KB
4,4 MB -> 3KB
1,6 MB-> 43 KB

How does it work:

Shared formula

   A1: "My Text",
   A2: "=SUM(B2:B9)",
   A3: "=SUM(B2:B9)",

As we can see, A2 and A3 share the same formula. They can be rewritten as

   A1: "My Text",
   'A2:A3': "=SUM(B2:B9)",

removing duplication completely

Formula with small differences

Usually formula do not repeat exactly the same, but offset their dependencies (being either references to other cells, numbers or strings) slightly. We can rewrite:

   A1: "My Text",
   A2: "=CONCAT(B2, $C$2, D2, "hello"),
   A3: "=CONCAT(B3, $C$2, D3, "hello"),
   A4: "=CONCAT(B4, $C$2, D4, "hello"),

to

   A1: "My Text",
   A2: "=CONCAT(B2, $C$2, D2, "hello"),
   A3: { R : "+R1|=|+R1" },
   A4: { R : "+R1|=|+R1" },
   ...

now we see that A3 and A4 have the same transformation, so we can rewrite them to

   A1: "My Text",
   A2: "=CONCAT(B2, $C$2, D2, "hello"),
   "A3:A4": { R : "+R1|=|+R1" },

We apply the same for number arguments and string arguments.
A formula with all the arguments slightly changed might look like

   A1: "=MY_FORMULA(1, B1, "coucou"),
   A2: { R : "+R1", N: "+1", S: ["hello"] },
   A3:A4: { R : "+R1", N: "+1"}

can be read as

   A1: "=MY_FORMULA(1, B1, "coucou"),
   A2: "=MY_FORMULA(2, B2, "hello"),
   A3: "=MY_FORMULA(3, B3, "hello"),
   A4: "=MY_FORMULA(4, B4, "hello"),

When reading the compressed JSON, the order of the keys in the JSON itself do not matter, they are sorted on the first part of the key, so either the cell reference or the left part of the range.

@robodoo
Copy link
Copy Markdown
Collaborator

robodoo commented Jan 13, 2026

Pull request status dashboard

@VincentSchippefilt VincentSchippefilt changed the base branch from 19.0 to master January 13, 2026 07:42
Comment thread packages/o-spreadsheet-engine/src/formulas/tokenizer.ts Outdated
Comment thread packages/o-spreadsheet-engine/src/helpers/misc.ts Outdated
Comment thread packages/o-spreadsheet-engine/src/plugins/core/cell.ts Outdated
@VincentSchippefilt VincentSchippefilt force-pushed the master-squish-vsc branch 4 times, most recently from 7516ed3 to 489a7be Compare January 15, 2026 12:26
@VincentSchippefilt VincentSchippefilt marked this pull request as ready for review January 15, 2026 12:28
Comment thread tests/clipboard/clipboard_plugin.test.ts Outdated
Comment thread packages/o-spreadsheet-engine/src/formulas/compiler.ts Outdated
Copy link
Copy Markdown
Collaborator

@LucasLefevre LucasLefevre left a comment

Choose a reason for hiding this comment

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

first review 👌

main point (but not the easiest): BananaCompiledFormula should be type-safe to raise at compile time instead of raising in production

Comment thread packages/o-spreadsheet-engine/src/formulas/tokenizer.ts Outdated
Comment thread packages/o-spreadsheet-engine/src/formulas/compiler.ts Outdated
Comment thread packages/o-spreadsheet-engine/src/formulas/compiler.ts Outdated
Comment thread packages/o-spreadsheet-engine/src/formulas/compiler.ts Outdated
Comment thread packages/o-spreadsheet-engine/src/formulas/compiler.ts
Comment thread tests/model/squish.test.ts
Comment thread tests/model/squish.test.ts
Comment thread packages/o-spreadsheet-engine/src/plugins/core/squisher.ts
Comment thread tests/test_helpers/helpers.ts Outdated
Copy link
Copy Markdown
Collaborator

@pro-odoo pro-odoo left a comment

Choose a reason for hiding this comment

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

Nice :D
Didn't fully read the squisher yet

Comment thread packages/o-spreadsheet-engine/src/formulas/compiler.ts Outdated
Comment thread packages/o-spreadsheet-engine/src/formulas/compiler.ts Outdated
Comment thread packages/o-spreadsheet-engine/src/formulas/compiler.ts Outdated
Comment thread packages/o-spreadsheet-engine/src/formulas/compiler.ts
Comment thread packages/o-spreadsheet-engine/src/formulas/compiler.ts
Comment thread packages/o-spreadsheet-engine/src/helpers/expand_range.ts Outdated
Comment thread packages/o-spreadsheet-engine/src/helpers/misc.ts
Comment thread packages/o-spreadsheet-engine/src/formulas/compiler.ts Outdated
@VincentSchippefilt VincentSchippefilt force-pushed the master-squish-vsc branch 2 times, most recently from 3224c45 to 1f3038b Compare January 20, 2026 15:55
@VincentSchippefilt VincentSchippefilt changed the title reduce json file size [IMP] export: reduce JSON size Jan 20, 2026
Copy link
Copy Markdown
Contributor

@hokolomopo hokolomopo left a comment

Choose a reason for hiding this comment

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

👋

Mostly small things. I didn't read the details of the squisher/unsquisher. Really cool feature 🥳

Comment thread tests/model/squish.test.ts
Comment thread packages/o-spreadsheet-engine/src/model.ts Outdated
Comment thread tests/model/squish.test.ts Outdated
Comment thread tests/model/squish.test.ts Outdated
Comment thread packages/o-spreadsheet-engine/src/plugins/core/squisher.ts Outdated
Comment thread packages/o-spreadsheet-engine/src/formulas/compiler.ts Outdated
Comment thread src/clipboard_handlers/cell_clipboard.ts Outdated
Comment thread tests/cells/cell_plugin.test.ts
Comment thread tests/composer/composer_component.test.ts Outdated
Comment thread packages/o-spreadsheet-engine/src/plugins/core/squisher.ts Outdated
Comment thread packages/o-spreadsheet-engine/src/plugins/core/squisher.ts Outdated
Comment thread packages/o-spreadsheet-engine/src/plugins/core/squisher.ts Outdated
Comment thread packages/o-spreadsheet-engine/src/plugins/core/squisher.ts Outdated
Comment thread packages/o-spreadsheet-engine/src/plugins/core/squisher.ts Outdated
Comment thread packages/o-spreadsheet-engine/src/plugins/core/cell.ts Outdated
Comment thread packages/o-spreadsheet-engine/src/plugins/core/cell.ts Outdated
Comment thread packages/o-spreadsheet-engine/src/plugins/core/cell.ts
Comment thread packages/o-spreadsheet-engine/src/plugins/core/cell.ts Outdated
Comment thread packages/o-spreadsheet-engine/src/plugins/core/cell.ts Outdated
@VincentSchippefilt VincentSchippefilt force-pushed the master-squish-vsc branch 6 times, most recently from e1b7c7f to 0adc821 Compare January 28, 2026 13:49
@VincentSchippefilt VincentSchippefilt force-pushed the master-squish-vsc branch 3 times, most recently from 4791b75 to c277d63 Compare February 3, 2026 13:46
@VincentSchippefilt
Copy link
Copy Markdown
Collaborator Author

robodoo rebase-ff

@robodoo
Copy link
Copy Markdown
Collaborator

robodoo commented Feb 11, 2026

Merge method set to rebase and fast-forward.

Copy link
Copy Markdown
Collaborator

@LucasLefevre LucasLefevre left a comment

Choose a reason for hiding this comment

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

deeper look at the squish/unsquish

Comment thread packages/o-spreadsheet-engine/src/formulas/compiler.ts Outdated
Comment thread packages/o-spreadsheet-engine/src/formulas/compiler.ts
Comment thread packages/o-spreadsheet-engine/src/formulas/compiler.ts Outdated
Comment thread packages/o-spreadsheet-engine/src/formulas/compiler.ts Outdated
Comment thread packages/o-spreadsheet-engine/src/formulas/compiler.ts Outdated
Comment thread packages/o-spreadsheet-engine/src/plugins/core/unsquisher.ts Outdated
Comment thread packages/o-spreadsheet-engine/src/plugins/core/unsquisher.ts Outdated
Comment thread packages/o-spreadsheet-engine/src/plugins/core/unsquisher.ts
Comment thread packages/o-spreadsheet-engine/src/plugins/core/unsquisher.ts Outdated
Comment thread packages/o-spreadsheet-engine/src/model.ts
@VincentSchippefilt VincentSchippefilt force-pushed the master-squish-vsc branch 6 times, most recently from 7c961d0 to 3313428 Compare February 19, 2026 08:09
Comment thread demo/main.js Outdated
const endPos = toCartesian(end);
for (
let col = Math.min(startPos.col, endPos.col);
col <= Math.max(startPos.col, endPos.col);
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.

can be evaluated a single time; same for the condition below

numbers: string[],
strings: string[],
references: string[]
): Partial<SquishedFormula> {
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.

useless Partial

@rrahir
Copy link
Copy Markdown
Collaborator

rrahir commented Feb 19, 2026

robodoo r+

robodoo pushed a commit that referenced this pull request Feb 19, 2026
- it manages the tokens privately
- it tells you if your formula is valid or not
- it replaces 2 classes: FormulaCellWithDependencies and RangeReferenceToken
- it is required for the next commit: allow to create multiple formulas based the same formula with different parameters

compiler.ts/`compile(formula: string)` --> `CompiledFormula.Compile(formula: string, sheetId: UID, getters: CoreGetters)`
fomulas/helpers.ts/`getFunctionsFromTokens(...)` --> `compiledFormula.getFunctionsFromTokens(functionNames: string[], getters: CoreGetters)`
removed `RangeCompiledFormula` --> `CompiledFormula`
removed plugins/core/cell.ts/`ReferenceToken` class --> it is implemented in CompiledFormula`
formulas/helper.ts/`isExportableToExcel` & `getFunctionsFromTokens` --> compiledFormula.`areAllFunctionsExportableToExcel` & `getFunctionsFromTokens`
removed FormulaCellWithDependencies and ReferenceToken

Task: 5489478
Part-of: #7756
Signed-off-by: Rémi Rahir (rar) <rar@odoo.com>
robodoo pushed a commit that referenced this pull request Feb 19, 2026
Today all cells have the property `content` that contain the raw content of the cell: either its value, its formula text or the markdown link.
Having the content re-create the formula from its parts is costly, and having the convenience of defining the property `content`
on an object, either through a dedicated class or though a closure is very expensive (100 MB on large models).
This PR move the property `content` out of Cell, in `LiteralCell` so it is no longer available on FormulaCell.
Update all the usages of `content` to be specific to LiteralCell (!FormulaCell).
Mostly, content was used to check if a cell is empty. This check was `if(!cell?.content)` and becomes `if (!cell?.isFormula && !cell?.content)`

Task: 5489478
Part-of: #7756
Signed-off-by: Rémi Rahir (rar) <rar@odoo.com>
robodoo pushed a commit that referenced this pull request Feb 19, 2026
Description:
Reduce the JSON file size of spreadsheets by storing only changes to formulae and, in a second pass,
collecting all the formulae or changes that are the same and storing them under one single key in the JSON file.

importing sheets:
~2300ms --> ~680 ms
1560 MB ram --> 580 MB

JSON Size:
40 MB -> 147 KB
4,4 MB -> 3KB
1,6 MB-> 43 KB

```cells: {
   A1: "My Text",
   A2: "=SUM(B2:B9)",
   A3: "=SUM(B2:B9)",
```
As we can see, A2 and A3 share the same formula. They can be rewritten as
```cells: {
   A1: "My Text",
   'A2:A3': "=SUM(B2:B9)",
```
removing duplication completely

Usually formula do not repeat exactly the same, but offset their dependencies (being either references to other cells, numbers or strings) slightly. We can rewrite:
```cells: {
   A1: "My Text",
   A2: "=CONCAT(B2, $C$2, D2, "hello"),
   A3: "=CONCAT(B3, $C$2, D3, "hello"),
   A4: "=CONCAT(B4, $C$2, D4, "hello"),
```
to
```cells: {
   A1: "My Text",
   A2: "=CONCAT(B2, $C$2, D2, "hello"),
   A3: { R : "R+1|=|R+1" },
   A4: { R : "R+1|=|R+1" },
   ...
```
now we see that A3 and A4 have the same transformation, so we can rewrite them to
```cells: {
   A1: "My Text",
   A2: "=CONCAT(B2, $C$2, D2, "hello"),
   "A3:A4": { R : "R+1|=|R+1" },
```
We apply the same for number arguments and string arguments.
A formula with all the arguments slightly changed might look like
```cells: {
   A1: "=MY_FORMULA(1, B1, "coucou"),
   A2: { R : "R+1", N: "+1", S: ["hello"] },
   A3:A4: { R : "R+1", N: "+1"}
```
can be read as
```cells: {
   A1: "=MY_FORMULA(1, B1, "coucou"),
   A2: "=MY_FORMULA(2, B2, "hello"),
   A3: "=MY_FORMULA(3, B3, "hello"),
   A4: "=MY_FORMULA(4, B4, "hello"),
```

closes #7756

Task: 5489478
Signed-off-by: Rémi Rahir (rar) <rar@odoo.com>
@robodoo
Copy link
Copy Markdown
Collaborator

robodoo commented Feb 19, 2026

@VincentSchippefilt @rrahir staging failed: ci/runbot (view more at https://runbot.odoo.com/runbot/batch/2378120/build/101554677)

- it manages the tokens privately
- it tells you if your formula is valid or not
- it replaces 2 classes: FormulaCellWithDependencies and RangeReferenceToken
- it is required for the next commit: allow to create multiple formulas based the same formula with different parameters

compiler.ts/`compile(formula: string)` --> `CompiledFormula.Compile(formula: string, sheetId: UID, getters: CoreGetters)`
fomulas/helpers.ts/`getFunctionsFromTokens(...)` --> `compiledFormula.getFunctionsFromTokens(functionNames: string[], getters: CoreGetters)`
removed `RangeCompiledFormula` --> `CompiledFormula`
removed plugins/core/cell.ts/`ReferenceToken` class --> it is implemented in CompiledFormula`
formulas/helper.ts/`isExportableToExcel` & `getFunctionsFromTokens` --> compiledFormula.`areAllFunctionsExportableToExcel` & `getFunctionsFromTokens`
removed FormulaCellWithDependencies and ReferenceToken

Task: 5489478
Today all cells have the property `content` that contain the raw content of the cell: either its value, its formula text or the markdown link.
Having the content re-create the formula from its parts is costly, and having the convenience of defining the property `content`
on an object, either through a dedicated class or though a closure is very expensive (100 MB on large models).
This PR move the property `content` out of Cell, in `LiteralCell` so it is no longer available on FormulaCell.
Update all the usages of `content` to be specific to LiteralCell (!FormulaCell).
Mostly, content was used to check if a cell is empty. This check was `if(!cell?.content)` and becomes `if (!cell?.isFormula && !cell?.content)`

Task: 5489478
Description:
Reduce the JSON file size of spreadsheets by storing only changes to formulae and, in a second pass,
collecting all the formulae or changes that are the same and storing them under one single key in the JSON file.

importing sheets:
~2300ms --> ~680 ms
1560 MB ram --> 580 MB

JSON Size:
40 MB -> 147 KB
4,4 MB -> 3KB
1,6 MB-> 43 KB

```cells: {
   A1: "My Text",
   A2: "=SUM(B2:B9)",
   A3: "=SUM(B2:B9)",
```
As we can see, A2 and A3 share the same formula. They can be rewritten as
```cells: {
   A1: "My Text",
   'A2:A3': "=SUM(B2:B9)",
```
removing duplication completely

Usually formula do not repeat exactly the same, but offset their dependencies (being either references to other cells, numbers or strings) slightly. We can rewrite:
```cells: {
   A1: "My Text",
   A2: "=CONCAT(B2, $C$2, D2, "hello"),
   A3: "=CONCAT(B3, $C$2, D3, "hello"),
   A4: "=CONCAT(B4, $C$2, D4, "hello"),
```
to
```cells: {
   A1: "My Text",
   A2: "=CONCAT(B2, $C$2, D2, "hello"),
   A3: { R : "R+1|=|R+1" },
   A4: { R : "R+1|=|R+1" },
   ...
```
now we see that A3 and A4 have the same transformation, so we can rewrite them to
```cells: {
   A1: "My Text",
   A2: "=CONCAT(B2, $C$2, D2, "hello"),
   "A3:A4": { R : "R+1|=|R+1" },
```
We apply the same for number arguments and string arguments.
A formula with all the arguments slightly changed might look like
```cells: {
   A1: "=MY_FORMULA(1, B1, "coucou"),
   A2: { R : "R+1", N: "+1", S: ["hello"] },
   A3:A4: { R : "R+1", N: "+1"}
```
can be read as
```cells: {
   A1: "=MY_FORMULA(1, B1, "coucou"),
   A2: "=MY_FORMULA(2, B2, "hello"),
   A3: "=MY_FORMULA(3, B3, "hello"),
   A4: "=MY_FORMULA(4, B4, "hello"),
```

Task: 5489478
@LucasLefevre
Copy link
Copy Markdown
Collaborator

robodoo r+

robodoo pushed a commit that referenced this pull request Feb 19, 2026
- it manages the tokens privately
- it tells you if your formula is valid or not
- it replaces 2 classes: FormulaCellWithDependencies and RangeReferenceToken
- it is required for the next commit: allow to create multiple formulas based the same formula with different parameters

compiler.ts/`compile(formula: string)` --> `CompiledFormula.Compile(formula: string, sheetId: UID, getters: CoreGetters)`
fomulas/helpers.ts/`getFunctionsFromTokens(...)` --> `compiledFormula.getFunctionsFromTokens(functionNames: string[], getters: CoreGetters)`
removed `RangeCompiledFormula` --> `CompiledFormula`
removed plugins/core/cell.ts/`ReferenceToken` class --> it is implemented in CompiledFormula`
formulas/helper.ts/`isExportableToExcel` & `getFunctionsFromTokens` --> compiledFormula.`areAllFunctionsExportableToExcel` & `getFunctionsFromTokens`
removed FormulaCellWithDependencies and ReferenceToken

Task: 5489478
Part-of: #7756
Signed-off-by: Lucas Lefèvre (lul) <lul@odoo.com>
robodoo pushed a commit that referenced this pull request Feb 19, 2026
Today all cells have the property `content` that contain the raw content of the cell: either its value, its formula text or the markdown link.
Having the content re-create the formula from its parts is costly, and having the convenience of defining the property `content`
on an object, either through a dedicated class or though a closure is very expensive (100 MB on large models).
This PR move the property `content` out of Cell, in `LiteralCell` so it is no longer available on FormulaCell.
Update all the usages of `content` to be specific to LiteralCell (!FormulaCell).
Mostly, content was used to check if a cell is empty. This check was `if(!cell?.content)` and becomes `if (!cell?.isFormula && !cell?.content)`

Task: 5489478
Part-of: #7756
Signed-off-by: Lucas Lefèvre (lul) <lul@odoo.com>
robodoo pushed a commit that referenced this pull request Feb 19, 2026
Description:
Reduce the JSON file size of spreadsheets by storing only changes to formulae and, in a second pass,
collecting all the formulae or changes that are the same and storing them under one single key in the JSON file.

importing sheets:
~2300ms --> ~680 ms
1560 MB ram --> 580 MB

JSON Size:
40 MB -> 147 KB
4,4 MB -> 3KB
1,6 MB-> 43 KB

```cells: {
   A1: "My Text",
   A2: "=SUM(B2:B9)",
   A3: "=SUM(B2:B9)",
```
As we can see, A2 and A3 share the same formula. They can be rewritten as
```cells: {
   A1: "My Text",
   'A2:A3': "=SUM(B2:B9)",
```
removing duplication completely

Usually formula do not repeat exactly the same, but offset their dependencies (being either references to other cells, numbers or strings) slightly. We can rewrite:
```cells: {
   A1: "My Text",
   A2: "=CONCAT(B2, $C$2, D2, "hello"),
   A3: "=CONCAT(B3, $C$2, D3, "hello"),
   A4: "=CONCAT(B4, $C$2, D4, "hello"),
```
to
```cells: {
   A1: "My Text",
   A2: "=CONCAT(B2, $C$2, D2, "hello"),
   A3: { R : "R+1|=|R+1" },
   A4: { R : "R+1|=|R+1" },
   ...
```
now we see that A3 and A4 have the same transformation, so we can rewrite them to
```cells: {
   A1: "My Text",
   A2: "=CONCAT(B2, $C$2, D2, "hello"),
   "A3:A4": { R : "R+1|=|R+1" },
```
We apply the same for number arguments and string arguments.
A formula with all the arguments slightly changed might look like
```cells: {
   A1: "=MY_FORMULA(1, B1, "coucou"),
   A2: { R : "R+1", N: "+1", S: ["hello"] },
   A3:A4: { R : "R+1", N: "+1"}
```
can be read as
```cells: {
   A1: "=MY_FORMULA(1, B1, "coucou"),
   A2: "=MY_FORMULA(2, B2, "hello"),
   A3: "=MY_FORMULA(3, B3, "hello"),
   A4: "=MY_FORMULA(4, B4, "hello"),
```

closes #7756

Task: 5489478
Signed-off-by: Lucas Lefèvre (lul) <lul@odoo.com>
@robodoo robodoo added the 19.2 label Feb 19, 2026
@robodoo robodoo closed this Feb 19, 2026
@fw-bot fw-bot deleted the master-squish-vsc branch February 26, 2026 14:45
matho-odoo pushed a commit that referenced this pull request Mar 3, 2026
- it manages the tokens privately
- it tells you if your formula is valid or not
- it replaces 2 classes: FormulaCellWithDependencies and RangeReferenceToken
- it is required for the next commit: allow to create multiple formulas based the same formula with different parameters

compiler.ts/`compile(formula: string)` --> `CompiledFormula.Compile(formula: string, sheetId: UID, getters: CoreGetters)`
fomulas/helpers.ts/`getFunctionsFromTokens(...)` --> `compiledFormula.getFunctionsFromTokens(functionNames: string[], getters: CoreGetters)`
removed `RangeCompiledFormula` --> `CompiledFormula`
removed plugins/core/cell.ts/`ReferenceToken` class --> it is implemented in CompiledFormula`
formulas/helper.ts/`isExportableToExcel` & `getFunctionsFromTokens` --> compiledFormula.`areAllFunctionsExportableToExcel` & `getFunctionsFromTokens`
removed FormulaCellWithDependencies and ReferenceToken

Task: 5489478
Part-of: #7756
Signed-off-by: Lucas Lefèvre (lul) <lul@odoo.com>
matho-odoo pushed a commit that referenced this pull request Mar 3, 2026
Today all cells have the property `content` that contain the raw content of the cell: either its value, its formula text or the markdown link.
Having the content re-create the formula from its parts is costly, and having the convenience of defining the property `content`
on an object, either through a dedicated class or though a closure is very expensive (100 MB on large models).
This PR move the property `content` out of Cell, in `LiteralCell` so it is no longer available on FormulaCell.
Update all the usages of `content` to be specific to LiteralCell (!FormulaCell).
Mostly, content was used to check if a cell is empty. This check was `if(!cell?.content)` and becomes `if (!cell?.isFormula && !cell?.content)`

Task: 5489478
Part-of: #7756
Signed-off-by: Lucas Lefèvre (lul) <lul@odoo.com>
matho-odoo pushed a commit that referenced this pull request Mar 3, 2026
Description:
Reduce the JSON file size of spreadsheets by storing only changes to formulae and, in a second pass,
collecting all the formulae or changes that are the same and storing them under one single key in the JSON file.

importing sheets:
~2300ms --> ~680 ms
1560 MB ram --> 580 MB

JSON Size:
40 MB -> 147 KB
4,4 MB -> 3KB
1,6 MB-> 43 KB

```cells: {
   A1: "My Text",
   A2: "=SUM(B2:B9)",
   A3: "=SUM(B2:B9)",
```
As we can see, A2 and A3 share the same formula. They can be rewritten as
```cells: {
   A1: "My Text",
   'A2:A3': "=SUM(B2:B9)",
```
removing duplication completely

Usually formula do not repeat exactly the same, but offset their dependencies (being either references to other cells, numbers or strings) slightly. We can rewrite:
```cells: {
   A1: "My Text",
   A2: "=CONCAT(B2, $C$2, D2, "hello"),
   A3: "=CONCAT(B3, $C$2, D3, "hello"),
   A4: "=CONCAT(B4, $C$2, D4, "hello"),
```
to
```cells: {
   A1: "My Text",
   A2: "=CONCAT(B2, $C$2, D2, "hello"),
   A3: { R : "R+1|=|R+1" },
   A4: { R : "R+1|=|R+1" },
   ...
```
now we see that A3 and A4 have the same transformation, so we can rewrite them to
```cells: {
   A1: "My Text",
   A2: "=CONCAT(B2, $C$2, D2, "hello"),
   "A3:A4": { R : "R+1|=|R+1" },
```
We apply the same for number arguments and string arguments.
A formula with all the arguments slightly changed might look like
```cells: {
   A1: "=MY_FORMULA(1, B1, "coucou"),
   A2: { R : "R+1", N: "+1", S: ["hello"] },
   A3:A4: { R : "R+1", N: "+1"}
```
can be read as
```cells: {
   A1: "=MY_FORMULA(1, B1, "coucou"),
   A2: "=MY_FORMULA(2, B2, "hello"),
   A3: "=MY_FORMULA(3, B3, "hello"),
   A4: "=MY_FORMULA(4, B4, "hello"),
```

closes #7756

Task: 5489478
Signed-off-by: Lucas Lefèvre (lul) <lul@odoo.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants