Skip to content

Commit 7640530

Browse files
committed
feat(datocms): load collection with route fragment definitions
1 parent 1118856 commit 7640530

File tree

5 files changed

+47
-40
lines changed

5 files changed

+47
-40
lines changed

.graphqlrc.ts

-2
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ module.exports = {
3434
* @see https://github.com/Tonel/typescript-type-generation-graphql-example/blob/2d43584b1d75c9086c4ddd594a6b2401a29b0055/graphql.config.yml#L11-L23
3535
*/
3636
config: {
37-
dedupeFragments: true,
3837
strictScalars: true,
3938
scalars: {
4039
BooleanType: 'boolean',
@@ -68,4 +67,3 @@ module.exports = {
6867
},
6968
},
7069
};
71-

src/env.d.ts

+6
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,9 @@ declare module '*.query.graphql' {
1515
const value: DocumentNode;
1616
export = value;
1717
}
18+
19+
declare module '*.fragment.graphql' {
20+
import { DocumentNode } from 'graphql';
21+
const value: DocumentNode;
22+
export default value;
23+
}

src/lib/datocms/index.ts

+30-11
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1-
import { parse } from 'graphql';
1+
import { Kind, parse, type DocumentNode } from 'graphql';
22
import { print } from 'graphql/language/printer';
3-
import type { DocumentNode } from 'graphql';
43
import type { SiteLocale } from '@lib/i18n/types';
54
import { titleSuffix } from '@lib/seo';
65
import { datocmsBuildTriggerId, datocmsEnvironment } from '../../../datocms-environment';
@@ -61,8 +60,13 @@ interface CollectionData<CollectionType> {
6160
[key: string]: CollectionType[];
6261
}
6362

64-
type CollectionMeta = {
65-
count: number;
63+
type CollectionInfo = {
64+
meta: {
65+
count: number;
66+
}
67+
records: [{
68+
__typename: string;
69+
}]
6670
};
6771

6872
/**
@@ -72,35 +76,50 @@ type CollectionMeta = {
7276
* DatoCMS GraphQL API has a limit of 100 records per request.
7377
* This function uses pagination to get all records.
7478
* @see https://www.datocms.com/docs/content-delivery-api/pagination
79+
*
80+
* @param {string} params.collection
81+
* - The name of the DatoCMS collection. For example, `"Pages"`
82+
* @param {DocumentNode|string} params.fragment
83+
* - The GraphQL fragment to include for each record, For example `pageRouteFragment`.
7584
*/
7685
export const datocmsCollection = async <CollectionType>({
7786
collection,
7887
fragment
7988
}: {
80-
collection: string,
81-
fragment: string
89+
collection: string;
90+
fragment: string | DocumentNode;
8291
}) => {
83-
const { meta } = await datocmsRequest({
92+
const {
93+
meta,
94+
records: [{ __typename: type }]
95+
} = await datocmsRequest<CollectionInfo>({
8496
query: parse(/* graphql */`
8597
query ${collection}Meta {
98+
records: all${collection}(first: 1) { __typename }
8699
meta: _all${collection}Meta { count }
87100
}
88101
`)
89-
}) as { meta: CollectionMeta };
90-
102+
});
91103
const recordsPerPage = 100; // DatoCMS GraphQL API has a limit of 100 records per request
92104
const totalPages = Math.ceil(meta.count / recordsPerPage);
93105
const records: CollectionType[] = [];
94-
106+
const fragmentDocument = typeof fragment === 'string'
107+
? parse(`fragment InlineFragment on ${type} { ${fragment} }`)
108+
: fragment;
109+
const { definitions } = fragmentDocument;
110+
const fragmentDefinition = definitions.find(({ kind }) => kind === Kind.FRAGMENT_DEFINITION);
111+
95112
for (let page = 0; page < totalPages; page++) {
96113
const data = await datocmsRequest({
97114
query: parse(/* graphql */`
115+
${print(fragmentDocument)}
116+
98117
query All${collection} {
99118
${collection}: all${collection} (
100119
first: ${recordsPerPage},
101120
skip: ${page * recordsPerPage}
102121
) {
103-
${fragment}
122+
...${fragmentDefinition?.name?.value}
104123
}
105124
}
106125
`),

src/lib/routing/page.ts

+3-8
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,6 @@
11
import type { PageRouteFragment, SiteLocale } from '@lib/datocms/types';
22
import { getLocalizedSlug, getSlugFromPath, type MaybeSlug } from './lib/slug';
33

4-
export type PageRouteForPath =
5-
& Pick<PageRouteFragment, '_allSlugLocales' | 'parentPage'>
6-
& { parentPage?: PageRouteForPath | null };
7-
8-
94
export function getParentPages(page: PageRouteFragment): PageRouteFragment[] {
105
if (page.parentPage) {
116
return [
@@ -27,9 +22,9 @@ export function getParentPages(page: PageRouteFragment): PageRouteFragment[] {
2722
* - ['grand-parent', 'parent-slug'] (grand parent and parent page available in given locale)
2823
* - ['grand-parent', undefined] (grand parent page available, parent page not available in given locale)
2924
*/
30-
export const getParentSlugs = ({ locale, page }: { locale?: SiteLocale, page: PageRouteForPath }): MaybeSlug[] => {
25+
export const getParentSlugs = ({ locale, page }: { locale?: SiteLocale, page: PageRouteFragment }): MaybeSlug[] => {
3126
if (page.parentPage) {
32-
const slug = getLocalizedSlug<PageRouteForPath>({ locale, record: page.parentPage });
27+
const slug = getLocalizedSlug<PageRouteFragment>({ locale, record: page.parentPage });
3328
return [
3429
...getParentSlugs({ locale, page: page.parentPage }),
3530
slug
@@ -51,7 +46,7 @@ export const getParentSlugs = ({ locale, page }: { locale?: SiteLocale, page: Pa
5146
* - -/-/page-slug (missing parent and grand parent in given locale)
5247
* - - (missing page in given locale)
5348
*/
54-
export const getPagePath = ({ locale, page }: { locale?: SiteLocale, page: PageRouteForPath }) => {
49+
export const getPagePath = ({ locale, page }: { locale?: SiteLocale, page: PageRouteFragment }) => {
5550
const slug = getLocalizedSlug({ locale, record: page });
5651
const parentSlugs = getParentSlugs({ locale, page });
5752
return [...parentSlugs, slug].join('/');

src/pages/[locale]/[...path]/index.astro

+8-19
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,16 @@
22
import { datocmsCollection, datocmsRequest } from '@lib/datocms';
33
import { getPageHref } from '@lib/routing/';
44
import {
5-
type PageRouteForPath,
65
getPagePath,
76
getPageSlugFromPath,
87
getParentPages,
98
} from '@lib/routing/page';
10-
import type { PageQuery, SiteLocale } from '@lib/datocms/types';
9+
import {
10+
PageRoute as fragment,
11+
type PageQuery,
12+
type PageRouteFragment,
13+
type SiteLocale
14+
} from '@lib/datocms/types';
1115
import type { PageUrl } from '@lib/seo';
1216
import Layout from '@layouts/Default.astro';
1317
import Blocks from '@blocks/Blocks.astro';
@@ -17,25 +21,10 @@ import PreviewModeSubscription from '@components/PreviewMode/PreviewModeSubscrip
1721
import query from './_index.query.graphql';
1822
1923
export async function getStaticPaths() {
20-
const pages = await datocmsCollection<PageRouteForPath>({
24+
const pages = await datocmsCollection<PageRouteFragment>({
2125
collection: 'Pages',
22-
fragment: `
23-
_allSlugLocales { locale, value }
24-
parentPage {
25-
_allSlugLocales { locale, value }
26-
parentPage {
27-
_allSlugLocales { locale, value }
28-
parentPage {
29-
_allSlugLocales { locale, value }
30-
parentPage {
31-
_allSlugLocales { locale, value }
32-
}
33-
}
34-
}
35-
}
36-
`,
26+
fragment,
3727
});
38-
3928
return pages.flatMap((page) => {
4029
const locales = page._allSlugLocales
4130
?.map((slug) => slug.locale)

0 commit comments

Comments
 (0)