Skip to content

Commit

Permalink
chore(lib-dynamodb): use pagination factory from core (#6345)
Browse files Browse the repository at this point in the history
  • Loading branch information
pasoevi authored Aug 1, 2024
1 parent fac05e1 commit 922292b
Show file tree
Hide file tree
Showing 3 changed files with 28 additions and 151 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,9 @@

import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Optional;
import software.amazon.smithy.codegen.core.CodegenException;
import software.amazon.smithy.codegen.core.Symbol;
import software.amazon.smithy.codegen.core.SymbolProvider;
import software.amazon.smithy.model.Model;
import software.amazon.smithy.model.knowledge.PaginatedIndex;
import software.amazon.smithy.model.knowledge.PaginationInfo;
import software.amazon.smithy.model.shapes.OperationShape;
import software.amazon.smithy.model.shapes.ServiceShape;
import software.amazon.smithy.typescript.codegen.TypeScriptDependency;
Expand All @@ -36,14 +32,13 @@ final class DocumentClientPaginationGenerator implements Runnable {
static final String PAGINATION_FOLDER = "pagination";

private final TypeScriptWriter writer;
private final PaginationInfo paginatedInfo;

private final String operationTypeName;
private final String inputTypeName;
private final String outputTypeName;

private final String operationName;
private final String methodName;

private final String paginationType;

DocumentClientPaginationGenerator(
Expand All @@ -65,14 +60,7 @@ final class DocumentClientPaginationGenerator implements Runnable {

// e.g. listObjects
this.operationName = operationTypeName.replace("Command", "");
this.methodName = Character.toLowerCase(operationName.charAt(0)) + operationName.substring(1);
this.paginationType = DocumentClientUtils.CLIENT_FULL_NAME + "PaginationConfiguration";

PaginatedIndex paginatedIndex = PaginatedIndex.of(model);
Optional<PaginationInfo> paginationInfo = paginatedIndex.getPaginationInfo(service, operation);
this.paginatedInfo = paginationInfo.orElseThrow(() -> {
return new CodegenException("Expected Paginator to have pagination information.");
});
}

@Override
Expand All @@ -90,13 +78,13 @@ public void run() {

// Import Pagination types
writer.addImport("Paginator", "Paginator", TypeScriptDependency.SMITHY_TYPES);
writer.addImport("createPaginator", "createPaginator", TypeScriptDependency.SMITHY_CORE);
writer.addRelativeImport(paginationType, paginationType,
Paths.get(".", getInterfaceFilelocation().replace(".ts", "")));

writer.writeDocs("@public");
writer.write("export { Paginator }");

writeCommandRequest();
writePager();
}

Expand Down Expand Up @@ -134,71 +122,18 @@ static void generateServicePaginationInterfaces(TypeScriptWriter writer) {
});
}

private String destructurePath(String path) {
return "." + path.replace(".", "!.");
}

private void writePager() {
String inputTokenName = paginatedInfo.getPaginatedTrait().getInputToken().get();
String outputTokenName = paginatedInfo.getPaginatedTrait().getOutputToken().get();

writer.writeDocs("@public\n\n"
+ String.format("@param %s - {@link %s}%n", inputTypeName, inputTypeName)
+ String.format("@returns {@link %s}%n", outputTypeName)
);
writer.openBlock(
"export async function* paginate$L(config: $L, input: $L, ...additionalArguments: any): Paginator<$L>{",
"}", operationName, paginationType, inputTypeName, outputTypeName, () -> {
String destructuredInputTokenName = destructurePath(inputTokenName);
writer.write("// ToDo: replace with actual type instead of typeof input$L", destructuredInputTokenName);
writer.write("let token: typeof input$L | undefined = config.startingToken || undefined;",
destructuredInputTokenName);

writer.write("let hasNext = true;");
writer.write("let page: $L;", outputTypeName);
writer.openBlock("while (hasNext) {", "}", () -> {
writer.write("input$L = token;", destructuredInputTokenName);

if (paginatedInfo.getPageSizeMember().isPresent()) {
String pageSize = paginatedInfo.getPageSizeMember().get().getMemberName();
writer.write("input[$S] = config.pageSize;", pageSize);
}

writer.openBlock("if (config.client instanceof $L) {", "}", DocumentClientUtils.CLIENT_NAME,
() -> {
writer.write(
"page = await makePagedClientRequest(config.client, input, ...additionalArguments);");
}
);
writer.openBlock("else {", "}", () -> {
writer.write("throw new Error(\"Invalid client, expected $L | $L\");",
DocumentClientUtils.CLIENT_FULL_NAME, DocumentClientUtils.CLIENT_NAME);
});

writer.write("yield page;");
writer.write("token = page$L;", destructurePath(outputTokenName));

writer.write("hasNext = !!(token);");
});

writer.write("// @ts-ignore");
writer.write("return undefined;");
});
}


/**
* Paginated command that calls CommandClient().send({...}) under the hood. This is meant for client side (browser)
* environments and does not generally expose the entire service.
*/
private void writeCommandRequest() {
writer.writeDocs("@internal");
writer.openBlock(
"const makePagedClientRequest = async (client: $L, input: $L, ...args: any): Promise<$L> => {",
"}", DocumentClientUtils.CLIENT_NAME, inputTypeName,
outputTypeName, () -> {
writer.write("// @ts-ignore");
writer.write("return await client.send(new $L(input), ...args);", operationTypeName);
});
writer.writeDocs("@public");
writer.write("""
export const paginate$1L: (
config: $2L,
input: $3L,
...additionalArguments: any
) => Paginator<$4L> = createPaginator<
$2L,
$3L,
$4L
>(DynamoDBDocumentClient, $1LCommand, "ExclusiveStartKey", "LastEvaluatedKey", "Limit");
""", operationName, paginationType, inputTypeName, outputTypeName);
}
}
43 changes: 7 additions & 36 deletions lib/lib-dynamodb/src/pagination/QueryPaginator.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// smithy-typescript generated code
import { createPaginator } from "@smithy/core";
import { Paginator } from "@smithy/types";

import { QueryCommand, QueryCommandInput, QueryCommandOutput } from "../commands/QueryCommand";
Expand All @@ -9,45 +10,15 @@ import { DynamoDBDocumentPaginationConfiguration } from "./Interfaces";
* @public
*/
export { Paginator };
/**
* @internal
*/
const makePagedClientRequest = async (
client: DynamoDBDocumentClient,
input: QueryCommandInput,
...args: any
): Promise<QueryCommandOutput> => {
// @ts-ignore
return await client.send(new QueryCommand(input), ...args);
};
/**
* @public
*
* @param QueryCommandInput - {@link QueryCommandInput}
* @returns {@link QueryCommandOutput}
*
*/
export async function* paginateQuery(
export const paginateQuery: (
config: DynamoDBDocumentPaginationConfiguration,
input: QueryCommandInput,
...additionalArguments: any
): Paginator<QueryCommandOutput> {
// ToDo: replace with actual type instead of typeof input.ExclusiveStartKey
let token: typeof input.ExclusiveStartKey | undefined = config.startingToken || undefined;
let hasNext = true;
let page: QueryCommandOutput;
while (hasNext) {
input.ExclusiveStartKey = token;
input["Limit"] = config.pageSize;
if (config.client instanceof DynamoDBDocumentClient) {
page = await makePagedClientRequest(config.client, input, ...additionalArguments);
} else {
throw new Error("Invalid client, expected DynamoDBDocument | DynamoDBDocumentClient");
}
yield page;
token = page.LastEvaluatedKey;
hasNext = !!token;
}
// @ts-ignore
return undefined;
}
) => Paginator<QueryCommandOutput> = createPaginator<
DynamoDBDocumentPaginationConfiguration,
QueryCommandInput,
QueryCommandOutput
>(DynamoDBDocumentClient, QueryCommand, "ExclusiveStartKey", "LastEvaluatedKey", "Limit");
43 changes: 7 additions & 36 deletions lib/lib-dynamodb/src/pagination/ScanPaginator.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// smithy-typescript generated code
import { createPaginator } from "@smithy/core";
import { Paginator } from "@smithy/types";

import { ScanCommand, ScanCommandInput, ScanCommandOutput } from "../commands/ScanCommand";
Expand All @@ -9,45 +10,15 @@ import { DynamoDBDocumentPaginationConfiguration } from "./Interfaces";
* @public
*/
export { Paginator };
/**
* @internal
*/
const makePagedClientRequest = async (
client: DynamoDBDocumentClient,
input: ScanCommandInput,
...args: any
): Promise<ScanCommandOutput> => {
// @ts-ignore
return await client.send(new ScanCommand(input), ...args);
};
/**
* @public
*
* @param ScanCommandInput - {@link ScanCommandInput}
* @returns {@link ScanCommandOutput}
*
*/
export async function* paginateScan(
export const paginateScan: (
config: DynamoDBDocumentPaginationConfiguration,
input: ScanCommandInput,
...additionalArguments: any
): Paginator<ScanCommandOutput> {
// ToDo: replace with actual type instead of typeof input.ExclusiveStartKey
let token: typeof input.ExclusiveStartKey | undefined = config.startingToken || undefined;
let hasNext = true;
let page: ScanCommandOutput;
while (hasNext) {
input.ExclusiveStartKey = token;
input["Limit"] = config.pageSize;
if (config.client instanceof DynamoDBDocumentClient) {
page = await makePagedClientRequest(config.client, input, ...additionalArguments);
} else {
throw new Error("Invalid client, expected DynamoDBDocument | DynamoDBDocumentClient");
}
yield page;
token = page.LastEvaluatedKey;
hasNext = !!token;
}
// @ts-ignore
return undefined;
}
) => Paginator<ScanCommandOutput> = createPaginator<
DynamoDBDocumentPaginationConfiguration,
ScanCommandInput,
ScanCommandOutput
>(DynamoDBDocumentClient, ScanCommand, "ExclusiveStartKey", "LastEvaluatedKey", "Limit");

0 comments on commit 922292b

Please sign in to comment.