diff --git a/api-reference.md b/api-reference.md
index 65a09ad..8e8b5ae 100644
--- a/api-reference.md
+++ b/api-reference.md
@@ -67,6 +67,7 @@ with GraphQL endpoint, GraphQL serviceURL and auth if needed
* [.listPersistedQueries([options], [retryOptions])](#AEMHeadless+listPersistedQueries) ⇒ Promise.<any>
* [.runPersistedQuery(path, [variables], [options], [retryOptions])](#AEMHeadless+runPersistedQuery) ⇒ Promise.<any>
* [.runPaginatedQuery(model, fields, [config], [args], [options], [retryOptions])](#AEMHeadless+runPaginatedQuery)
+ * [.runModelQuery(model, fields, [config], [args], [options], [retryOptions])](#AEMHeadless+runModelQuery) ⇒ Promise.<any>
* [.buildQuery(model, fields, [config], [args])](#AEMHeadless+buildQuery) ⇒ [QueryBuilderResult
](#QueryBuilderResult)
@@ -246,6 +247,41 @@ Returns a Generator Function.
+
+
+### aemHeadless.runModelQuery(model, fields, [config], [args], [options], [retryOptions]) ⇒ Promise.<any>
+Returns a Promise that resolves with a filtered POST request JSON data.
+
+**Kind**: instance method of [AEMHeadless
](#AEMHeadless)
+**Returns**: Promise.<any>
- - the response data wrapped inside a Promise
+
+
+
+ Param | Type | Default | Description |
+
+
+
+
+ model | string | | contentFragment model name
+ |
+
+ fields | string | | The query string for item fields
+ |
+
+ [config] | ModelConfig | {} | Pagination config
+ |
+
+ [args] | ModelArgs | {} | Query arguments
+ |
+
+ [options] | object | {} | additional POST request options
+ |
+
+ [retryOptions] | object | {} | retry options for @adobe/aio-lib-core-networking
+ |
+
+
+
### aemHeadless.buildQuery(model, fields, [config], [args]) ⇒ [QueryBuilderResult
](#QueryBuilderResult)
diff --git a/src/index.js b/src/index.js
index 6e26f65..14f3be1 100644
--- a/src/index.js
+++ b/src/index.js
@@ -144,7 +144,6 @@ class AEMHeadless {
let hasNext = true
let after = args.after || ''
const limit = args.limit
- const size = args.first || limit
let pagingArgs = args
while (hasNext) {
const offset = pagingArgs.offset || 0
@@ -153,27 +152,55 @@ class AEMHeadless {
}
isInitial = false
+ const filteredData = await this.runModelQuery(model, fields, config, pagingArgs, options, retryOptions)
- const { query, type } = this.buildQuery(model, fields, config, pagingArgs)
- const { data } = await this.runQuery(query, options, retryOptions)
+ hasNext = filteredData.hasNext
+ after = filteredData.endCursor
- let filteredData = {}
- try {
- filteredData = this.__filterData(model, type, data, size)
- } catch (e) {
- throw new API_ERROR({
- sdkDetails: {
- serviceURL: this.serviceURL
- },
- messageValues: `Error while filtering response data. ${e.message}`
- })
+ yield {
+ data: filteredData.data,
+ hasNext
}
+ }
+ }
- hasNext = filteredData.hasNext
- after = filteredData.endCursor
+ /**
+ * Returns a Promise that resolves with a filtered POST request JSON data.
+ *
+ * @param {string} model - contentFragment model name
+ * @param {string} fields - The query string for item fields
+ * @param {ModelConfig} [config={}] - Pagination config
+ * @param {ModelArgs} [args={}] - Query arguments
+ * @param {object} [options={}] - additional POST request options
+ * @param {object} [retryOptions={}] - retry options for @adobe/aio-lib-core-networking
+ * @returns {Promise} - the response data wrapped inside a Promise
+ */
+ async runModelQuery (model, fields, config, args, options, retryOptions) {
+ if (!model || !fields) {
+ throw new INVALID_PARAM({
+ sdkDetails: {
+ serviceURL: this.serviceURL
+ },
+ messageValues: 'Required param missing: @param {string} fields - query string for item fields'
+ })
+ }
- yield filteredData.data
+ const size = args.first || args.limit
+ const { query, type } = this.buildQuery(model, fields, config, args)
+ const { data } = await this.runQuery(query, options, retryOptions)
+ let filteredData = {}
+ try {
+ filteredData = this.__filterData(model, type, data, size)
+ } catch (e) {
+ throw new API_ERROR({
+ sdkDetails: {
+ serviceURL: this.serviceURL
+ },
+ messageValues: `Error while filtering response data. ${e.message}`
+ })
}
+
+ return filteredData
}
/**
diff --git a/test/shared/index.test.js b/test/shared/index.test.js
index 3b159a8..8ad3291 100644
--- a/test/shared/index.test.js
+++ b/test/shared/index.test.js
@@ -241,12 +241,12 @@ describe('runPaginatedQuery', () => {
const mockRetryOptions = {}
it('should throw an error if model is missing', async () => {
- const gen = sdk.runPaginatedQuery(null, mockFields, mockConfig, mockArgs, mockOptions, mockRetryOptions)
+ const gen = await sdk.runPaginatedQuery(null, mockFields, mockConfig, mockArgs, mockOptions, mockRetryOptions)
await expect(gen.next()).rejects.toThrow(ErrorCodes.INVALID_PARAM)
})
it('should throw an error if fields are missing', async () => {
- const gen = sdk.runPaginatedQuery(mockModel, null, mockConfig, mockArgs, mockOptions, mockRetryOptions)
+ const gen = await sdk.runPaginatedQuery(mockModel, null, mockConfig, mockArgs, mockOptions, mockRetryOptions)
await expect(gen.next()).rejects.toThrow(ErrorCodes.INVALID_PARAM)
})
@@ -268,9 +268,150 @@ describe('runPaginatedQuery', () => {
})
})
- const gen = sdk.runPaginatedQuery(mockModel, mockFields, mockConfig, mockArgs, mockOptions, mockRetryOptions)
+ const gen = await sdk.runPaginatedQuery(mockModel, mockFields, mockConfig, mockArgs, mockOptions, mockRetryOptions)
+ const { value } = await gen.next()
+
+ expect(value.data).toEqual([mockData])
+ })
+
+ it('should yield done true and value false, at the last iteration', async () => {
+ const mockData = { id: '1', name: 'foo' }
+ fetch.resetMocks()
+ fetch.mockResolvedValue({
+ ok: true,
+ status: 200,
+ json: async () => ({
+ data: {
+ mockModelPaginated: {
+ edges: [
+ { node: mockData }
+ ],
+ pageInfo: {
+ hasNextPage: false
+ }
+ }
+ }
+ })
+ })
+
+ const gen = await sdk.runPaginatedQuery(mockModel, mockFields, mockConfig, mockArgs, mockOptions, mockRetryOptions)
const result = await gen.next()
- expect(result).toEqual({ done: false, value: [mockData] })
+ expect(result.done).toBeFalsy()
+ expect(result.value.data).toEqual([mockData])
+
+ const { done, value } = await gen.next()
+
+ expect(done).toBeTruthy()
+ expect(value).toBeFalsy()
+ })
+
+ it('should yield only first item - cursor query', async () => {
+ const mockData = [
+ { id: '1', name: 'foo' },
+ { id: '2', name: 'bar' }
+ ]
+ fetch.resetMocks()
+ fetch.mockResolvedValue({
+ ok: true,
+ status: 200,
+ json: async () => ({
+ data: {
+ mockModelPaginated: {
+ edges: [
+ { node: mockData[0] }
+ ],
+ pageInfo: {
+ hasNextPage: true
+ }
+ }
+ }
+ })
+ })
+
+ const gen = await sdk.runPaginatedQuery(mockModel, mockFields, mockConfig, { first: 1 }, mockOptions, mockRetryOptions)
+ const result = await gen.next()
+
+ expect(result).toEqual({ done: false, value: { data: [mockData[0]], hasNext: true } })
+ })
+
+ it('should yield only first item - offset query', async () => {
+ const mockData = [
+ { id: '1', name: 'foo' },
+ { id: '2', name: 'bar' }
+ ]
+ fetch.resetMocks()
+ fetch.mockResolvedValue({
+ ok: true,
+ status: 200,
+ json: async () => ({
+ data: {
+ mockModelList: {
+ items: [
+ mockData[0]
+ ]
+ }
+ }
+ })
+ })
+
+ const gen = await sdk.runPaginatedQuery('mockModel', mockFields, { useLimitOffset: true }, { limit: 1 }, mockOptions, mockRetryOptions)
+ const { value } = await gen.next()
+
+ expect(value.data).toEqual([mockData[0]])
+ })
+
+ it('should yield item - path query', async () => {
+ const mockData = { id: '1', name: 'foo' }
+ fetch.resetMocks()
+ fetch.mockResolvedValue({
+ ok: true,
+ status: 200,
+ json: async () => ({
+ data: {
+ mockModelByPath: {
+ item: mockData
+ }
+ }
+ })
+ })
+
+ const gen = await sdk.runPaginatedQuery(mockModel, mockFields, {}, { _path: 'path' }, mockOptions, mockRetryOptions)
+ const { value } = await gen.next()
+
+ expect(value.data).toEqual(mockData)
+ })
+
+ it('should update pagingArgs', async () => {
+ const mockData = { id: '1', name: 'foo' }
+ fetch.resetMocks()
+ fetch.mockResolvedValue({
+ ok: true,
+ status: 200,
+ json: async () => ({
+ data: {
+ mockModel2Paginated: {
+ edges: [
+ { node: mockData },
+ { node: mockData }
+ ],
+ pageInfo: {
+ hasNextPage: true
+ }
+ }
+ }
+ })
+ })
+
+ const gen = await sdk.runPaginatedQuery('mockModel2', mockFields, { pageSize: 1 }, { limit: 1 }, mockOptions, mockRetryOptions)
+ const result = await gen.next()
+
+ expect(result.done).toBeFalsy()
+ expect(result.value.data).toEqual([mockData, mockData])
+
+ const { done, value } = await gen.next()
+
+ expect(done).toBeFalsy()
+ expect(value.data).toEqual([mockData, mockData])
})
})