diff --git a/api-js/src/email-scan/objects/dkim-result.js b/api-js/src/email-scan/objects/dkim-result.js index 176d50373f..cbfd9483e0 100644 --- a/api-js/src/email-scan/objects/dkim-result.js +++ b/api-js/src/email-scan/objects/dkim-result.js @@ -8,7 +8,8 @@ import { GraphQLJSON } from 'graphql-scalars' import { dkimType } from './dkim' import { nodeInterface } from '../../node' -import { guidanceTagConnection } from '../../guidance-tag' +import { guidanceTagOrder } from '../../guidance-tag/inputs' +import { guidanceTagConnection } from '../../guidance-tag/objects' export const dkimResultType = new GraphQLObjectType({ name: 'DKIMResult', @@ -47,6 +48,10 @@ export const dkimResultType = new GraphQLObjectType({ guidanceTags: { type: guidanceTagConnection.connectionType, args: { + orderBy: { + type: guidanceTagOrder, + description: 'Ordering options for guidance tag connections', + }, ...connectionArgs, }, description: 'Key tags found during scan.', diff --git a/api-js/src/email-scan/objects/dmarc.js b/api-js/src/email-scan/objects/dmarc.js index fcf13946ce..31e2eb12b0 100644 --- a/api-js/src/email-scan/objects/dmarc.js +++ b/api-js/src/email-scan/objects/dmarc.js @@ -8,7 +8,8 @@ import { GraphQLJSON } from 'graphql-scalars' import { domainType } from '../../domain/objects' import { nodeInterface } from '../../node' -import { guidanceTagConnection } from '../../guidance-tag' +import { guidanceTagOrder } from '../../guidance-tag/inputs' +import { guidanceTagConnection } from '../../guidance-tag/objects' export const dmarcType = new GraphQLObjectType({ name: 'DMARC', @@ -59,6 +60,10 @@ subdomains where mail is failing the DMARC authentication and alignment checks.` guidanceTags: { type: guidanceTagConnection.connectionType, args: { + orderBy: { + type: guidanceTagOrder, + description: 'Ordering options for guidance tag connections', + }, ...connectionArgs, }, description: `Key tags found during DMARC Scan.`, diff --git a/api-js/src/email-scan/objects/spf.js b/api-js/src/email-scan/objects/spf.js index b6b40f6103..03a7168af0 100644 --- a/api-js/src/email-scan/objects/spf.js +++ b/api-js/src/email-scan/objects/spf.js @@ -8,7 +8,8 @@ import { GraphQLJSON } from 'graphql-scalars' import { domainType } from '../../domain/objects' import { nodeInterface } from '../../node' -import { guidanceTagConnection } from '../../guidance-tag' +import { guidanceTagOrder } from '../../guidance-tag/inputs' +import { guidanceTagConnection } from '../../guidance-tag/objects' export const spfType = new GraphQLObjectType({ name: 'SPF', @@ -52,6 +53,10 @@ export const spfType = new GraphQLObjectType({ guidanceTags: { type: guidanceTagConnection.connectionType, args: { + orderBy: { + type: guidanceTagOrder, + description: 'Ordering options for guidance tag connections', + }, ...connectionArgs, }, description: `Key tags found during scan.`, diff --git a/api-js/src/enums/guidance-tag-order-field.js b/api-js/src/enums/guidance-tag-order-field.js new file mode 100644 index 0000000000..092398e983 --- /dev/null +++ b/api-js/src/enums/guidance-tag-order-field.js @@ -0,0 +1,20 @@ +import { GraphQLEnumType } from 'graphql' + +export const GuidanceTagOrderField = new GraphQLEnumType({ + name: 'GuidanceTagOrderField', + description: 'Properties by which Guidance Tag connections can be ordered.', + values: { + TAG_ID: { + value: 'tag-id', + description: 'Order guidance tag edges by tag id.', + }, + TAG_NAME: { + value: 'tag-name', + description: 'Order guidance tag edges by tag name.', + }, + GUIDANCE: { + value: 'guidance', + description: 'Order guidance tag edges by tag guidance.', + }, + }, +}) diff --git a/api-js/src/enums/index.js b/api-js/src/enums/index.js index 86b753d7ba..25f06fde8a 100644 --- a/api-js/src/enums/index.js +++ b/api-js/src/enums/index.js @@ -3,6 +3,7 @@ export * from './dkim-result-order-field' export * from './dmarc-order-field' export * from './dmarc-summary-order-field' export * from './domain-order-field' +export * from './guidance-tag-order-field' export * from './https-order-field' export * from './languages' export * from './order-direction' diff --git a/api-js/src/guidance-tag/index.js b/api-js/src/guidance-tag/index.js index 84c283025a..6d2a5b5879 100644 --- a/api-js/src/guidance-tag/index.js +++ b/api-js/src/guidance-tag/index.js @@ -1,2 +1,3 @@ +export * from './inputs' export * from './loaders' export * from './objects' diff --git a/api-js/src/guidance-tag/inputs/__tests__/guidance-tag-order.test.js b/api-js/src/guidance-tag/inputs/__tests__/guidance-tag-order.test.js new file mode 100644 index 0000000000..c67d01c637 --- /dev/null +++ b/api-js/src/guidance-tag/inputs/__tests__/guidance-tag-order.test.js @@ -0,0 +1,25 @@ +import { GraphQLNonNull } from 'graphql' + +import { guidanceTagOrder } from '../guidance-tag-order' +import { OrderDirection, GuidanceTagOrderField } from '../../../enums' + +describe('given the guidanceTagOrder input object', () => { + describe('testing fields', () => { + it('has a direction field', () => { + const demoType = guidanceTagOrder.getFields() + + expect(demoType).toHaveProperty('direction') + expect(demoType.direction.type).toMatchObject( + GraphQLNonNull(OrderDirection), + ) + }) + it('has a field field', () => { + const demoType = guidanceTagOrder.getFields() + + expect(demoType).toHaveProperty('field') + expect(demoType.field.type).toMatchObject( + GraphQLNonNull(GuidanceTagOrderField), + ) + }) + }) +}) diff --git a/api-js/src/guidance-tag/inputs/guidance-tag-order.js b/api-js/src/guidance-tag/inputs/guidance-tag-order.js new file mode 100644 index 0000000000..d32253cdb0 --- /dev/null +++ b/api-js/src/guidance-tag/inputs/guidance-tag-order.js @@ -0,0 +1,18 @@ +import { GraphQLInputObjectType, GraphQLNonNull } from 'graphql' + +import { OrderDirection, GuidanceTagOrderField } from '../../enums' + +export const guidanceTagOrder = new GraphQLInputObjectType({ + name: 'GuidanceTagOrder', + description: 'Ordering options for guidance tag connections.', + fields: () => ({ + field: { + type: GraphQLNonNull(GuidanceTagOrderField), + description: 'The field to order guidance tags by.', + }, + direction: { + type: GraphQLNonNull(OrderDirection), + description: 'The ordering direction.', + }, + }), +}) diff --git a/api-js/src/guidance-tag/inputs/index.js b/api-js/src/guidance-tag/inputs/index.js new file mode 100644 index 0000000000..bb35677086 --- /dev/null +++ b/api-js/src/guidance-tag/inputs/index.js @@ -0,0 +1 @@ +export * from './guidance-tag-order' diff --git a/api-js/src/guidance-tag/loaders/__tests__/load-dkim-guidance-tags-connections.test.js b/api-js/src/guidance-tag/loaders/__tests__/load-dkim-guidance-tags-connections.test.js index 09ce2763e4..53885b6766 100644 --- a/api-js/src/guidance-tag/loaders/__tests__/load-dkim-guidance-tags-connections.test.js +++ b/api-js/src/guidance-tag/loaders/__tests__/load-dkim-guidance-tags-connections.test.js @@ -45,7 +45,6 @@ describe('when given the load dkim guidance tag connection function', () => { }) beforeEach(async () => { - await truncate() consoleWarnOutput.length = 0 consoleErrorOutput.length = 0 @@ -65,6 +64,10 @@ describe('when given the load dkim guidance tag connection function', () => { }) }) + afterEach(async () => { + await truncate() + }) + afterAll(async () => { await drop() }) @@ -297,6 +300,302 @@ describe('when given the load dkim guidance tag connection function', () => { expect(dkimTags).toEqual(expectedStructure) }) }) + describe('using orderBy field', () => { + beforeEach(async () => { + await truncate() + await collections.dkimGuidanceTags.save({ + _key: 'dkim1', + tagName: 'a', + guidance: 'a', + }) + await collections.dkimGuidanceTags.save({ + _key: 'dkim2', + tagName: 'b', + guidance: 'b', + }) + await collections.dkimGuidanceTags.save({ + _key: 'dkim3', + tagName: 'c', + guidance: 'c', + }) + }) + describe('ordering on TAG_ID', () => { + describe('order is set to ASC', () => { + it('returns guidance tag', async () => { + const loader = dkimGuidanceTagLoader(query) + const expectedDkimTag = await loader.load('dkim2') + + const connectionLoader = dkimGuidanceTagConnectionsLoader( + query, + user._key, + cleanseInput, + i18n, + ) + + const connectionArgs = { + dkimGuidanceTags: ['dkim1', 'dkim2', 'dkim3'], + first: 5, + after: toGlobalId('guidanceTags', 'dkim1'), + before: toGlobalId('guidanceTags', 'dkim3'), + orderBy: { + field: 'tag-id', + direction: 'ASC', + }, + } + const dkimTags = await connectionLoader(connectionArgs) + + const expectedStructure = { + edges: [ + { + cursor: toGlobalId('guidanceTags', expectedDkimTag._key), + node: { + ...expectedDkimTag, + }, + }, + ], + totalCount: 3, + pageInfo: { + hasNextPage: true, + hasPreviousPage: true, + startCursor: toGlobalId('guidanceTags', expectedDkimTag._key), + endCursor: toGlobalId('guidanceTags', expectedDkimTag._key), + }, + } + + expect(dkimTags).toEqual(expectedStructure) + }) + }) + describe('ordering is set to DESC', () => { + it('returns guidance tag', async () => { + const loader = dkimGuidanceTagLoader(query) + const expectedDkimTag = await loader.load('dkim2') + + const connectionLoader = dkimGuidanceTagConnectionsLoader( + query, + user._key, + cleanseInput, + i18n, + ) + + const connectionArgs = { + dkimGuidanceTags: ['dkim1', 'dkim2', 'dkim3'], + first: 5, + after: toGlobalId('guidanceTags', 'dkim3'), + before: toGlobalId('guidanceTags', 'dkim1'), + orderBy: { + field: 'tag-id', + direction: 'DESC', + }, + } + const dkimTags = await connectionLoader(connectionArgs) + + const expectedStructure = { + edges: [ + { + cursor: toGlobalId('guidanceTags', expectedDkimTag._key), + node: { + ...expectedDkimTag, + }, + }, + ], + totalCount: 3, + pageInfo: { + hasNextPage: true, + hasPreviousPage: true, + startCursor: toGlobalId('guidanceTags', expectedDkimTag._key), + endCursor: toGlobalId('guidanceTags', expectedDkimTag._key), + }, + } + + expect(dkimTags).toEqual(expectedStructure) + }) + }) + }) + describe('ordering on TAG_NAME', () => { + describe('order is set to ASC', () => { + it('returns guidance tag', async () => { + const loader = dkimGuidanceTagLoader(query) + const expectedDkimTag = await loader.load('dkim2') + + const connectionLoader = dkimGuidanceTagConnectionsLoader( + query, + user._key, + cleanseInput, + i18n, + ) + + const connectionArgs = { + dkimGuidanceTags: ['dkim1', 'dkim2', 'dkim3'], + first: 5, + after: toGlobalId('guidanceTags', 'dkim1'), + before: toGlobalId('guidanceTags', 'dkim3'), + orderBy: { + field: 'tag-name', + direction: 'ASC', + }, + } + const dkimTags = await connectionLoader(connectionArgs) + + const expectedStructure = { + edges: [ + { + cursor: toGlobalId('guidanceTags', expectedDkimTag._key), + node: { + ...expectedDkimTag, + }, + }, + ], + totalCount: 3, + pageInfo: { + hasNextPage: true, + hasPreviousPage: true, + startCursor: toGlobalId('guidanceTags', expectedDkimTag._key), + endCursor: toGlobalId('guidanceTags', expectedDkimTag._key), + }, + } + + expect(dkimTags).toEqual(expectedStructure) + }) + }) + describe('ordering is set to DESC', () => { + it('returns guidance tag', async () => { + const loader = dkimGuidanceTagLoader(query) + const expectedDkimTag = await loader.load('dkim2') + + const connectionLoader = dkimGuidanceTagConnectionsLoader( + query, + user._key, + cleanseInput, + i18n, + ) + + const connectionArgs = { + dkimGuidanceTags: ['dkim1', 'dkim2', 'dkim3'], + first: 5, + after: toGlobalId('guidanceTags', 'dkim3'), + before: toGlobalId('guidanceTags', 'dkim1'), + orderBy: { + field: 'tag-name', + direction: 'DESC', + }, + } + const dkimTags = await connectionLoader(connectionArgs) + + const expectedStructure = { + edges: [ + { + cursor: toGlobalId('guidanceTags', expectedDkimTag._key), + node: { + ...expectedDkimTag, + }, + }, + ], + totalCount: 3, + pageInfo: { + hasNextPage: true, + hasPreviousPage: true, + startCursor: toGlobalId('guidanceTags', expectedDkimTag._key), + endCursor: toGlobalId('guidanceTags', expectedDkimTag._key), + }, + } + + expect(dkimTags).toEqual(expectedStructure) + }) + }) + }) + describe('ordering on GUIDANCE', () => { + describe('order is set to ASC', () => { + it('returns guidance tag', async () => { + const loader = dkimGuidanceTagLoader(query) + const expectedDkimTag = await loader.load('dkim2') + + const connectionLoader = dkimGuidanceTagConnectionsLoader( + query, + user._key, + cleanseInput, + i18n, + ) + + const connectionArgs = { + dkimGuidanceTags: ['dkim1', 'dkim2', 'dkim3'], + first: 5, + after: toGlobalId('guidanceTags', 'dkim1'), + before: toGlobalId('guidanceTags', 'dkim3'), + orderBy: { + field: 'guidance', + direction: 'ASC', + }, + } + const dkimTags = await connectionLoader(connectionArgs) + + const expectedStructure = { + edges: [ + { + cursor: toGlobalId('guidanceTags', expectedDkimTag._key), + node: { + ...expectedDkimTag, + }, + }, + ], + totalCount: 3, + pageInfo: { + hasNextPage: true, + hasPreviousPage: true, + startCursor: toGlobalId('guidanceTags', expectedDkimTag._key), + endCursor: toGlobalId('guidanceTags', expectedDkimTag._key), + }, + } + + expect(dkimTags).toEqual(expectedStructure) + }) + }) + describe('ordering is set to DESC', () => { + it('returns guidance tag', async () => { + const loader = dkimGuidanceTagLoader(query) + const expectedDkimTag = await loader.load('dkim2') + + const connectionLoader = dkimGuidanceTagConnectionsLoader( + query, + user._key, + cleanseInput, + i18n, + ) + + const connectionArgs = { + dkimGuidanceTags: ['dkim1', 'dkim2', 'dkim3'], + first: 5, + after: toGlobalId('guidanceTags', 'dkim3'), + before: toGlobalId('guidanceTags', 'dkim1'), + orderBy: { + field: 'guidance', + direction: 'DESC', + }, + } + const dkimTags = await connectionLoader(connectionArgs) + + const expectedStructure = { + edges: [ + { + cursor: toGlobalId('guidanceTags', expectedDkimTag._key), + node: { + ...expectedDkimTag, + }, + }, + ], + totalCount: 3, + pageInfo: { + hasNextPage: true, + hasPreviousPage: true, + startCursor: toGlobalId('guidanceTags', expectedDkimTag._key), + endCursor: toGlobalId('guidanceTags', expectedDkimTag._key), + }, + } + + expect(dkimTags).toEqual(expectedStructure) + }) + }) + }) + }) describe('no dkim results are found', () => { it('returns an empty structure', async () => { await truncate() diff --git a/api-js/src/guidance-tag/loaders/__tests__/load-dmarc-guidance-tags-connections.test.js b/api-js/src/guidance-tag/loaders/__tests__/load-dmarc-guidance-tags-connections.test.js index b1485598a8..05f8d81f17 100644 --- a/api-js/src/guidance-tag/loaders/__tests__/load-dmarc-guidance-tags-connections.test.js +++ b/api-js/src/guidance-tag/loaders/__tests__/load-dmarc-guidance-tags-connections.test.js @@ -45,7 +45,6 @@ describe('when given the load dmarc guidance tag connection function', () => { }) beforeEach(async () => { - await truncate() consoleWarnOutput.length = 0 consoleErrorOutput.length = 0 @@ -65,6 +64,10 @@ describe('when given the load dmarc guidance tag connection function', () => { }) }) + afterEach(async () => { + await truncate() + }) + afterAll(async () => { await drop() }) @@ -307,6 +310,302 @@ describe('when given the load dmarc guidance tag connection function', () => { expect(dmarcTags).toEqual(expectedStructure) }) }) + describe('using orderBy field', () => { + beforeEach(async () => { + await truncate() + await collections.dmarcGuidanceTags.save({ + _key: 'dmarc1', + tagName: 'a', + guidance: 'a', + }) + await collections.dmarcGuidanceTags.save({ + _key: 'dmarc2', + tagName: 'b', + guidance: 'b', + }) + await collections.dmarcGuidanceTags.save({ + _key: 'dmarc3', + tagName: 'c', + guidance: 'c', + }) + }) + describe('ordering on TAG_ID', () => { + describe('order is set to ASC', () => { + it('returns guidance tag', async () => { + const loader = dmarcGuidanceTagLoader(query) + const expectedDmarcTag = await loader.load('dmarc2') + + const connectionLoader = dmarcGuidanceTagConnectionsLoader( + query, + user._key, + cleanseInput, + i18n, + ) + + const connectionArgs = { + dmarcGuidanceTags: ['dmarc1', 'dmarc2', 'dmarc3'], + first: 5, + after: toGlobalId('guidanceTags', 'dmarc1'), + before: toGlobalId('guidanceTags', 'dmarc3'), + orderBy: { + field: 'tag-id', + direction: 'ASC', + }, + } + const dkimTags = await connectionLoader(connectionArgs) + + const expectedStructure = { + edges: [ + { + cursor: toGlobalId('guidanceTags', expectedDmarcTag._key), + node: { + ...expectedDmarcTag, + }, + }, + ], + totalCount: 3, + pageInfo: { + hasNextPage: true, + hasPreviousPage: true, + startCursor: toGlobalId('guidanceTags', expectedDmarcTag._key), + endCursor: toGlobalId('guidanceTags', expectedDmarcTag._key), + }, + } + + expect(dkimTags).toEqual(expectedStructure) + }) + }) + describe('ordering is set to DESC', () => { + it('returns guidance tag', async () => { + const loader = dmarcGuidanceTagLoader(query) + const expectedDmarcTag = await loader.load('dmarc2') + + const connectionLoader = dmarcGuidanceTagConnectionsLoader( + query, + user._key, + cleanseInput, + i18n, + ) + + const connectionArgs = { + dmarcGuidanceTags: ['dmarc1', 'dmarc2', 'dmarc3'], + first: 5, + after: toGlobalId('guidanceTags', 'dmarc3'), + before: toGlobalId('guidanceTags', 'dmarc1'), + orderBy: { + field: 'tag-id', + direction: 'DESC', + }, + } + const dmarcTags = await connectionLoader(connectionArgs) + + const expectedStructure = { + edges: [ + { + cursor: toGlobalId('guidanceTags', expectedDmarcTag._key), + node: { + ...expectedDmarcTag, + }, + }, + ], + totalCount: 3, + pageInfo: { + hasNextPage: true, + hasPreviousPage: true, + startCursor: toGlobalId('guidanceTags', expectedDmarcTag._key), + endCursor: toGlobalId('guidanceTags', expectedDmarcTag._key), + }, + } + + expect(dmarcTags).toEqual(expectedStructure) + }) + }) + }) + describe('ordering on TAG_NAME', () => { + describe('order is set to ASC', () => { + it('returns guidance tag', async () => { + const loader = dmarcGuidanceTagLoader(query) + const expectedDmarcTag = await loader.load('dmarc2') + + const connectionLoader = dmarcGuidanceTagConnectionsLoader( + query, + user._key, + cleanseInput, + i18n, + ) + + const connectionArgs = { + dmarcGuidanceTags: ['dmarc1', 'dmarc2', 'dmarc3'], + first: 5, + after: toGlobalId('guidanceTags', 'dmarc1'), + before: toGlobalId('guidanceTags', 'dmarc3'), + orderBy: { + field: 'tag-name', + direction: 'ASC', + }, + } + const dkimTags = await connectionLoader(connectionArgs) + + const expectedStructure = { + edges: [ + { + cursor: toGlobalId('guidanceTags', expectedDmarcTag._key), + node: { + ...expectedDmarcTag, + }, + }, + ], + totalCount: 3, + pageInfo: { + hasNextPage: true, + hasPreviousPage: true, + startCursor: toGlobalId('guidanceTags', expectedDmarcTag._key), + endCursor: toGlobalId('guidanceTags', expectedDmarcTag._key), + }, + } + + expect(dkimTags).toEqual(expectedStructure) + }) + }) + describe('ordering is set to DESC', () => { + it('returns guidance tag', async () => { + const loader = dmarcGuidanceTagLoader(query) + const expectedDmarcTag = await loader.load('dmarc2') + + const connectionLoader = dmarcGuidanceTagConnectionsLoader( + query, + user._key, + cleanseInput, + i18n, + ) + + const connectionArgs = { + dmarcGuidanceTags: ['dmarc1', 'dmarc2', 'dmarc3'], + first: 5, + after: toGlobalId('guidanceTags', 'dmarc3'), + before: toGlobalId('guidanceTags', 'dmarc1'), + orderBy: { + field: 'tag-name', + direction: 'DESC', + }, + } + const dmarcTags = await connectionLoader(connectionArgs) + + const expectedStructure = { + edges: [ + { + cursor: toGlobalId('guidanceTags', expectedDmarcTag._key), + node: { + ...expectedDmarcTag, + }, + }, + ], + totalCount: 3, + pageInfo: { + hasNextPage: true, + hasPreviousPage: true, + startCursor: toGlobalId('guidanceTags', expectedDmarcTag._key), + endCursor: toGlobalId('guidanceTags', expectedDmarcTag._key), + }, + } + + expect(dmarcTags).toEqual(expectedStructure) + }) + }) + }) + describe('ordering on GUIDANCE', () => { + describe('order is set to ASC', () => { + it('returns guidance tag', async () => { + const loader = dmarcGuidanceTagLoader(query) + const expectedDmarcTag = await loader.load('dmarc2') + + const connectionLoader = dmarcGuidanceTagConnectionsLoader( + query, + user._key, + cleanseInput, + i18n, + ) + + const connectionArgs = { + dmarcGuidanceTags: ['dmarc1', 'dmarc2', 'dmarc3'], + first: 5, + after: toGlobalId('guidanceTags', 'dmarc1'), + before: toGlobalId('guidanceTags', 'dmarc3'), + orderBy: { + field: 'guidance', + direction: 'ASC', + }, + } + const dkimTags = await connectionLoader(connectionArgs) + + const expectedStructure = { + edges: [ + { + cursor: toGlobalId('guidanceTags', expectedDmarcTag._key), + node: { + ...expectedDmarcTag, + }, + }, + ], + totalCount: 3, + pageInfo: { + hasNextPage: true, + hasPreviousPage: true, + startCursor: toGlobalId('guidanceTags', expectedDmarcTag._key), + endCursor: toGlobalId('guidanceTags', expectedDmarcTag._key), + }, + } + + expect(dkimTags).toEqual(expectedStructure) + }) + }) + describe('ordering is set to DESC', () => { + it('returns guidance tag', async () => { + const loader = dmarcGuidanceTagLoader(query) + const expectedDmarcTag = await loader.load('dmarc2') + + const connectionLoader = dmarcGuidanceTagConnectionsLoader( + query, + user._key, + cleanseInput, + i18n, + ) + + const connectionArgs = { + dmarcGuidanceTags: ['dmarc1', 'dmarc2', 'dmarc3'], + first: 5, + after: toGlobalId('guidanceTags', 'dmarc3'), + before: toGlobalId('guidanceTags', 'dmarc1'), + orderBy: { + field: 'guidance', + direction: 'DESC', + }, + } + const dmarcTags = await connectionLoader(connectionArgs) + + const expectedStructure = { + edges: [ + { + cursor: toGlobalId('guidanceTags', expectedDmarcTag._key), + node: { + ...expectedDmarcTag, + }, + }, + ], + totalCount: 3, + pageInfo: { + hasNextPage: true, + hasPreviousPage: true, + startCursor: toGlobalId('guidanceTags', expectedDmarcTag._key), + endCursor: toGlobalId('guidanceTags', expectedDmarcTag._key), + }, + } + + expect(dmarcTags).toEqual(expectedStructure) + }) + }) + }) + }) describe('no dmarc results are found', () => { it('returns an empty structure', async () => { await truncate() diff --git a/api-js/src/guidance-tag/loaders/__tests__/load-https-guidance-tags-connections.test.js b/api-js/src/guidance-tag/loaders/__tests__/load-https-guidance-tags-connections.test.js index cf5c7e4a22..3b99ac4cf9 100644 --- a/api-js/src/guidance-tag/loaders/__tests__/load-https-guidance-tags-connections.test.js +++ b/api-js/src/guidance-tag/loaders/__tests__/load-https-guidance-tags-connections.test.js @@ -45,7 +45,6 @@ describe('when given the load https guidance tag connection function', () => { }) beforeEach(async () => { - await truncate() consoleWarnOutput.length = 0 consoleErrorOutput.length = 0 @@ -65,6 +64,10 @@ describe('when given the load https guidance tag connection function', () => { }) }) + afterEach(async () => { + await truncate() + }) + afterAll(async () => { await drop() }) @@ -307,6 +310,302 @@ describe('when given the load https guidance tag connection function', () => { expect(httpsTags).toEqual(expectedStructure) }) }) + describe('using orderBy field', () => { + beforeEach(async () => { + await truncate() + await collections.httpsGuidanceTags.save({ + _key: 'https1', + tagName: 'a', + guidance: 'a', + }) + await collections.httpsGuidanceTags.save({ + _key: 'https2', + tagName: 'b', + guidance: 'b', + }) + await collections.httpsGuidanceTags.save({ + _key: 'https3', + tagName: 'c', + guidance: 'c', + }) + }) + describe('ordering on TAG_ID', () => { + describe('order is set to ASC', () => { + it('returns guidance tag', async () => { + const loader = httpsGuidanceTagLoader(query) + const expectedHttpsTag = await loader.load('https2') + + const connectionLoader = httpsGuidanceTagConnectionsLoader( + query, + user._key, + cleanseInput, + i18n, + ) + + const connectionArgs = { + httpsGuidanceTags: ['https1', 'https2', 'https3'], + first: 5, + after: toGlobalId('guidanceTags', 'https1'), + before: toGlobalId('guidanceTags', 'https3'), + orderBy: { + field: 'tag-id', + direction: 'ASC', + }, + } + const httpsTags = await connectionLoader(connectionArgs) + + const expectedStructure = { + edges: [ + { + cursor: toGlobalId('guidanceTags', expectedHttpsTag._key), + node: { + ...expectedHttpsTag, + }, + }, + ], + totalCount: 3, + pageInfo: { + hasNextPage: true, + hasPreviousPage: true, + startCursor: toGlobalId('guidanceTags', expectedHttpsTag._key), + endCursor: toGlobalId('guidanceTags', expectedHttpsTag._key), + }, + } + + expect(httpsTags).toEqual(expectedStructure) + }) + }) + describe('ordering is set to DESC', () => { + it('returns guidance tag', async () => { + const loader = httpsGuidanceTagLoader(query) + const expectedHttpsTag = await loader.load('https2') + + const connectionLoader = httpsGuidanceTagConnectionsLoader( + query, + user._key, + cleanseInput, + i18n, + ) + + const connectionArgs = { + httpsGuidanceTags: ['https1', 'https2', 'https3'], + first: 5, + after: toGlobalId('guidanceTags', 'https3'), + before: toGlobalId('guidanceTags', 'https1'), + orderBy: { + field: 'tag-id', + direction: 'DESC', + }, + } + const httpsTags = await connectionLoader(connectionArgs) + + const expectedStructure = { + edges: [ + { + cursor: toGlobalId('guidanceTags', expectedHttpsTag._key), + node: { + ...expectedHttpsTag, + }, + }, + ], + totalCount: 3, + pageInfo: { + hasNextPage: true, + hasPreviousPage: true, + startCursor: toGlobalId('guidanceTags', expectedHttpsTag._key), + endCursor: toGlobalId('guidanceTags', expectedHttpsTag._key), + }, + } + + expect(httpsTags).toEqual(expectedStructure) + }) + }) + }) + describe('ordering on TAG_NAME', () => { + describe('order is set to ASC', () => { + it('returns guidance tag', async () => { + const loader = httpsGuidanceTagLoader(query) + const expectedHttpsTag = await loader.load('https2') + + const connectionLoader = httpsGuidanceTagConnectionsLoader( + query, + user._key, + cleanseInput, + i18n, + ) + + const connectionArgs = { + httpsGuidanceTags: ['https1', 'https2', 'https3'], + first: 5, + after: toGlobalId('guidanceTags', 'https1'), + before: toGlobalId('guidanceTags', 'https3'), + orderBy: { + field: 'tag-name', + direction: 'ASC', + }, + } + const httpsTags = await connectionLoader(connectionArgs) + + const expectedStructure = { + edges: [ + { + cursor: toGlobalId('guidanceTags', expectedHttpsTag._key), + node: { + ...expectedHttpsTag, + }, + }, + ], + totalCount: 3, + pageInfo: { + hasNextPage: true, + hasPreviousPage: true, + startCursor: toGlobalId('guidanceTags', expectedHttpsTag._key), + endCursor: toGlobalId('guidanceTags', expectedHttpsTag._key), + }, + } + + expect(httpsTags).toEqual(expectedStructure) + }) + }) + describe('ordering is set to DESC', () => { + it('returns guidance tag', async () => { + const loader = httpsGuidanceTagLoader(query) + const expectedHttpsTag = await loader.load('https2') + + const connectionLoader = httpsGuidanceTagConnectionsLoader( + query, + user._key, + cleanseInput, + i18n, + ) + + const connectionArgs = { + httpsGuidanceTags: ['https1', 'https2', 'https3'], + first: 5, + after: toGlobalId('guidanceTags', 'https3'), + before: toGlobalId('guidanceTags', 'https1'), + orderBy: { + field: 'tag-name', + direction: 'DESC', + }, + } + const httpsTags = await connectionLoader(connectionArgs) + + const expectedStructure = { + edges: [ + { + cursor: toGlobalId('guidanceTags', expectedHttpsTag._key), + node: { + ...expectedHttpsTag, + }, + }, + ], + totalCount: 3, + pageInfo: { + hasNextPage: true, + hasPreviousPage: true, + startCursor: toGlobalId('guidanceTags', expectedHttpsTag._key), + endCursor: toGlobalId('guidanceTags', expectedHttpsTag._key), + }, + } + + expect(httpsTags).toEqual(expectedStructure) + }) + }) + }) + describe('ordering on GUIDANCE', () => { + describe('order is set to ASC', () => { + it('returns guidance tag', async () => { + const loader = httpsGuidanceTagLoader(query) + const expectedHttpsTag = await loader.load('https2') + + const connectionLoader = httpsGuidanceTagConnectionsLoader( + query, + user._key, + cleanseInput, + i18n, + ) + + const connectionArgs = { + httpsGuidanceTags: ['https1', 'https2', 'https3'], + first: 5, + after: toGlobalId('guidanceTags', 'https1'), + before: toGlobalId('guidanceTags', 'https3'), + orderBy: { + field: 'guidance', + direction: 'ASC', + }, + } + const httpsTags = await connectionLoader(connectionArgs) + + const expectedStructure = { + edges: [ + { + cursor: toGlobalId('guidanceTags', expectedHttpsTag._key), + node: { + ...expectedHttpsTag, + }, + }, + ], + totalCount: 3, + pageInfo: { + hasNextPage: true, + hasPreviousPage: true, + startCursor: toGlobalId('guidanceTags', expectedHttpsTag._key), + endCursor: toGlobalId('guidanceTags', expectedHttpsTag._key), + }, + } + + expect(httpsTags).toEqual(expectedStructure) + }) + }) + describe('ordering is set to DESC', () => { + it('returns guidance tag', async () => { + const loader = httpsGuidanceTagLoader(query) + const expectedHttpsTag = await loader.load('https2') + + const connectionLoader = httpsGuidanceTagConnectionsLoader( + query, + user._key, + cleanseInput, + i18n, + ) + + const connectionArgs = { + httpsGuidanceTags: ['https1', 'https2', 'https3'], + first: 5, + after: toGlobalId('guidanceTags', 'https3'), + before: toGlobalId('guidanceTags', 'https1'), + orderBy: { + field: 'guidance', + direction: 'DESC', + }, + } + const httpsTags = await connectionLoader(connectionArgs) + + const expectedStructure = { + edges: [ + { + cursor: toGlobalId('guidanceTags', expectedHttpsTag._key), + node: { + ...expectedHttpsTag, + }, + }, + ], + totalCount: 3, + pageInfo: { + hasNextPage: true, + hasPreviousPage: true, + startCursor: toGlobalId('guidanceTags', expectedHttpsTag._key), + endCursor: toGlobalId('guidanceTags', expectedHttpsTag._key), + }, + } + + expect(httpsTags).toEqual(expectedStructure) + }) + }) + }) + }) describe('no https results are found', () => { it('returns an empty structure', async () => { await truncate() diff --git a/api-js/src/guidance-tag/loaders/__tests__/load-spf-guidance-tags-connections.test.js b/api-js/src/guidance-tag/loaders/__tests__/load-spf-guidance-tags-connections.test.js index f0d608c4d8..1ef416088e 100644 --- a/api-js/src/guidance-tag/loaders/__tests__/load-spf-guidance-tags-connections.test.js +++ b/api-js/src/guidance-tag/loaders/__tests__/load-spf-guidance-tags-connections.test.js @@ -42,7 +42,6 @@ describe('when given the load spf guidance tag connection function', () => { }) beforeEach(async () => { - await truncate() consoleWarnOutput.length = 0 consoleErrorOutput.length = 0 @@ -62,6 +61,10 @@ describe('when given the load spf guidance tag connection function', () => { }) }) + afterEach(async () => { + await truncate() + }) + afterAll(async () => { await drop() }) @@ -294,6 +297,302 @@ describe('when given the load spf guidance tag connection function', () => { expect(spfTags).toEqual(expectedStructure) }) }) + describe('using orderBy field', () => { + beforeEach(async () => { + await truncate() + await collections.spfGuidanceTags.save({ + _key: 'spf1', + tagName: 'a', + guidance: 'a', + }) + await collections.spfGuidanceTags.save({ + _key: 'spf2', + tagName: 'b', + guidance: 'b', + }) + await collections.spfGuidanceTags.save({ + _key: 'spf3', + tagName: 'c', + guidance: 'c', + }) + }) + describe('ordering on TAG_ID', () => { + describe('order is set to ASC', () => { + it('returns guidance tag', async () => { + const loader = spfGuidanceTagLoader(query) + const expectedSpfTag = await loader.load('spf2') + + const connectionLoader = spfGuidanceTagConnectionsLoader( + query, + user._key, + cleanseInput, + i18n, + ) + + const connectionArgs = { + spfGuidanceTags: ['spf1', 'spf2', 'spf3'], + first: 5, + after: toGlobalId('guidanceTags', 'spf1'), + before: toGlobalId('guidanceTags', 'spf3'), + orderBy: { + field: 'tag-id', + direction: 'ASC', + }, + } + const spfTags = await connectionLoader(connectionArgs) + + const expectedStructure = { + edges: [ + { + cursor: toGlobalId('guidanceTags', expectedSpfTag._key), + node: { + ...expectedSpfTag, + }, + }, + ], + totalCount: 3, + pageInfo: { + hasNextPage: true, + hasPreviousPage: true, + startCursor: toGlobalId('guidanceTags', expectedSpfTag._key), + endCursor: toGlobalId('guidanceTags', expectedSpfTag._key), + }, + } + + expect(spfTags).toEqual(expectedStructure) + }) + }) + describe('ordering is set to DESC', () => { + it('returns guidance tag', async () => { + const loader = spfGuidanceTagLoader(query) + const expectedSpfTag = await loader.load('spf2') + + const connectionLoader = spfGuidanceTagConnectionsLoader( + query, + user._key, + cleanseInput, + i18n, + ) + + const connectionArgs = { + spfGuidanceTags: ['spf1', 'spf2', 'spf3'], + first: 5, + after: toGlobalId('guidanceTags', 'spf3'), + before: toGlobalId('guidanceTags', 'spf1'), + orderBy: { + field: 'tag-id', + direction: 'DESC', + }, + } + const spfTags = await connectionLoader(connectionArgs) + + const expectedStructure = { + edges: [ + { + cursor: toGlobalId('guidanceTags', expectedSpfTag._key), + node: { + ...expectedSpfTag, + }, + }, + ], + totalCount: 3, + pageInfo: { + hasNextPage: true, + hasPreviousPage: true, + startCursor: toGlobalId('guidanceTags', expectedSpfTag._key), + endCursor: toGlobalId('guidanceTags', expectedSpfTag._key), + }, + } + + expect(spfTags).toEqual(expectedStructure) + }) + }) + }) + describe('ordering on TAG_NAME', () => { + describe('order is set to ASC', () => { + it('returns guidance tag', async () => { + const loader = spfGuidanceTagLoader(query) + const expectedSpfTag = await loader.load('spf2') + + const connectionLoader = spfGuidanceTagConnectionsLoader( + query, + user._key, + cleanseInput, + i18n, + ) + + const connectionArgs = { + spfGuidanceTags: ['spf1', 'spf2', 'spf3'], + first: 5, + after: toGlobalId('guidanceTags', 'spf1'), + before: toGlobalId('guidanceTags', 'spf3'), + orderBy: { + field: 'tag-name', + direction: 'ASC', + }, + } + const spfTags = await connectionLoader(connectionArgs) + + const expectedStructure = { + edges: [ + { + cursor: toGlobalId('guidanceTags', expectedSpfTag._key), + node: { + ...expectedSpfTag, + }, + }, + ], + totalCount: 3, + pageInfo: { + hasNextPage: true, + hasPreviousPage: true, + startCursor: toGlobalId('guidanceTags', expectedSpfTag._key), + endCursor: toGlobalId('guidanceTags', expectedSpfTag._key), + }, + } + + expect(spfTags).toEqual(expectedStructure) + }) + }) + describe('ordering is set to DESC', () => { + it('returns guidance tag', async () => { + const loader = spfGuidanceTagLoader(query) + const expectedSpfTag = await loader.load('spf2') + + const connectionLoader = spfGuidanceTagConnectionsLoader( + query, + user._key, + cleanseInput, + i18n, + ) + + const connectionArgs = { + spfGuidanceTags: ['spf1', 'spf2', 'spf3'], + first: 5, + after: toGlobalId('guidanceTags', 'spf3'), + before: toGlobalId('guidanceTags', 'spf1'), + orderBy: { + field: 'tag-name', + direction: 'DESC', + }, + } + const spfTags = await connectionLoader(connectionArgs) + + const expectedStructure = { + edges: [ + { + cursor: toGlobalId('guidanceTags', expectedSpfTag._key), + node: { + ...expectedSpfTag, + }, + }, + ], + totalCount: 3, + pageInfo: { + hasNextPage: true, + hasPreviousPage: true, + startCursor: toGlobalId('guidanceTags', expectedSpfTag._key), + endCursor: toGlobalId('guidanceTags', expectedSpfTag._key), + }, + } + + expect(spfTags).toEqual(expectedStructure) + }) + }) + }) + describe('ordering on GUIDANCE', () => { + describe('order is set to ASC', () => { + it('returns guidance tag', async () => { + const loader = spfGuidanceTagLoader(query) + const expectedSpfTag = await loader.load('spf2') + + const connectionLoader = spfGuidanceTagConnectionsLoader( + query, + user._key, + cleanseInput, + i18n, + ) + + const connectionArgs = { + spfGuidanceTags: ['spf1', 'spf2', 'spf3'], + first: 5, + after: toGlobalId('guidanceTags', 'spf1'), + before: toGlobalId('guidanceTags', 'spf3'), + orderBy: { + field: 'guidance', + direction: 'ASC', + }, + } + const spfTags = await connectionLoader(connectionArgs) + + const expectedStructure = { + edges: [ + { + cursor: toGlobalId('guidanceTags', expectedSpfTag._key), + node: { + ...expectedSpfTag, + }, + }, + ], + totalCount: 3, + pageInfo: { + hasNextPage: true, + hasPreviousPage: true, + startCursor: toGlobalId('guidanceTags', expectedSpfTag._key), + endCursor: toGlobalId('guidanceTags', expectedSpfTag._key), + }, + } + + expect(spfTags).toEqual(expectedStructure) + }) + }) + describe('ordering is set to DESC', () => { + it('returns guidance tag', async () => { + const loader = spfGuidanceTagLoader(query) + const expectedSpfTag = await loader.load('spf2') + + const connectionLoader = spfGuidanceTagConnectionsLoader( + query, + user._key, + cleanseInput, + i18n, + ) + + const connectionArgs = { + spfGuidanceTags: ['spf1', 'spf2', 'spf3'], + first: 5, + after: toGlobalId('guidanceTags', 'spf3'), + before: toGlobalId('guidanceTags', 'spf1'), + orderBy: { + field: 'guidance', + direction: 'DESC', + }, + } + const spfTags = await connectionLoader(connectionArgs) + + const expectedStructure = { + edges: [ + { + cursor: toGlobalId('guidanceTags', expectedSpfTag._key), + node: { + ...expectedSpfTag, + }, + }, + ], + totalCount: 3, + pageInfo: { + hasNextPage: true, + hasPreviousPage: true, + startCursor: toGlobalId('guidanceTags', expectedSpfTag._key), + endCursor: toGlobalId('guidanceTags', expectedSpfTag._key), + }, + } + + expect(spfTags).toEqual(expectedStructure) + }) + }) + }) + }) describe('no spf results are found', () => { it('returns an empty structure', async () => { await truncate() diff --git a/api-js/src/guidance-tag/loaders/__tests__/load-ssl-guidance-tags-connections.test.js b/api-js/src/guidance-tag/loaders/__tests__/load-ssl-guidance-tags-connections.test.js index 181a62d9e1..cd35aaee33 100644 --- a/api-js/src/guidance-tag/loaders/__tests__/load-ssl-guidance-tags-connections.test.js +++ b/api-js/src/guidance-tag/loaders/__tests__/load-ssl-guidance-tags-connections.test.js @@ -42,7 +42,6 @@ describe('when given the load ssl guidance tag connection function', () => { }) beforeEach(async () => { - await truncate() consoleWarnOutput.length = 0 consoleErrorOutput.length = 0 @@ -62,6 +61,10 @@ describe('when given the load ssl guidance tag connection function', () => { }) }) + afterEach(async () => { + await truncate() + }) + afterAll(async () => { await drop() }) @@ -294,6 +297,302 @@ describe('when given the load ssl guidance tag connection function', () => { expect(sslTags).toEqual(expectedStructure) }) }) + describe('using orderBy field', () => { + beforeEach(async () => { + await truncate() + await collections.sslGuidanceTags.save({ + _key: 'ssl1', + tagName: 'a', + guidance: 'a', + }) + await collections.sslGuidanceTags.save({ + _key: 'ssl2', + tagName: 'b', + guidance: 'b', + }) + await collections.sslGuidanceTags.save({ + _key: 'ssl3', + tagName: 'c', + guidance: 'c', + }) + }) + describe('ordering on TAG_ID', () => { + describe('order is set to ASC', () => { + it('returns guidance tag', async () => { + const loader = sslGuidanceTagLoader(query) + const expectedSslTag = await loader.load('ssl2') + + const connectionLoader = sslGuidanceTagConnectionsLoader( + query, + user._key, + cleanseInput, + i18n, + ) + + const connectionArgs = { + sslGuidanceTags: ['ssl1', 'ssl2', 'ssl3'], + first: 5, + after: toGlobalId('guidanceTags', 'ssl1'), + before: toGlobalId('guidanceTags', 'ssl3'), + orderBy: { + field: 'tag-id', + direction: 'ASC', + }, + } + const sslTags = await connectionLoader(connectionArgs) + + const expectedStructure = { + edges: [ + { + cursor: toGlobalId('guidanceTags', expectedSslTag._key), + node: { + ...expectedSslTag, + }, + }, + ], + totalCount: 3, + pageInfo: { + hasNextPage: true, + hasPreviousPage: true, + startCursor: toGlobalId('guidanceTags', expectedSslTag._key), + endCursor: toGlobalId('guidanceTags', expectedSslTag._key), + }, + } + + expect(sslTags).toEqual(expectedStructure) + }) + }) + describe('ordering is set to DESC', () => { + it('returns guidance tag', async () => { + const loader = sslGuidanceTagLoader(query) + const expectedSslTag = await loader.load('ssl2') + + const connectionLoader = sslGuidanceTagConnectionsLoader( + query, + user._key, + cleanseInput, + i18n, + ) + + const connectionArgs = { + sslGuidanceTags: ['ssl1', 'ssl2', 'ssl3'], + first: 5, + after: toGlobalId('guidanceTags', 'ssl3'), + before: toGlobalId('guidanceTags', 'ssl1'), + orderBy: { + field: 'tag-id', + direction: 'DESC', + }, + } + const sslTags = await connectionLoader(connectionArgs) + + const expectedStructure = { + edges: [ + { + cursor: toGlobalId('guidanceTags', expectedSslTag._key), + node: { + ...expectedSslTag, + }, + }, + ], + totalCount: 3, + pageInfo: { + hasNextPage: true, + hasPreviousPage: true, + startCursor: toGlobalId('guidanceTags', expectedSslTag._key), + endCursor: toGlobalId('guidanceTags', expectedSslTag._key), + }, + } + + expect(sslTags).toEqual(expectedStructure) + }) + }) + }) + describe('ordering on TAG_NAME', () => { + describe('order is set to ASC', () => { + it('returns guidance tag', async () => { + const loader = sslGuidanceTagLoader(query) + const expectedSslTag = await loader.load('ssl2') + + const connectionLoader = sslGuidanceTagConnectionsLoader( + query, + user._key, + cleanseInput, + i18n, + ) + + const connectionArgs = { + sslGuidanceTags: ['ssl1', 'ssl2', 'ssl3'], + first: 5, + after: toGlobalId('guidanceTags', 'ssl1'), + before: toGlobalId('guidanceTags', 'ssl3'), + orderBy: { + field: 'tag-name', + direction: 'ASC', + }, + } + const sslTags = await connectionLoader(connectionArgs) + + const expectedStructure = { + edges: [ + { + cursor: toGlobalId('guidanceTags', expectedSslTag._key), + node: { + ...expectedSslTag, + }, + }, + ], + totalCount: 3, + pageInfo: { + hasNextPage: true, + hasPreviousPage: true, + startCursor: toGlobalId('guidanceTags', expectedSslTag._key), + endCursor: toGlobalId('guidanceTags', expectedSslTag._key), + }, + } + + expect(sslTags).toEqual(expectedStructure) + }) + }) + describe('ordering is set to DESC', () => { + it('returns guidance tag', async () => { + const loader = sslGuidanceTagLoader(query) + const expectedSslTag = await loader.load('ssl2') + + const connectionLoader = sslGuidanceTagConnectionsLoader( + query, + user._key, + cleanseInput, + i18n, + ) + + const connectionArgs = { + sslGuidanceTags: ['ssl1', 'ssl2', 'ssl3'], + first: 5, + after: toGlobalId('guidanceTags', 'ssl3'), + before: toGlobalId('guidanceTags', 'ssl1'), + orderBy: { + field: 'tag-name', + direction: 'DESC', + }, + } + const sslTags = await connectionLoader(connectionArgs) + + const expectedStructure = { + edges: [ + { + cursor: toGlobalId('guidanceTags', expectedSslTag._key), + node: { + ...expectedSslTag, + }, + }, + ], + totalCount: 3, + pageInfo: { + hasNextPage: true, + hasPreviousPage: true, + startCursor: toGlobalId('guidanceTags', expectedSslTag._key), + endCursor: toGlobalId('guidanceTags', expectedSslTag._key), + }, + } + + expect(sslTags).toEqual(expectedStructure) + }) + }) + }) + describe('ordering on GUIDANCE', () => { + describe('order is set to ASC', () => { + it('returns guidance tag', async () => { + const loader = sslGuidanceTagLoader(query) + const expectedSslTag = await loader.load('ssl2') + + const connectionLoader = sslGuidanceTagConnectionsLoader( + query, + user._key, + cleanseInput, + i18n, + ) + + const connectionArgs = { + sslGuidanceTags: ['ssl1', 'ssl2', 'ssl3'], + first: 5, + after: toGlobalId('guidanceTags', 'ssl1'), + before: toGlobalId('guidanceTags', 'ssl3'), + orderBy: { + field: 'guidance', + direction: 'ASC', + }, + } + const sslTags = await connectionLoader(connectionArgs) + + const expectedStructure = { + edges: [ + { + cursor: toGlobalId('guidanceTags', expectedSslTag._key), + node: { + ...expectedSslTag, + }, + }, + ], + totalCount: 3, + pageInfo: { + hasNextPage: true, + hasPreviousPage: true, + startCursor: toGlobalId('guidanceTags', expectedSslTag._key), + endCursor: toGlobalId('guidanceTags', expectedSslTag._key), + }, + } + + expect(sslTags).toEqual(expectedStructure) + }) + }) + describe('ordering is set to DESC', () => { + it('returns guidance tag', async () => { + const loader = sslGuidanceTagLoader(query) + const expectedSslTag = await loader.load('ssl2') + + const connectionLoader = sslGuidanceTagConnectionsLoader( + query, + user._key, + cleanseInput, + i18n, + ) + + const connectionArgs = { + sslGuidanceTags: ['ssl1', 'ssl2', 'ssl3'], + first: 5, + after: toGlobalId('guidanceTags', 'ssl3'), + before: toGlobalId('guidanceTags', 'ssl1'), + orderBy: { + field: 'guidance', + direction: 'DESC', + }, + } + const sslTags = await connectionLoader(connectionArgs) + + const expectedStructure = { + edges: [ + { + cursor: toGlobalId('guidanceTags', expectedSslTag._key), + node: { + ...expectedSslTag, + }, + }, + ], + totalCount: 3, + pageInfo: { + hasNextPage: true, + hasPreviousPage: true, + startCursor: toGlobalId('guidanceTags', expectedSslTag._key), + endCursor: toGlobalId('guidanceTags', expectedSslTag._key), + }, + } + + expect(sslTags).toEqual(expectedStructure) + }) + }) + }) + }) describe('no ssl results are found', () => { it('returns an empty structure', async () => { await truncate() diff --git a/api-js/src/guidance-tag/loaders/load-dkim-guidance-tags-connections.js b/api-js/src/guidance-tag/loaders/load-dkim-guidance-tags-connections.js index d08cd87a30..55d9aa68d3 100644 --- a/api-js/src/guidance-tag/loaders/load-dkim-guidance-tags-connections.js +++ b/api-js/src/guidance-tag/loaders/load-dkim-guidance-tags-connections.js @@ -7,17 +7,73 @@ export const dkimGuidanceTagConnectionsLoader = ( userKey, cleanseInput, i18n, -) => async ({ dkimGuidanceTags, after, before, first, last }) => { +) => async ({ dkimGuidanceTags, after, before, first, last, orderBy }) => { let afterTemplate = aql`` if (typeof after !== 'undefined') { const { id: afterId } = fromGlobalId(cleanseInput(after)) - afterTemplate = aql`FILTER TO_NUMBER(REGEX_SPLIT(tag._key, "[a-z]+")[1]) > TO_NUMBER(REGEX_SPLIT(${afterId}, "[a-z]+")[1])` + if (typeof orderBy === 'undefined') { + afterTemplate = aql`FILTER TO_NUMBER(REGEX_SPLIT(tag._key, "[a-z]+")[1]) > TO_NUMBER(REGEX_SPLIT(${afterId}, "[a-z]+")[1])` + } else { + let afterTemplateDirection + if (orderBy.direction === 'ASC') { + afterTemplateDirection = aql`>` + } else { + afterTemplateDirection = aql`<` + } + + let tagField, documentField + /* istanbul ignore else */ + if (orderBy.field === 'tag-id') { + tagField = aql`tag._key` + documentField = aql`DOCUMENT(dkimGuidanceTags, ${afterId})._key` + } else if (orderBy.field === 'tag-name') { + tagField = aql`tag.tagName` + documentField = aql`DOCUMENT(dkimGuidanceTags, ${afterId}).tagName` + } else if (orderBy.field === 'guidance') { + tagField = aql`tag.guidance` + documentField = aql`DOCUMENT(dkimGuidanceTags, ${afterId}).guidance` + } + + afterTemplate = aql` + FILTER ${tagField} ${afterTemplateDirection} ${documentField} + OR (${tagField} == ${documentField} + AND TO_NUMBER(REGEX_SPLIT(tag._key, "[a-z]+")[1]) > TO_NUMBER(REGEX_SPLIT(${afterId}, "[a-z]+")[1])) + ` + } } let beforeTemplate = aql`` if (typeof before !== 'undefined') { const { id: beforeId } = fromGlobalId(cleanseInput(before)) - beforeTemplate = aql`FILTER TO_NUMBER(REGEX_SPLIT(tag._key, "[a-z]+")[1]) < TO_NUMBER(REGEX_SPLIT(${beforeId}, "[a-z]+")[1])` + if (typeof orderBy === 'undefined') { + beforeTemplate = aql`FILTER TO_NUMBER(REGEX_SPLIT(tag._key, "[a-z]+")[1]) < TO_NUMBER(REGEX_SPLIT(${beforeId}, "[a-z]+")[1])` + } else { + let beforeTemplateDirection + if (orderBy.direction === 'ASC') { + beforeTemplateDirection = aql`<` + } else { + beforeTemplateDirection = aql`>` + } + + let tagField, documentField + /* istanbul ignore else */ + if (orderBy.field === 'tag-id') { + tagField = aql`tag._key` + documentField = aql`DOCUMENT(dkimGuidanceTags, ${beforeId})._key` + } else if (orderBy.field === 'tag-name') { + tagField = aql`tag.tagName` + documentField = aql`DOCUMENT(dkimGuidanceTags, ${beforeId}).tagName` + } else if (orderBy.field === 'guidance') { + tagField = aql`tag.guidance` + documentField = aql`DOCUMENT(dkimGuidanceTags, ${beforeId}).guidance` + } + + beforeTemplate = aql` + FILTER ${tagField} ${beforeTemplateDirection} ${documentField} + OR (${tagField} == ${documentField} + AND TO_NUMBER(REGEX_SPLIT(tag._key, "[a-z]+")[1]) < TO_NUMBER(REGEX_SPLIT(${beforeId}, "[a-z]+")[1])) + ` + } } let limitTemplate = aql`` @@ -63,9 +119,9 @@ export const dkimGuidanceTagConnectionsLoader = ( ), ) } else if (typeof first !== 'undefined' && typeof last === 'undefined') { - limitTemplate = aql`SORT TO_NUMBER(REGEX_SPLIT(tag._key, "[a-z]+")[1]) ASC LIMIT TO_NUMBER(${first})` + limitTemplate = aql`TO_NUMBER(REGEX_SPLIT(tag._key, "[a-z]+")[1]) ASC LIMIT TO_NUMBER(${first})` } else if (typeof first === 'undefined' && typeof last !== 'undefined') { - limitTemplate = aql`SORT TO_NUMBER(REGEX_SPLIT(tag._key, "[a-z]+")[1]) DESC LIMIT TO_NUMBER(${last})` + limitTemplate = aql`TO_NUMBER(REGEX_SPLIT(tag._key, "[a-z]+")[1]) DESC LIMIT TO_NUMBER(${last})` } } else { const argSet = typeof first !== 'undefined' ? 'first' : 'last' @@ -78,6 +134,60 @@ export const dkimGuidanceTagConnectionsLoader = ( ) } + let hasNextPageFilter = aql`FILTER TO_NUMBER(REGEX_SPLIT(tag._key, "[a-z]+")[1]) > TO_NUMBER(REGEX_SPLIT(LAST(retrievedDkimGuidanceTags)._key, "[a-z]+")[1])` + let hasPreviousPageFilter = aql`FILTER TO_NUMBER(REGEX_SPLIT(tag._key, "[a-z]+")[1]) < TO_NUMBER(REGEX_SPLIT(FIRST(retrievedDkimGuidanceTags)._key, "[a-z]+")[1])` + if (typeof orderBy !== 'undefined') { + let hasNextPageDirection + let hasPreviousPageDirection + if (orderBy.direction === 'ASC') { + hasNextPageDirection = aql`>` + hasPreviousPageDirection = aql`<` + } else { + hasNextPageDirection = aql`<` + hasPreviousPageDirection = aql`>` + } + + let tagField, hasNextPageDocument, hasPreviousPageDocument + /* istanbul ignore else */ + if (orderBy.field === 'tag-id') { + tagField = aql`tag._key` + hasNextPageDocument = aql`LAST(retrievedDkimGuidanceTags)._key` + hasPreviousPageDocument = aql`FIRST(retrievedDkimGuidanceTags)._key` + } else if (orderBy.field === 'tag-name') { + tagField = aql`tag.tagName` + hasNextPageDocument = aql`LAST(retrievedDkimGuidanceTags).tagName` + hasPreviousPageDocument = aql`FIRST(retrievedDkimGuidanceTags).tagName` + } else if (orderBy.field === 'guidance') { + tagField = aql`tag.guidance` + hasNextPageDocument = aql`LAST(retrievedDkimGuidanceTags).guidance` + hasPreviousPageDocument = aql`FIRST(retrievedDkimGuidanceTags).guidance` + } + + hasNextPageFilter = aql` + FILTER ${tagField} ${hasNextPageDirection} ${hasNextPageDocument} + OR (${tagField} == ${hasNextPageDocument} + AND TO_NUMBER(REGEX_SPLIT(tag._key, "[a-z]+")[1]) > TO_NUMBER(REGEX_SPLIT(LAST(retrievedDkimGuidanceTags)._key, "[a-z]+")[1])) + ` + + hasPreviousPageFilter = aql` + FILTER ${tagField} ${hasPreviousPageDirection} ${hasPreviousPageDocument} + OR (${tagField} == ${hasPreviousPageDocument} + AND TO_NUMBER(REGEX_SPLIT(tag._key, "[a-z]+")[1]) < TO_NUMBER(REGEX_SPLIT(FIRST(retrievedDkimGuidanceTags)._key, "[a-z]+")[1])) + ` + } + + let sortByField = aql`` + if (typeof orderBy !== 'undefined') { + /* istanbul ignore else */ + if (orderBy.field === 'tag-id') { + sortByField = aql`tag._key ${orderBy.direction},` + } else if (orderBy.field === 'tag-name') { + sortByField = aql`tag.tagName ${orderBy.direction},` + } else if (orderBy.field === 'guidance') { + sortByField = aql`tag.guidance ${orderBy.direction},` + } + } + let sortString if (typeof last !== 'undefined') { sortString = aql`DESC` @@ -93,6 +203,8 @@ export const dkimGuidanceTagConnectionsLoader = ( FILTER tag._key IN ${dkimGuidanceTags} ${afterTemplate} ${beforeTemplate} + SORT + ${sortByField} ${limitTemplate} RETURN MERGE(tag, { tagId: tag._key, id: tag._key, _type: "guidanceTag" }) ) @@ -100,16 +212,16 @@ export const dkimGuidanceTagConnectionsLoader = ( LET hasNextPage = (LENGTH( FOR tag IN dkimGuidanceTags FILTER tag._key IN ${dkimGuidanceTags} - FILTER TO_NUMBER(REGEX_SPLIT(tag._key, "[a-z]+")[1]) > TO_NUMBER(REGEX_SPLIT(LAST(retrievedDkimGuidanceTags)._key, "[a-z]+")[1]) - SORT TO_NUMBER(REGEX_SPLIT(tag._key, "[a-z]+")[1]) ${sortString} LIMIT 1 + ${hasNextPageFilter} + SORT ${sortByField} TO_NUMBER(REGEX_SPLIT(tag._key, "[a-z]+")[1]) ${sortString} LIMIT 1 RETURN tag ) > 0 ? true : false) LET hasPreviousPage = (LENGTH( FOR tag IN dkimGuidanceTags FILTER tag._key IN ${dkimGuidanceTags} - FILTER TO_NUMBER(REGEX_SPLIT(tag._key, "[a-z]+")[1]) < TO_NUMBER(REGEX_SPLIT(FIRST(retrievedDkimGuidanceTags)._key, "[a-z]+")[1]) - SORT TO_NUMBER(REGEX_SPLIT(tag._key, "[a-z]+")[1]) ${sortString} LIMIT 1 + ${hasPreviousPageFilter} + SORT ${sortByField} TO_NUMBER(REGEX_SPLIT(tag._key, "[a-z]+")[1]) ${sortString} LIMIT 1 RETURN tag ) > 0 ? true : false) diff --git a/api-js/src/guidance-tag/loaders/load-dmarc-guidance-tags-connections.js b/api-js/src/guidance-tag/loaders/load-dmarc-guidance-tags-connections.js index 08e74ba7cd..4dd75862e4 100644 --- a/api-js/src/guidance-tag/loaders/load-dmarc-guidance-tags-connections.js +++ b/api-js/src/guidance-tag/loaders/load-dmarc-guidance-tags-connections.js @@ -7,17 +7,73 @@ export const dmarcGuidanceTagConnectionsLoader = ( userKey, cleanseInput, i18n, -) => async ({ dmarcGuidanceTags, after, before, first, last }) => { +) => async ({ dmarcGuidanceTags, after, before, first, last, orderBy }) => { let afterTemplate = aql`` if (typeof after !== 'undefined') { const { id: afterId } = fromGlobalId(cleanseInput(after)) - afterTemplate = aql`FILTER TO_NUMBER(REGEX_SPLIT(tag._key, "[a-z]+")[1]) > TO_NUMBER(REGEX_SPLIT(${afterId}, "[a-z]+")[1])` + if (typeof orderBy === 'undefined') { + afterTemplate = aql`FILTER TO_NUMBER(REGEX_SPLIT(tag._key, "[a-z]+")[1]) > TO_NUMBER(REGEX_SPLIT(${afterId}, "[a-z]+")[1])` + } else { + let afterTemplateDirection + if (orderBy.direction === 'ASC') { + afterTemplateDirection = aql`>` + } else { + afterTemplateDirection = aql`<` + } + + let tagField, documentField + /* istanbul ignore else */ + if (orderBy.field === 'tag-id') { + tagField = aql`tag._key` + documentField = aql`DOCUMENT(dmarcGuidanceTags, ${afterId})._key` + } else if (orderBy.field === 'tag-name') { + tagField = aql`tag.tagName` + documentField = aql`DOCUMENT(dmarcGuidanceTags, ${afterId}).tagName` + } else if (orderBy.field === 'guidance') { + tagField = aql`tag.guidance` + documentField = aql`DOCUMENT(dmarcGuidanceTags, ${afterId}).guidance` + } + + afterTemplate = aql` + FILTER ${tagField} ${afterTemplateDirection} ${documentField} + OR (${tagField} == ${documentField} + AND TO_NUMBER(REGEX_SPLIT(tag._key, "[a-z]+")[1]) > TO_NUMBER(REGEX_SPLIT(${afterId}, "[a-z]+")[1])) + ` + } } let beforeTemplate = aql`` if (typeof before !== 'undefined') { const { id: beforeId } = fromGlobalId(cleanseInput(before)) - beforeTemplate = aql`FILTER TO_NUMBER(REGEX_SPLIT(tag._key, "[a-z]+")[1]) < TO_NUMBER(REGEX_SPLIT(${beforeId}, "[a-z]+")[1])` + if (typeof orderBy === 'undefined') { + beforeTemplate = aql`FILTER TO_NUMBER(REGEX_SPLIT(tag._key, "[a-z]+")[1]) < TO_NUMBER(REGEX_SPLIT(${beforeId}, "[a-z]+")[1])` + } else { + let beforeTemplateDirection + if (orderBy.direction === 'ASC') { + beforeTemplateDirection = aql`<` + } else { + beforeTemplateDirection = aql`>` + } + + let tagField, documentField + /* istanbul ignore else */ + if (orderBy.field === 'tag-id') { + tagField = aql`tag._key` + documentField = aql`DOCUMENT(dmarcGuidanceTags, ${beforeId})._key` + } else if (orderBy.field === 'tag-name') { + tagField = aql`tag.tagName` + documentField = aql`DOCUMENT(dmarcGuidanceTags, ${beforeId}).tagName` + } else if (orderBy.field === 'guidance') { + tagField = aql`tag.guidance` + documentField = aql`DOCUMENT(dmarcGuidanceTags, ${beforeId}).guidance` + } + + beforeTemplate = aql` + FILTER ${tagField} ${beforeTemplateDirection} ${documentField} + OR (${tagField} == ${documentField} + AND TO_NUMBER(REGEX_SPLIT(tag._key, "[a-z]+")[1]) < TO_NUMBER(REGEX_SPLIT(${beforeId}, "[a-z]+")[1])) + ` + } } let limitTemplate = aql`` @@ -63,9 +119,9 @@ export const dmarcGuidanceTagConnectionsLoader = ( ), ) } else if (typeof first !== 'undefined' && typeof last === 'undefined') { - limitTemplate = aql`SORT TO_NUMBER(REGEX_SPLIT(tag._key, "[a-z]+")[1]) ASC LIMIT TO_NUMBER(${first})` + limitTemplate = aql`TO_NUMBER(REGEX_SPLIT(tag._key, "[a-z]+")[1]) ASC LIMIT TO_NUMBER(${first})` } else if (typeof first === 'undefined' && typeof last !== 'undefined') { - limitTemplate = aql`SORT TO_NUMBER(REGEX_SPLIT(tag._key, "[a-z]+")[1]) DESC LIMIT TO_NUMBER(${last})` + limitTemplate = aql`TO_NUMBER(REGEX_SPLIT(tag._key, "[a-z]+")[1]) DESC LIMIT TO_NUMBER(${last})` } } else { const argSet = typeof first !== 'undefined' ? 'first' : 'last' @@ -78,6 +134,60 @@ export const dmarcGuidanceTagConnectionsLoader = ( ) } + let hasNextPageFilter = aql`FILTER TO_NUMBER(REGEX_SPLIT(tag._key, "[a-z]+")[1]) > TO_NUMBER(REGEX_SPLIT(LAST(retrievedDmarcGuidanceTags)._key, "[a-z]+")[1])` + let hasPreviousPageFilter = aql`FILTER TO_NUMBER(REGEX_SPLIT(tag._key, "[a-z]+")[1]) < TO_NUMBER(REGEX_SPLIT(FIRST(retrievedDmarcGuidanceTags)._key, "[a-z]+")[1])` + if (typeof orderBy !== 'undefined') { + let hasNextPageDirection + let hasPreviousPageDirection + if (orderBy.direction === 'ASC') { + hasNextPageDirection = aql`>` + hasPreviousPageDirection = aql`<` + } else { + hasNextPageDirection = aql`<` + hasPreviousPageDirection = aql`>` + } + + let tagField, hasNextPageDocument, hasPreviousPageDocument + /* istanbul ignore else */ + if (orderBy.field === 'tag-id') { + tagField = aql`tag._key` + hasNextPageDocument = aql`LAST(retrievedDmarcGuidanceTags)._key` + hasPreviousPageDocument = aql`FIRST(retrievedDmarcGuidanceTags)._key` + } else if (orderBy.field === 'tag-name') { + tagField = aql`tag.tagName` + hasNextPageDocument = aql`LAST(retrievedDmarcGuidanceTags).tagName` + hasPreviousPageDocument = aql`FIRST(retrievedDmarcGuidanceTags).tagName` + } else if (orderBy.field === 'guidance') { + tagField = aql`tag.guidance` + hasNextPageDocument = aql`LAST(retrievedDmarcGuidanceTags).guidance` + hasPreviousPageDocument = aql`FIRST(retrievedDmarcGuidanceTags).guidance` + } + + hasNextPageFilter = aql` + FILTER ${tagField} ${hasNextPageDirection} ${hasNextPageDocument} + OR (${tagField} == ${hasNextPageDocument} + AND TO_NUMBER(REGEX_SPLIT(tag._key, "[a-z]+")[1]) > TO_NUMBER(REGEX_SPLIT(LAST(retrievedDmarcGuidanceTags)._key, "[a-z]+")[1])) + ` + + hasPreviousPageFilter = aql` + FILTER ${tagField} ${hasPreviousPageDirection} ${hasPreviousPageDocument} + OR (${tagField} == ${hasPreviousPageDocument} + AND TO_NUMBER(REGEX_SPLIT(tag._key, "[a-z]+")[1]) < TO_NUMBER(REGEX_SPLIT(FIRST(retrievedDmarcGuidanceTags)._key, "[a-z]+")[1])) + ` + } + + let sortByField = aql`` + if (typeof orderBy !== 'undefined') { + /* istanbul ignore else */ + if (orderBy.field === 'tag-id') { + sortByField = aql`tag._key ${orderBy.direction},` + } else if (orderBy.field === 'tag-name') { + sortByField = aql`tag.tagName ${orderBy.direction},` + } else if (orderBy.field === 'guidance') { + sortByField = aql`tag.guidance ${orderBy.direction},` + } + } + let sortString if (typeof last !== 'undefined') { sortString = aql`DESC` @@ -93,6 +203,8 @@ export const dmarcGuidanceTagConnectionsLoader = ( FILTER tag._key IN ${dmarcGuidanceTags} ${afterTemplate} ${beforeTemplate} + SORT + ${sortByField} ${limitTemplate} RETURN MERGE(tag, { tagId: tag._key, id: tag._key, _type: "guidanceTag" }) ) @@ -100,16 +212,16 @@ export const dmarcGuidanceTagConnectionsLoader = ( LET hasNextPage = (LENGTH( FOR tag IN dmarcGuidanceTags FILTER tag._key IN ${dmarcGuidanceTags} - FILTER TO_NUMBER(REGEX_SPLIT(tag._key, "[a-z]+")[1]) > TO_NUMBER(REGEX_SPLIT(LAST(retrievedDmarcGuidanceTags)._key, "[a-z]+")[1]) - SORT TO_NUMBER(REGEX_SPLIT(tag._key, "[a-z]+")[1]) ${sortString} LIMIT 1 + ${hasNextPageFilter} + SORT ${sortByField} TO_NUMBER(REGEX_SPLIT(tag._key, "[a-z]+")[1]) ${sortString} LIMIT 1 RETURN tag ) > 0 ? true : false) LET hasPreviousPage = (LENGTH( FOR tag IN dmarcGuidanceTags FILTER tag._key IN ${dmarcGuidanceTags} - FILTER TO_NUMBER(REGEX_SPLIT(tag._key, "[a-z]+")[1]) < TO_NUMBER(REGEX_SPLIT(FIRST(retrievedDmarcGuidanceTags)._key, "[a-z]+")[1]) - SORT TO_NUMBER(REGEX_SPLIT(tag._key, "[a-z]+")[1]) ${sortString} LIMIT 1 + ${hasPreviousPageFilter} + SORT ${sortByField} TO_NUMBER(REGEX_SPLIT(tag._key, "[a-z]+")[1]) ${sortString} LIMIT 1 RETURN tag ) > 0 ? true : false) diff --git a/api-js/src/guidance-tag/loaders/load-https-guidance-tags-connections.js b/api-js/src/guidance-tag/loaders/load-https-guidance-tags-connections.js index 3f02c36f74..12f1cc8c97 100644 --- a/api-js/src/guidance-tag/loaders/load-https-guidance-tags-connections.js +++ b/api-js/src/guidance-tag/loaders/load-https-guidance-tags-connections.js @@ -7,17 +7,73 @@ export const httpsGuidanceTagConnectionsLoader = ( userKey, cleanseInput, i18n, -) => async ({ httpsGuidanceTags, after, before, first, last }) => { +) => async ({ httpsGuidanceTags, after, before, first, last, orderBy }) => { let afterTemplate = aql`` if (typeof after !== 'undefined') { const { id: afterId } = fromGlobalId(cleanseInput(after)) - afterTemplate = aql`FILTER TO_NUMBER(REGEX_SPLIT(tag._key, "[a-z]+")[1]) > TO_NUMBER(REGEX_SPLIT(${afterId}, "[a-z]+")[1])` + if (typeof orderBy === 'undefined') { + afterTemplate = aql`FILTER TO_NUMBER(REGEX_SPLIT(tag._key, "[a-z]+")[1]) > TO_NUMBER(REGEX_SPLIT(${afterId}, "[a-z]+")[1])` + } else { + let afterTemplateDirection + if (orderBy.direction === 'ASC') { + afterTemplateDirection = aql`>` + } else { + afterTemplateDirection = aql`<` + } + + let tagField, documentField + /* istanbul ignore else */ + if (orderBy.field === 'tag-id') { + tagField = aql`tag._key` + documentField = aql`DOCUMENT(httpsGuidanceTags, ${afterId})._key` + } else if (orderBy.field === 'tag-name') { + tagField = aql`tag.tagName` + documentField = aql`DOCUMENT(httpsGuidanceTags, ${afterId}).tagName` + } else if (orderBy.field === 'guidance') { + tagField = aql`tag.guidance` + documentField = aql`DOCUMENT(httpsGuidanceTags, ${afterId}).guidance` + } + + afterTemplate = aql` + FILTER ${tagField} ${afterTemplateDirection} ${documentField} + OR (${tagField} == ${documentField} + AND TO_NUMBER(REGEX_SPLIT(tag._key, "[a-z]+")[1]) > TO_NUMBER(REGEX_SPLIT(${afterId}, "[a-z]+")[1])) + ` + } } let beforeTemplate = aql`` if (typeof before !== 'undefined') { const { id: beforeId } = fromGlobalId(cleanseInput(before)) - beforeTemplate = aql`FILTER TO_NUMBER(REGEX_SPLIT(tag._key, "[a-z]+")[1]) < TO_NUMBER(REGEX_SPLIT(${beforeId}, "[a-z]+")[1])` + if (typeof orderBy === 'undefined') { + beforeTemplate = aql`FILTER TO_NUMBER(REGEX_SPLIT(tag._key, "[a-z]+")[1]) < TO_NUMBER(REGEX_SPLIT(${beforeId}, "[a-z]+")[1])` + } else { + let beforeTemplateDirection + if (orderBy.direction === 'ASC') { + beforeTemplateDirection = aql`<` + } else { + beforeTemplateDirection = aql`>` + } + + let tagField, documentField + /* istanbul ignore else */ + if (orderBy.field === 'tag-id') { + tagField = aql`tag._key` + documentField = aql`DOCUMENT(httpsGuidanceTags, ${beforeId})._key` + } else if (orderBy.field === 'tag-name') { + tagField = aql`tag.tagName` + documentField = aql`DOCUMENT(httpsGuidanceTags, ${beforeId}).tagName` + } else if (orderBy.field === 'guidance') { + tagField = aql`tag.guidance` + documentField = aql`DOCUMENT(httpsGuidanceTags, ${beforeId}).guidance` + } + + beforeTemplate = aql` + FILTER ${tagField} ${beforeTemplateDirection} ${documentField} + OR (${tagField} == ${documentField} + AND TO_NUMBER(REGEX_SPLIT(tag._key, "[a-z]+")[1]) < TO_NUMBER(REGEX_SPLIT(${beforeId}, "[a-z]+")[1])) + ` + } } let limitTemplate = aql`` @@ -63,9 +119,9 @@ export const httpsGuidanceTagConnectionsLoader = ( ), ) } else if (typeof first !== 'undefined' && typeof last === 'undefined') { - limitTemplate = aql`SORT TO_NUMBER(REGEX_SPLIT(tag._key, "[a-z]+")[1]) ASC LIMIT TO_NUMBER(${first})` + limitTemplate = aql`TO_NUMBER(REGEX_SPLIT(tag._key, "[a-z]+")[1]) ASC LIMIT TO_NUMBER(${first})` } else if (typeof first === 'undefined' && typeof last !== 'undefined') { - limitTemplate = aql`SORT TO_NUMBER(REGEX_SPLIT(tag._key, "[a-z]+")[1]) DESC LIMIT TO_NUMBER(${last})` + limitTemplate = aql`TO_NUMBER(REGEX_SPLIT(tag._key, "[a-z]+")[1]) DESC LIMIT TO_NUMBER(${last})` } } else { const argSet = typeof first !== 'undefined' ? 'first' : 'last' @@ -78,6 +134,60 @@ export const httpsGuidanceTagConnectionsLoader = ( ) } + let hasNextPageFilter = aql`FILTER TO_NUMBER(REGEX_SPLIT(tag._key, "[a-z]+")[1]) > TO_NUMBER(REGEX_SPLIT(LAST(retrievedHttpsGuidanceTags)._key, "[a-z]+")[1])` + let hasPreviousPageFilter = aql`FILTER TO_NUMBER(REGEX_SPLIT(tag._key, "[a-z]+")[1]) < TO_NUMBER(REGEX_SPLIT(FIRST(retrievedHttpsGuidanceTags)._key, "[a-z]+")[1])` + if (typeof orderBy !== 'undefined') { + let hasNextPageDirection + let hasPreviousPageDirection + if (orderBy.direction === 'ASC') { + hasNextPageDirection = aql`>` + hasPreviousPageDirection = aql`<` + } else { + hasNextPageDirection = aql`<` + hasPreviousPageDirection = aql`>` + } + + let tagField, hasNextPageDocument, hasPreviousPageDocument + /* istanbul ignore else */ + if (orderBy.field === 'tag-id') { + tagField = aql`tag._key` + hasNextPageDocument = aql`LAST(retrievedHttpsGuidanceTags)._key` + hasPreviousPageDocument = aql`FIRST(retrievedHttpsGuidanceTags)._key` + } else if (orderBy.field === 'tag-name') { + tagField = aql`tag.tagName` + hasNextPageDocument = aql`LAST(retrievedHttpsGuidanceTags).tagName` + hasPreviousPageDocument = aql`FIRST(retrievedHttpsGuidanceTags).tagName` + } else if (orderBy.field === 'guidance') { + tagField = aql`tag.guidance` + hasNextPageDocument = aql`LAST(retrievedHttpsGuidanceTags).guidance` + hasPreviousPageDocument = aql`FIRST(retrievedHttpsGuidanceTags).guidance` + } + + hasNextPageFilter = aql` + FILTER ${tagField} ${hasNextPageDirection} ${hasNextPageDocument} + OR (${tagField} == ${hasNextPageDocument} + AND TO_NUMBER(REGEX_SPLIT(tag._key, "[a-z]+")[1]) > TO_NUMBER(REGEX_SPLIT(LAST(retrievedHttpsGuidanceTags)._key, "[a-z]+")[1])) + ` + + hasPreviousPageFilter = aql` + FILTER ${tagField} ${hasPreviousPageDirection} ${hasPreviousPageDocument} + OR (${tagField} == ${hasPreviousPageDocument} + AND TO_NUMBER(REGEX_SPLIT(tag._key, "[a-z]+")[1]) < TO_NUMBER(REGEX_SPLIT(FIRST(retrievedHttpsGuidanceTags)._key, "[a-z]+")[1])) + ` + } + + let sortByField = aql`` + if (typeof orderBy !== 'undefined') { + /* istanbul ignore else */ + if (orderBy.field === 'tag-id') { + sortByField = aql`tag._key ${orderBy.direction},` + } else if (orderBy.field === 'tag-name') { + sortByField = aql`tag.tagName ${orderBy.direction},` + } else if (orderBy.field === 'guidance') { + sortByField = aql`tag.guidance ${orderBy.direction},` + } + } + let sortString if (typeof last !== 'undefined') { sortString = aql`DESC` @@ -93,6 +203,8 @@ export const httpsGuidanceTagConnectionsLoader = ( FILTER tag._key IN ${httpsGuidanceTags} ${afterTemplate} ${beforeTemplate} + SORT + ${sortByField} ${limitTemplate} RETURN MERGE(tag, { tagId: tag._key, id: tag._key, _type: "guidanceTag" }) ) @@ -100,16 +212,16 @@ export const httpsGuidanceTagConnectionsLoader = ( LET hasNextPage = (LENGTH( FOR tag IN httpsGuidanceTags FILTER tag._key IN ${httpsGuidanceTags} - FILTER TO_NUMBER(REGEX_SPLIT(tag._key, "[a-z]+")[1]) > TO_NUMBER(REGEX_SPLIT(LAST(retrievedHttpsGuidanceTags)._key, "[a-z]+")[1]) - SORT TO_NUMBER(REGEX_SPLIT(tag._key, "[a-z]+")[1]) ${sortString} LIMIT 1 + ${hasNextPageFilter} + SORT ${sortByField} TO_NUMBER(REGEX_SPLIT(tag._key, "[a-z]+")[1]) ${sortString} LIMIT 1 RETURN tag ) > 0 ? true : false) LET hasPreviousPage = (LENGTH( FOR tag IN httpsGuidanceTags FILTER tag._key IN ${httpsGuidanceTags} - FILTER TO_NUMBER(REGEX_SPLIT(tag._key, "[a-z]+")[1]) < TO_NUMBER(REGEX_SPLIT(FIRST(retrievedHttpsGuidanceTags)._key, "[a-z]+")[1]) - SORT TO_NUMBER(REGEX_SPLIT(tag._key, "[a-z]+")[1]) ${sortString} LIMIT 1 + ${hasPreviousPageFilter} + SORT ${sortByField} TO_NUMBER(REGEX_SPLIT(tag._key, "[a-z]+")[1]) ${sortString} LIMIT 1 RETURN tag ) > 0 ? true : false) diff --git a/api-js/src/guidance-tag/loaders/load-spf-guidance-tags-connections.js b/api-js/src/guidance-tag/loaders/load-spf-guidance-tags-connections.js index 3f7c611499..65415b9b9f 100644 --- a/api-js/src/guidance-tag/loaders/load-spf-guidance-tags-connections.js +++ b/api-js/src/guidance-tag/loaders/load-spf-guidance-tags-connections.js @@ -7,17 +7,73 @@ export const spfGuidanceTagConnectionsLoader = ( userKey, cleanseInput, i18n, -) => async ({ spfGuidanceTags, after, before, first, last }) => { +) => async ({ spfGuidanceTags, after, before, first, last, orderBy }) => { let afterTemplate = aql`` if (typeof after !== 'undefined') { const { id: afterId } = fromGlobalId(cleanseInput(after)) - afterTemplate = aql`FILTER TO_NUMBER(REGEX_SPLIT(tag._key, "[a-z]+")[1]) > TO_NUMBER(REGEX_SPLIT(${afterId}, "[a-z]+")[1])` + if (typeof orderBy === 'undefined') { + afterTemplate = aql`FILTER TO_NUMBER(REGEX_SPLIT(tag._key, "[a-z]+")[1]) > TO_NUMBER(REGEX_SPLIT(${afterId}, "[a-z]+")[1])` + } else { + let afterTemplateDirection + if (orderBy.direction === 'ASC') { + afterTemplateDirection = aql`>` + } else { + afterTemplateDirection = aql`<` + } + + let tagField, documentField + /* istanbul ignore else */ + if (orderBy.field === 'tag-id') { + tagField = aql`tag._key` + documentField = aql`DOCUMENT(spfGuidanceTags, ${afterId})._key` + } else if (orderBy.field === 'tag-name') { + tagField = aql`tag.tagName` + documentField = aql`DOCUMENT(spfGuidanceTags, ${afterId}).tagName` + } else if (orderBy.field === 'guidance') { + tagField = aql`tag.guidance` + documentField = aql`DOCUMENT(spfGuidanceTags, ${afterId}).guidance` + } + + afterTemplate = aql` + FILTER ${tagField} ${afterTemplateDirection} ${documentField} + OR (${tagField} == ${documentField} + AND TO_NUMBER(REGEX_SPLIT(tag._key, "[a-z]+")[1]) > TO_NUMBER(REGEX_SPLIT(${afterId}, "[a-z]+")[1])) + ` + } } let beforeTemplate = aql`` if (typeof before !== 'undefined') { const { id: beforeId } = fromGlobalId(cleanseInput(before)) - beforeTemplate = aql`FILTER TO_NUMBER(REGEX_SPLIT(tag._key, "[a-z]+")[1]) < TO_NUMBER(REGEX_SPLIT(${beforeId}, "[a-z]+")[1])` + if (typeof orderBy === 'undefined') { + beforeTemplate = aql`FILTER TO_NUMBER(REGEX_SPLIT(tag._key, "[a-z]+")[1]) < TO_NUMBER(REGEX_SPLIT(${beforeId}, "[a-z]+")[1])` + } else { + let beforeTemplateDirection + if (orderBy.direction === 'ASC') { + beforeTemplateDirection = aql`<` + } else { + beforeTemplateDirection = aql`>` + } + + let tagField, documentField + /* istanbul ignore else */ + if (orderBy.field === 'tag-id') { + tagField = aql`tag._key` + documentField = aql`DOCUMENT(spfGuidanceTags, ${beforeId})._key` + } else if (orderBy.field === 'tag-name') { + tagField = aql`tag.tagName` + documentField = aql`DOCUMENT(spfGuidanceTags, ${beforeId}).tagName` + } else if (orderBy.field === 'guidance') { + tagField = aql`tag.guidance` + documentField = aql`DOCUMENT(spfGuidanceTags, ${beforeId}).guidance` + } + + beforeTemplate = aql` + FILTER ${tagField} ${beforeTemplateDirection} ${documentField} + OR (${tagField} == ${documentField} + AND TO_NUMBER(REGEX_SPLIT(tag._key, "[a-z]+")[1]) < TO_NUMBER(REGEX_SPLIT(${beforeId}, "[a-z]+")[1])) + ` + } } let limitTemplate = aql`` @@ -63,9 +119,9 @@ export const spfGuidanceTagConnectionsLoader = ( ), ) } else if (typeof first !== 'undefined' && typeof last === 'undefined') { - limitTemplate = aql`SORT TO_NUMBER(REGEX_SPLIT(tag._key, "[a-z]+")[1]) ASC LIMIT TO_NUMBER(${first})` + limitTemplate = aql`TO_NUMBER(REGEX_SPLIT(tag._key, "[a-z]+")[1]) ASC LIMIT TO_NUMBER(${first})` } else if (typeof first === 'undefined' && typeof last !== 'undefined') { - limitTemplate = aql`SORT TO_NUMBER(REGEX_SPLIT(tag._key, "[a-z]+")[1]) DESC LIMIT TO_NUMBER(${last})` + limitTemplate = aql`TO_NUMBER(REGEX_SPLIT(tag._key, "[a-z]+")[1]) DESC LIMIT TO_NUMBER(${last})` } } else { const argSet = typeof first !== 'undefined' ? 'first' : 'last' @@ -78,6 +134,60 @@ export const spfGuidanceTagConnectionsLoader = ( ) } + let hasNextPageFilter = aql`FILTER TO_NUMBER(REGEX_SPLIT(tag._key, "[a-z]+")[1]) > TO_NUMBER(REGEX_SPLIT(LAST(retrievedSpfGuidanceTags)._key, "[a-z]+")[1])` + let hasPreviousPageFilter = aql`FILTER TO_NUMBER(REGEX_SPLIT(tag._key, "[a-z]+")[1]) < TO_NUMBER(REGEX_SPLIT(FIRST(retrievedSpfGuidanceTags)._key, "[a-z]+")[1])` + if (typeof orderBy !== 'undefined') { + let hasNextPageDirection + let hasPreviousPageDirection + if (orderBy.direction === 'ASC') { + hasNextPageDirection = aql`>` + hasPreviousPageDirection = aql`<` + } else { + hasNextPageDirection = aql`<` + hasPreviousPageDirection = aql`>` + } + + let tagField, hasNextPageDocument, hasPreviousPageDocument + /* istanbul ignore else */ + if (orderBy.field === 'tag-id') { + tagField = aql`tag._key` + hasNextPageDocument = aql`LAST(retrievedSpfGuidanceTags)._key` + hasPreviousPageDocument = aql`FIRST(retrievedSpfGuidanceTags)._key` + } else if (orderBy.field === 'tag-name') { + tagField = aql`tag.tagName` + hasNextPageDocument = aql`LAST(retrievedSpfGuidanceTags).tagName` + hasPreviousPageDocument = aql`FIRST(retrievedSpfGuidanceTags).tagName` + } else if (orderBy.field === 'guidance') { + tagField = aql`tag.guidance` + hasNextPageDocument = aql`LAST(retrievedSpfGuidanceTags).guidance` + hasPreviousPageDocument = aql`FIRST(retrievedSpfGuidanceTags).guidance` + } + + hasNextPageFilter = aql` + FILTER ${tagField} ${hasNextPageDirection} ${hasNextPageDocument} + OR (${tagField} == ${hasNextPageDocument} + AND TO_NUMBER(REGEX_SPLIT(tag._key, "[a-z]+")[1]) > TO_NUMBER(REGEX_SPLIT(LAST(retrievedSpfGuidanceTags)._key, "[a-z]+")[1])) + ` + + hasPreviousPageFilter = aql` + FILTER ${tagField} ${hasPreviousPageDirection} ${hasPreviousPageDocument} + OR (${tagField} == ${hasPreviousPageDocument} + AND TO_NUMBER(REGEX_SPLIT(tag._key, "[a-z]+")[1]) < TO_NUMBER(REGEX_SPLIT(FIRST(retrievedSpfGuidanceTags)._key, "[a-z]+")[1])) + ` + } + + let sortByField = aql`` + if (typeof orderBy !== 'undefined') { + /* istanbul ignore else */ + if (orderBy.field === 'tag-id') { + sortByField = aql`tag._key ${orderBy.direction},` + } else if (orderBy.field === 'tag-name') { + sortByField = aql`tag.tagName ${orderBy.direction},` + } else if (orderBy.field === 'guidance') { + sortByField = aql`tag.guidance ${orderBy.direction},` + } + } + let sortString if (typeof last !== 'undefined') { sortString = aql`DESC` @@ -93,6 +203,8 @@ export const spfGuidanceTagConnectionsLoader = ( FILTER tag._key IN ${spfGuidanceTags} ${afterTemplate} ${beforeTemplate} + SORT + ${sortByField} ${limitTemplate} RETURN MERGE(tag, { tagId: tag._key, id: tag._key, _type: "guidanceTag" }) ) @@ -100,16 +212,16 @@ export const spfGuidanceTagConnectionsLoader = ( LET hasNextPage = (LENGTH( FOR tag IN spfGuidanceTags FILTER tag._key IN ${spfGuidanceTags} - FILTER TO_NUMBER(REGEX_SPLIT(tag._key, "[a-z]+")[1]) > TO_NUMBER(REGEX_SPLIT(LAST(retrievedSpfGuidanceTags)._key, "[a-z]+")[1]) - SORT TO_NUMBER(REGEX_SPLIT(tag._key, "[a-z]+")[1]) ${sortString} LIMIT 1 + ${hasNextPageFilter} + SORT ${sortByField} TO_NUMBER(REGEX_SPLIT(tag._key, "[a-z]+")[1]) ${sortString} LIMIT 1 RETURN tag ) > 0 ? true : false) LET hasPreviousPage = (LENGTH( FOR tag IN spfGuidanceTags FILTER tag._key IN ${spfGuidanceTags} - FILTER TO_NUMBER(REGEX_SPLIT(tag._key, "[a-z]+")[1]) < TO_NUMBER(REGEX_SPLIT(FIRST(retrievedSpfGuidanceTags)._key, "[a-z]+")[1]) - SORT TO_NUMBER(REGEX_SPLIT(tag._key, "[a-z]+")[1]) ${sortString} LIMIT 1 + ${hasPreviousPageFilter} + SORT ${sortByField} TO_NUMBER(REGEX_SPLIT(tag._key, "[a-z]+")[1]) ${sortString} LIMIT 1 RETURN tag ) > 0 ? true : false) diff --git a/api-js/src/guidance-tag/loaders/load-ssl-guidance-tags-connections.js b/api-js/src/guidance-tag/loaders/load-ssl-guidance-tags-connections.js index e550e86884..8c1591749d 100644 --- a/api-js/src/guidance-tag/loaders/load-ssl-guidance-tags-connections.js +++ b/api-js/src/guidance-tag/loaders/load-ssl-guidance-tags-connections.js @@ -7,17 +7,73 @@ export const sslGuidanceTagConnectionsLoader = ( userKey, cleanseInput, i18n, -) => async ({ sslGuidanceTags, after, before, first, last }) => { +) => async ({ sslGuidanceTags, after, before, first, last, orderBy }) => { let afterTemplate = aql`` if (typeof after !== 'undefined') { const { id: afterId } = fromGlobalId(cleanseInput(after)) - afterTemplate = aql`FILTER TO_NUMBER(REGEX_SPLIT(tag._key, "[a-z]+")[1]) > TO_NUMBER(REGEX_SPLIT(${afterId}, "[a-z]+")[1])` + if (typeof orderBy === 'undefined') { + afterTemplate = aql`FILTER TO_NUMBER(REGEX_SPLIT(tag._key, "[a-z]+")[1]) > TO_NUMBER(REGEX_SPLIT(${afterId}, "[a-z]+")[1])` + } else { + let afterTemplateDirection + if (orderBy.direction === 'ASC') { + afterTemplateDirection = aql`>` + } else { + afterTemplateDirection = aql`<` + } + + let tagField, documentField + /* istanbul ignore else */ + if (orderBy.field === 'tag-id') { + tagField = aql`tag._key` + documentField = aql`DOCUMENT(sslGuidanceTags, ${afterId})._key` + } else if (orderBy.field === 'tag-name') { + tagField = aql`tag.tagName` + documentField = aql`DOCUMENT(sslGuidanceTags, ${afterId}).tagName` + } else if (orderBy.field === 'guidance') { + tagField = aql`tag.guidance` + documentField = aql`DOCUMENT(sslGuidanceTags, ${afterId}).guidance` + } + + afterTemplate = aql` + FILTER ${tagField} ${afterTemplateDirection} ${documentField} + OR (${tagField} == ${documentField} + AND TO_NUMBER(REGEX_SPLIT(tag._key, "[a-z]+")[1]) > TO_NUMBER(REGEX_SPLIT(${afterId}, "[a-z]+")[1])) + ` + } } let beforeTemplate = aql`` if (typeof before !== 'undefined') { const { id: beforeId } = fromGlobalId(cleanseInput(before)) - beforeTemplate = aql`FILTER TO_NUMBER(REGEX_SPLIT(tag._key, "[a-z]+")[1]) < TO_NUMBER(REGEX_SPLIT(${beforeId}, "[a-z]+")[1])` + if (typeof orderBy === 'undefined') { + beforeTemplate = aql`FILTER TO_NUMBER(REGEX_SPLIT(tag._key, "[a-z]+")[1]) < TO_NUMBER(REGEX_SPLIT(${beforeId}, "[a-z]+")[1])` + } else { + let beforeTemplateDirection + if (orderBy.direction === 'ASC') { + beforeTemplateDirection = aql`<` + } else { + beforeTemplateDirection = aql`>` + } + + let tagField, documentField + /* istanbul ignore else */ + if (orderBy.field === 'tag-id') { + tagField = aql`tag._key` + documentField = aql`DOCUMENT(sslGuidanceTags, ${beforeId})._key` + } else if (orderBy.field === 'tag-name') { + tagField = aql`tag.tagName` + documentField = aql`DOCUMENT(sslGuidanceTags, ${beforeId}).tagName` + } else if (orderBy.field === 'guidance') { + tagField = aql`tag.guidance` + documentField = aql`DOCUMENT(sslGuidanceTags, ${beforeId}).guidance` + } + + beforeTemplate = aql` + FILTER ${tagField} ${beforeTemplateDirection} ${documentField} + OR (${tagField} == ${documentField} + AND TO_NUMBER(REGEX_SPLIT(tag._key, "[a-z]+")[1]) < TO_NUMBER(REGEX_SPLIT(${beforeId}, "[a-z]+")[1])) + ` + } } let limitTemplate = aql`` @@ -63,9 +119,9 @@ export const sslGuidanceTagConnectionsLoader = ( ), ) } else if (typeof first !== 'undefined' && typeof last === 'undefined') { - limitTemplate = aql`SORT TO_NUMBER(REGEX_SPLIT(tag._key, "[a-z]+")[1]) ASC LIMIT TO_NUMBER(${first})` + limitTemplate = aql`TO_NUMBER(REGEX_SPLIT(tag._key, "[a-z]+")[1]) ASC LIMIT TO_NUMBER(${first})` } else if (typeof first === 'undefined' && typeof last !== 'undefined') { - limitTemplate = aql`SORT TO_NUMBER(REGEX_SPLIT(tag._key, "[a-z]+")[1]) DESC LIMIT TO_NUMBER(${last})` + limitTemplate = aql`TO_NUMBER(REGEX_SPLIT(tag._key, "[a-z]+")[1]) DESC LIMIT TO_NUMBER(${last})` } } else { const argSet = typeof first !== 'undefined' ? 'first' : 'last' @@ -78,6 +134,60 @@ export const sslGuidanceTagConnectionsLoader = ( ) } + let hasNextPageFilter = aql`FILTER TO_NUMBER(REGEX_SPLIT(tag._key, "[a-z]+")[1]) > TO_NUMBER(REGEX_SPLIT(LAST(retrievedSslGuidanceTags)._key, "[a-z]+")[1])` + let hasPreviousPageFilter = aql`FILTER TO_NUMBER(REGEX_SPLIT(tag._key, "[a-z]+")[1]) < TO_NUMBER(REGEX_SPLIT(FIRST(retrievedSslGuidanceTags)._key, "[a-z]+")[1])` + if (typeof orderBy !== 'undefined') { + let hasNextPageDirection + let hasPreviousPageDirection + if (orderBy.direction === 'ASC') { + hasNextPageDirection = aql`>` + hasPreviousPageDirection = aql`<` + } else { + hasNextPageDirection = aql`<` + hasPreviousPageDirection = aql`>` + } + + let tagField, hasNextPageDocument, hasPreviousPageDocument + /* istanbul ignore else */ + if (orderBy.field === 'tag-id') { + tagField = aql`tag._key` + hasNextPageDocument = aql`LAST(retrievedSslGuidanceTags)._key` + hasPreviousPageDocument = aql`FIRST(retrievedSslGuidanceTags)._key` + } else if (orderBy.field === 'tag-name') { + tagField = aql`tag.tagName` + hasNextPageDocument = aql`LAST(retrievedSslGuidanceTags).tagName` + hasPreviousPageDocument = aql`FIRST(retrievedSslGuidanceTags).tagName` + } else if (orderBy.field === 'guidance') { + tagField = aql`tag.guidance` + hasNextPageDocument = aql`LAST(retrievedSslGuidanceTags).guidance` + hasPreviousPageDocument = aql`FIRST(retrievedSslGuidanceTags).guidance` + } + + hasNextPageFilter = aql` + FILTER ${tagField} ${hasNextPageDirection} ${hasNextPageDocument} + OR (${tagField} == ${hasNextPageDocument} + AND TO_NUMBER(REGEX_SPLIT(tag._key, "[a-z]+")[1]) > TO_NUMBER(REGEX_SPLIT(LAST(retrievedSslGuidanceTags)._key, "[a-z]+")[1])) + ` + + hasPreviousPageFilter = aql` + FILTER ${tagField} ${hasPreviousPageDirection} ${hasPreviousPageDocument} + OR (${tagField} == ${hasPreviousPageDocument} + AND TO_NUMBER(REGEX_SPLIT(tag._key, "[a-z]+")[1]) < TO_NUMBER(REGEX_SPLIT(FIRST(retrievedSslGuidanceTags)._key, "[a-z]+")[1])) + ` + } + + let sortByField = aql`` + if (typeof orderBy !== 'undefined') { + /* istanbul ignore else */ + if (orderBy.field === 'tag-id') { + sortByField = aql`tag._key ${orderBy.direction},` + } else if (orderBy.field === 'tag-name') { + sortByField = aql`tag.tagName ${orderBy.direction},` + } else if (orderBy.field === 'guidance') { + sortByField = aql`tag.guidance ${orderBy.direction},` + } + } + let sortString if (typeof last !== 'undefined') { sortString = aql`DESC` @@ -93,6 +203,8 @@ export const sslGuidanceTagConnectionsLoader = ( FILTER tag._key IN ${sslGuidanceTags} ${afterTemplate} ${beforeTemplate} + SORT + ${sortByField} ${limitTemplate} RETURN MERGE(tag, { tagId: tag._key, id: tag._key, _type: "guidanceTag" }) ) @@ -100,16 +212,16 @@ export const sslGuidanceTagConnectionsLoader = ( LET hasNextPage = (LENGTH( FOR tag IN sslGuidanceTags FILTER tag._key IN ${sslGuidanceTags} - FILTER TO_NUMBER(REGEX_SPLIT(tag._key, "[a-z]+")[1]) > TO_NUMBER(REGEX_SPLIT(LAST(retrievedSslGuidanceTags)._key, "[a-z]+")[1]) - SORT TO_NUMBER(REGEX_SPLIT(tag._key, "[a-z]+")[1]) ${sortString} LIMIT 1 + ${hasNextPageFilter} + SORT ${sortByField} TO_NUMBER(REGEX_SPLIT(tag._key, "[a-z]+")[1]) ${sortString} LIMIT 1 RETURN tag ) > 0 ? true : false) LET hasPreviousPage = (LENGTH( FOR tag IN sslGuidanceTags FILTER tag._key IN ${sslGuidanceTags} - FILTER TO_NUMBER(REGEX_SPLIT(tag._key, "[a-z]+")[1]) < TO_NUMBER(REGEX_SPLIT(FIRST(retrievedSslGuidanceTags)._key, "[a-z]+")[1]) - SORT TO_NUMBER(REGEX_SPLIT(tag._key, "[a-z]+")[1]) ${sortString} LIMIT 1 + ${hasPreviousPageFilter} + SORT ${sortByField} TO_NUMBER(REGEX_SPLIT(tag._key, "[a-z]+")[1]) ${sortString} LIMIT 1 RETURN tag ) > 0 ? true : false) diff --git a/api-js/src/web-scan/objects/https.js b/api-js/src/web-scan/objects/https.js index c7b2060e0e..3d42ea61e1 100644 --- a/api-js/src/web-scan/objects/https.js +++ b/api-js/src/web-scan/objects/https.js @@ -7,8 +7,9 @@ import { import { GraphQLDateTime, GraphQLJSON } from 'graphql-scalars' import { domainType } from '../../domain/objects' -import { guidanceTagConnection } from '../../guidance-tag' import { nodeInterface } from '../../node' +import { guidanceTagOrder } from '../../guidance-tag/inputs' +import { guidanceTagConnection } from '../../guidance-tag/objects' export const httpsType = new GraphQLObjectType({ name: 'HTTPS', @@ -62,6 +63,10 @@ export const httpsType = new GraphQLObjectType({ guidanceTags: { type: guidanceTagConnection.connectionType, args: { + orderBy: { + type: guidanceTagOrder, + description: 'Ordering options for guidance tag connections', + }, ...connectionArgs, }, description: `Key tags found during scan.`, diff --git a/api-js/src/web-scan/objects/ssl.js b/api-js/src/web-scan/objects/ssl.js index 8809d4bb55..60f4b42e0d 100644 --- a/api-js/src/web-scan/objects/ssl.js +++ b/api-js/src/web-scan/objects/ssl.js @@ -13,8 +13,9 @@ import { import { GraphQLJSON } from 'graphql-scalars' import { domainType } from '../../domain/objects' -import { guidanceTagConnection } from '../../guidance-tag' import { nodeInterface } from '../../node' +import { guidanceTagOrder } from '../../guidance-tag/inputs' +import { guidanceTagConnection } from '../../guidance-tag/objects' export const sslType = new GraphQLObjectType({ name: 'SSL', @@ -51,6 +52,10 @@ export const sslType = new GraphQLObjectType({ guidanceTags: { type: guidanceTagConnection.connectionType, args: { + orderBy: { + type: guidanceTagOrder, + description: 'Ordering options for guidance tag connections', + }, ...connectionArgs, }, description: `Key tags found during scan.`,