@datocms/cda-client
Advanced tools
Comparing version 0.2.5 to 0.2.6
@@ -7,8 +7,13 @@ "use strict"; | ||
(0, vitest_1.test)('convertToAutoPaginationQueryAndVariables: no variables, first > 100', function () { | ||
var query = (0, graphql_web_1.parse)(/* GraphQL */ "\n query BuildSitemapUrls {\n allBlogPosts {\n slug\n }\n entries: allSuccessStories(first: 500) {\n ...SuccessStoryUrlFragment\n }\n }\n\n fragment SuccessStoryUrlFragment on SuccessStoryRecord {\n slug\n }\n "); | ||
var query = (0, graphql_web_1.parse)(/* GraphQL */ "\n query BuildSitemapUrls {\n allBlogPosts {\n slug\n }\n entries: allSuccessStories(first: 2500) {\n ...SuccessStoryUrlFragment\n }\n }\n\n fragment SuccessStoryUrlFragment on SuccessStoryRecord {\n slug\n }\n "); | ||
var _a = (0, executeQueryWithAutoPagination_1.convertToAutoPaginationQueryAndVariables)(query), newQuery = _a[0], variables = _a[1]; | ||
(0, vitest_1.expect)([(0, graphql_web_1.print)(newQuery), variables]).toMatchSnapshot(); | ||
}); | ||
(0, vitest_1.test)('convertToAutoPaginationQueryAndVariables: no variables, first > 100, starting from item 14', function () { | ||
var query = (0, graphql_web_1.parse)(/* GraphQL */ "\n query BuildSitemapUrls {\n allBlogPosts {\n slug\n }\n entries: allSuccessStories(skip: 13, first: 526) {\n ...SuccessStoryUrlFragment\n }\n }\n\n fragment SuccessStoryUrlFragment on SuccessStoryRecord {\n slug\n }\n "); | ||
var _a = (0, executeQueryWithAutoPagination_1.convertToAutoPaginationQueryAndVariables)(query), newQuery = _a[0], variables = _a[1]; | ||
(0, vitest_1.expect)([(0, graphql_web_1.print)(newQuery), variables]).toMatchSnapshot(); | ||
}); | ||
(0, vitest_1.test)('convertToAutoPaginationQueryAndVariables: multiple selections to paginate', function () { | ||
var query = (0, graphql_web_1.parse)(/* GraphQL */ "\n query BuildSitemapUrls {\n allBlogPosts(first: 500) {\n slug\n }\n entries: allSuccessStories(first: 500) {\n ...SuccessStoryUrlFragment\n }\n }\n\n fragment SuccessStoryUrlFragment on SuccessStoryRecord {\n slug\n }\n "); | ||
var query = (0, graphql_web_1.parse)(/* GraphQL */ "\n query BuildSitemapUrls {\n allBlogPosts(first: 2500) {\n slug\n }\n entries: allSuccessStories(first: 2500) {\n ...SuccessStoryUrlFragment\n }\n }\n\n fragment SuccessStoryUrlFragment on SuccessStoryRecord {\n slug\n }\n "); | ||
(0, vitest_1.expect)(function () { | ||
@@ -31,3 +36,3 @@ return (0, executeQueryWithAutoPagination_1.convertToAutoPaginationQueryAndVariables)(query); | ||
var query = (0, graphql_web_1.parse)(/* GraphQL */ "\n query BuildSitemapUrls($first: IntType!) {\n entries: allSuccessStories(first: $first) {\n ...SuccessStoryUrlFragment\n }\n }\n\n fragment SuccessStoryUrlFragment on SuccessStoryRecord {\n slug\n }\n "); | ||
var _a = (0, executeQueryWithAutoPagination_1.convertToAutoPaginationQueryAndVariables)(query, { first: 500, other: 'foo' }), newQuery = _a[0], variables = _a[1]; | ||
var _a = (0, executeQueryWithAutoPagination_1.convertToAutoPaginationQueryAndVariables)(query, { first: 2500, other: 'foo' }), newQuery = _a[0], variables = _a[1]; | ||
(0, vitest_1.expect)([(0, graphql_web_1.print)(newQuery), variables]).toMatchSnapshot(); | ||
@@ -34,0 +39,0 @@ }); |
@@ -65,2 +65,3 @@ "use strict"; | ||
var executeQuery_1 = require("./executeQuery"); | ||
var MAX_PAGINATION_LENGTH = 500; | ||
function rawExecuteQueryWithAutoPagination(query, options) { | ||
@@ -126,3 +127,3 @@ return __awaiter(this, void 0, void 0, function () { | ||
var skip = void 0; | ||
for (skip = info.initialSkip; info.numberOfTotalRecords - skip + info.initialSkip > 0; skip += 100) { | ||
for (skip = info.initialSkip; info.numberOfTotalRecords - skip + info.initialSkip > 0; skip += MAX_PAGINATION_LENGTH) { | ||
var newSelectionNode = __assign(__assign({}, selectionNode), { alias: { | ||
@@ -140,3 +141,3 @@ kind: graphql_web_1.Kind.NAME, | ||
kind: graphql_web_1.Kind.INT, | ||
value: Math.min(info.numberOfTotalRecords - skip + info.initialSkip, 100).toString(), | ||
value: Math.min(info.numberOfTotalRecords - skip + info.initialSkip, MAX_PAGINATION_LENGTH).toString(), | ||
}, | ||
@@ -215,4 +216,4 @@ }, | ||
} | ||
// ignore if first < 100 | ||
if (!numberOfTotalRecords || numberOfTotalRecords <= 100) { | ||
// ignore if first < MAX_PAGINATION_LENGTH | ||
if (!numberOfTotalRecords || numberOfTotalRecords <= MAX_PAGINATION_LENGTH) { | ||
return false; | ||
@@ -219,0 +220,0 @@ } |
@@ -5,8 +5,13 @@ import { parse, print } from '@0no-co/graphql.web'; | ||
test('convertToAutoPaginationQueryAndVariables: no variables, first > 100', function () { | ||
var query = parse(/* GraphQL */ "\n query BuildSitemapUrls {\n allBlogPosts {\n slug\n }\n entries: allSuccessStories(first: 500) {\n ...SuccessStoryUrlFragment\n }\n }\n\n fragment SuccessStoryUrlFragment on SuccessStoryRecord {\n slug\n }\n "); | ||
var query = parse(/* GraphQL */ "\n query BuildSitemapUrls {\n allBlogPosts {\n slug\n }\n entries: allSuccessStories(first: 2500) {\n ...SuccessStoryUrlFragment\n }\n }\n\n fragment SuccessStoryUrlFragment on SuccessStoryRecord {\n slug\n }\n "); | ||
var _a = convertToAutoPaginationQueryAndVariables(query), newQuery = _a[0], variables = _a[1]; | ||
expect([print(newQuery), variables]).toMatchSnapshot(); | ||
}); | ||
test('convertToAutoPaginationQueryAndVariables: no variables, first > 100, starting from item 14', function () { | ||
var query = parse(/* GraphQL */ "\n query BuildSitemapUrls {\n allBlogPosts {\n slug\n }\n entries: allSuccessStories(skip: 13, first: 526) {\n ...SuccessStoryUrlFragment\n }\n }\n\n fragment SuccessStoryUrlFragment on SuccessStoryRecord {\n slug\n }\n "); | ||
var _a = convertToAutoPaginationQueryAndVariables(query), newQuery = _a[0], variables = _a[1]; | ||
expect([print(newQuery), variables]).toMatchSnapshot(); | ||
}); | ||
test('convertToAutoPaginationQueryAndVariables: multiple selections to paginate', function () { | ||
var query = parse(/* GraphQL */ "\n query BuildSitemapUrls {\n allBlogPosts(first: 500) {\n slug\n }\n entries: allSuccessStories(first: 500) {\n ...SuccessStoryUrlFragment\n }\n }\n\n fragment SuccessStoryUrlFragment on SuccessStoryRecord {\n slug\n }\n "); | ||
var query = parse(/* GraphQL */ "\n query BuildSitemapUrls {\n allBlogPosts(first: 2500) {\n slug\n }\n entries: allSuccessStories(first: 2500) {\n ...SuccessStoryUrlFragment\n }\n }\n\n fragment SuccessStoryUrlFragment on SuccessStoryRecord {\n slug\n }\n "); | ||
expect(function () { | ||
@@ -29,3 +34,3 @@ return convertToAutoPaginationQueryAndVariables(query); | ||
var query = parse(/* GraphQL */ "\n query BuildSitemapUrls($first: IntType!) {\n entries: allSuccessStories(first: $first) {\n ...SuccessStoryUrlFragment\n }\n }\n\n fragment SuccessStoryUrlFragment on SuccessStoryRecord {\n slug\n }\n "); | ||
var _a = convertToAutoPaginationQueryAndVariables(query, { first: 500, other: 'foo' }), newQuery = _a[0], variables = _a[1]; | ||
var _a = convertToAutoPaginationQueryAndVariables(query, { first: 2500, other: 'foo' }), newQuery = _a[0], variables = _a[1]; | ||
expect([print(newQuery), variables]).toMatchSnapshot(); | ||
@@ -32,0 +37,0 @@ }); |
@@ -59,2 +59,3 @@ var __assign = (this && this.__assign) || function () { | ||
import { rawExecuteQuery, } from './executeQuery'; | ||
var MAX_PAGINATION_LENGTH = 500; | ||
export function rawExecuteQueryWithAutoPagination(query, options) { | ||
@@ -120,3 +121,3 @@ return __awaiter(this, void 0, void 0, function () { | ||
var skip = void 0; | ||
for (skip = info.initialSkip; info.numberOfTotalRecords - skip + info.initialSkip > 0; skip += 100) { | ||
for (skip = info.initialSkip; info.numberOfTotalRecords - skip + info.initialSkip > 0; skip += MAX_PAGINATION_LENGTH) { | ||
var newSelectionNode = __assign(__assign({}, selectionNode), { alias: { | ||
@@ -134,3 +135,3 @@ kind: Kind.NAME, | ||
kind: Kind.INT, | ||
value: Math.min(info.numberOfTotalRecords - skip + info.initialSkip, 100).toString(), | ||
value: Math.min(info.numberOfTotalRecords - skip + info.initialSkip, MAX_PAGINATION_LENGTH).toString(), | ||
}, | ||
@@ -209,4 +210,4 @@ }, | ||
} | ||
// ignore if first < 100 | ||
if (!numberOfTotalRecords || numberOfTotalRecords <= 100) { | ||
// ignore if first < MAX_PAGINATION_LENGTH | ||
if (!numberOfTotalRecords || numberOfTotalRecords <= MAX_PAGINATION_LENGTH) { | ||
return false; | ||
@@ -213,0 +214,0 @@ } |
{ | ||
"name": "@datocms/cda-client", | ||
"version": "0.2.5", | ||
"version": "0.2.6", | ||
"description": "JS client for DatoCMS GraphQL Content Delivery API based on the browser Fetch API", | ||
@@ -5,0 +5,0 @@ "main": "dist/cjs/index.js", |
132
README.md
@@ -24,3 +24,3 @@ <!--datocms-autoinclude-header start--> | ||
```typescript | ||
import { executeQuery } from '@datocms/cda-client'; | ||
import { executeQuery } from "@datocms/cda-client"; | ||
@@ -37,3 +37,3 @@ const query = ` | ||
const result = await executeQuery(query, { | ||
token: 'your-api-token-here', | ||
token: "your-api-token-here", | ||
}); | ||
@@ -47,7 +47,7 @@ | ||
```typescript | ||
import { executeQuery } from '@datocms/cda-client'; | ||
import { AllArticlesQuery } from './generated/graphql'; | ||
import { executeQuery } from "@datocms/cda-client"; | ||
import { AllArticlesQuery } from "./generated/graphql"; | ||
const result = await executeQuery(AllArticlesQuery, { | ||
token: 'your-api-token-here', | ||
token: "your-api-token-here", | ||
variables: { | ||
@@ -76,3 +76,3 @@ limit: 10, | ||
```typescript | ||
import { executeQuery } from '@datocms/cda-client'; | ||
import { executeQuery } from "@datocms/cda-client"; | ||
@@ -103,3 +103,2 @@ const result = await executeQuery(query, options); | ||
### `rawExecuteQuery` | ||
@@ -110,8 +109,110 @@ | ||
```typescript | ||
import { rawExecuteQuery } from '@datocms/cda-client'; | ||
import { rawExecuteQuery } from "@datocms/cda-client"; | ||
const [result, response] = await rawExecuteQuery(query, { token: 'your-api-token-here', returnCacheTags: true }); | ||
const cacheTags = response.headers.get('x-cache-tags'); | ||
const [result, response] = await rawExecuteQuery(query, { | ||
token: "your-api-token-here", | ||
returnCacheTags: true, | ||
}); | ||
const cacheTags = response.headers.get("x-cache-tags"); | ||
``` | ||
### `executeQueryWithAutoPagination` | ||
This function comes handy when the query contains a paginated collection: behind the scene, | ||
`executeQueryWithAutoPagination` reworks the passed query and collects the results, so that | ||
it's possible to get a collection of records that is longer than Content Delivery API's result limit. | ||
That is done with a single API call, in a transparent way. | ||
```typescript | ||
import { executeQueryWithAutoPagination } from "@datocms/cda-client"; | ||
const result = await executeQueryWithAutoPagination(query, options); | ||
``` | ||
#### Parameters | ||
Parameters are the same available for `executeQuery`: | ||
- `query`: A GraphQL query string, `DocumentNode`, or `TypedDocumentNode`. | ||
- `options`: An object containing execution options with the same shape of options for `executeQuery`. | ||
### How does it work? | ||
Suppose you want to execute the following query: | ||
```graphql | ||
query BuildSitemapUrls { | ||
allBlogPosts { | ||
slug | ||
} | ||
entries: allSuccessStories(first: 500) { | ||
...SuccessStoryUrlFragment | ||
} | ||
} | ||
fragment SuccessStoryUrlFragment on SuccessStoryRecord { | ||
slug | ||
} | ||
``` | ||
Well, that's a roadblock: DatoCMS CDA has limitations on the pagination page length (currently 100 item). | ||
That means you should introduce a variable and execute the query multiple times, each time skipping the record | ||
that have been returned by the previous query. | ||
`executeQueryWithAutoPagination` does that on your behalf: the above query is analyzed and rewritten on the fly like this: | ||
```graphql | ||
query BuildSitemapUrls { | ||
allBlogPosts { | ||
slug | ||
} | ||
splitted_0_entries: allSuccessStories(first: 100, skip: 0) { | ||
...SuccessStoryUrlFragment | ||
} | ||
splitted_100_entries: allSuccessStories(first: 100, skip: 100) { | ||
...SuccessStoryUrlFragment | ||
} | ||
splitted_200_entries: allSuccessStories(first: 100, skip: 200) { | ||
...SuccessStoryUrlFragment | ||
} | ||
splitted_300_entries: allSuccessStories(first: 100, skip: 300) { | ||
...SuccessStoryUrlFragment | ||
} | ||
splitted_400_entries: allSuccessStories(first: 100, skip: 400) { | ||
...SuccessStoryUrlFragment | ||
} | ||
} | ||
fragment SuccessStoryUrlFragment on SuccessStoryRecord { | ||
slug | ||
} | ||
``` | ||
Once executed, the results get collected and recomposed as if nothing happened. | ||
#### Limitations | ||
`executeQueryWithAutoPagination` works only when the query contains only one selection that has | ||
an oversized `first:` argument (i.e. `first:` argument surpasses the Content Delivery API's result limit). | ||
If two or more fields have oversiaed patination, the function triggers an error. | ||
The rewritten query must still respect the [complexity cost](https://www.datocms.com/docs/content-delivery-api/complexity). | ||
### `rawExecuteQueryWithAutoPagination` | ||
As for `executeQuery`, also `executeQueryWithAutoPagination` has a pair raw version that returns both the query result and the full response object. | ||
This can be handy when used together with returnCacheTags to actually retrieve the cache tags. | ||
```typescript | ||
import { rawExecuteQueryWithAutoPagination } from "@datocms/cda-client"; | ||
const [result, response] = await rawExecuteQueryWithAutoPagination(query, { | ||
token: "your-api-token-here", | ||
returnCacheTags: true, | ||
}); | ||
const cacheTags = response.headers.get("x-cache-tags"); | ||
``` | ||
### `buildRequestHeaders` | ||
@@ -122,3 +223,3 @@ | ||
```typescript | ||
import { buildRequestHeaders } from '@datocms/cda-client'; | ||
import { buildRequestHeaders } from "@datocms/cda-client"; | ||
@@ -137,3 +238,3 @@ const headers = buildRequestHeaders(options); | ||
```typescript | ||
import { buildRequestInit } from '@datocms/cda-client'; | ||
import { buildRequestInit } from "@datocms/cda-client"; | ||
@@ -155,3 +256,3 @@ const requestInit = buildRequestInit(query, options); | ||
```typescript | ||
import { executeQuery, ApiError } from '@datocms/cda-client'; | ||
import { executeQuery, ApiError } from "@datocms/cda-client"; | ||
@@ -169,3 +270,3 @@ const query = ` | ||
const result = await executeQuery(query, { | ||
token: 'your-api-token-here', | ||
token: "your-api-token-here", | ||
}); | ||
@@ -199,3 +300,2 @@ console.log(result); | ||
<!--datocms-autoinclude-footer start--> | ||
@@ -206,2 +306,3 @@ | ||
# What is DatoCMS? | ||
<a href="https://www.datocms.com/"><img src="https://www.datocms.com/images/full_logo.svg" height="60"></a> | ||
@@ -221,2 +322,3 @@ | ||
**Our featured repos:** | ||
- [datocms/react-datocms](https://github.com/datocms/react-datocms): React helper components for images, Structured Text rendering, and more | ||
@@ -223,0 +325,0 @@ - [datocms/js-rest-api-clients](https://github.com/datocms/js-rest-api-clients): Node and browser JavaScript clients for updating and administering your content. For frontend fetches, we recommend using our [GraphQL Content Delivery API](https://www.datocms.com/docs/content-delivery-api) instead. |
@@ -18,2 +18,4 @@ import { | ||
const MAX_PAGINATION_LENGTH = 500; | ||
/** | ||
@@ -182,3 +184,3 @@ * Extends the functionality of `rawExecuteQuery()` with automatic pagination | ||
info.numberOfTotalRecords - skip + info.initialSkip > 0; | ||
skip += 100 | ||
skip += MAX_PAGINATION_LENGTH | ||
) { | ||
@@ -203,3 +205,3 @@ const newSelectionNode: FieldNode = { | ||
info.numberOfTotalRecords - skip + info.initialSkip, | ||
100, | ||
MAX_PAGINATION_LENGTH, | ||
).toString(), | ||
@@ -306,4 +308,4 @@ }, | ||
// ignore if first < 100 | ||
if (!numberOfTotalRecords || numberOfTotalRecords <= 100) { | ||
// ignore if first < MAX_PAGINATION_LENGTH | ||
if (!numberOfTotalRecords || numberOfTotalRecords <= MAX_PAGINATION_LENGTH) { | ||
return false; | ||
@@ -310,0 +312,0 @@ } |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
145779
2243
320