You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
docs: cover the union consolidation and discriminator decoding
Add a Changed entry for discriminator-driven decoding and the strict
request-selected accessors, and a Removed entry for the 135 consolidated union
types.
Give the v4 -> v5 deep dive three sections: the rename table, the six unions
that now name their own branch, and the aggregation unions that cannot, with
the typed_keys guidance those need.
Retarget the tasks guide at TasksStatus and BulkByScrollTaskStatusOrException,
and thread the error return through its examples.
Signed-off-by: Sean Chittenden <sean.chittenden@crowdstrike.com>
Copy file name to clipboardExpand all lines: CHANGELOG.md
+3Lines changed: 3 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -179,6 +179,8 @@ Inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
179
179
180
180
### Changed
181
181
182
+
- `cmd/osgen` now honors the OpenAPI `discriminator`, which it previously ignored entirely. Eight schemas in the spec declare one and every branch of all eight resolves to a distinct value, so 146 subtypes whose branch the payload names outright were being decoded by a JSON token-class heuristic instead. The discriminator is how OpenAPI expresses polymorphism, and the spec encodes the hierarchy through `allOf` (a subtype is `allOf[Base, {type: enum[keyword]}]`), so resolving a discriminant walks `allOf` transitively: the constant sits on the narrowing member while the inherited fields come from the base. A union is only discriminated when every branch resolves distinctly, so a partially-understood schema falls back rather than emitting a decoder with an unreachable case. Six emitted unions gain a `Type()`, discriminant constants, and an `UnmarshalJSON` that reads one property and decodes exactly that branch: `CommonMappingProperty` (on `type`, honoring the spec's `x-default` for the implicit object mapping), `CommonAnalysis{Analyzer,CharFilterDefinition,TokenFilterDefinition,TokenizerDefinition,Normalizer}`, plus `ClusterRemoteInfoCluster` on `mode`. A value naming no branch is an error rather than a silent mis-decode, and `ClusterRemoteInfoResp.Entries` becomes `map[string]ClusterRemoteInfoCluster` instead of an untyped map, dropping it from the `json.RawMessage` allowlist. Internal vocabulary follows the spec rather than the decode mechanism: `IsLazy`/`LazyAccessors` conflated "the spec provides no discriminator" with "we never read the discriminator" and become `RequestSelected`, since the aggregation and suggester unions carry `x-supports-typed-keys` and genuinely cannot be discriminated (the branch is chosen by the request and echoed only in the response map key, `avg#my_agg`); `TypeLazyUnion` becomes `TypeAmbiguousWire`, `unionNeedsTryEach` becomes `branchesCollideOnTokenClass`, and the token-class heuristic is retained and documented as the fallback it is
183
+
- Union branch accessors on a request-selected union no longer return a zero value with a nil error when the payload cannot be that branch. `AsSum()` against histogram bytes returned an empty `Sum` and no error, indistinguishable from a genuine zero, because `encoding/json` ignores unknown keys and a decode-error check cannot see the mismatch; a required-property probe now rejects it. It still cannot distinguish `avg` from `sum`, which share one wire shape -- that is a property of the protocol, and is documented on the generated type. `UnionBranchError` gains an `Err` field and `Unwrap()`, so the underlying decode failure is reachable through `errors.As`, and `Got` may be `"incompatible payload"`
182
184
- Generated doc comments now lead with the identifier they document, as godoc expects. Field and enum-member comments previously carried the spec description verbatim, so godoc rendered "The time taken by different phases of the search." against `PhaseTook` rather than a sentence naming the field. Prefixing cannot be uniform, because the descriptions are not one grammatical shape: 2,545 are noun phrases naming the value, where a copula reads correctly ("PhaseTook is the time taken by ..."), while 297 open with a verb or a conditional, where the same treatment yields "Found is whether the document was found". A copula is inserted only after a leading article; otherwise the description becomes its own sentence after the name. Enum members take the sentence form always, since their descriptions say what selecting the value means rather than naming an attribute of the constant, making the copula wrong for all 43 of them ("NodeRoleDataHot is the node can store hot data"). A promoted sentence is capitalized, since 161 spec descriptions are lowercase fragments. Descriptions already leading with the identifier keep their text, and a `Deprecated` marker is never prefixed, since godoc only honors it at the start of a paragraph
183
185
-`cmd/osgen` bounds its generic-substitution traversals by detecting `$ref` cycles rather than capping descent depth. The previous seven-level cap was not a termination guarantee: `declaresProperty` follows `allOf``$ref` members with no stopping rule and overflows the stack on a mutually recursive pair, which the cap merely hid. Each traversal now carries the set of `$ref` keys on the current path, since only a `$ref` can revisit a schema; a repeat resolves as concrete and keeps the field, matching how an unresolvable `$ref` is already treated. Sibling probes each get their own set, so a schema reached through one `allOf` member cannot suppress the answer for another. Generated output is byte-identical, and the diagnostic the cap emitted on exceeding the bound is removed with it
184
186
- Configure Dependabot to scan the nested Go modules (`osprom`, `osotel`, `cmd/osgen`, `cmd/osapilint`) alongside the root module, and pin the weekly schedule to Tuesday 14:00 `America/Los_Angeles` rather than leaving the day to Dependabot and the time to UTC
@@ -242,6 +244,7 @@ Inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
242
244
243
245
### Removed
244
246
247
+
- 135 generated union types are removed and 45 added, as a `oneOf`/`anyOf` schema reached through a `$ref` is now named after the schema itself rather than the field that referenced it, and emitted once instead of once per reference. This collapses 212 union types to 122. The removals are consolidations rather than lost functionality: every branch and accessor survives on the shared type, and more distinct union shapes survive than before (91, up from 87). Renames include `MGetRespBodyDocsItem` to `MGetRespItem`, `MSearchMultiSearchResultResponsesItem` to `MSearchRespItem`, `SortResultsItem` and `CommonAggregationsCompositeAggregateKeyValue` to `FieldValue`, `ErrorCauseHeaderValue` to `StringOrStringArray`, `SearchResultAggregationsValue` to `CommonAggregationsAggregate`, `IndicesIndexSettingsAnalysis{Analyzer,Normalizer}Value` to `CommonAnalysis{Analyzer,Normalizer}`, and `CatRecoveryRecord{Start,Stop}TimeMillis` with `Replication{,Index}FollowerStatusTotalWriteTimeMillis` to `StringifiedEpochTimeUnitMillis`. Branch accessors also drop the group prefix the union name already carries, so `MGetMultiGetError()` becomes `MultiGetError()` and `SearchHitsMetadataTotal.SearchTotalHits()` becomes `.TotalHits()`. See [`opensearchapi/UPGRADING_V4_TO_V5.md`](opensearchapi/UPGRADING_V4_TO_V5.md) for the rename table
245
248
-**BREAKING**: Remove the `IncludeDedicatedClusterManagers` config flag from `opensearch.Config` and `opensearchtransport.Config`. Dedicated cluster managers (`cluster_manager` role with no work roles) are now unconditionally excluded from request routing: they are kept in the connection inventory for discovery reuse/eviction but never selected for query traffic (a user-supplied seed remains selectable so discovery can bootstrap against it). The flag previously defaulted to excluding them; opting them into routing is no longer supported. Delete any `IncludeDedicatedClusterManagers` field from your config (it is a compile error otherwise) ([#1004](https://github.com/opensearch-project/opensearch-go/pull/1004))
246
249
- Remove deprecated `(*opensearch.Client).Perform` and `(*opensearchtransport.Transport).Perform`; `Stream(*http.Request) (*http.Response, error)` is now the sole method on `opensearchtransport.Interface`. Custom transport implementations must implement `Stream` instead of `Perform`. The `opensearch.Streamer` opt-in interface and `opensearch.ErrTransportMissingMethodStream` sentinel are removed. ([#872](https://github.com/opensearch-project/opensearch-go/issues/872))
247
250
-**BREAKING**: Remove the `EnableMetrics` config flag from `opensearch.Config` and `opensearchtransport.Config`. The detailed-metrics snapshot (per-connection enumeration, per-policy breakdowns, and router cache state) is now always available; `Metrics()` returns the full snapshot unconditionally. The flag's only remaining purpose after [#891](https://github.com/opensearch-project/opensearch-go/issues/891) was to gate the detailed path, which now does its work lazily and lock-free at call time and so costs nothing until `Metrics()` is called. Delete any `EnableMetrics` field from your config (it is a compile error otherwise); see [`UPGRADING_V5.md`](UPGRADING_V5.md#enablemetrics-removed). ([#892](https://github.com/opensearch-project/opensearch-go/issues/892))
Copy file name to clipboardExpand all lines: guides/usage-tasks.md
+33-18Lines changed: 33 additions & 18 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -120,14 +120,17 @@ Use `Tasks.Get` to poll a task by ID. The `Completed` field indicates whether th
120
120
121
121
## Inspecting Task Status
122
122
123
-
The `Status` field on a task is a discriminated union (`*opensearchapi.TasksTaskInfoBaseStatus`) because its shape depends on the task type. Call `Type()` to determine which branch was decoded, then call the matching accessor. The raw JSON is always available via `RawJSON()`.
123
+
The `Status` field on a task is a union (`*opensearchapi.TasksStatus`) because its shape depends on the task type. Call `Type()` to determine which branch was decoded, then call the matching accessor. The raw JSON is always available via `RawJSON()`.
For reindex, delete_by_query, and update_by_query tasks, call `BulkByScrollTaskStatus()` to get the typed struct. Note that `Created` and `Updated` are pointers and should be nil-checked:
For sliced requests, the `Slices` field contains per-slice status. Each element is a `BulkByScrollTaskStatusSlicesItem` -- a discriminated union that is either a nested `BulkByScrollTaskStatus` (on success) or an `ErrorCause` (on failure). Call `Type()` then the matching accessor:
150
+
For sliced requests, the `Slices` field contains per-slice status. Each element is a `BulkByScrollTaskStatusOrException` -- a union that is either a nested `BulkByScrollTaskStatus` (on success) or an `ErrorCause` (on failure). Call `Type()` then the matching accessor. Each accessor returns `(T, error)` and reports a `*opensearchapi.UnionBranchError` when the union holds a different branch, so the zero value is never mistaken for real data:
148
151
149
152
```go
150
153
fori, slice:=range status.Slices {
151
154
switch slice.Type() {
152
-
case opensearchapi.BulkByScrollTaskStatusSlicesItemBulkByScrollTaskStatusType:
153
-
sliceStatus:= slice.BulkByScrollTaskStatus()
155
+
case opensearchapi.BulkByScrollTaskStatusOrExceptionBulkByScrollTaskStatusType:
156
+
sliceStatus, err:= slice.BulkByScrollTaskStatus()
157
+
if err != nil {
158
+
return err
159
+
}
154
160
fmt.Printf("Slice %d: %d total\n", i, sliceStatus.Total)
155
-
case opensearchapi.BulkByScrollTaskStatusSlicesItemExceptionType:
156
-
exc:= slice.Exception()
161
+
case opensearchapi.BulkByScrollTaskStatusOrExceptionExceptionType:
162
+
exc, err:= slice.Exception()
163
+
if err != nil {
164
+
return err
165
+
}
157
166
reason:=""
158
167
if exc.Reason != nil {
159
168
reason = *exc.Reason
@@ -165,19 +174,25 @@ For sliced requests, the `Slices` field contains per-slice status. Each element
@@ -244,13 +259,13 @@ Long-running tasks can be cancelled by task ID. The response body has a dynamic
244
259
245
260
## Status Type Reference
246
261
247
-
The OpenSearch server returns different status structures depending on the task type. The `Status` field is a discriminated union (`*opensearchapi.TasksTaskInfoBaseStatus`); call `Type()` to determine the branch, then the matching accessor.
262
+
The OpenSearch server returns different status structures depending on the task type. The `Status` field is a union (`*opensearchapi.TasksStatus`); call `Type()` to determine the branch, then the matching accessor. Every accessor returns `(T, error)`.
248
263
249
-
| Task Type | Accessor | Status Struct | Key Fields |
For any unrecognized task type, the raw JSON is available via `Status.RawJSON()` for direct unmarshaling, or `Status.Map()` for a `map[string]json.RawMessage`.
256
271
@@ -259,7 +274,7 @@ For any unrecognized task type, the raw JSON is available via `Status.RawJSON()`
259
274
If you read the same status type frequently, you can define a short helper in your own code:
0 commit comments