Skip to content

HF-85: Implement DCOUNT database function#1652

Open
marcin-kordas-hoc wants to merge 23 commits intodevelopfrom
feature/HF-85-implement-function-dcount
Open

HF-85: Implement DCOUNT database function#1652
marcin-kordas-hoc wants to merge 23 commits intodevelopfrom
feature/HF-85-implement-function-dcount

Conversation

@marcin-kordas-hoc
Copy link
Copy Markdown
Collaborator

@marcin-kordas-hoc marcin-kordas-hoc commented Apr 10, 2026

Context

Implements all 12 Excel database functions (D-functions family). Originally scoped to DCOUNT only, expanded to the full family since all share the same infrastructure (field resolution, criteria parsing, row matching).

How did you test your changes?

  • 185 unit tests in hyperformula-tests (handsontable/hyperformula-tests#9)
  • 167-case Excel validation workbook (all PASS in Excel Desktop)
  • 147-test runtime integration suite + 30 edge case tests (booleans, negatives, zeros, wildcards, large DB, comparison operators)
  • Verified all error types match Excel precisely (#VALUE!, #DIV/0!, #NUM!)

Types of changes

  • New feature or improvement (a non-breaking change that adds functionality)
  • Additional language file, or a change to an existing language file (translations)
  • Change to the documentation

Related issues:

  1. Fixes HF-85

Checklist:

  • I have reviewed the guidelines about Contributing to HyperFormula and I confirm that my code follows the code style of this project.
  • My change is compatible with Microsoft Excel.
  • My change is compatible with Google Sheets.
  • I described my changes in the CHANGELOG.md file.
  • My changes require a documentation update.

Summary

  • 12 database functions: DCOUNT, DCOUNTA, DSUM, DAVERAGE, DMAX, DMIN, DGET, DPRODUCT, DSTDEV, DSTDEVP, DVAR, DVARP
  • New DatabasePlugin (533 lines) with shared infrastructure
  • i18n translations for all 17 languages (proper Excel-localized names)
  • Documentation: built-in-functions.md (Database section), known-limitations.md (Nuances)

Implementation

  • withDatabaseArgs() helper eliminates boilerplate across all 12 functions
  • resolveFieldIndex() — string (case-insensitive header match) or 1-based numeric index with Math.trunc()
  • buildDatabaseCriteria() — OR across rows, AND within row, reuses CriterionBuilder
  • rowMatchesCriteria().some() (OR) + .every() (AND)
  • collectNumericValues() — shared by DSTDEV/DSTDEVP/DVAR/DVARP

Excel behavior edge cases

Function Edge case Behavior
DMAX, DMIN, DPRODUCT No matches Returns 0
DGET 0 matches / 2+ matches #VALUE! / #NUM!
DAVERAGE No numeric values #DIV/0!
DSTDEV, DVAR ≤1 value #DIV/0! (sample, n-1)
DSTDEVP, DVARP 1 value / 0 values 0 / #DIV/0! (population, n)

Linked

  • Tests PR: handsontable/hyperformula-tests#9
  • ClickUp: HF-85

Note

Medium Risk
Adds a new interpreter plugin and criteria/field parsing logic that affects formula evaluation and error semantics, which could introduce edge-case regressions in calculations.

Overview
Implements the Excel database function family by adding a new DatabasePlugin with DAVERAGE, DCOUNT, DCOUNTA, DGET, DMAX, DMIN, DPRODUCT, DSTDEV, DSTDEVP, DSUM, DVAR, and DVARP, including shared field resolution and criteria parsing/matching.

Updates public-facing docs to list the new Database function category and function semantics, adds basic integration examples for Angular/React/Svelte/Vue, and extends i18n language packs with localized names for all new functions. Also records the addition in CHANGELOG.md and notes key behavioral nuances in known-limitations.md.

Reviewed by Cursor Bugbot for commit 9d07107. Bugbot is set up for automated code reviews on this repo. Configure here.

@qunabu
Copy link
Copy Markdown

qunabu commented Apr 10, 2026

Task linked: HF-85 Implement function DCOUNT

@github-actions
Copy link
Copy Markdown

github-actions bot commented Apr 10, 2026

Performance comparison of head (9d07107) vs base (1852159)

                                     testName |   base |   head | change
------------------------------------------------------------------------
                                      Sheet A | 503.73 | 503.32 | -0.08%
                                      Sheet B | 162.81 | 164.44 | +1.00%
                                      Sheet T | 140.39 | 147.47 | +5.04%
                                Column ranges | 476.11 | 478.17 | +0.43%
Sheet A:  change value, add/remove row/column |  17.37 |   16.1 | -7.31%
 Sheet B: change value, add/remove row/column | 146.71 | 138.49 | -5.60%
                   Column ranges - add column | 161.19 | 146.27 | -9.26%
                Column ranges - without batch | 487.62 | 457.67 | -6.14%
                        Column ranges - batch | 121.79 | 113.18 | -7.07%

marcin-kordas-hoc and others added 10 commits April 16, 2026 11:53
Add idiomatic code examples to React, Angular, Vue, and Svelte
integration pages showing HyperFormula initialization and reading
calculated values. Each guide uses framework-specific patterns
(React hooks, Angular service, Vue ref/markRaw, Svelte reactivity).

Closes HF-122.
Add new DatabasePlugin with DCOUNT(database, field, criteria) that counts
numeric values in a specified field column for rows matching criteria.
Supports field resolution by name (case-insensitive) and 1-based index,
OR logic across criteria rows, AND logic within rows, and comparison
operators in criteria values. Includes translations for all 17 languages.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add three new database functions to DatabasePlugin with i18n
translations for all 17 languages.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Remove unnecessary type assertions in DAVERAGE, DMAX, DMIN methods.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
New DatabasePlugin with shared helpers for the complete D-function family:
DCOUNT, DSUM, DAVERAGE, DMAX, DMIN, DGET, DPRODUCT, DCOUNTA,
DSTDEV, DSTDEVP, DVAR, DVARP.

169 tests across 12 test suites. All pass.
17 language translations per function.
Excel validation: 152/152 PASS (verified in Excel Desktop).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…own-limitations.md

- Add ### Database section with all 12 D-functions (DAVERAGE, DCOUNT, DCOUNTA,
  DGET, DMAX, DMIN, DPRODUCT, DSTDEV, DSTDEVP, DSUM, DVAR, DVARP) to
  built-in-functions.md in alphabetical order between Date and Engineering
- Add Database to TOC and remove "database" from "yet to be supported" intro
- Add nuance notes for DGET (#VALUE!/#NUM! error semantics) and
  DMAX/DMIN/DPRODUCT (return 0 when no records match)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@marcin-kordas-hoc marcin-kordas-hoc force-pushed the feature/HF-85-implement-function-dcount branch from c7dd75e to 18906bc Compare April 16, 2026 12:00
marcin-kordas-hoc and others added 3 commits April 16, 2026 12:12
Introduce databaseFunctionParameters constant and withDatabaseArgs()
helper to eliminate repeated field/criteria resolution across all 12
database functions. Reduces file from 725 to 533 lines with no
behavioral changes.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Remove "(consistent with Excel behavior)" from known-limitations.md
  per review guideline: describe HF behavior only, no Excel references
- Remove trailing space in collectNumericValues

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@marcin-kordas-hoc marcin-kordas-hoc marked this pull request as ready for review April 17, 2026 07:53
Comment thread src/i18n/languages/csCZ.ts Outdated
Comment thread src/interpreter/plugin/DatabasePlugin.ts
Addresses Cursor Bugbot findings on PR #1652:

- csCZ.ts: DCOUNT was English 'DCOUNT' instead of localized 'DPOCET'
  (consistent with DCOUNTA = 'DPOCET2')
- resolveFieldIndex: coerce boolean field arg to number (TRUE -> 1,
  FALSE -> 0) per Excel convention, matching ArithmeticHelper semantics

Regression test added in hyperformula-tests.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Comment thread src/interpreter/plugin/DatabasePlugin.ts
Use Number.isFinite to reject NaN and Infinity before the bounds
check — the previous `index < 1 || index > headers.length` comparison
silently returns false for NaN, which would let a NaN index through
and produce incorrect results. Addresses Cursor Bugbot finding.

Regression test added in hyperformula-tests.
Comment thread src/interpreter/plugin/DatabasePlugin.ts
SCALAR argument types do not auto-propagate CellError in the framework
(coerceArgumentsToRequiredTypes skips propagation for SCALAR), so the
raw error reaches resolveFieldIndex and buildDatabaseCriteria. Both
sites used to fall through into generic #VALUE! / BadCriterion,
discarding the original error type.

Now both check for CellError upfront and return it verbatim, preserving
#DIV/0!, #NUM!, etc. — matching Excel's error-propagation behavior.
Addresses Cursor Bugbot finding.

Regression tests added in hyperformula-tests.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Comment thread src/i18n/languages/nlNL.ts Outdated
marcin-kordas-hoc and others added 2 commits April 17, 2026 09:12
The Dutch translation had a triple A typo — DCOUNT is DBAANTAL and the
COUNTA variant with C suffix should be DBAANTALC. Addresses Cursor
Bugbot finding.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The previous value lacked the D prefix and reversed the word order.
Verified against Microsoft Support's official Norwegian Excel
reference: DCOUNT → DANTALL.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Comment thread src/interpreter/plugin/DatabasePlugin.ts
isExtendedNumber silently skipped CellError values, letting numeric
aggregation D-functions return a clean number even when a matching
field cell contained #DIV/0! / #N/A / etc. Excel propagates the error
instead.

Each of DSUM, DPRODUCT, DAVERAGE, DMAX, DMIN now returns the error
immediately when encountered. collectNumericValues (shared by DSTDEV,
DSTDEVP, DVAR, DVARP) now returns CellError | number[] so those four
propagate too. DCOUNT, DCOUNTA, and DGET are unchanged — COUNT-family
semantics in Excel do not propagate field errors, and DGET already
returns the cell verbatim.

Regression test added in hyperformula-tests. Addresses Cursor Bugbot
finding.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Comment thread src/interpreter/plugin/DatabasePlugin.ts
Comment thread src/interpreter/plugin/DatabasePlugin.ts
Extends the CellError propagation introduced in 947a9fd to DCOUNT
and DCOUNTA. This keeps all 12 D-functions consistent: a matching
field cell containing an error surfaces the error with its original
type rather than being silently skipped or counted. Addresses Cursor
Bugbot findings.

Regression tests added in hyperformula-tests.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Comment thread src/i18n/languages/plPL.ts Outdated
- plPL: DCOUNTA 'BD.ILE.REKORDOW.A' -> 'BD.ILE.REKORDÓW.A' (missing Ó,
  matches DCOUNT pattern; Cursor Bugbot finding).
- plPL: DAVERAGE 'BD.SREDNIA' -> 'BD.ŚREDNIA' (missing Ś, per Microsoft
  Polish documentation; pre-emptive fix for the same class of issue).
- DGET: explicit CellError check on the matched cell makes the error-
  propagation path consistent with the other D-functions (previously
  worked by accident via fall-through).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 4e73545. Configure here.

Comment thread src/interpreter/plugin/DatabasePlugin.ts Outdated
marcin-kordas-hoc and others added 2 commits April 17, 2026 10:18
… docs

Proactive audit against Microsoft's official localized Excel
documentation (https://support.microsoft.com/{lang}/office/...) caught
systemic mismatches beyond what Cursor Bugbot had flagged so far.

Czech (csCZ) — 7 corrections (diacritics + DSUM word):
- DAVERAGE DPRUMER -> DPRŮMĚR
- DCOUNT   DPOCET -> DPOČET
- DCOUNTA  DPOCET2 -> DPOČET2
- DGET     DZISKAT -> DZÍSKAT
- DPRODUCT DSOUCIN -> DSOUČIN
- DSTDEV   DSMODCH.VYBER -> DSMODCH.VÝBĚR
- DSUM     DSOUCET -> DSUMA (entire word was wrong)
- DVAR     DVAR.VYBER -> DVAR.VÝBĚR

Turkish (trTR) — 11 corrections (VSEÇ prefix across the family):
- DAVERAGE VORTALAMA -> VSEÇORT
- DCOUNT   VSAY -> VSEÇSAY
- DCOUNTA  VSAYMA -> VSEÇSAYDOLU
- DMAX     VMAKS -> VSEÇMAK
- DMIN     VMİN -> VSEÇMİN
- DPRODUCT VÇARPIM -> VSEÇÇARP
- DSTDEV   VSTDSAPMA -> VSEÇSTDSAPMA
- DSTDEVP  VSTDSAPMAP -> VSEÇSTDSAPMAS
- DSUM     VTOPLA -> VSEÇTOPLA
- DVAR     VVAR -> VSEÇVAR
- DVARP    VVARP -> VSEÇVARS
(DGET stays as VAL — Microsoft Turkish keeps the short form.)

Danish (daDK) — 3 corrections:
- DAVERAGE DGENNEMSNIT -> DMIDDEL
- DCOUNT   ANTAL.DB -> DTÆL
- DCOUNTA  ANTAL.DBV -> DTÆLV

Portuguese (ptPT) — 3 corrections:
- DCOUNTA  BDCONTARA -> BDCONTAR.VAL
- DGET     BDEXTRAIR -> BDOBTER
- DPRODUCT BDPRODUTO -> BDMULTIPL

All 24 changes verified directly against Microsoft's support pages.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The defensive CellError guard added earlier returned the error as soon
as a matching row with a field error was seen, even when more rows
also matched. Excel's DGET resolves the "multiple matches → #NUM!"
check first and only surfaces field errors when exactly one record
matches.

Move the CellError check to after the loop so the match count is
finalised first. Addresses Cursor Bugbot finding.

Regression tests added in hyperformula-tests.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@codecov
Copy link
Copy Markdown

codecov bot commented Apr 17, 2026

Codecov Report

❌ Patch coverage is 94.34783% with 13 lines in your changes missing coverage. Please review.
✅ Project coverage is 97.15%. Comparing base (1852159) to head (9d07107).

Files with missing lines Patch % Lines
src/interpreter/plugin/DatabasePlugin.ts 94.32% 13 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@             Coverage Diff             @@
##           develop    #1652      +/-   ##
===========================================
+ Coverage    96.77%   97.15%   +0.38%     
===========================================
  Files          174      175       +1     
  Lines        15086    15316     +230     
  Branches      3223     3286      +63     
===========================================
+ Hits         14599    14880     +281     
+ Misses         487      436      -51     
Files with missing lines Coverage Δ
src/i18n/languages/csCZ.ts 100.00% <ø> (ø)
src/i18n/languages/daDK.ts 100.00% <ø> (ø)
src/i18n/languages/deDE.ts 100.00% <ø> (ø)
src/i18n/languages/enGB.ts 100.00% <ø> (ø)
src/i18n/languages/esES.ts 100.00% <ø> (ø)
src/i18n/languages/fiFI.ts 100.00% <ø> (ø)
src/i18n/languages/frFR.ts 100.00% <ø> (ø)
src/i18n/languages/huHU.ts 100.00% <ø> (ø)
src/i18n/languages/itIT.ts 100.00% <ø> (ø)
src/i18n/languages/nbNO.ts 100.00% <ø> (ø)
... and 8 more

... and 2 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants