From 3e4a673fdbe3fffbad39815acb9a215e42c81e87 Mon Sep 17 00:00:00 2001 From: Dmitry Kurochkin Date: Thu, 24 Sep 2026 11:33:24 +0000 Subject: [PATCH 1/4] fix(schema): require groupBy when having is present Add dependentRequired { having: [groupBy] } to the root object and minItems: 1 on groupBy, so having without grouping (or with an empty groupBy) fails validation. Bump version to 0.1.0-preview.1.0.0 and update CHANGELOG and README. Closes #40 Co-Authored-By: Claude Opus 5.5 --- CHANGELOG.md | 13 +++++++++++++ PureQL-Specification.json | 10 ++++++++-- README.md | 6 +++--- 3 files changed, 24 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dbd626c..5411bb0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,19 @@ Versioning follows Semantic Versioning with preview suffix `major.minor.patch-pr --- +## [0.1.0-preview.1.0.0] - 2026-09-24 + +Makes `having` without `groupBy` a schema error. `having` filters aggregation groups, so without `groupBy` it has no defined meaning; the schema previously accepted such queries silently. + +Tracking issue: #40. + +### Changed + +- **`having` now requires `groupBy`**: the root object declares `"dependentRequired": { "having": ["groupBy"] }`. Queries that use `having` without `groupBy` no longer validate. +- **`groupBy` now requires at least one field** (`minItems: 1`). An empty `groupBy` array no longer validates; omit the clause instead. + +--- + ## [0.1.0-preview.0.5.0] - 2026-05-25 Introduces sort direction control for `orderBy`. Previously `orderBy` accepted bare field references, making sort direction implementation-defined. Queries that used bare fields in `orderBy` must be migrated to the new `orderByItem` wrapper. diff --git a/PureQL-Specification.json b/PureQL-Specification.json index 7f90964..d730952 100644 --- a/PureQL-Specification.json +++ b/PureQL-Specification.json @@ -1,7 +1,7 @@ { "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://github.com/kudima03/PureQL-Specification/releases/download/0.1.0-preview.0.5.0/PureQL-Specification.json", - "version": "0.1.0-preview.0.5.0", + "$id": "https://github.com/kudima03/PureQL-Specification/releases/download/0.1.0-preview.1.0.0/PureQL-Specification.json", + "version": "0.1.0-preview.1.0.0", "definitions": { "arrayParameters": { "stringArrayParameter": { @@ -3238,6 +3238,7 @@ }, "groupBy": { "type": "array", + "minItems": 1, "items": { "$ref": "#/definitions/field" } @@ -3259,6 +3260,11 @@ "from", "select" ], + "dependentRequired": { + "having": [ + "groupBy" + ] + }, "title": "PureQL specification", "type": "object" } diff --git a/README.md b/README.md index 3cf7aae..edf6e94 100644 --- a/README.md +++ b/README.md @@ -10,8 +10,8 @@ PureQL is a JSON-based declarative query language for relational data. Queries a | `select` | yes | Array of expressions to return | | `where` | no | Boolean filter applied before grouping | | `joins` | no | Array of join clauses | -| `groupBy` | no | Fields to group rows by | -| `having` | no | Boolean filter applied after grouping | +| `groupBy` | no | Fields to group rows by (at least one) | +| `having` | no | Boolean filter applied after grouping; requires `groupBy` | | `orderBy` | no | Fields to order results by | | `pagination` | no | `skip` and `take` for paging | | `distinct` | no | When `true`, deduplicate result rows (default: `false`) | @@ -104,7 +104,7 @@ Each item in `select` is a value-returning expression (field, scalar, aggregate, They accept different shapes because they evaluate in different scopes: - **`where`** is evaluated per row. It accepts either a **boolean-returning** expression (single boolean) or a **boolean-array-returning** expression (per-row boolean column). Use the `each*` family for per-row predicates against fields. -- **`having`** is evaluated per group, after `groupBy`. It accepts only a **boolean-returning** expression. Operands must reduce to a single value per group — typically aggregates compared with `greaterThan` / `equal` / etc. Per-row `each*` operators do **not** fit in `having`. +- **`having`** is evaluated per group, after `groupBy`, and requires a non-empty `groupBy` to be present. It accepts only a **boolean-returning** expression. Operands must reduce to a single value per group — typically aggregates compared with `greaterThan` / `equal` / etc. Per-row `each*` operators do **not** fit in `having`. `where` example using per-row predicates: From ef9fb0d9f8ea516ebb3244355c2ebe6eabbdc7fd Mon Sep 17 00:00:00 2001 From: Dmitry Kurochkin Date: Thu, 24 Sep 2026 11:37:20 +0000 Subject: [PATCH 2/4] docs(changelog): rewrite 0.1.0-preview.1.0.0 entry as user-facing notes Co-Authored-By: Claude Opus 5.5 --- CHANGELOG.md | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5411bb0..fb1d4b2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,14 +9,10 @@ Versioning follows Semantic Versioning with preview suffix `major.minor.patch-pr ## [0.1.0-preview.1.0.0] - 2026-09-24 -Makes `having` without `groupBy` a schema error. `having` filters aggregation groups, so without `groupBy` it has no defined meaning; the schema previously accepted such queries silently. +### ⚠️ Breaking Changes -Tracking issue: #40. - -### Changed - -- **`having` now requires `groupBy`**: the root object declares `"dependentRequired": { "having": ["groupBy"] }`. Queries that use `having` without `groupBy` no longer validate. -- **`groupBy` now requires at least one field** (`minItems: 1`). An empty `groupBy` array no longer validates; omit the clause instead. +- **`having` now requires `groupBy`**: Queries that filter with `having` must also group their rows with `groupBy`. Previously the schema accepted `having` on its own, even though it has no meaning without groups. (#40) +- **`groupBy` can no longer be empty**: `groupBy` must list at least one field. To skip grouping, leave the clause out. --- From 19487cf927301bc6f12e2709966aefe37da6dbab Mon Sep 17 00:00:00 2001 From: Dmitry Kurochkin Date: Thu, 24 Sep 2026 11:38:40 +0000 Subject: [PATCH 3/4] docs(changelog): mark having/groupBy entry as unreleased Co-Authored-By: Claude Opus 5.5 --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fb1d4b2..38e1439 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,7 @@ Versioning follows Semantic Versioning with preview suffix `major.minor.patch-pr --- -## [0.1.0-preview.1.0.0] - 2026-09-24 +## [Unreleased] ### ⚠️ Breaking Changes From fd7e69b3a9252cc27d68a89c2dfe7cbb70712d97 Mon Sep 17 00:00:00 2001 From: Dmitry Kurochkin Date: Thu, 24 Sep 2026 11:45:28 +0000 Subject: [PATCH 4/4] chore(schema): revert version bump until release Co-Authored-By: Claude Opus 5.5 --- PureQL-Specification.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/PureQL-Specification.json b/PureQL-Specification.json index d730952..b683849 100644 --- a/PureQL-Specification.json +++ b/PureQL-Specification.json @@ -1,7 +1,7 @@ { "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://github.com/kudima03/PureQL-Specification/releases/download/0.1.0-preview.1.0.0/PureQL-Specification.json", - "version": "0.1.0-preview.1.0.0", + "$id": "https://github.com/kudima03/PureQL-Specification/releases/download/0.1.0-preview.0.5.0/PureQL-Specification.json", + "version": "0.1.0-preview.0.5.0", "definitions": { "arrayParameters": { "stringArrayParameter": {