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

Allow query hook parameters to be null. #1046

Merged
merged 3 commits into from
Mar 9, 2023
Merged
Show file tree
Hide file tree
Changes from 2 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
69 changes: 42 additions & 27 deletions packages/commerce-sdk-react/src/hooks/ShopperBaskets/query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,25 @@
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
*/
import {UseQueryResult} from '@tanstack/react-query'
import {ApiClients, ApiQueryOptions, Argument, DataType} from '../types'
import {ApiClients, ApiQueryOptions, Argument, DataType, NullableParameters} from '../types'
import useCommerceApi from '../useCommerceApi'
import {useQuery} from '../useQuery'
import {mergeOptions} from '../utils'
import {mergeOptions, omitNullableParameters} from '../utils'
import * as queryKeyHelpers from './queryKeyHelpers'

type Client = ApiClients['shopperBaskets']

/**
* Gets a basket.
* @parameter apiOptions - Options to pass through to `commerce-sdk-isomorphic`, with `null` accepted for unset API parameters.
* @parameter queryOptions - TanStack Query query options, with `enabled` by default set to check that all required API parameters have been set.
* @returns A TanStack Query query hook with data from the Shopper Baskets `getBasket` endpoint.
* @see {@link https://developer.salesforce.com/docs/commerce/commerce-api/references/shopper-baskets?meta=getBasket| Salesforce Developer Center} for more information about the API endpoint.
* @see {@link https://salesforcecommercecloud.github.io/commerce-sdk-isomorphic/classes/shopperbaskets.shopperbaskets-1.html#getbasket | `commerce-sdk-isomorphic` documentation} for more information on the parameters and returned data type.
* @see {@link https://tanstack.com/query/latest/docs/react/reference/useQuery | TanStack Query `useQuery` reference} for more information about the return value.
*/
export const useBasket = (
apiOptions: Argument<Client['getBasket']>,
apiOptions: NullableParameters<Argument<Client['getBasket']>>,
queryOptions: ApiQueryOptions<Client['getBasket']> = {}
): UseQueryResult<DataType<Client['getBasket']>> => {
type Options = Argument<Client['getBasket']>
Expand All @@ -30,29 +32,32 @@ export const useBasket = (
const methodName = 'getBasket'
const requiredParameters = ['organizationId', 'basketId', 'siteId'] as const

// Parameters can be set in `apiOptions` or `client.clientConfig`, we must merge them in order
// to generate the correct query key.
const netOptions = mergeOptions(client, apiOptions)
// Parameters can be set in `apiOptions` or `client.clientConfig`;
// we must merge them in order to generate the correct query key.
const netOptions = omitNullableParameters(mergeOptions(client, apiOptions))
const queryKey = queryKeyHelpers[methodName].queryKey(netOptions.parameters)
// We don't use `netOptions` here because we manipulate the options in `useQuery`.
const method = async (options: Options) => await client[methodName](options)

// For some reason, if we don't explicitly set these generic parameters, the inferred type for
// `Data` sometimes, but not always, includes `Response`, which is incorrect. I don't know why.
return useQuery<Options, Data>(netOptions, queryOptions, {
return useQuery<Client, Options, Data>(netOptions, queryOptions, {
method,
queryKey,
requiredParameters
})
}
/**
* Gets applicable payment methods for an existing basket considering the open payment amount only.
* @parameter apiOptions - Options to pass through to `commerce-sdk-isomorphic`, with `null` accepted for unset API parameters.
* @parameter queryOptions - TanStack Query query options, with `enabled` by default set to check that all required API parameters have been set.
* @returns A TanStack Query query hook with data from the Shopper Baskets `getPaymentMethodsForBasket` endpoint.
* @see {@link https://developer.salesforce.com/docs/commerce/commerce-api/references/shopper-baskets?meta=getPaymentMethodsForBasket| Salesforce Developer Center} for more information about the API endpoint.
* @see {@link https://salesforcecommercecloud.github.io/commerce-sdk-isomorphic/classes/shopperbaskets.shopperbaskets-1.html#getpaymentmethodsforbasket | `commerce-sdk-isomorphic` documentation} for more information on the parameters and returned data type.
* @see {@link https://tanstack.com/query/latest/docs/react/reference/useQuery | TanStack Query `useQuery` reference} for more information about the return value.
*/
export const usePaymentMethodsForBasket = (
apiOptions: Argument<Client['getPaymentMethodsForBasket']>,
apiOptions: NullableParameters<Argument<Client['getPaymentMethodsForBasket']>>,
queryOptions: ApiQueryOptions<Client['getPaymentMethodsForBasket']> = {}
): UseQueryResult<DataType<Client['getPaymentMethodsForBasket']>> => {
type Options = Argument<Client['getPaymentMethodsForBasket']>
Expand All @@ -61,29 +66,32 @@ export const usePaymentMethodsForBasket = (
const methodName = 'getPaymentMethodsForBasket'
const requiredParameters = ['organizationId', 'basketId', 'siteId'] as const

// Parameters can be set in `apiOptions` or `client.clientConfig`, we must merge them in order
// to generate the correct query key.
const netOptions = mergeOptions(client, apiOptions)
// Parameters can be set in `apiOptions` or `client.clientConfig`;
// we must merge them in order to generate the correct query key.
const netOptions = omitNullableParameters(mergeOptions(client, apiOptions))
const queryKey = queryKeyHelpers[methodName].queryKey(netOptions.parameters)
// We don't use `netOptions` here because we manipulate the options in `useQuery`.
const method = async (options: Options) => await client[methodName](options)

// For some reason, if we don't explicitly set these generic parameters, the inferred type for
// `Data` sometimes, but not always, includes `Response`, which is incorrect. I don't know why.
return useQuery<Options, Data>(netOptions, queryOptions, {
return useQuery<Client, Options, Data>(netOptions, queryOptions, {
method,
queryKey,
requiredParameters
})
}
/**
* Gets applicable price books for an existing basket.
* @parameter apiOptions - Options to pass through to `commerce-sdk-isomorphic`, with `null` accepted for unset API parameters.
* @parameter queryOptions - TanStack Query query options, with `enabled` by default set to check that all required API parameters have been set.
* @returns A TanStack Query query hook with data from the Shopper Baskets `getPriceBooksForBasket` endpoint.
* @see {@link https://developer.salesforce.com/docs/commerce/commerce-api/references/shopper-baskets?meta=getPriceBooksForBasket| Salesforce Developer Center} for more information about the API endpoint.
* @see {@link https://salesforcecommercecloud.github.io/commerce-sdk-isomorphic/classes/shopperbaskets.shopperbaskets-1.html#getpricebooksforbasket | `commerce-sdk-isomorphic` documentation} for more information on the parameters and returned data type.
* @see {@link https://tanstack.com/query/latest/docs/react/reference/useQuery | TanStack Query `useQuery` reference} for more information about the return value.
*/
export const usePriceBooksForBasket = (
apiOptions: Argument<Client['getPriceBooksForBasket']>,
apiOptions: NullableParameters<Argument<Client['getPriceBooksForBasket']>>,
queryOptions: ApiQueryOptions<Client['getPriceBooksForBasket']> = {}
): UseQueryResult<DataType<Client['getPriceBooksForBasket']>> => {
type Options = Argument<Client['getPriceBooksForBasket']>
Expand All @@ -92,29 +100,32 @@ export const usePriceBooksForBasket = (
const methodName = 'getPriceBooksForBasket'
const requiredParameters = ['organizationId', 'basketId', 'siteId'] as const

// Parameters can be set in `apiOptions` or `client.clientConfig`, we must merge them in order
// to generate the correct query key.
const netOptions = mergeOptions(client, apiOptions)
// Parameters can be set in `apiOptions` or `client.clientConfig`;
// we must merge them in order to generate the correct query key.
const netOptions = omitNullableParameters(mergeOptions(client, apiOptions))
const queryKey = queryKeyHelpers[methodName].queryKey(netOptions.parameters)
// We don't use `netOptions` here because we manipulate the options in `useQuery`.
const method = async (options: Options) => await client[methodName](options)

// For some reason, if we don't explicitly set these generic parameters, the inferred type for
// `Data` sometimes, but not always, includes `Response`, which is incorrect. I don't know why.
return useQuery<Options, Data>(netOptions, queryOptions, {
return useQuery<Client, Options, Data>(netOptions, queryOptions, {
method,
queryKey,
requiredParameters
})
}
/**
* Gets the applicable shipping methods for a certain shipment of a basket.
* @parameter apiOptions - Options to pass through to `commerce-sdk-isomorphic`, with `null` accepted for unset API parameters.
* @parameter queryOptions - TanStack Query query options, with `enabled` by default set to check that all required API parameters have been set.
* @returns A TanStack Query query hook with data from the Shopper Baskets `getShippingMethodsForShipment` endpoint.
* @see {@link https://developer.salesforce.com/docs/commerce/commerce-api/references/shopper-baskets?meta=getShippingMethodsForShipment| Salesforce Developer Center} for more information about the API endpoint.
* @see {@link https://salesforcecommercecloud.github.io/commerce-sdk-isomorphic/classes/shopperbaskets.shopperbaskets-1.html#getshippingmethodsforshipment | `commerce-sdk-isomorphic` documentation} for more information on the parameters and returned data type.
* @see {@link https://tanstack.com/query/latest/docs/react/reference/useQuery | TanStack Query `useQuery` reference} for more information about the return value.
*/
export const useShippingMethodsForShipment = (
apiOptions: Argument<Client['getShippingMethodsForShipment']>,
apiOptions: NullableParameters<Argument<Client['getShippingMethodsForShipment']>>,
queryOptions: ApiQueryOptions<Client['getShippingMethodsForShipment']> = {}
): UseQueryResult<DataType<Client['getShippingMethodsForShipment']>> => {
type Options = Argument<Client['getShippingMethodsForShipment']>
Expand All @@ -123,29 +134,32 @@ export const useShippingMethodsForShipment = (
const methodName = 'getShippingMethodsForShipment'
const requiredParameters = ['organizationId', 'basketId', 'shipmentId', 'siteId'] as const

// Parameters can be set in `apiOptions` or `client.clientConfig`, we must merge them in order
// to generate the correct query key.
const netOptions = mergeOptions(client, apiOptions)
// Parameters can be set in `apiOptions` or `client.clientConfig`;
// we must merge them in order to generate the correct query key.
const netOptions = omitNullableParameters(mergeOptions(client, apiOptions))
const queryKey = queryKeyHelpers[methodName].queryKey(netOptions.parameters)
// We don't use `netOptions` here because we manipulate the options in `useQuery`.
const method = async (options: Options) => await client[methodName](options)

// For some reason, if we don't explicitly set these generic parameters, the inferred type for
// `Data` sometimes, but not always, includes `Response`, which is incorrect. I don't know why.
return useQuery<Options, Data>(netOptions, queryOptions, {
return useQuery<Client, Options, Data>(netOptions, queryOptions, {
method,
queryKey,
requiredParameters
})
}
/**
* This method gives you the external taxation data set by the PUT taxes API. This endpoint can be called only if external taxation mode was used for basket creation. See POST /baskets for more information.
* @parameter apiOptions - Options to pass through to `commerce-sdk-isomorphic`, with `null` accepted for unset API parameters.
* @parameter queryOptions - TanStack Query query options, with `enabled` by default set to check that all required API parameters have been set.
* @returns A TanStack Query query hook with data from the Shopper Baskets `getTaxesFromBasket` endpoint.
* @see {@link https://developer.salesforce.com/docs/commerce/commerce-api/references/shopper-baskets?meta=getTaxesFromBasket| Salesforce Developer Center} for more information about the API endpoint.
* @see {@link https://salesforcecommercecloud.github.io/commerce-sdk-isomorphic/classes/shopperbaskets.shopperbaskets-1.html#gettaxesfrombasket | `commerce-sdk-isomorphic` documentation} for more information on the parameters and returned data type.
* @see {@link https://tanstack.com/query/latest/docs/react/reference/useQuery | TanStack Query `useQuery` reference} for more information about the return value.
*/
export const useTaxesFromBasket = (
apiOptions: Argument<Client['getTaxesFromBasket']>,
apiOptions: NullableParameters<Argument<Client['getTaxesFromBasket']>>,
queryOptions: ApiQueryOptions<Client['getTaxesFromBasket']> = {}
): UseQueryResult<DataType<Client['getTaxesFromBasket']>> => {
type Options = Argument<Client['getTaxesFromBasket']>
Expand All @@ -154,15 +168,16 @@ export const useTaxesFromBasket = (
const methodName = 'getTaxesFromBasket'
const requiredParameters = ['organizationId', 'basketId', 'siteId'] as const

// Parameters can be set in `apiOptions` or `client.clientConfig`, we must merge them in order
// to generate the correct query key.
const netOptions = mergeOptions(client, apiOptions)
// Parameters can be set in `apiOptions` or `client.clientConfig`;
// we must merge them in order to generate the correct query key.
const netOptions = omitNullableParameters(mergeOptions(client, apiOptions))
const queryKey = queryKeyHelpers[methodName].queryKey(netOptions.parameters)
// We don't use `netOptions` here because we manipulate the options in `useQuery`.
const method = async (options: Options) => await client[methodName](options)

// For some reason, if we don't explicitly set these generic parameters, the inferred type for
// `Data` sometimes, but not always, includes `Response`, which is incorrect. I don't know why.
return useQuery<Options, Data>(netOptions, queryOptions, {
return useQuery<Client, Options, Data>(netOptions, queryOptions, {
method,
queryKey,
requiredParameters
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,40 +10,46 @@ import {pick} from '../utils'

// We must use a client with no parameters in order to have required/optional match the API spec
type Client = ShopperBaskets<{shortCode: string}>
type Params<T extends keyof QueryKeys> = NonNullable<Argument<Client[T]>['parameters']>
type Params<T extends keyof QueryKeys> = Partial<Argument<Client[T]>['parameters']>
export type QueryKeys = {
getBasket: ['/organizations/', string, '/baskets/', string, Params<'getBasket'>]
getBasket: [
'/organizations/',
string | undefined,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

React query allows undefined as a query key, but converts it to null when comparing query hashes (essentially converting the query key to a JSON string). I don't think that this matters, I think it's an internal implementation detail, and we can use undefined just fine, but maybe I'm wrong.

'/baskets/',
string | undefined,
Params<'getBasket'>
]
getPaymentMethodsForBasket: [
'/organizations/',
string,
string | undefined,
'/baskets/',
string,
string | undefined,
'/payment-methods',
Params<'getPaymentMethodsForBasket'>
]
getPriceBooksForBasket: [
'/organizations/',
string,
string | undefined,
'/baskets/',
string,
string | undefined,
'/price-books',
Params<'getPriceBooksForBasket'>
]
getShippingMethodsForShipment: [
'/organizations/',
string,
string | undefined,
'/baskets/',
string,
string | undefined,
'/shipments/',
string,
string | undefined,
'/shipping-methods',
Params<'getShippingMethodsForShipment'>
]
getTaxesFromBasket: [
'/organizations/',
string,
string | undefined,
'/baskets/',
string,
string | undefined,
'/taxes',
Params<'getTaxesFromBasket'>
]
Expand Down
17 changes: 10 additions & 7 deletions packages/commerce-sdk-react/src/hooks/ShopperContexts/query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,25 @@
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
*/
import {UseQueryResult} from '@tanstack/react-query'
import {ApiClients, ApiQueryOptions, Argument, DataType} from '../types'
import {ApiClients, ApiQueryOptions, Argument, DataType, NullableParameters} from '../types'
import useCommerceApi from '../useCommerceApi'
import {useQuery} from '../useQuery'
import {mergeOptions} from '../utils'
import {mergeOptions, omitNullableParameters} from '../utils'
import * as queryKeyHelpers from './queryKeyHelpers'

type Client = ApiClients['shopperContexts']

/**
* Gets the shopper's context based on the shopperJWT. ******** This API is currently a work in progress, and not available to use yet. ********
* @parameter apiOptions - Options to pass through to `commerce-sdk-isomorphic`, with `null` accepted for unset API parameters.
* @parameter queryOptions - TanStack Query query options, with `enabled` by default set to check that all required API parameters have been set.
* @returns A TanStack Query query hook with data from the Shopper Contexts `getShopperContext` endpoint.
* @see {@link https://developer.salesforce.com/docs/commerce/commerce-api/references/shopper-contexts?meta=getShopperContext| Salesforce Developer Center} for more information about the API endpoint.
* @see {@link https://salesforcecommercecloud.github.io/commerce-sdk-isomorphic/classes/shoppercontexts.shoppercontexts-1.html#getshoppercontext | `commerce-sdk-isomorphic` documentation} for more information on the parameters and returned data type.
* @see {@link https://tanstack.com/query/latest/docs/react/reference/useQuery | TanStack Query `useQuery` reference} for more information about the return value.
*/
export const useShopperContext = (
apiOptions: Argument<Client['getShopperContext']>,
apiOptions: NullableParameters<Argument<Client['getShopperContext']>>,
queryOptions: ApiQueryOptions<Client['getShopperContext']> = {}
): UseQueryResult<DataType<Client['getShopperContext']>> => {
type Options = Argument<Client['getShopperContext']>
Expand All @@ -30,15 +32,16 @@ export const useShopperContext = (
const methodName = 'getShopperContext'
const requiredParameters = ['organizationId', 'usid'] as const

// Parameters can be set in `apiOptions` or `client.clientConfig`, we must merge them in order
// to generate the correct query key.
const netOptions = mergeOptions(client, apiOptions)
// Parameters can be set in `apiOptions` or `client.clientConfig`;
// we must merge them in order to generate the correct query key.
const netOptions = omitNullableParameters(mergeOptions(client, apiOptions))
const queryKey = queryKeyHelpers[methodName].queryKey(netOptions.parameters)
// We don't use `netOptions` here because we manipulate the options in `useQuery`.
const method = async (options: Options) => await client[methodName](options)

// For some reason, if we don't explicitly set these generic parameters, the inferred type for
// `Data` sometimes, but not always, includes `Response`, which is incorrect. I don't know why.
return useQuery<Options, Data>(netOptions, queryOptions, {
return useQuery<Client, Options, Data>(netOptions, queryOptions, {
method,
queryKey,
requiredParameters
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@ import {pick} from '../utils'

// We must use a client with no parameters in order to have required/optional match the API spec
type Client = ShopperContexts<{shortCode: string}>
type Params<T extends keyof QueryKeys> = NonNullable<Argument<Client[T]>['parameters']>
type Params<T extends keyof QueryKeys> = Partial<Argument<Client[T]>['parameters']>
export type QueryKeys = {
getShopperContext: [
'/organizations/',
string,
string | undefined,
'/shopper-context/',
string,
string | undefined,
Params<'getShopperContext'>
]
}
Expand Down
Loading