frail-apricot
frail-apricot5d ago

useList CrudSort, wrong naming convention

I am having difficulties using Hasura as my dataProvider, using the graphql-default naming convention, it expects uppercase values for the order_by variable, which useList does not comply with. My code:
useList<GetFieldsFromList<LatestActivitiesAuditsQuery>>({
resource: "audits",
pagination: {
pageSize: limit,
},
sorters: [
{
field: "createdAt",
order: "DESC",
},
],
...
useList<GetFieldsFromList<LatestActivitiesAuditsQuery>>({
resource: "audits",
pagination: {
pageSize: limit,
},
sorters: [
{
field: "createdAt",
order: "DESC",
},
],
...
Error in console (attempting query): Error: expected one of the values ['ASC', 'ASC_NULLS_FIRST', 'ASC_NULLS_LAST', 'DESC', 'DESC_NULLS_FIRST', 'DESC_NULLS_LAST'] for type 'OrderBy', but found 'asc': Then I get error for ‘order: «DESC»’ in VSCode: Type '"DESC"' is not assignable to type '"asc" | "desc"'. Did you mean '"desc"'? CrudSort in refinedev core:
export type CrudSort = {
field: string;
order: "asc" | "desc";
};
export type CrudSort = {
field: string;
order: "asc" | "desc";
};
It seems the query is sent with lowercase. Is the only solution to edit CrudSort in @refinedev/core/src/contexts/data/types.ts?
12 Replies
kapa.ai
kapa.ai5d ago
Hi @Henrik. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave: ---------------------- The issue you're encountering is due to the mismatch between the expected values for the order_by variable in Hasura and the values provided by the CrudSort type in refine. Hasura expects uppercase values like ASC and DESC, while CrudSort in refine uses lowercase values asc and desc. To address this issue, you can create a custom data provider that transforms the sort order values to match Hasura's expectations. Here's a step-by-step guide on how to achieve this: 1. Create a Custom Data Provider: Extend the existing Hasura data provider to transform the sort order values. 2. Transform Sort Order Values: Modify the sorters property to convert asc to ASC and desc to DESC. Here is an example of how you can implement this:
import { DataProvider } from "@refinedev/core";
import { hasuraDataProvider } from "@refinedev/hasura";

const customHasuraDataProvider: DataProvider = {
...hasuraDataProvider,
getList: async (resource, params) => {
const { sorters, ...restParams } = params;

const transformedSorters = sorters?.map((sort) => ({
...sort,
order: sort.order.toUpperCase(),
}));

return hasuraDataProvider.getList(resource, {
...restParams,
sorters: transformedSorters,
});
},
// Similarly, you can override other methods like getOne, createMany, update, etc.
};

export default customHasuraDataProvider;
import { DataProvider } from "@refinedev/core";
import { hasuraDataProvider } from "@refinedev/hasura";

const customHasuraDataProvider: DataProvider = {
...hasuraDataProvider,
getList: async (resource, params) => {
const { sorters, ...restParams } = params;

const transformedSorters = sorters?.map((sort) => ({
...sort,
order: sort.order.toUpperCase(),
}));

return hasuraDataProvider.getList(resource, {
...restParams,
sorters: transformedSorters,
});
},
// Similarly, you can override other methods like getOne, createMany, update, etc.
};

export default customHasuraDataProvider;
3. Use the Custom Data Provider: Replace the default data provider with your custom data provider in your refine configuration.
import { Refine } from "@refinedev/core";
import customHasuraDataProvider from "./path-to-your-custom-data-provider";

const App = () => (
<Refine dataProvider={customHasuraDataProvider} />
);
import { Refine } from "@refinedev/core";
import customHasuraDataProvider from "./path-to-your-custom-data-provider";

const App = () => (
<Refine dataProvider={customHasuraDataProvider} />
);
By following these steps, you can ensure that the sort order values are correctly transformed to match Hasura's expectations, thus resolving the error you encountered. For more information on the useList hook and sorting, you can refer to the useList documentation (https://refine.dev/docs/data/hooks/use-list/#sorting). If you need further assistance, you can also check the Hasura DataProvider documentation (https://github.com/refinedev/refine/blob/master/examples/dataProvider/hasura/README.md) for additional context. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai5d ago
<@135097094825443328> kapa.ai is still learning and improving, please let us know how it did by reacting below
frail-apricot
frail-apricot5d ago
Is this the best solution? @kapa.ai Is this the best solution? It did not work
kapa.ai
kapa.ai5d ago
Let me check the knowledge base for you. One moment! :books: ---------------------- Given the constraints and the error you're encountering, it seems like the issue is deeply rooted in the type definitions and the expectations of the Hasura GraphQL API. Since modifying the CrudSort type directly in @refinedev/core is not ideal, another approach would be to handle the transformation at the query level. Here’s a refined approach to ensure the sort order values are correctly transformed: 1. Create a Custom Hook: Instead of modifying the data provider, you can create a custom hook that transforms the sort order values before passing them to useList. 2. Transform Sort Order Values: Modify the sorters property to convert asc to ASC and desc to DESC. Here is an example of how you can implement this:
import { useList, CrudSort } from "@refinedev/core";

const useCustomList = (params) => {
const { sorters, ...restParams } = params;

const transformedSorters = sorters?.map((sort: CrudSort) => ({
...sort,
order: sort.order.toUpperCase() as "ASC" | "DESC",
}));

return useList({
...restParams,
sorters: transformedSorters,
});
};

export default useCustomList;
import { useList, CrudSort } from "@refinedev/core";

const useCustomList = (params) => {
const { sorters, ...restParams } = params;

const transformedSorters = sorters?.map((sort: CrudSort) => ({
...sort,
order: sort.order.toUpperCase() as "ASC" | "DESC",
}));

return useList({
...restParams,
sorters: transformedSorters,
});
};

export default useCustomList;
3. Use the Custom Hook: Replace the useList hook with your custom hook in your component.
const { data, isLoading, error } = useCustomList<GetFieldsFromList<LatestActivitiesAuditsQuery>>({
resource: "audits",
pagination: {
pageSize: limit,
},
sorters: [
{
field: "createdAt",
order: "DESC",
},
],
// other parameters
});
const { data, isLoading, error } = useCustomList<GetFieldsFromList<LatestActivitiesAuditsQuery>>({
resource: "audits",
pagination: {
pageSize: limit,
},
sorters: [
{
field: "createdAt",
order: "DESC",
},
],
// other parameters
});
By using this custom hook, you ensure that the sort order values are transformed to match Hasura's expectations before they are passed to useList. If this approach still does not resolve the issue, it might be necessary to look into more advanced customizations or reach out to the refine community for further support. You can also refer to the refine documentation (https://refine.dev/docs) for more detailed guidance on customizing data providers and hooks. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai5d ago
<@135097094825443328> kapa.ai is still learning and improving, please let us know how it did by reacting below
frail-apricot
frail-apricot5d ago
@kapa.ai
const useCustomList = (params) => {
const { sorters, ...restParams } = params;

const transformedSorters = sorters?.map((sort: CrudSort) => ({
...sort,
order: sort.order.toUpperCase() as "ASC" | "DESC",
}));

return useList({
...restParams,
sorters: transformedSorters,
});
};
const useCustomList = (params) => {
const { sorters, ...restParams } = params;

const transformedSorters = sorters?.map((sort: CrudSort) => ({
...sort,
order: sort.order.toUpperCase() as "ASC" | "DESC",
}));

return useList({
...restParams,
sorters: transformedSorters,
});
};
Parameter 'params' implicitly has an 'any' type. @kapa.ai
const useCustomList = (params) => {
const { sorters, ...restParams } = params;

const transformedSorters = sorters?.map((sort: CrudSort) => ({
...sort,
order: sort.order.toUpperCase() as "ASC" | "DESC",
}));

return useList({
...restParams,
sorters: transformedSorters,
});
};
const useCustomList = (params) => {
const { sorters, ...restParams } = params;

const transformedSorters = sorters?.map((sort: CrudSort) => ({
...sort,
order: sort.order.toUpperCase() as "ASC" | "DESC",
}));

return useList({
...restParams,
sorters: transformedSorters,
});
};
Parameter 'params' implicitly has an 'any' type.
kapa.ai
kapa.ai5d ago
Let me check the knowledge base for you. One moment! :books: ---------------------- To address the TypeScript error where the parameter params implicitly has an any type, you need to explicitly define the type for params. Here’s how you can modify the custom hook to include proper type definitions: 1. Define the Type for Params: Create an interface for the parameters expected by the custom hook. 2. Use the Interface in the Custom Hook: Apply the interface to the params parameter. Here’s the updated code:
import { useList, CrudSort, BaseRecord, GetListResponse } from "@refinedev/core";

interface CustomListParams {
resource: string;
pagination?: {
pageSize: number;
current?: number;
};
sorters?: CrudSort[];
filters?: any[];
hasPagination?: boolean;
metaData?: any;
}

const useCustomList = <TData extends BaseRecord = BaseRecord>(
params: CustomListParams
): GetListResponse<TData> => {
const { sorters, ...restParams } = params;

const transformedSorters = sorters?.map((sort: CrudSort) => ({
...sort,
order: sort.order.toUpperCase() as "ASC" | "DESC",
}));

return useList<TData>({
...restParams,
sorters: transformedSorters,
});
};

export default useCustomList;
import { useList, CrudSort, BaseRecord, GetListResponse } from "@refinedev/core";

interface CustomListParams {
resource: string;
pagination?: {
pageSize: number;
current?: number;
};
sorters?: CrudSort[];
filters?: any[];
hasPagination?: boolean;
metaData?: any;
}

const useCustomList = <TData extends BaseRecord = BaseRecord>(
params: CustomListParams
): GetListResponse<TData> => {
const { sorters, ...restParams } = params;

const transformedSorters = sorters?.map((sort: CrudSort) => ({
...sort,
order: sort.order.toUpperCase() as "ASC" | "DESC",
}));

return useList<TData>({
...restParams,
sorters: transformedSorters,
});
};

export default useCustomList;
Usage Example Now you can use the useCustomList hook in your component:
const { data, isLoading, error } = useCustomList<GetFieldsFromList<LatestActivitiesAuditsQuery>>({
resource: "audits",
pagination: {
pageSize: limit,
},
sorters: [
{
field: "createdAt",
order: "DESC",
},
],
// other parameters
});
const { data, isLoading, error } = useCustomList<GetFieldsFromList<LatestActivitiesAuditsQuery>>({
resource: "audits",
pagination: {
pageSize: limit,
},
sorters: [
{
field: "createdAt",
order: "DESC",
},
],
// other parameters
});
This approach ensures that the params parameter has the correct type, and the sort order values are transformed to match Hasura's expectations. For more information on the useList hook and sorting, you can refer to the useList documentation (https://refine.dev/docs/data/hooks/use-list/#sorting). If you need further assistance, you can also check the Hasura DataProvider documentation (https://github.com/refinedev/refine/blob/master/examples/dataProvider/hasura/README.md) for additional context. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai5d ago
<@135097094825443328> kapa.ai is still learning and improving, please let us know how it did by reacting below
frail-apricot
frail-apricot5d ago
@kapa.ai Type 'QueryObserverResult<GetListResponse<TQueryFnData>, HttpError> & UseLoadingOvertimeReturnType' is not assignable to type 'GetListResponse<TData>'. Property 'total' is missing in type 'QueryObserverRefetchErrorResult<GetListResponse<TQueryFnData>, HttpError> & UseLoadingOvertimeReturnType' but required in type 'GetListResponse<TData>'.ts(2322) types.d.ts(186, 5): 'total' is declared here.
kapa.ai
kapa.ai5d ago
Let me check the knowledge base for you. One moment! :books: ---------------------- The error you're encountering indicates that the return type of your custom hook does not match the expected GetListResponse<TData> type, specifically because the total property is missing. To resolve this, you need to ensure that the return type of your custom hook includes all the necessary properties, including total. Here’s how you can adjust your custom hook to ensure it returns the correct type: 1. Ensure Correct Return Type: Make sure the custom hook returns an object that includes all properties expected by GetListResponse<TData>. 2. Type the Return Value Properly: Explicitly type the return value of the custom hook to match GetListResponse<TData>. Here’s the updated code:
import { useList, CrudSort, BaseRecord, GetListResponse, HttpError } from "@refinedev/core";
import { QueryObserverResult } from "react-query";

interface CustomListParams {
resource: string;
pagination?: {
pageSize: number;
current?: number;
};
sorters?: CrudSort[];
filters?: any[];
hasPagination?: boolean;
metaData?: any;
}

const useCustomList = <TData extends BaseRecord = BaseRecord>(
params: CustomListParams
): QueryObserverResult<GetListResponse<TData>, HttpError> & { elapsedTime?: number } => {
const { sorters, ...restParams } = params;

const transformedSorters = sorters?.map((sort: CrudSort) => ({
...sort,
order: sort.order.toUpperCase() as "ASC" | "DESC",
}));

return useList<TData>({
...restParams,
sorters: transformedSorters,
});
};

export default useCustomList;
import { useList, CrudSort, BaseRecord, GetListResponse, HttpError } from "@refinedev/core";
import { QueryObserverResult } from "react-query";

interface CustomListParams {
resource: string;
pagination?: {
pageSize: number;
current?: number;
};
sorters?: CrudSort[];
filters?: any[];
hasPagination?: boolean;
metaData?: any;
}

const useCustomList = <TData extends BaseRecord = BaseRecord>(
params: CustomListParams
): QueryObserverResult<GetListResponse<TData>, HttpError> & { elapsedTime?: number } => {
const { sorters, ...restParams } = params;

const transformedSorters = sorters?.map((sort: CrudSort) => ({
...sort,
order: sort.order.toUpperCase() as "ASC" | "DESC",
}));

return useList<TData>({
...restParams,
sorters: transformedSorters,
});
};

export default useCustomList;
Usage Example Now you can use the useCustomList hook in your component:
const { data, isLoading, error } = useCustomList<GetFieldsFromList<LatestActivitiesAuditsQuery>>({
resource: "audits",
pagination: {
pageSize: limit,
},
sorters: [
{
field: "createdAt",
order: "DESC",
},
],
// other parameters
});
const { data, isLoading, error } = useCustomList<GetFieldsFromList<LatestActivitiesAuditsQuery>>({
resource: "audits",
pagination: {
pageSize: limit,
},
sorters: [
{
field: "createdAt",
order: "DESC",
},
],
// other parameters
});
This approach ensures that the custom hook returns the correct type, including the total property, and matches the expected GetListResponse<TData> type. For more information on the useList hook and sorting, you can refer to the useList documentation (https://refine.dev/docs/data/hooks/use-list/#sorting). If you need further assistance, you can also check the Hasura DataProvider documentation (https://github.com/refinedev/refine/blob/master/examples/dataProvider/hasura/README.md) for additional context. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai5d ago
<@135097094825443328> kapa.ai is still learning and improving, please let us know how it did by reacting below
frail-apricot
frail-apricot4d ago
@contributor Is there any way to pass uppercase order (ASC/DESC) to Hasura, my chosen data provider, using the useList sorters? UPDATE I am having difficulties correctly fetching data from my database using Hasura as the data provider. I am trying to utilize the useList hook to retrieve data, using the following code snippet:
export const DashboardTasksChart: React.FC = () => {
const { list } = useNavigation();
const { data, isError, error } = useList<
GetFieldsFromList<DashboardTasksChartQuery>
>({
resource: "task_stages",
pagination: {
pageSize: 4,
},
sorters: [
{
field: "title",
order: "asc",
},
],
filters: [
{
field: "id",
operator: "eq",
value: 1,
},
],
meta: {
gqlQuery: DASHBOARD_TASKS_CHART_QUERY
},
});

if (isError) {
console.error("Error fetching task chart data", error);
return null;
}

...
export const DashboardTasksChart: React.FC = () => {
const { list } = useNavigation();
const { data, isError, error } = useList<
GetFieldsFromList<DashboardTasksChartQuery>
>({
resource: "task_stages",
pagination: {
pageSize: 4,
},
sorters: [
{
field: "title",
order: "asc",
},
],
filters: [
{
field: "id",
operator: "eq",
value: 1,
},
],
meta: {
gqlQuery: DASHBOARD_TASKS_CHART_QUERY
},
});

if (isError) {
console.error("Error fetching task chart data", error);
return null;
}

...
While using sorters, I get the following error in the console: Error: expected one of the values ['ASC', 'ASC_NULLS_FIRST', 'ASC_NULLS_LAST', 'DESC', 'DESC_NULLS_FIRST', 'DESC_NULLS_LAST'] for type 'OrderBy', but found 'asc': If I make 'asc' uppercase, I get the following warning in my IDE:
Type '"DESC"' is not assignable to type '"asc" | "desc"'. Did you mean '"desc"'?
Type '"DESC"' is not assignable to type '"asc" | "desc"'. Did you mean '"desc"'?
It seems crudSort is hard-coded to only accept lowercase sorters, which Hasura does not accept (using the graphql-default naming convention, released 2022). If I remove the sorters, and only use the filtering, I get the following error in the console:
Error: variable 'where' is declared as 'taskStages_bool_exp', but used where 'TaskStagesBoolExp' is expected: {"response":{"errors":[{"message":"variable 'where' is declared as 'taskStages_bool_exp', but used where 'TaskStagesBoolExp' is expected","extensions":{"path":"$.selectionSet.taskStages.args.where","code":"validation-failed"}}],"status":200,"headers":{"map":{"content-type":"application/json; charset=utf-8"}}},"request":{"query":"query ($limit: Int, $offset: Int, $where: taskStages_bool_exp) { taskStages (limit: $limit, offset: $offset, where: $where) taskStages_aggregate (where: $where) { aggregate { count } } }","variables":{"limit":4,"offset":0,"where":{"_and":[{"id":{"_eq":1}}]}}}}
Error: variable 'where' is declared as 'taskStages_bool_exp', but used where 'TaskStagesBoolExp' is expected: {"response":{"errors":[{"message":"variable 'where' is declared as 'taskStages_bool_exp', but used where 'TaskStagesBoolExp' is expected","extensions":{"path":"$.selectionSet.taskStages.args.where","code":"validation-failed"}}],"status":200,"headers":{"map":{"content-type":"application/json; charset=utf-8"}}},"request":{"query":"query ($limit: Int, $offset: Int, $where: taskStages_bool_exp) { taskStages (limit: $limit, offset: $offset, where: $where) taskStages_aggregate (where: $where) { aggregate { count } } }","variables":{"limit":4,"offset":0,"where":{"_and":[{"id":{"_eq":1}}]}}}}
Hasura default uses taskStages_bool_exp, but with the graphql-default naming convention, it expects types as PascalCase, such as: TaskStagesBoolExp, which is defined in my query:
export const DASHBOARD_TASKS_CHART_QUERY = gql`
query DashboardTasksChart(
$where: TaskStagesBoolExp
$order_by: [TaskStagesOrderBy!]
$limit: Int!
$offset: Int!
) {
taskStages(where: $where, orderBy: $order_by, limit: $limit, offset: $offset) {
title
tasksAggregate {
aggregate {
totalCount: count
}
}
}
}
`;
export const DASHBOARD_TASKS_CHART_QUERY = gql`
query DashboardTasksChart(
$where: TaskStagesBoolExp
$order_by: [TaskStagesOrderBy!]
$limit: Int!
$offset: Int!
) {
taskStages(where: $where, orderBy: $order_by, limit: $limit, offset: $offset) {
title
tasksAggregate {
aggregate {
totalCount: count
}
}
}
}
`;
Is there any quick-fix to making the naming-convention I have started with, correctly working? Thanks in advance. UPDATE 2 Adding:
meta: {
gqlQuery: DASHBOARD_TASKS_CHART_QUERY
},
meta: {
gqlQuery: DASHBOARD_TASKS_CHART_QUERY
},
to the useList hook, seems to get rid of the error Error: variable 'where' is declared as 'taskStages_bool_exp', but used where 'TaskStagesBoolExp' is expected: ... This, on the other hand, causes several other errors, such as: Error fetching task chart data TypeError: H[c] is undefined and errors relating to authentication error. Also:
Uncaught Error: Rendered fewer hooks than expected. This may be caused by an accidental early return statement.
Uncaught Error: Rendered fewer hooks than expected. This may be caused by an accidental early return statement.
I do believe I have correctly defined Hasura as a graphql data provider, as I have managed to correctly fetch data using the useCustom hook.