Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

http-client-java, support (non-nested) continuationToken for unbranded #6143

Merged
Changes from 1 commit
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
8f04696
fix interface
weidongxu-microsoft Feb 14, 2025
25e05d0
test code and initial interface of PageableContinuationToken
weidongxu-microsoft Feb 14, 2025
f7a0c45
handle PagedResponse
weidongxu-microsoft Feb 18, 2025
224703c
handle query/header
weidongxu-microsoft Feb 18, 2025
03d005c
hack for test
weidongxu-microsoft Feb 19, 2025
928ab36
Merge branch 'main' into http-client-java_continuation-token
weidongxu-microsoft Feb 20, 2025
32137b1
refactor to use ModelPropertySegment, instead of itemName/itemSeriali…
weidongxu-microsoft Feb 20, 2025
3785ba3
hide continuationToken parameter from API
weidongxu-microsoft Feb 20, 2025
d2c8831
add throw calls on not support items in PagingOptions
weidongxu-microsoft Feb 20, 2025
18f8ae0
Merge branch 'main' into http-client-java_continuation-token
weidongxu-microsoft Feb 25, 2025
feb1c68
use tcgc for continuationToken
weidongxu-microsoft Feb 25, 2025
a6cb649
Merge branch 'main' into http-client-java_continuation-token
weidongxu-microsoft Feb 25, 2025
c168edd
enable for unbranded
weidongxu-microsoft Feb 25, 2025
0cd5416
fix
weidongxu-microsoft Feb 25, 2025
9ce5472
bump http-specs and regen
weidongxu-microsoft Feb 25, 2025
905abfe
update test
weidongxu-microsoft Feb 25, 2025
d9924ae
test
weidongxu-microsoft Feb 25, 2025
c85e84d
fix
weidongxu-microsoft Feb 25, 2025
c6b7a2c
comment
weidongxu-microsoft Feb 25, 2025
59e1d38
add test for page2
weidongxu-microsoft Feb 25, 2025
c6d3eb3
revert Main
weidongxu-microsoft Feb 25, 2025
4aa4b0f
bump jar
weidongxu-microsoft Feb 25, 2025
6af2a02
bump version
weidongxu-microsoft Feb 25, 2025
9d81f37
test for throws if non-supported param is set
weidongxu-microsoft Feb 25, 2025
e15b44e
fix test package ref
weidongxu-microsoft Feb 25, 2025
df60efe
Merge branch 'main' into http-client-java_continuation-token
weidongxu-microsoft Feb 27, 2025
77b4d3c
0.1.12
weidongxu-microsoft Feb 27, 2025
cbf31a6
review feedback
weidongxu-microsoft Feb 28, 2025
87491a1
simplify paged op logic, do early return
weidongxu-microsoft Feb 28, 2025
77234d1
Merge branch 'main' into http-client-java_continuation-token
weidongxu-microsoft Feb 28, 2025
34f4cb6
Fix typo in comment: "mutally" to "mutually"
weidongxu-microsoft Mar 4, 2025
89b3638
Merge branch 'main' into http-client-java_continuation-token
weidongxu-microsoft Mar 4, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
review feedback
  • Loading branch information
weidongxu-microsoft committed Feb 28, 2025
commit cbf31a6310b7d837540fbd7fd156879bce2972ed
240 changes: 120 additions & 120 deletions packages/http-client-java/emitter/src/code-model-builder.ts
Original file line number Diff line number Diff line change
@@ -982,7 +982,7 @@ export class CodeModelBuilder {
}

// check for paged
this.processRouteForPaged(codeModelOperation, sdkMethod.operation.responses, sdkMethod);
this.processRouteForPaged(codeModelOperation, sdkMethod);

// check for long-running operation
this.processRouteForLongRunning(codeModelOperation, lroMetadata);
@@ -994,151 +994,151 @@ export class CodeModelBuilder {

private processRouteForPaged(
op: CodeModelOperation,
responses: SdkHttpResponse[],
sdkMethod: SdkServiceMethod<SdkHttpOperation>,
) {
if (sdkMethod.kind === "paging" || sdkMethod.kind === "lropaging") {
for (const response of responses) {
const bodyType = response.type;
if (bodyType && bodyType.kind === "model") {
op.responses?.forEach((r) => {
if (r instanceof SchemaResponse) {
this.trackSchemaUsage(r.schema, { usage: [SchemaContext.Paged] });
}
});
const responses = sdkMethod.operation.responses;
if (sdkMethod.kind !== "paging" && sdkMethod.kind !== "lropaging") {
return;
}

function getLastPropertySegment(
segments: SdkModelPropertyType[] | undefined,
): SdkBodyModelPropertyType | undefined {
if (segments) {
const lastSegment = segments[segments.length - 1];
if (lastSegment.kind === "property") {
return lastSegment;
}
}
return undefined;
for (const response of responses) {
const bodyType = response.type;
if (bodyType && bodyType.kind === "model") {
op.responses?.forEach((r) => {
if (r instanceof SchemaResponse) {
this.trackSchemaUsage(r.schema, { usage: [SchemaContext.Paged] });
}
function getLastSegment(
segments: SdkModelPropertyType[] | undefined,
): SdkModelPropertyType | undefined {
if (segments) {
return segments[segments.length - 1];
});

function getLastPropertySegment(
segments: SdkModelPropertyType[] | undefined,
): SdkBodyModelPropertyType | undefined {
if (segments) {
const lastSegment = segments[segments.length - 1];
if (lastSegment.kind === "property") {
return lastSegment;
}
return undefined;
}
function getLastSegmentSerializedName(
segments: SdkModelPropertyType[] | undefined,
): string | undefined {
const lastSegment = getLastPropertySegment(segments);
return lastSegment ? getPropertySerializedName(lastSegment) : undefined;
return undefined;
}
function getLastSegment(
segments: SdkModelPropertyType[] | undefined,
): SdkModelPropertyType | undefined {
if (segments) {
return segments[segments.length - 1];
}
return undefined;
}
function getLastSegmentSerializedName(
segments: SdkModelPropertyType[] | undefined,
): string | undefined {
const lastSegment = getLastPropertySegment(segments);
return lastSegment ? getPropertySerializedName(lastSegment) : undefined;
}

// TODO: in future the property could be nested, so that the "itemSegments" or "nextLinkSegments" would contain more than 1 element
// item/result
// "itemsSegments" should exist for "paging"/"lropaging"
const itemSerializedName = getLastSegmentSerializedName(
sdkMethod.response.resultSegments,
// TODO: in future the property could be nested, so that the "itemSegments" or "nextLinkSegments" would contain more than 1 element
// item/result
// "itemsSegments" should exist for "paging"/"lropaging"
const itemSerializedName = getLastSegmentSerializedName(sdkMethod.response.resultSegments);
// nextLink
const nextLinkSerializedName = getLastSegmentSerializedName(
sdkMethod.pagingMetadata.nextLinkSegments,
);

// continuationToken
let continuationTokenParameter: Parameter | undefined;
let continuationTokenResponseProperty: Property[] | undefined;
let continuationTokenResponseHeader: HttpHeader | undefined;
if (!this.isBranded()) {
const continuationTokenParameterSegment = getLastSegment(
sdkMethod.pagingMetadata.continuationTokenParameterSegments,
);
// nextLink
const nextLinkSerializedName = getLastSegmentSerializedName(
sdkMethod.pagingMetadata.nextLinkSegments,
const continuationTokenResponseSegment = getLastSegment(
sdkMethod.pagingMetadata.continuationTokenResponseSegments,
);

// continuationToken
let continuationTokenParameter: Parameter | undefined;
let continuationTokenResponseProperty: Property[] | undefined;
let continuationTokenResponseHeader: HttpHeader | undefined;
if (!this.isBranded()) {
const continuationTokenParameterSegment = getLastSegment(
sdkMethod.pagingMetadata.continuationTokenParameterSegments,
if (continuationTokenParameterSegment && op.parameters) {
// for now, continuationToken is either request query or header parameter
const parameter = getHttpOperationParameter(
sdkMethod,
continuationTokenParameterSegment,
);
const continuationTokenResponseSegment = getLastSegment(
sdkMethod.pagingMetadata.continuationTokenResponseSegments,
);
if (continuationTokenParameterSegment) {
// for now, continuationToken is either request query or header parameter
const parameter = getHttpOperationParameter(
sdkMethod,
continuationTokenParameterSegment,
);
if (parameter && op.parameters) {
for (const param of op.parameters) {
if (param.protocol.http?.in === parameter.kind) {
if (parameter) {
for (const param of op.parameters) {
if (param.protocol.http?.in === parameter.kind) {
if (
parameter.kind === "header" &&
param.language.default.serializedName.toLowerCase() ===
parameter.serializedName.toLowerCase()
) {
continuationTokenParameter = param;
break;
} else if (param.language.default.serializedName === parameter.serializedName) {
continuationTokenParameter = param;
break;
}
}
}
}
}
if (continuationTokenResponseSegment && op.responses) {
if (continuationTokenResponseSegment?.kind === "responseheader") {
// continuationToken is response header
for (const response of op.responses) {
if (response instanceof SchemaResponse && response.protocol.http) {
for (const header of response.protocol.http.headers) {
if (
parameter.kind === "header" &&
param.language.default.serializedName.toLowerCase() ===
parameter.serializedName.toLowerCase()
header.header.toLowerCase() ===
continuationTokenResponseSegment.serializedName.toLowerCase()
) {
continuationTokenParameter = param;
break;
} else if (param.language.default.serializedName === parameter.serializedName) {
continuationTokenParameter = param;
continuationTokenResponseHeader = header;
break;
}
}
}
if (continuationTokenResponseHeader) {
break;
}
}
}
if (continuationTokenResponseSegment && op.responses) {
if (continuationTokenResponseSegment?.kind === "responseheader") {
// continuationToken is response header
for (const response of op.responses) {
if (response instanceof SchemaResponse && response.protocol.http) {
for (const header of response.protocol.http.headers) {
if (
header.header.toLowerCase() ===
continuationTokenResponseSegment.serializedName.toLowerCase()
) {
continuationTokenResponseHeader = header;
break;
}
} else if (continuationTokenResponseSegment?.kind === "property") {
// continuationToken is response body property
// TODO: the property could be nested
for (const response of op.responses) {
if (
response instanceof SchemaResponse &&
response.schema instanceof ObjectSchema &&
response.schema.properties
) {
for (const property of response.schema.properties) {
if (
property.serializedName ===
getPropertySerializedName(continuationTokenResponseSegment)
) {
continuationTokenResponseProperty = [property];
break;
}
}
if (continuationTokenResponseHeader) {
break;
}
}
} else if (continuationTokenResponseSegment?.kind === "property") {
// continuationToken is response body property
// TODO: the property could be nested
for (const response of op.responses) {
if (
response instanceof SchemaResponse &&
response.schema instanceof ObjectSchema &&
response.schema.properties
) {
for (const property of response.schema.properties) {
if (
property.serializedName ===
getPropertySerializedName(continuationTokenResponseSegment)
) {
continuationTokenResponseProperty = [property];
break;
}
}
}
if (continuationTokenResponseProperty) {
break;
}
if (continuationTokenResponseProperty) {
break;
}
}
}
}

op.extensions = op.extensions ?? {};
op.extensions["x-ms-pageable"] = {
itemName: itemSerializedName,
nextLinkName: nextLinkSerializedName,
continuationToken: continuationTokenParameter
? new PageableContinuationToken(
continuationTokenParameter,
continuationTokenResponseProperty,
continuationTokenResponseHeader,
)
: undefined,
};
break;
}

op.extensions = op.extensions ?? {};
op.extensions["x-ms-pageable"] = {
itemName: itemSerializedName,
nextLinkName: nextLinkSerializedName,
continuationToken: continuationTokenParameter
? new PageableContinuationToken(
continuationTokenParameter,
continuationTokenResponseProperty,
continuationTokenResponseHeader,
)
: undefined,
};
break;
}
}
}
28 changes: 27 additions & 1 deletion packages/http-client-java/emitter/src/common/client.ts
Original file line number Diff line number Diff line change
@@ -20,9 +20,21 @@ export interface Client extends Aspect {

serviceVersion?: ServiceVersion; // apiVersions is in

/**
* Parent client of this client, if exists.
*/
parent?: Client;
/**
* Sub clients of this client, if exists.
*/
subClients: Array<Client>;
/**
* Whether the Builder class has a public method (e.g. "buildSubClient") to initiate this client.
*/
buildMethodPublic: boolean;
/**
* Whether the parent client has a public accessor method (e.g. "getSubClient") to initiate this client.
*/
parentAccessorPublic: boolean;
}

@@ -76,13 +88,27 @@ export class ServiceVersion extends Metadata {
}

export interface EncodedSchema {
/**
* The encoded type -- the type on wire.
* E.g., the type for SDK maybe "int32", but type on wire be "string".
*/
encode?: string;
}

export class PageableContinuationToken {
/**
* The parameter of the operation as continuationToken in API request.
*/
parameter: Parameter;
// responseProperty and responseHeader is mutally exclusive
responseProperty?: Property[];
/**
* The reference to response body property of the operation as continuationToken in API request.
* Array because the property may be at "links.nextToken".
*/
responseProperty?: Array<Property>;
/**
* The reference to response header of the operation as continuationToken in API request.
*/
responseHeader?: HttpHeader;

constructor(parameter: Parameter, responseProperty?: Property[], responseHeader?: HttpHeader) {
Loading
Oops, something went wrong.