Skip to content

Commit

Permalink
Introduce more usages to describe things related with the states of L…
Browse files Browse the repository at this point in the history
…RO (#1887)

Remove this workaround since #311 is closed.
Fixes #1752
Fixes #1530

This PR adds three new usage flags: `LroInitial`, `LroPolling`,
`LroFinalEnvelope`.
These new usage flags are previously represented by `Output`, now the
`Output` flag no longer contain the semantics of these usages.
Therefore, if a model's usage is only `LroInitial`, this means it is
only used as the initial response of an LRO.
if a model has both `LroInitial` and `Output`, this means it is used as
the initial response of an LRO, and it also used as a normal output in
other places.
The final result will not have above new usages unless it participates
as those roles as well. It will have output usage.
  • Loading branch information
ArcturusZhang authored and iscai-msft committed Dec 6, 2024
1 parent 4304758 commit 2f00cc0
Show file tree
Hide file tree
Showing 6 changed files with 308 additions and 59 deletions.
9 changes: 9 additions & 0 deletions .chronus/changes/remove-lro-workaround-2024-10-19-9-4-1.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
# Change versionKind to one of: internal, fix, dependencies, feature, deprecation, breaking
changeKind: feature
packages:
- "@azure-tools/typespec-client-generator-core"
---

1. Introduce new usage: `LroInitial`, `LroPolling`, `LroFinalEnvelope`.
2. usage and access now properly propagate on polling model, final result and final envelop result of `lroMetadata`.
6 changes: 6 additions & 0 deletions packages/typespec-client-generator-core/src/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -743,6 +743,12 @@ export enum UsageFlags {
Xml = 1 << 9,
// Set when type is used for exception output.
Exception = 1 << 10,
// Set when type is used as LRO initial response.
LroInitial = 1 << 11,
// Set when type is used as LRO polling response.
LroPolling = 1 << 12,
// Set when type is used as LRO final envelop response.
LroFinalEnvelope = 1 << 13,
}

interface SdkExampleBase {
Expand Down
50 changes: 30 additions & 20 deletions packages/typespec-client-generator-core/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1595,6 +1595,7 @@ function updateTypesFromOperation(
diagnostics.pipe(updateUsageOrAccess(context, access, sdkType));
}

const lroMetaData = getLroMetadata(program, operation);
for (const response of httpOperation.responses) {
for (const innerResponse of response.responses) {
if (innerResponse.body?.type && !isNeverOrVoidType(innerResponse.body.type)) {
Expand All @@ -1606,6 +1607,9 @@ function updateTypesFromOperation(
if (generateConvenient) {
if (response.statusCodes === "*" || isErrorModel(context.program, body)) {
diagnostics.pipe(updateUsageOrAccess(context, UsageFlags.Exception, sdkType));
} else if (lroMetaData !== undefined) {
// when the operation is an lro, the response should be its initial response.
diagnostics.pipe(updateUsageOrAccess(context, UsageFlags.LroInitial, sdkType));
} else {
diagnostics.pipe(updateUsageOrAccess(context, UsageFlags.Output, sdkType));
}
Expand Down Expand Up @@ -1633,29 +1637,35 @@ function updateTypesFromOperation(
}
}
}
const lroMetaData = getLroMetadata(program, operation);

if (lroMetaData && generateConvenient) {
if (lroMetaData.finalResult !== undefined && lroMetaData.finalResult !== "void") {
const sdkType = diagnostics.pipe(
getClientTypeWithDiagnostics(context, lroMetaData.finalResult, operation),
);
diagnostics.pipe(updateUsageOrAccess(context, UsageFlags.Output, sdkType));
const access = getAccessOverride(context, operation) ?? "public";
diagnostics.pipe(updateUsageOrAccess(context, access, sdkType));

if (!context.arm) {
// TODO: currently skipping adding of envelopeResult due to arm error
// https://github.com/Azure/typespec-azure/issues/311
const sdkType = diagnostics.pipe(
getClientTypeWithDiagnostics(context, lroMetaData.envelopeResult, operation),
);
diagnostics.pipe(updateUsageOrAccess(context, UsageFlags.Output, sdkType));
const access = getAccessOverride(context, operation) ?? "public";
diagnostics.pipe(updateUsageOrAccess(context, access, sdkType));
}
}
// the final result will be normal output usage.
updateUsageOrAccessForLroComponent(lroMetaData.finalResult, UsageFlags.Output);

// the final envelope result will have LroFinalEnvelope.
updateUsageOrAccessForLroComponent(
lroMetaData.finalEnvelopeResult,
UsageFlags.LroFinalEnvelope,
);

// the polling model will have LroPolling.
updateUsageOrAccessForLroComponent(
lroMetaData.pollingInfo.responseModel,
UsageFlags.LroPolling,
);
}
return diagnostics.wrap(undefined);

function updateUsageOrAccessForLroComponent(
model: Model | "void" | undefined,
usage: UsageFlags,
) {
if (model === undefined || model === "void") return;
const sdkType = diagnostics.pipe(getClientTypeWithDiagnostics(context, model, operation));
diagnostics.pipe(updateUsageOrAccess(context, usage, sdkType));
const access = getAccessOverride(context, operation) ?? "public";
diagnostics.pipe(updateUsageOrAccess(context, access, sdkType));
}
}

function updateAccessOverride(context: TCGCContext): [void, readonly Diagnostic[]] {
Expand Down
Loading

0 comments on commit 2f00cc0

Please sign in to comment.