feat(core): add em.countBy() for grouped counting#7372
Merged
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## next #7372 +/- ##
========================================
Coverage 99.65% 99.65%
========================================
Files 263 263
Lines 26888 26942 +54
Branches 6985 7455 +470
========================================
+ Hits 26794 26848 +54
Misses 88 88
Partials 6 6 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
2dcf6fe to
3b6d014
Compare
ad5be5b to
cfbd345
Compare
Adds `em.countBy(entityName, groupBy, options?)` — counts entities grouped by one or more properties, returning `Dictionary<number>`. For composite `groupBy`, result keys are joined with `~~~`. SQL drivers issue a single GROUP BY query via QueryBuilder. MongoDB uses an aggregation pipeline with `$group` + `$sum`. Also available on repositories via `repo.countBy(groupBy, options?)`. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- SQL/MongoDB countBy now calls processWhere (applies entity filters and discriminator conditions) and tryFlush (honors FlushMode.AUTO/ALWAYS) - MongoDB countBy routes through driver.aggregate() for transaction context, query logging, and error wrapping; applies renameFields to the where clause for correct field name mapping - Trim CountByOptions to only relevant properties instead of inheriting all of CountOptions - Fix unquoted SQL alias for MySQL compatibility - Move SQL countBy tests to dedicated test file with filter coverage Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Call prepareOptions() in both SQL and MongoDB countBy so EM-level schema defaults and logger context are inherited (matching every other EM method) - Throw when `having` is passed to MongoDB countBy instead of silently ignoring it - Add test for nullable groupBy columns (null publisher key) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Exercise the remaining branches of the new `countBy` API so the PR reaches 100% patch coverage on the touched source files: - base `EntityManager.countBy` throw for drivers that don't override it - SQL `having`/`schema` option paths - SQL/Mongo raw-field fallback when groupBy isn't a declared property - Mongo composite groupBy pipeline - Mongo `having` rejection
B4nan
added a commit
that referenced
this pull request
Apr 18, 2026
## Summary - Adds dataloader batching for `Collection.loadCount()` — multiple count calls in the same tick are grouped into a single query - 1:M relations: uses `em.countBy()` for a single GROUP BY query - M:N relations: falls back to parallel `em.count()` calls (entity filters correctly applied) - Adds `dataloader` option to `LoadCountOptions`, respects global `DataloaderType.ALL`/`COLLECTION` config Depends on #7372. Closes #6425 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
B4nan
added a commit
that referenced
this pull request
Apr 19, 2026
## Summary
- Adds `em.countBy(entityName, groupBy, options?)` — counts entities
grouped by one or more properties, returning `Dictionary<number>`
- Type-safe `groupBy` parameter (`EntityKey<Entity> | readonly
EntityKey<Entity>[]`)
- For composite `groupBy`, result keys are joined with `~~~`
(`Utils.PK_SEPARATOR`)
- SQL: single `GROUP BY` query via QueryBuilder
- MongoDB: aggregation pipeline with `$group` + `$sum`
- Also available on `EntityRepository` via `repo.countBy(groupBy,
options?)`
- New `CountByOptions` type extends `CountOptions` (without `groupBy`)
and adds `where`
```ts
const counts = await em.countBy(Book, 'author');
// { '1': 2, '2': 1, '3': 3 }
const counts = await em.countBy(Order, ['status', 'country']);
// { 'pending~~~US': 5, 'shipped~~~DE': 3 }
```
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
B4nan
added a commit
that referenced
this pull request
Apr 19, 2026
## Summary - Adds dataloader batching for `Collection.loadCount()` — multiple count calls in the same tick are grouped into a single query - 1:M relations: uses `em.countBy()` for a single GROUP BY query - M:N relations: falls back to parallel `em.count()` calls (entity filters correctly applied) - Adds `dataloader` option to `LoadCountOptions`, respects global `DataloaderType.ALL`/`COLLECTION` config Depends on #7372. Closes #6425 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
B4nan
added a commit
that referenced
this pull request
Apr 20, 2026
## Summary
- Adds `em.countBy(entityName, groupBy, options?)` — counts entities
grouped by one or more properties, returning `Dictionary<number>`
- Type-safe `groupBy` parameter (`EntityKey<Entity> | readonly
EntityKey<Entity>[]`)
- For composite `groupBy`, result keys are joined with `~~~`
(`Utils.PK_SEPARATOR`)
- SQL: single `GROUP BY` query via QueryBuilder
- MongoDB: aggregation pipeline with `$group` + `$sum`
- Also available on `EntityRepository` via `repo.countBy(groupBy,
options?)`
- New `CountByOptions` type extends `CountOptions` (without `groupBy`)
and adds `where`
```ts
const counts = await em.countBy(Book, 'author');
// { '1': 2, '2': 1, '3': 3 }
const counts = await em.countBy(Order, ['status', 'country']);
// { 'pending~~~US': 5, 'shipped~~~DE': 3 }
```
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
B4nan
added a commit
that referenced
this pull request
Apr 20, 2026
## Summary - Adds dataloader batching for `Collection.loadCount()` — multiple count calls in the same tick are grouped into a single query - 1:M relations: uses `em.countBy()` for a single GROUP BY query - M:N relations: falls back to parallel `em.count()` calls (entity filters correctly applied) - Adds `dataloader` option to `LoadCountOptions`, respects global `DataloaderType.ALL`/`COLLECTION` config Depends on #7372. Closes #6425 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
em.countBy(entityName, groupBy, options?)— counts entities grouped by one or more properties, returningDictionary<number>groupByparameter (EntityKey<Entity> | readonly EntityKey<Entity>[])groupBy, result keys are joined with~~~(Utils.PK_SEPARATOR)GROUP BYquery via QueryBuilder$group+$sumEntityRepositoryviarepo.countBy(groupBy, options?)CountByOptionstype extendsCountOptions(withoutgroupBy) and addswhere🤖 Generated with Claude Code