diff --git a/.changeset/modern-masks-film.md b/.changeset/modern-masks-film.md deleted file mode 100644 index 1391ff5b..00000000 --- a/.changeset/modern-masks-film.md +++ /dev/null @@ -1,131 +0,0 @@ ---- -'@rushdb/javascript-sdk': minor -'rushdb-dashboard': minor -'rushdb-core': minor -'rushdb-website': minor -'rushdb-docs': minor ---- - -## Summary -Adds first-class grouping support to the Search API (`groupBy`) across core, JavaScript SDK, dashboard, website, and docs. Also standardizes terminology (`uniq` -> `unique`), refines aggregation semantics, and updates documentation with a dedicated grouping concept page. - ---- -## ✨ New Feature: `groupBy` Clause -You can now pivot / summarize search results by one or more keys. Keys reference an alias + property (root alias is implicitly `$record`). - -Example (JS SDK): -```ts -const dealsByStage = await db.records.find({ - labels: ['HS_DEAL'], - aggregate: { - count: { fn: 'count', alias: '$record' }, - avgAmount: { fn: 'avg', field: 'amount', alias: '$record' } - }, - groupBy: ['$record.dealstage'], - orderBy: { count: 'desc' } -}); -// β†’ rows like: [{ dealstage: 'prospecting', count: 120, avgAmount: 3400 }, ...] -``` - -Key capabilities: -* Multiple grouping keys: `groupBy: ['$record.category', '$record.active']` -* Group by related aliases (declare alias in `where` traversal first) -* Works with all existing aggregation functions (count, sum, avg, min, max, collect, similarity, etc.) -* Ordering applies to aggregated rows when `groupBy` is present -* Requires at least one aggregation entry to take effect - -Result shape when using `groupBy`: each row contains only the grouping fields plus aggregated fields (raw record bodies are not returned unless you also aggregate them via `collect`). - ---- -## πŸ”„ Aggregation & Semantics Updates -* `collect` results are unique by default. Set `unique: false` to retain duplicates. -* Aggregation entries now consistently use the `unique` flag (replacing legacy `uniq`). -* Distinct handling for grouped queries unified under the `unique` option. -* Improved Cypher generation: clearer alias usage and property quoting; vector similarity function formatting tightened. -* Added internal `PROPERTY_WILDCARD_PROJECTION` support (enables future selective projections) – not yet a public API, but impacts generated queries. - ---- -## πŸ’₯ Breaking Changes -| Area | Change | Action Required | -|------|--------|-----------------| -| Schema field definitions | `uniq` key renamed to `unique` | Rename all occurrences (`{ uniq: true }` β†’ `{ unique: true }`). | -| Aggregation definitions | Aggregator option `uniq` renamed to `unique` | Update custom aggregation objects (`uniq: false` β†’ `unique: false`). | -| Result shape (when using `groupBy`) | Raw record objects no longer returned automatically | If you previously expected full records, add a `collect` aggregation (e.g. `rows: { fn: 'collect', alias: '$record' }`). | -| Default uniqueness for `collect` | Now unique by default | Add `unique: false` if you require duplicates. | -| Internal alias constant | `DEFAULT_RECORD_ALIAS` β†’ `ROOT_RECORD_ALIAS` | Only relevant if you referenced internal constants (avoid relying on these). | - -If any code or saved JSON queries still send `uniq`, they will now fail unless a compatibility shim exists (none added in this release). Treat this as a required migration. - ---- -## πŸ›  Migration Guide -1. Rename all schema property options: - * Before: `email: { type: 'string', uniq: true }` - * After: `email: { type: 'string', unique: true }` -2. Update aggregation specs: - * Before: `names: { fn: 'collect', field: 'name', alias: '$user', uniq: true }` - * After: `names: { fn: 'collect', field: 'name', alias: '$user' }` (omit `unique` if true) -3. Reintroduce duplicate collection (if needed): add `unique: false`. -4. When adopting `groupBy`, ensure at least one aggregation is defined; queries with only `groupBy` are invalid. -5. Adjust consumer code to handle aggregated row shape instead of full record instances. -6. For hierarchical drill‑downs: group at the parent level; use nested `collect` for children instead of adding child keys to `groupBy`. - -### Example Migration (JS) -```diff - aggregate: { -- employeeNames: { fn: 'collect', field: 'name', alias: '$employee', uniq: true }, -+ employeeNames: { fn: 'collect', field: 'name', alias: '$employee' }, - } -``` - -### Adding Grouping -```ts -const deptProjects = await db.records.find({ - labels: ['DEPARTMENT'], - where: { PROJECT: { $alias: '$project' } }, - aggregate: { - projectCount: { fn: 'count', alias: '$project' }, - projects: { fn: 'collect', field: 'name', alias: '$project', unique: true } - }, - groupBy: ['$record.name'], - orderBy: { projectCount: 'desc' } -}); -``` - ---- -## πŸ“˜ Documentation -* Added dedicated concept page: `concepts/search/group-by` centralizing all grouping patterns (multi-key, alias-based, nested, uniqueness nuances, limitations). -* Updated Python, REST, and TypeScript SDK "Get Records" guides with concise grouping sections linking to the concept page. -* Refactored Aggregations doc to avoid duplication and point to new grouping guide. -* Standardized examples to use `unique` terminology. - ---- -## πŸ§ͺ Tests & Internal Refactors -* Extended aggregate & query builder tests to cover `groupBy` permutations (single key, multi-key, alias grouping, collect uniqueness flags). -* Parser adjustments for: property quoting, alias resolution, vector similarity formatting, optional matches, and root alias constant rename. -* Introduced `AggregateContext` enhancements to track grouping state. - ---- -## ⚠️ Edge Cases & Notes -* An empty `groupBy` array is ignored; supply at least one key. -* Supplying a group key for a property that does not exist yields rows with `null` for that column (consistent with underlying graph behavior) – validate upstream if needed. -* Ordering by an aggregation that isn't defined will be rejected; always define the aggregate you sort by. -* To sort by a group key, just reference it in `orderBy` using the property name (without alias prefix) after grouping. - ---- -## βœ… Quick Checklist -| Task | Done? | -|------|-------| -| Renamed all `uniq` β†’ `unique` in schema & aggregations | | -| Reviewed any `collect` aggregations for unintended de-duplication | | -| Added `unique: false` where duplicates are required | | -| Updated UI / API consumers for aggregated row shape under `groupBy` | | -| Added `collect` fields if raw record snapshots are still needed | | -| Added / validated ordering under grouped queries | | - ---- -## Feedback -Please report any unexpected behavior with grouped queries (especially multi-key or alias-based grouping) so we can refine edge case handling in upcoming releases. - ---- -## TL;DR -Use `groupBy` + `aggregate` to pivot results; rename `uniq` β†’ `unique`; `collect` is now unique by default; aggregated queries return row sets, not raw records. \ No newline at end of file diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index eb79ddfb..a72887ec 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -1,5 +1,157 @@ # rushdb-docs +## 1.15.0 + +### Minor Changes + +- 7f19708: ## Summary + Adds first-class grouping support to the Search API (`groupBy`) across core, JavaScript SDK, dashboard, website, and docs. Also standardizes terminology (`uniq` -> `unique`), refines aggregation semantics, and updates documentation with a dedicated grouping concept page. + + *** + + ## ✨ New Feature: `groupBy` Clause + + You can now pivot / summarize search results by one or more keys. Keys reference an alias + property (root alias is implicitly `$record`). + + Example (JS SDK): + + ```ts + const dealsByStage = await db.records.find({ + labels: ['HS_DEAL'], + aggregate: { + count: { fn: 'count', alias: '$record' }, + avgAmount: { fn: 'avg', field: 'amount', alias: '$record' } + }, + groupBy: ['$record.dealstage'], + orderBy: { count: 'desc' } + }) + // β†’ rows like: [{ dealstage: 'prospecting', count: 120, avgAmount: 3400 }, ...] + ``` + + Key capabilities: + + - Multiple grouping keys: `groupBy: ['$record.category', '$record.active']` + - Group by related aliases (declare alias in `where` traversal first) + - Works with all existing aggregation functions (count, sum, avg, min, max, collect, similarity, etc.) + - Ordering applies to aggregated rows when `groupBy` is present + - Requires at least one aggregation entry to take effect + + Result shape when using `groupBy`: each row contains only the grouping fields plus aggregated fields (raw record bodies are not returned unless you also aggregate them via `collect`). + + *** + + ## πŸ”„ Aggregation & Semantics Updates + + - `collect` results are unique by default. Set `unique: false` to retain duplicates. + - Aggregation entries now consistently use the `unique` flag (replacing legacy `uniq`). + - Distinct handling for grouped queries unified under the `unique` option. + - Improved Cypher generation: clearer alias usage and property quoting; vector similarity function formatting tightened. + - Added internal `PROPERTY_WILDCARD_PROJECTION` support (enables future selective projections) – not yet a public API, but impacts generated queries. + + *** + + ## πŸ’₯ Breaking Changes + + | Area | Change | Action Required | + | ----------------------------------- | --------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ | + | Schema field definitions | `uniq` key renamed to `unique` | Rename all occurrences (`{ uniq: true }` β†’ `{ unique: true }`). | + | Aggregation definitions | Aggregator option `uniq` renamed to `unique` | Update custom aggregation objects (`uniq: false` β†’ `unique: false`). | + | Result shape (when using `groupBy`) | Raw record objects no longer returned automatically | If you previously expected full records, add a `collect` aggregation (e.g. `rows: { fn: 'collect', alias: '$record' }`). | + | Default uniqueness for `collect` | Now unique by default | Add `unique: false` if you require duplicates. | + | Internal alias constant | `DEFAULT_RECORD_ALIAS` β†’ `ROOT_RECORD_ALIAS` | Only relevant if you referenced internal constants (avoid relying on these). | + + If any code or saved JSON queries still send `uniq`, they will now fail unless a compatibility shim exists (none added in this release). Treat this as a required migration. + + *** + + ## πŸ›  Migration Guide + + 1. Rename all schema property options: + - Before: `email: { type: 'string', uniq: true }` + - After: `email: { type: 'string', unique: true }` + 2. Update aggregation specs: + - Before: `names: { fn: 'collect', field: 'name', alias: '$user', uniq: true }` + - After: `names: { fn: 'collect', field: 'name', alias: '$user' }` (omit `unique` if true) + 3. Reintroduce duplicate collection (if needed): add `unique: false`. + 4. When adopting `groupBy`, ensure at least one aggregation is defined; queries with only `groupBy` are invalid. + 5. Adjust consumer code to handle aggregated row shape instead of full record instances. + 6. For hierarchical drill‑downs: group at the parent level; use nested `collect` for children instead of adding child keys to `groupBy`. + + ### Example Migration (JS) + + ```diff + aggregate: { + - employeeNames: { fn: 'collect', field: 'name', alias: '$employee', uniq: true }, + + employeeNames: { fn: 'collect', field: 'name', alias: '$employee' }, + } + ``` + + ### Adding Grouping + + ```ts + const deptProjects = await db.records.find({ + labels: ['DEPARTMENT'], + where: { PROJECT: { $alias: '$project' } }, + aggregate: { + projectCount: { fn: 'count', alias: '$project' }, + projects: { fn: 'collect', field: 'name', alias: '$project', unique: true } + }, + groupBy: ['$record.name'], + orderBy: { projectCount: 'desc' } + }) + ``` + + *** + + ## πŸ“˜ Documentation + + - Added dedicated concept page: `concepts/search/group-by` centralizing all grouping patterns (multi-key, alias-based, nested, uniqueness nuances, limitations). + - Updated Python, REST, and TypeScript SDK "Get Records" guides with concise grouping sections linking to the concept page. + - Refactored Aggregations doc to avoid duplication and point to new grouping guide. + - Standardized examples to use `unique` terminology. + + *** + + ## πŸ§ͺ Tests & Internal Refactors + + - Extended aggregate & query builder tests to cover `groupBy` permutations (single key, multi-key, alias grouping, collect uniqueness flags). + - Parser adjustments for: property quoting, alias resolution, vector similarity formatting, optional matches, and root alias constant rename. + - Introduced `AggregateContext` enhancements to track grouping state. + + *** + + ## ⚠️ Edge Cases & Notes + + - An empty `groupBy` array is ignored; supply at least one key. + - Supplying a group key for a property that does not exist yields rows with `null` for that column (consistent with underlying graph behavior) – validate upstream if needed. + - Ordering by an aggregation that isn't defined will be rejected; always define the aggregate you sort by. + - To sort by a group key, just reference it in `orderBy` using the property name (without alias prefix) after grouping. + + *** + + ## βœ… Quick Checklist + + | Task | Done? | + | ------------------------------------------------------------------- | ----- | + | Renamed all `uniq` β†’ `unique` in schema & aggregations | | + | Reviewed any `collect` aggregations for unintended de-duplication | | + | Added `unique: false` where duplicates are required | | + | Updated UI / API consumers for aggregated row shape under `groupBy` | | + | Added `collect` fields if raw record snapshots are still needed | | + | Added / validated ordering under grouped queries | | + + *** + + ## Feedback + + Please report any unexpected behavior with grouped queries (especially multi-key or alias-based grouping) so we can refine edge case handling in upcoming releases. + + *** + + ## TL;DR + + Use `groupBy` + `aggregate` to pivot results; rename `uniq` β†’ `unique`; `collect` is now unique by default; aggregated queries return row sets, not raw records. + ## 1.14.2 ### Patch Changes diff --git a/docs/package.json b/docs/package.json index 65c32663..c85fd643 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "rushdb-docs", - "version": "1.14.2", + "version": "1.15.0", "private": true, "license": "Apache-2.0", "scripts": { diff --git a/packages/javascript-sdk/CHANGELOG.md b/packages/javascript-sdk/CHANGELOG.md index 83cb1955..cfd587e4 100644 --- a/packages/javascript-sdk/CHANGELOG.md +++ b/packages/javascript-sdk/CHANGELOG.md @@ -1,5 +1,157 @@ # @rushdb/javascript-sdk +## 1.15.0 + +### Minor Changes + +- 7f19708: ## Summary + Adds first-class grouping support to the Search API (`groupBy`) across core, JavaScript SDK, dashboard, website, and docs. Also standardizes terminology (`uniq` -> `unique`), refines aggregation semantics, and updates documentation with a dedicated grouping concept page. + + *** + + ## ✨ New Feature: `groupBy` Clause + + You can now pivot / summarize search results by one or more keys. Keys reference an alias + property (root alias is implicitly `$record`). + + Example (JS SDK): + + ```ts + const dealsByStage = await db.records.find({ + labels: ['HS_DEAL'], + aggregate: { + count: { fn: 'count', alias: '$record' }, + avgAmount: { fn: 'avg', field: 'amount', alias: '$record' } + }, + groupBy: ['$record.dealstage'], + orderBy: { count: 'desc' } + }) + // β†’ rows like: [{ dealstage: 'prospecting', count: 120, avgAmount: 3400 }, ...] + ``` + + Key capabilities: + + - Multiple grouping keys: `groupBy: ['$record.category', '$record.active']` + - Group by related aliases (declare alias in `where` traversal first) + - Works with all existing aggregation functions (count, sum, avg, min, max, collect, similarity, etc.) + - Ordering applies to aggregated rows when `groupBy` is present + - Requires at least one aggregation entry to take effect + + Result shape when using `groupBy`: each row contains only the grouping fields plus aggregated fields (raw record bodies are not returned unless you also aggregate them via `collect`). + + *** + + ## πŸ”„ Aggregation & Semantics Updates + + - `collect` results are unique by default. Set `unique: false` to retain duplicates. + - Aggregation entries now consistently use the `unique` flag (replacing legacy `uniq`). + - Distinct handling for grouped queries unified under the `unique` option. + - Improved Cypher generation: clearer alias usage and property quoting; vector similarity function formatting tightened. + - Added internal `PROPERTY_WILDCARD_PROJECTION` support (enables future selective projections) – not yet a public API, but impacts generated queries. + + *** + + ## πŸ’₯ Breaking Changes + + | Area | Change | Action Required | + | ----------------------------------- | --------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ | + | Schema field definitions | `uniq` key renamed to `unique` | Rename all occurrences (`{ uniq: true }` β†’ `{ unique: true }`). | + | Aggregation definitions | Aggregator option `uniq` renamed to `unique` | Update custom aggregation objects (`uniq: false` β†’ `unique: false`). | + | Result shape (when using `groupBy`) | Raw record objects no longer returned automatically | If you previously expected full records, add a `collect` aggregation (e.g. `rows: { fn: 'collect', alias: '$record' }`). | + | Default uniqueness for `collect` | Now unique by default | Add `unique: false` if you require duplicates. | + | Internal alias constant | `DEFAULT_RECORD_ALIAS` β†’ `ROOT_RECORD_ALIAS` | Only relevant if you referenced internal constants (avoid relying on these). | + + If any code or saved JSON queries still send `uniq`, they will now fail unless a compatibility shim exists (none added in this release). Treat this as a required migration. + + *** + + ## πŸ›  Migration Guide + + 1. Rename all schema property options: + - Before: `email: { type: 'string', uniq: true }` + - After: `email: { type: 'string', unique: true }` + 2. Update aggregation specs: + - Before: `names: { fn: 'collect', field: 'name', alias: '$user', uniq: true }` + - After: `names: { fn: 'collect', field: 'name', alias: '$user' }` (omit `unique` if true) + 3. Reintroduce duplicate collection (if needed): add `unique: false`. + 4. When adopting `groupBy`, ensure at least one aggregation is defined; queries with only `groupBy` are invalid. + 5. Adjust consumer code to handle aggregated row shape instead of full record instances. + 6. For hierarchical drill‑downs: group at the parent level; use nested `collect` for children instead of adding child keys to `groupBy`. + + ### Example Migration (JS) + + ```diff + aggregate: { + - employeeNames: { fn: 'collect', field: 'name', alias: '$employee', uniq: true }, + + employeeNames: { fn: 'collect', field: 'name', alias: '$employee' }, + } + ``` + + ### Adding Grouping + + ```ts + const deptProjects = await db.records.find({ + labels: ['DEPARTMENT'], + where: { PROJECT: { $alias: '$project' } }, + aggregate: { + projectCount: { fn: 'count', alias: '$project' }, + projects: { fn: 'collect', field: 'name', alias: '$project', unique: true } + }, + groupBy: ['$record.name'], + orderBy: { projectCount: 'desc' } + }) + ``` + + *** + + ## πŸ“˜ Documentation + + - Added dedicated concept page: `concepts/search/group-by` centralizing all grouping patterns (multi-key, alias-based, nested, uniqueness nuances, limitations). + - Updated Python, REST, and TypeScript SDK "Get Records" guides with concise grouping sections linking to the concept page. + - Refactored Aggregations doc to avoid duplication and point to new grouping guide. + - Standardized examples to use `unique` terminology. + + *** + + ## πŸ§ͺ Tests & Internal Refactors + + - Extended aggregate & query builder tests to cover `groupBy` permutations (single key, multi-key, alias grouping, collect uniqueness flags). + - Parser adjustments for: property quoting, alias resolution, vector similarity formatting, optional matches, and root alias constant rename. + - Introduced `AggregateContext` enhancements to track grouping state. + + *** + + ## ⚠️ Edge Cases & Notes + + - An empty `groupBy` array is ignored; supply at least one key. + - Supplying a group key for a property that does not exist yields rows with `null` for that column (consistent with underlying graph behavior) – validate upstream if needed. + - Ordering by an aggregation that isn't defined will be rejected; always define the aggregate you sort by. + - To sort by a group key, just reference it in `orderBy` using the property name (without alias prefix) after grouping. + + *** + + ## βœ… Quick Checklist + + | Task | Done? | + | ------------------------------------------------------------------- | ----- | + | Renamed all `uniq` β†’ `unique` in schema & aggregations | | + | Reviewed any `collect` aggregations for unintended de-duplication | | + | Added `unique: false` where duplicates are required | | + | Updated UI / API consumers for aggregated row shape under `groupBy` | | + | Added `collect` fields if raw record snapshots are still needed | | + | Added / validated ordering under grouped queries | | + + *** + + ## Feedback + + Please report any unexpected behavior with grouped queries (especially multi-key or alias-based grouping) so we can refine edge case handling in upcoming releases. + + *** + + ## TL;DR + + Use `groupBy` + `aggregate` to pivot results; rename `uniq` β†’ `unique`; `collect` is now unique by default; aggregated queries return row sets, not raw records. + ## 1.14.2 ### Patch Changes diff --git a/packages/javascript-sdk/package.json b/packages/javascript-sdk/package.json index de31e499..24aa2dfc 100644 --- a/packages/javascript-sdk/package.json +++ b/packages/javascript-sdk/package.json @@ -33,7 +33,7 @@ "rushdb" ], "license": "Apache-2.0", - "version": "1.14.2", + "version": "1.15.0", "type": "module", "files": [ "dist" diff --git a/platform/core/CHANGELOG.md b/platform/core/CHANGELOG.md index aaa05b2a..7d3b1ed6 100644 --- a/platform/core/CHANGELOG.md +++ b/platform/core/CHANGELOG.md @@ -1,5 +1,157 @@ # rushdb-core +## 1.15.0 + +### Minor Changes + +- 7f19708: ## Summary + Adds first-class grouping support to the Search API (`groupBy`) across core, JavaScript SDK, dashboard, website, and docs. Also standardizes terminology (`uniq` -> `unique`), refines aggregation semantics, and updates documentation with a dedicated grouping concept page. + + *** + + ## ✨ New Feature: `groupBy` Clause + + You can now pivot / summarize search results by one or more keys. Keys reference an alias + property (root alias is implicitly `$record`). + + Example (JS SDK): + + ```ts + const dealsByStage = await db.records.find({ + labels: ['HS_DEAL'], + aggregate: { + count: { fn: 'count', alias: '$record' }, + avgAmount: { fn: 'avg', field: 'amount', alias: '$record' } + }, + groupBy: ['$record.dealstage'], + orderBy: { count: 'desc' } + }) + // β†’ rows like: [{ dealstage: 'prospecting', count: 120, avgAmount: 3400 }, ...] + ``` + + Key capabilities: + + - Multiple grouping keys: `groupBy: ['$record.category', '$record.active']` + - Group by related aliases (declare alias in `where` traversal first) + - Works with all existing aggregation functions (count, sum, avg, min, max, collect, similarity, etc.) + - Ordering applies to aggregated rows when `groupBy` is present + - Requires at least one aggregation entry to take effect + + Result shape when using `groupBy`: each row contains only the grouping fields plus aggregated fields (raw record bodies are not returned unless you also aggregate them via `collect`). + + *** + + ## πŸ”„ Aggregation & Semantics Updates + + - `collect` results are unique by default. Set `unique: false` to retain duplicates. + - Aggregation entries now consistently use the `unique` flag (replacing legacy `uniq`). + - Distinct handling for grouped queries unified under the `unique` option. + - Improved Cypher generation: clearer alias usage and property quoting; vector similarity function formatting tightened. + - Added internal `PROPERTY_WILDCARD_PROJECTION` support (enables future selective projections) – not yet a public API, but impacts generated queries. + + *** + + ## πŸ’₯ Breaking Changes + + | Area | Change | Action Required | + | ----------------------------------- | --------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ | + | Schema field definitions | `uniq` key renamed to `unique` | Rename all occurrences (`{ uniq: true }` β†’ `{ unique: true }`). | + | Aggregation definitions | Aggregator option `uniq` renamed to `unique` | Update custom aggregation objects (`uniq: false` β†’ `unique: false`). | + | Result shape (when using `groupBy`) | Raw record objects no longer returned automatically | If you previously expected full records, add a `collect` aggregation (e.g. `rows: { fn: 'collect', alias: '$record' }`). | + | Default uniqueness for `collect` | Now unique by default | Add `unique: false` if you require duplicates. | + | Internal alias constant | `DEFAULT_RECORD_ALIAS` β†’ `ROOT_RECORD_ALIAS` | Only relevant if you referenced internal constants (avoid relying on these). | + + If any code or saved JSON queries still send `uniq`, they will now fail unless a compatibility shim exists (none added in this release). Treat this as a required migration. + + *** + + ## πŸ›  Migration Guide + + 1. Rename all schema property options: + - Before: `email: { type: 'string', uniq: true }` + - After: `email: { type: 'string', unique: true }` + 2. Update aggregation specs: + - Before: `names: { fn: 'collect', field: 'name', alias: '$user', uniq: true }` + - After: `names: { fn: 'collect', field: 'name', alias: '$user' }` (omit `unique` if true) + 3. Reintroduce duplicate collection (if needed): add `unique: false`. + 4. When adopting `groupBy`, ensure at least one aggregation is defined; queries with only `groupBy` are invalid. + 5. Adjust consumer code to handle aggregated row shape instead of full record instances. + 6. For hierarchical drill‑downs: group at the parent level; use nested `collect` for children instead of adding child keys to `groupBy`. + + ### Example Migration (JS) + + ```diff + aggregate: { + - employeeNames: { fn: 'collect', field: 'name', alias: '$employee', uniq: true }, + + employeeNames: { fn: 'collect', field: 'name', alias: '$employee' }, + } + ``` + + ### Adding Grouping + + ```ts + const deptProjects = await db.records.find({ + labels: ['DEPARTMENT'], + where: { PROJECT: { $alias: '$project' } }, + aggregate: { + projectCount: { fn: 'count', alias: '$project' }, + projects: { fn: 'collect', field: 'name', alias: '$project', unique: true } + }, + groupBy: ['$record.name'], + orderBy: { projectCount: 'desc' } + }) + ``` + + *** + + ## πŸ“˜ Documentation + + - Added dedicated concept page: `concepts/search/group-by` centralizing all grouping patterns (multi-key, alias-based, nested, uniqueness nuances, limitations). + - Updated Python, REST, and TypeScript SDK "Get Records" guides with concise grouping sections linking to the concept page. + - Refactored Aggregations doc to avoid duplication and point to new grouping guide. + - Standardized examples to use `unique` terminology. + + *** + + ## πŸ§ͺ Tests & Internal Refactors + + - Extended aggregate & query builder tests to cover `groupBy` permutations (single key, multi-key, alias grouping, collect uniqueness flags). + - Parser adjustments for: property quoting, alias resolution, vector similarity formatting, optional matches, and root alias constant rename. + - Introduced `AggregateContext` enhancements to track grouping state. + + *** + + ## ⚠️ Edge Cases & Notes + + - An empty `groupBy` array is ignored; supply at least one key. + - Supplying a group key for a property that does not exist yields rows with `null` for that column (consistent with underlying graph behavior) – validate upstream if needed. + - Ordering by an aggregation that isn't defined will be rejected; always define the aggregate you sort by. + - To sort by a group key, just reference it in `orderBy` using the property name (without alias prefix) after grouping. + + *** + + ## βœ… Quick Checklist + + | Task | Done? | + | ------------------------------------------------------------------- | ----- | + | Renamed all `uniq` β†’ `unique` in schema & aggregations | | + | Reviewed any `collect` aggregations for unintended de-duplication | | + | Added `unique: false` where duplicates are required | | + | Updated UI / API consumers for aggregated row shape under `groupBy` | | + | Added `collect` fields if raw record snapshots are still needed | | + | Added / validated ordering under grouped queries | | + + *** + + ## Feedback + + Please report any unexpected behavior with grouped queries (especially multi-key or alias-based grouping) so we can refine edge case handling in upcoming releases. + + *** + + ## TL;DR + + Use `groupBy` + `aggregate` to pivot results; rename `uniq` β†’ `unique`; `collect` is now unique by default; aggregated queries return row sets, not raw records. + ## 1.14.2 ### Patch Changes diff --git a/platform/core/package.json b/platform/core/package.json index 6218e1db..52dc2120 100755 --- a/platform/core/package.json +++ b/platform/core/package.json @@ -1,6 +1,6 @@ { "name": "rushdb-core", - "version": "1.14.2", + "version": "1.15.0", "description": "RushDB Core", "private": true, "license": "Elastic License 2.0", diff --git a/platform/dashboard/CHANGELOG.md b/platform/dashboard/CHANGELOG.md index ed4a3ca4..9ebdb1ef 100644 --- a/platform/dashboard/CHANGELOG.md +++ b/platform/dashboard/CHANGELOG.md @@ -1,5 +1,162 @@ # rushdb-dashboard +## 1.15.0 + +### Minor Changes + +- 7f19708: ## Summary + Adds first-class grouping support to the Search API (`groupBy`) across core, JavaScript SDK, dashboard, website, and docs. Also standardizes terminology (`uniq` -> `unique`), refines aggregation semantics, and updates documentation with a dedicated grouping concept page. + + *** + + ## ✨ New Feature: `groupBy` Clause + + You can now pivot / summarize search results by one or more keys. Keys reference an alias + property (root alias is implicitly `$record`). + + Example (JS SDK): + + ```ts + const dealsByStage = await db.records.find({ + labels: ['HS_DEAL'], + aggregate: { + count: { fn: 'count', alias: '$record' }, + avgAmount: { fn: 'avg', field: 'amount', alias: '$record' } + }, + groupBy: ['$record.dealstage'], + orderBy: { count: 'desc' } + }) + // β†’ rows like: [{ dealstage: 'prospecting', count: 120, avgAmount: 3400 }, ...] + ``` + + Key capabilities: + + - Multiple grouping keys: `groupBy: ['$record.category', '$record.active']` + - Group by related aliases (declare alias in `where` traversal first) + - Works with all existing aggregation functions (count, sum, avg, min, max, collect, similarity, etc.) + - Ordering applies to aggregated rows when `groupBy` is present + - Requires at least one aggregation entry to take effect + + Result shape when using `groupBy`: each row contains only the grouping fields plus aggregated fields (raw record bodies are not returned unless you also aggregate them via `collect`). + + *** + + ## πŸ”„ Aggregation & Semantics Updates + + - `collect` results are unique by default. Set `unique: false` to retain duplicates. + - Aggregation entries now consistently use the `unique` flag (replacing legacy `uniq`). + - Distinct handling for grouped queries unified under the `unique` option. + - Improved Cypher generation: clearer alias usage and property quoting; vector similarity function formatting tightened. + - Added internal `PROPERTY_WILDCARD_PROJECTION` support (enables future selective projections) – not yet a public API, but impacts generated queries. + + *** + + ## πŸ’₯ Breaking Changes + + | Area | Change | Action Required | + | ----------------------------------- | --------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ | + | Schema field definitions | `uniq` key renamed to `unique` | Rename all occurrences (`{ uniq: true }` β†’ `{ unique: true }`). | + | Aggregation definitions | Aggregator option `uniq` renamed to `unique` | Update custom aggregation objects (`uniq: false` β†’ `unique: false`). | + | Result shape (when using `groupBy`) | Raw record objects no longer returned automatically | If you previously expected full records, add a `collect` aggregation (e.g. `rows: { fn: 'collect', alias: '$record' }`). | + | Default uniqueness for `collect` | Now unique by default | Add `unique: false` if you require duplicates. | + | Internal alias constant | `DEFAULT_RECORD_ALIAS` β†’ `ROOT_RECORD_ALIAS` | Only relevant if you referenced internal constants (avoid relying on these). | + + If any code or saved JSON queries still send `uniq`, they will now fail unless a compatibility shim exists (none added in this release). Treat this as a required migration. + + *** + + ## πŸ›  Migration Guide + + 1. Rename all schema property options: + - Before: `email: { type: 'string', uniq: true }` + - After: `email: { type: 'string', unique: true }` + 2. Update aggregation specs: + - Before: `names: { fn: 'collect', field: 'name', alias: '$user', uniq: true }` + - After: `names: { fn: 'collect', field: 'name', alias: '$user' }` (omit `unique` if true) + 3. Reintroduce duplicate collection (if needed): add `unique: false`. + 4. When adopting `groupBy`, ensure at least one aggregation is defined; queries with only `groupBy` are invalid. + 5. Adjust consumer code to handle aggregated row shape instead of full record instances. + 6. For hierarchical drill‑downs: group at the parent level; use nested `collect` for children instead of adding child keys to `groupBy`. + + ### Example Migration (JS) + + ```diff + aggregate: { + - employeeNames: { fn: 'collect', field: 'name', alias: '$employee', uniq: true }, + + employeeNames: { fn: 'collect', field: 'name', alias: '$employee' }, + } + ``` + + ### Adding Grouping + + ```ts + const deptProjects = await db.records.find({ + labels: ['DEPARTMENT'], + where: { PROJECT: { $alias: '$project' } }, + aggregate: { + projectCount: { fn: 'count', alias: '$project' }, + projects: { fn: 'collect', field: 'name', alias: '$project', unique: true } + }, + groupBy: ['$record.name'], + orderBy: { projectCount: 'desc' } + }) + ``` + + *** + + ## πŸ“˜ Documentation + + - Added dedicated concept page: `concepts/search/group-by` centralizing all grouping patterns (multi-key, alias-based, nested, uniqueness nuances, limitations). + - Updated Python, REST, and TypeScript SDK "Get Records" guides with concise grouping sections linking to the concept page. + - Refactored Aggregations doc to avoid duplication and point to new grouping guide. + - Standardized examples to use `unique` terminology. + + *** + + ## πŸ§ͺ Tests & Internal Refactors + + - Extended aggregate & query builder tests to cover `groupBy` permutations (single key, multi-key, alias grouping, collect uniqueness flags). + - Parser adjustments for: property quoting, alias resolution, vector similarity formatting, optional matches, and root alias constant rename. + - Introduced `AggregateContext` enhancements to track grouping state. + + *** + + ## ⚠️ Edge Cases & Notes + + - An empty `groupBy` array is ignored; supply at least one key. + - Supplying a group key for a property that does not exist yields rows with `null` for that column (consistent with underlying graph behavior) – validate upstream if needed. + - Ordering by an aggregation that isn't defined will be rejected; always define the aggregate you sort by. + - To sort by a group key, just reference it in `orderBy` using the property name (without alias prefix) after grouping. + + *** + + ## βœ… Quick Checklist + + | Task | Done? | + | ------------------------------------------------------------------- | ----- | + | Renamed all `uniq` β†’ `unique` in schema & aggregations | | + | Reviewed any `collect` aggregations for unintended de-duplication | | + | Added `unique: false` where duplicates are required | | + | Updated UI / API consumers for aggregated row shape under `groupBy` | | + | Added `collect` fields if raw record snapshots are still needed | | + | Added / validated ordering under grouped queries | | + + *** + + ## Feedback + + Please report any unexpected behavior with grouped queries (especially multi-key or alias-based grouping) so we can refine edge case handling in upcoming releases. + + *** + + ## TL;DR + + Use `groupBy` + `aggregate` to pivot results; rename `uniq` β†’ `unique`; `collect` is now unique by default; aggregated queries return row sets, not raw records. + +### Patch Changes + +- Updated dependencies [7f19708] + - @rushdb/javascript-sdk@1.15.0 + ## 1.14.2 ### Patch Changes diff --git a/platform/dashboard/package.json b/platform/dashboard/package.json index 7786626f..19385d1b 100644 --- a/platform/dashboard/package.json +++ b/platform/dashboard/package.json @@ -1,6 +1,6 @@ { "name": "rushdb-dashboard", - "version": "1.14.2", + "version": "1.15.0", "description": "RushDB Dashboard", "type": "module", "private": true, diff --git a/website/CHANGELOG.md b/website/CHANGELOG.md index b0b06fa8..61863936 100644 --- a/website/CHANGELOG.md +++ b/website/CHANGELOG.md @@ -1,5 +1,162 @@ # rushdb-website +## 1.15.0 + +### Minor Changes + +- 7f19708: ## Summary + Adds first-class grouping support to the Search API (`groupBy`) across core, JavaScript SDK, dashboard, website, and docs. Also standardizes terminology (`uniq` -> `unique`), refines aggregation semantics, and updates documentation with a dedicated grouping concept page. + + *** + + ## ✨ New Feature: `groupBy` Clause + + You can now pivot / summarize search results by one or more keys. Keys reference an alias + property (root alias is implicitly `$record`). + + Example (JS SDK): + + ```ts + const dealsByStage = await db.records.find({ + labels: ['HS_DEAL'], + aggregate: { + count: { fn: 'count', alias: '$record' }, + avgAmount: { fn: 'avg', field: 'amount', alias: '$record' } + }, + groupBy: ['$record.dealstage'], + orderBy: { count: 'desc' } + }) + // β†’ rows like: [{ dealstage: 'prospecting', count: 120, avgAmount: 3400 }, ...] + ``` + + Key capabilities: + + - Multiple grouping keys: `groupBy: ['$record.category', '$record.active']` + - Group by related aliases (declare alias in `where` traversal first) + - Works with all existing aggregation functions (count, sum, avg, min, max, collect, similarity, etc.) + - Ordering applies to aggregated rows when `groupBy` is present + - Requires at least one aggregation entry to take effect + + Result shape when using `groupBy`: each row contains only the grouping fields plus aggregated fields (raw record bodies are not returned unless you also aggregate them via `collect`). + + *** + + ## πŸ”„ Aggregation & Semantics Updates + + - `collect` results are unique by default. Set `unique: false` to retain duplicates. + - Aggregation entries now consistently use the `unique` flag (replacing legacy `uniq`). + - Distinct handling for grouped queries unified under the `unique` option. + - Improved Cypher generation: clearer alias usage and property quoting; vector similarity function formatting tightened. + - Added internal `PROPERTY_WILDCARD_PROJECTION` support (enables future selective projections) – not yet a public API, but impacts generated queries. + + *** + + ## πŸ’₯ Breaking Changes + + | Area | Change | Action Required | + | ----------------------------------- | --------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ | + | Schema field definitions | `uniq` key renamed to `unique` | Rename all occurrences (`{ uniq: true }` β†’ `{ unique: true }`). | + | Aggregation definitions | Aggregator option `uniq` renamed to `unique` | Update custom aggregation objects (`uniq: false` β†’ `unique: false`). | + | Result shape (when using `groupBy`) | Raw record objects no longer returned automatically | If you previously expected full records, add a `collect` aggregation (e.g. `rows: { fn: 'collect', alias: '$record' }`). | + | Default uniqueness for `collect` | Now unique by default | Add `unique: false` if you require duplicates. | + | Internal alias constant | `DEFAULT_RECORD_ALIAS` β†’ `ROOT_RECORD_ALIAS` | Only relevant if you referenced internal constants (avoid relying on these). | + + If any code or saved JSON queries still send `uniq`, they will now fail unless a compatibility shim exists (none added in this release). Treat this as a required migration. + + *** + + ## πŸ›  Migration Guide + + 1. Rename all schema property options: + - Before: `email: { type: 'string', uniq: true }` + - After: `email: { type: 'string', unique: true }` + 2. Update aggregation specs: + - Before: `names: { fn: 'collect', field: 'name', alias: '$user', uniq: true }` + - After: `names: { fn: 'collect', field: 'name', alias: '$user' }` (omit `unique` if true) + 3. Reintroduce duplicate collection (if needed): add `unique: false`. + 4. When adopting `groupBy`, ensure at least one aggregation is defined; queries with only `groupBy` are invalid. + 5. Adjust consumer code to handle aggregated row shape instead of full record instances. + 6. For hierarchical drill‑downs: group at the parent level; use nested `collect` for children instead of adding child keys to `groupBy`. + + ### Example Migration (JS) + + ```diff + aggregate: { + - employeeNames: { fn: 'collect', field: 'name', alias: '$employee', uniq: true }, + + employeeNames: { fn: 'collect', field: 'name', alias: '$employee' }, + } + ``` + + ### Adding Grouping + + ```ts + const deptProjects = await db.records.find({ + labels: ['DEPARTMENT'], + where: { PROJECT: { $alias: '$project' } }, + aggregate: { + projectCount: { fn: 'count', alias: '$project' }, + projects: { fn: 'collect', field: 'name', alias: '$project', unique: true } + }, + groupBy: ['$record.name'], + orderBy: { projectCount: 'desc' } + }) + ``` + + *** + + ## πŸ“˜ Documentation + + - Added dedicated concept page: `concepts/search/group-by` centralizing all grouping patterns (multi-key, alias-based, nested, uniqueness nuances, limitations). + - Updated Python, REST, and TypeScript SDK "Get Records" guides with concise grouping sections linking to the concept page. + - Refactored Aggregations doc to avoid duplication and point to new grouping guide. + - Standardized examples to use `unique` terminology. + + *** + + ## πŸ§ͺ Tests & Internal Refactors + + - Extended aggregate & query builder tests to cover `groupBy` permutations (single key, multi-key, alias grouping, collect uniqueness flags). + - Parser adjustments for: property quoting, alias resolution, vector similarity formatting, optional matches, and root alias constant rename. + - Introduced `AggregateContext` enhancements to track grouping state. + + *** + + ## ⚠️ Edge Cases & Notes + + - An empty `groupBy` array is ignored; supply at least one key. + - Supplying a group key for a property that does not exist yields rows with `null` for that column (consistent with underlying graph behavior) – validate upstream if needed. + - Ordering by an aggregation that isn't defined will be rejected; always define the aggregate you sort by. + - To sort by a group key, just reference it in `orderBy` using the property name (without alias prefix) after grouping. + + *** + + ## βœ… Quick Checklist + + | Task | Done? | + | ------------------------------------------------------------------- | ----- | + | Renamed all `uniq` β†’ `unique` in schema & aggregations | | + | Reviewed any `collect` aggregations for unintended de-duplication | | + | Added `unique: false` where duplicates are required | | + | Updated UI / API consumers for aggregated row shape under `groupBy` | | + | Added `collect` fields if raw record snapshots are still needed | | + | Added / validated ordering under grouped queries | | + + *** + + ## Feedback + + Please report any unexpected behavior with grouped queries (especially multi-key or alias-based grouping) so we can refine edge case handling in upcoming releases. + + *** + + ## TL;DR + + Use `groupBy` + `aggregate` to pivot results; rename `uniq` β†’ `unique`; `collect` is now unique by default; aggregated queries return row sets, not raw records. + +### Patch Changes + +- Updated dependencies [7f19708] + - @rushdb/javascript-sdk@1.15.0 + ## 1.14.2 ### Patch Changes diff --git a/website/package.json b/website/package.json index fb6ae664..307e8288 100644 --- a/website/package.json +++ b/website/package.json @@ -1,6 +1,6 @@ { "name": "rushdb-website", - "version": "1.14.2", + "version": "1.15.0", "private": true, "license": "Apache-2.0", "scripts": {