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

Adding initialPageParam and nested nextPageParam support #143

Merged
merged 5 commits into from
Sep 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
39 changes: 21 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,24 +42,25 @@ Usage: openapi-rq [options]
Generate React Query code based on OpenAPI

Options:
-V, --version output the version number
-i, --input <value> OpenAPI specification, can be a path, url or string content (required)
-o, --output <value> Output directory (default: "openapi")
-c, --client <value> HTTP client to generate (choices: "angular", "axios", "fetch", "node", "xhr", default: "fetch")
--request <value> Path to custom request file
--format <value> Process output folder with formatter? (choices: "biome", "prettier")
--lint <value> Process output folder with linter? (choices: "biome", "eslint")
--operationId Use operation ID to generate operation names?
--serviceResponse <value> Define shape of returned value from service calls (choices: "body", "response", default: "body")
--base <value> Manually set base in OpenAPI config instead of inferring from server value
--enums <value> Generate JavaScript objects from enum definitions? ['javascript', 'typescript', 'typescript+namespace']
--enums <value> Generate JavaScript objects from enum definitions? (choices: "javascript", "typescript")
--useDateType Use Date type instead of string for date types for models, this will not convert the data to a Date object
--debug Run in debug mode?
--noSchemas Disable generating JSON schemas
--schemaType <value> Type of JSON schema [Default: 'json'] (choices: "form", "json")
--pageParam <value> Name of the query parameter used for pagination (default: "page")
--nextPageParam <value> Name of the response parameter used for next page (default: "nextPage")
-V, --version output the version number
-i, --input <value> OpenAPI specification, can be a path, url or string content (required)
-o, --output <value> Output directory (default: "openapi")
-c, --client <value> HTTP client to generate (choices: "angular", "axios", "fetch", "node", "xhr", default: "fetch")
--request <value> Path to custom request file
--format <value> Process output folder with formatter? (choices: "biome", "prettier")
--lint <value> Process output folder with linter? (choices: "biome", "eslint")
--operationId Use operation ID to generate operation names?
--serviceResponse <value> Define shape of returned value from service calls (choices: "body", "response", default: "body")
--base <value> Manually set base in OpenAPI config instead of inferring from server value
--enums <value> Generate JavaScript objects from enum definitions? ['javascript', 'typescript', 'typescript+namespace']
--enums <value> Generate JavaScript objects from enum definitions? (choices: "javascript", "typescript")
--useDateType Use Date type instead of string for date types for models, this will not convert the data to a Date object
--debug Run in debug mode?
--noSchemas Disable generating JSON schemas
--schemaType <value> Type of JSON schema [Default: 'json'] (choices: "form", "json")
--pageParam <value> Name of the query parameter used for pagination (default: "page")
--nextPageParam <value> Name of the response parameter used for next page (default: "nextPage")
--initialPageParam <value> Initial value for the pagination parameter (default: "1")
-h, --help display help for command
```

Expand Down Expand Up @@ -241,6 +242,8 @@ export default App;

This feature will generate a function in infiniteQueries.ts when the name specified by the `pageParam` option exists in the query parameters and the name specified by the `nextPageParam` option exists in the response.

The `initialPageParam` option can be specified to set the intial page to load, defaults to 1. The `nextPageParam` supports dot notation for nested values (i.e. `meta.next`).

Example Schema:

```yml
Expand Down
6 changes: 6 additions & 0 deletions src/cli.mts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export type LimitedUserConfig = {
schemaType?: "form" | "json";
pageParam: string;
nextPageParam: string;
initialPageParam: string | number;
};

async function setupProgram() {
Expand Down Expand Up @@ -102,6 +103,11 @@ async function setupProgram() {
"Name of the response parameter used for next page",
"nextPage",
)
.option(
"--initialPageParam <value>",
"Initial page value to query",
"initialPageParam",
)
.parse();

const options = program.opts<LimitedUserConfig>();
Expand Down
9 changes: 6 additions & 3 deletions src/common.mts
Original file line number Diff line number Diff line change
Expand Up @@ -163,9 +163,12 @@ export function formatOptions(options: LimitedUserConfig) {
} else if (!Number.isNaN(parsedNumber)) {
(acc as unknown as Record<string, number>)[typedKey] = parsedNumber;
} else {
(acc as unknown as Record<string, string | undefined | boolean>)[
typedKey
] = typedValue;
(
acc as unknown as Record<
string,
string | number | undefined | boolean
>
)[typedKey] = typedValue;
}
return acc;
},
Expand Down
3 changes: 2 additions & 1 deletion src/createExports.mts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export const createExports = (
service: Service,
pageParam: string,
nextPageParam: string,
initialPageParam: string,
) => {
const { klasses } = service;
const methods = klasses.flatMap((k) => k.methods);
Expand All @@ -29,7 +30,7 @@ export const createExports = (
);

const allGetQueries = allGet.map((m) =>
createUseQuery(m, pageParam, nextPageParam),
createUseQuery(m, pageParam, nextPageParam, initialPageParam),
);
const allPrefetchQueries = allGet.map((m) => createPrefetch(m));

Expand Down
11 changes: 10 additions & 1 deletion src/createSource.mts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ const createSourceFile = async (
serviceEndName: string,
pageParam: string,
nextPageParam: string,
initialPageParam: string,
) => {
const project = new Project({
// Optionally specify compiler options, tsconfig.json, in-memory file system, and more here.
Expand All @@ -30,7 +31,12 @@ const createSourceFile = async (
project,
});

const exports = createExports(service, pageParam, nextPageParam);
const exports = createExports(
service,
pageParam,
nextPageParam,
initialPageParam,
);

const commonSource = ts.factory.createSourceFile(
[...imports, ...exports.allCommon],
Expand Down Expand Up @@ -111,12 +117,14 @@ export const createSource = async ({
serviceEndName,
pageParam,
nextPageParam,
initialPageParam,
}: {
outputPath: string;
version: string;
serviceEndName: string;
pageParam: string;
nextPageParam: string;
initialPageParam: string;
}) => {
const queriesFile = ts.createSourceFile(
`${OpenApiRqFiles.queries}.ts`,
Expand Down Expand Up @@ -180,6 +188,7 @@ export const createSource = async ({
serviceEndName,
pageParam,
nextPageParam,
initialPageParam,
);

const comment = `// generated with @7nohe/openapi-react-query-codegen@${version} \n\n`;
Expand Down
33 changes: 27 additions & 6 deletions src/createUseQuery.mts
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,7 @@ export function createQueryHook({
className,
pageParam,
nextPageParam,
initialPageParam,
}: {
queryString: "useSuspenseQuery" | "useQuery" | "useInfiniteQuery";
suffix: string;
Expand All @@ -238,6 +239,7 @@ export function createQueryHook({
className: string;
pageParam?: string;
nextPageParam?: string;
initialPageParam?: string;
}) {
const methodName = getNameFromMethod(method);
const customHookName = hookNameFromMethod({ method, className });
Expand Down Expand Up @@ -447,7 +449,11 @@ export function createQueryHook({
),
),
),
...createInfiniteQueryParams(pageParam, nextPageParam),
...createInfiniteQueryParams(
pageParam,
nextPageParam,
initialPageParam,
),
ts.factory.createSpreadAssignment(
ts.factory.createIdentifier("options"),
),
Expand All @@ -467,6 +473,7 @@ export const createUseQuery = (
{ className, method, jsDoc }: MethodDescription,
pageParam: string,
nextPageParam: string,
initialPageParam: string,
) => {
const methodName = getNameFromMethod(method);
const queryKey = createQueryKeyFromMethod({ method, className });
Expand Down Expand Up @@ -517,6 +524,7 @@ export const createUseQuery = (
className,
pageParam,
nextPageParam,
initialPageParam,
})
: undefined;

Expand Down Expand Up @@ -625,14 +633,18 @@ function queryKeyFn(
);
}

function createInfiniteQueryParams(pageParam?: string, nextPageParam?: string) {
function createInfiniteQueryParams(
pageParam?: string,
nextPageParam?: string,
initialPageParam = "1",
) {
if (pageParam === undefined || nextPageParam === undefined) {
return [];
}
return [
ts.factory.createPropertyAssignment(
ts.factory.createIdentifier("initialPageParam"),
ts.factory.createNumericLiteral(1),
ts.factory.createStringLiteral(initialPageParam),
),
ts.factory.createPropertyAssignment(
ts.factory.createIdentifier("getNextPageParam"),
Expand All @@ -655,9 +667,18 @@ function createInfiniteQueryParams(pageParam?: string, nextPageParam?: string) {
ts.factory.createParenthesizedExpression(
ts.factory.createAsExpression(
ts.factory.createIdentifier("response"),
ts.factory.createTypeReferenceNode(
ts.factory.createIdentifier(`{ ${nextPageParam}: number }`),
),
nextPageParam.split(".").reduceRight((acc, segment) => {
return ts.factory.createTypeLiteralNode([
ts.factory.createPropertySignature(
undefined,
ts.factory.createIdentifier(segment),
undefined,
acc,
),
]);
}, ts.factory.createKeywordTypeNode(
ts.SyntaxKind.NumberKeyword,
) as ts.TypeNode),
),
),
ts.factory.createIdentifier(nextPageParam),
Expand Down
1 change: 1 addition & 0 deletions src/generate.mts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ export async function generate(options: LimitedUserConfig, version: string) {
serviceEndName: "Service", // we are hard coding this because changing the service end name was depreciated in @hey-api/openapi-ts
pageParam: formattedOptions.pageParam,
nextPageParam: formattedOptions.nextPageParam,
initialPageParam: formattedOptions.initialPageParam.toString(),
});
await print(source, formattedOptions);
const queriesOutputPath = buildQueriesOutputPath(options.output);
Expand Down
8 changes: 7 additions & 1 deletion tests/__snapshots__/generate.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,13 @@ import * as Common from "./common";
export const useDefaultServiceFindPaginatedPetsInfinite = <TData = InfiniteData<Common.DefaultServiceFindPaginatedPetsDefaultResponse>, TError = unknown, TQueryKey extends Array<unknown> = unknown[]>({ limit, tags }: {
limit?: number;
tags?: string[];
} = {}, queryKey?: TQueryKey, options?: Omit<UseInfiniteQueryOptions<TData, TError>, "queryKey" | "queryFn">) => useInfiniteQuery({ queryKey: Common.UseDefaultServiceFindPaginatedPetsKeyFn({ limit, tags }, queryKey), queryFn: ({ pageParam }) => DefaultService.findPaginatedPets({ limit, page: pageParam as number, tags }) as TData, initialPageParam: 1, getNextPageParam: response => (response as { nextPage: number }).nextPage, ...options });
} = {}, queryKey?: TQueryKey, options?: Omit<UseInfiniteQueryOptions<TData, TError>, "queryKey" | "queryFn">) => useInfiniteQuery({
queryKey: Common.UseDefaultServiceFindPaginatedPetsKeyFn({ limit, tags }, queryKey), queryFn: ({ pageParam }) => DefaultService.findPaginatedPets({ limit, page: pageParam as number, tags }) as TData, initialPageParam: "initial", getNextPageParam: response => (response as {
meta: {
next: number;
};
}).meta.next, ...options
});
"
`;

Expand Down
2 changes: 1 addition & 1 deletion tests/createExports.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ describe(fileName, () => {
});
project.addSourceFilesAtPaths(path.join(outputPath(fileName), "**", "*"));
const service = await getServices(project);
const exports = createExports(service, "page", "nextPage");
const exports = createExports(service, "page", "nextPage", "initial");

const commonTypes = exports.allCommon
.filter((c) => c.kind === SyntaxKind.TypeAliasDeclaration)
Expand Down
3 changes: 2 additions & 1 deletion tests/generate.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ describe("generate", () => {
output: path.join("tests", "outputs"),
lint: "eslint",
pageParam: "page",
nextPageParam: "nextPage",
nextPageParam: "meta.next",
initialPageParam: "initial",
};
await generate(options, "1.0.0");
});
Expand Down
Loading