Skip to content

Commit

Permalink
support skipping count aggregate on hasura (#120)
Browse files Browse the repository at this point in the history
  • Loading branch information
mohammad-bolt authored Jul 27, 2022
1 parent b757809 commit 8503ba7
Show file tree
Hide file tree
Showing 5 changed files with 60 additions and 37 deletions.
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "ra-data-hasura",
"version": "0.5.1",
"version": "0.5.2",
"description": "A data provider for connecting react-admin to a Hasura endpoint",
"main": "dist/index.js",
"typings": "dist/index.d.ts",
Expand Down
57 changes: 31 additions & 26 deletions src/buildGqlQuery/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,35 +59,40 @@ export const buildGqlQuery: BuildGqlQuery =
aorFetchType === GET_MANY ||
aorFetchType === GET_MANY_REFERENCE
) {
let gqlArray = [
gqlTypes.field(
gqlTypes.name(queryType.name),
gqlTypes.name('items'),
args,
null,
gqlTypes.selectionSet(fields)
),
];
// Skip aggregate calls when provided aggregateFieldName function returns NO_COUNT.
// This is useful to avoid expensive count queries.
if (aggregateFieldName(queryType.name) !== 'NO_COUNT') {
gqlArray.push(
gqlTypes.field(
gqlTypes.name(aggregateFieldName(queryType.name)),
gqlTypes.name('total'),
metaArgs,
null,
gqlTypes.selectionSet([
gqlTypes.field(
gqlTypes.name('aggregate'),
null,
null,
null,
gqlTypes.selectionSet([gqlTypes.field(gqlTypes.name('count'))])
),
])
)
);
}
return gqlTypes.document([
gqlTypes.operationDefinition(
'query',
gqlTypes.selectionSet([
gqlTypes.field(
gqlTypes.name(queryType.name),
gqlTypes.name('items'),
args,
null,
gqlTypes.selectionSet(fields)
),
gqlTypes.field(
gqlTypes.name(aggregateFieldName(queryType.name)),
gqlTypes.name('total'),
metaArgs,
null,
gqlTypes.selectionSet([
gqlTypes.field(
gqlTypes.name('aggregate'),
null,
null,
null,
gqlTypes.selectionSet([
gqlTypes.field(gqlTypes.name('count')),
])
),
])
),
]),
gqlTypes.selectionSet(gqlArray),
gqlTypes.name(queryType.name),
apolloArgs
),
Expand Down
11 changes: 10 additions & 1 deletion src/buildQuery/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,23 @@ import buildGqlQuery, { BuildGqlQueryFactory } from '../buildGqlQuery';
import { getResponseParser, GetResponseParser } from '../getResponseParser';
import type { FetchType, IntrospectionResult } from '../types';

export type QueryResponse = {
data: any;
total?: number;
pageInfo?: {
hasNextPage?: boolean;
hasPreviousPage?: boolean;
};
};

export type BuildQuery = (introspectionResults: IntrospectionResult) => (
aorFetchType: FetchType,
resourceName: string,
params: any
) => {
query: any;
variables: any;
parseResponse: ({ data }: any) => { data: any; total?: number };
parseResponse: ({ data }: any) => QueryResponse;
};

export type BuildQueryFactory = (
Expand Down
23 changes: 16 additions & 7 deletions src/getResponseParser/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,15 @@ import {
DELETE_MANY,
} from '../helpers/fetchActions';
import { IntrospectionResult, IntrospectedResource, FetchType } from '../types';
import { QueryResponse } from '../buildQuery';
import { sanitizeResource } from './sanitizeResource';

export type GetResponseParser = (introspectionResults: IntrospectionResult) => (
export type GetResponseParser = (
introspectionResults: IntrospectionResult
) => (
aorFetchType: FetchType,
resource?: IntrospectedResource
) => (res: { data: any }) => {
data: any;
total?: number;
};
) => (res: { data: any }) => QueryResponse;

export const getResponseParser: GetResponseParser =
() => (aorFetchType) => (res) => {
Expand All @@ -27,10 +27,19 @@ export const getResponseParser: GetResponseParser =
switch (aorFetchType) {
case GET_MANY_REFERENCE:
case GET_LIST:
return {
let output: QueryResponse = {
data: response.items.map(sanitizeResource),
total: response.total.aggregate.count,
};
if (typeof response.total !== 'undefined') {
output.total = response.total.aggregate.count;
} else {
// TODO: behave smarter and set hasNextPage=false when no more records exist.
output.pageInfo = {
hasPreviousPage: true,
hasNextPage: true,
};
}
return output;

case GET_MANY:
return { data: response.items.map(sanitizeResource) };
Expand Down

0 comments on commit 8503ba7

Please sign in to comment.