From 738aa8df960e36827298c077b05d4d350b9677e7 Mon Sep 17 00:00:00 2001 From: Meriem-BM Date: Wed, 24 Jul 2024 17:12:49 +0100 Subject: [PATCH] feat: add recurring donations statistics queries for dashboard analytics --- package.json | 2 +- .../recurringDonationResolver.test.ts | 238 -------------- src/resolvers/recurringDonationResolver.ts | 150 ++++++--- src/services/recurringDonationService.ts | 295 ++++++++++++++++++ .../validators/graphqlQueryValidators.ts | 11 - test/graphqlQueries.ts | 57 +++- 6 files changed, 442 insertions(+), 311 deletions(-) diff --git a/package.json b/package.json index 95392122a..7448cd7cd 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "giveth-graphql-api", - "version": "1.24.1", + "version": "1.24.2", "description": "Backend GraphQL server for Giveth originally forked from Topia", "main": "./dist/index.js", "dependencies": { diff --git a/src/resolvers/recurringDonationResolver.test.ts b/src/resolvers/recurringDonationResolver.test.ts index 7965241c6..48021ebc4 100644 --- a/src/resolvers/recurringDonationResolver.test.ts +++ b/src/resolvers/recurringDonationResolver.test.ts @@ -19,7 +19,6 @@ import { updateRecurringDonationQuery, updateRecurringDonationQueryById, updateRecurringDonationStatusMutation, - fetchRecurringDonationStatsQuery, } from '../../test/graphqlQueries'; describe( @@ -57,11 +56,6 @@ describe( updateRecurringDonationByIdTestCases, ); -describe( - 'getRecurringDonationStatsTestCases test cases', - getRecurringDonationStatsTestCases, -); - function createRecurringDonationTestCases() { it('should create recurringDonation successfully', async () => { const projectOwner = await saveUserDirectlyToDb( @@ -2943,235 +2937,3 @@ function updateRecurringDonationStatusTestCases() { ); }); } - -function getRecurringDonationStatsTestCases() { - const lastYear = new Date().getFullYear() - 1; - const beginDate = `${lastYear}-01-01`; - const endDate = `${lastYear}-03-01`; - - it(`should return the correct stats for a given date range (${beginDate} to ${endDate})`, async () => { - const donor = await saveUserDirectlyToDb(generateRandomEtheriumAddress()); - await saveRecurringDonationDirectlyToDb({ - donationData: { - donorId: donor.id, - totalUsdStreamed: 400, - createdAt: new Date(`${lastYear}-01-02`), - }, - }); - - await saveRecurringDonationDirectlyToDb({ - donationData: { - donorId: donor.id, - totalUsdStreamed: 100, - createdAt: new Date(`${lastYear}-01-24`), - }, - }); - - // we are querying from January 1st of last year to the 1st of March of last year - const result = await axios.post(graphqlUrl, { - query: fetchRecurringDonationStatsQuery, - variables: { - beginDate, - endDate, - }, - }); - - const stats = result.data.data.getRecurringDonationStats; - assert.equal(stats.activeRecurringDonationsCount, 0); - assert.equal(stats.totalStreamedUsdValue, 500); - }); - - it(`should return the correct stats for a given date range (${beginDate} -> ${endDate}) and currency`, async () => { - const donor = await saveUserDirectlyToDb(generateRandomEtheriumAddress()); - await saveRecurringDonationDirectlyToDb({ - donationData: { - donorId: donor.id, - totalUsdStreamed: 400, - currency: 'DAI', - createdAt: new Date(`${lastYear}-01-01`), - }, - }); - await saveRecurringDonationDirectlyToDb({ - donationData: { - donorId: donor.id, - totalUsdStreamed: 100, - currency: 'USDT', - createdAt: new Date(`${lastYear}-02-01`), - }, - }); - - const result = await axios.post(graphqlUrl, { - query: fetchRecurringDonationStatsQuery, - variables: { - beginDate, - endDate, - currency: 'USDT', - }, - }); - - const stats = result.data.data.getRecurringDonationStats; - assert.equal(stats.activeRecurringDonationsCount, 0); - assert.equal(stats.totalStreamedUsdValue, 600); - }); - - it(`should return the correct stats for a given date range (${beginDate} -> ${endDate}) with correct active count`, async () => { - const donor1 = await saveUserDirectlyToDb(generateRandomEtheriumAddress()); - const donor2 = await saveUserDirectlyToDb(generateRandomEtheriumAddress()); - - await saveRecurringDonationDirectlyToDb({ - donationData: { - donorId: donor1.id, - totalUsdStreamed: 400, - status: RECURRING_DONATION_STATUS.ACTIVE, - currency: 'DAI', - createdAt: new Date(`${lastYear}-01-01`), - }, - }); - await saveRecurringDonationDirectlyToDb({ - donationData: { - donorId: donor2.id, - totalUsdStreamed: 100, - status: RECURRING_DONATION_STATUS.ACTIVE, - currency: 'DAI', - createdAt: new Date(`${lastYear}-02-01`), - }, - }); - await saveRecurringDonationDirectlyToDb({ - donationData: { - donorId: donor1.id, - totalUsdStreamed: 200, - currency: 'DAI', - createdAt: new Date(`${lastYear}-02-01`), - }, - }); - await saveRecurringDonationDirectlyToDb({ - donationData: { - donorId: donor2.id, - totalUsdStreamed: 100, - status: RECURRING_DONATION_STATUS.ACTIVE, - currency: 'USDT', - createdAt: new Date(`${lastYear}-02-01`), - }, - }); - - const result = await axios.post(graphqlUrl, { - query: fetchRecurringDonationStatsQuery, - variables: { - beginDate, - endDate, - status: RECURRING_DONATION_STATUS.ACTIVE, - currency: 'DAI', - }, - }); - - const stats = result.data.data.getRecurringDonationStats; - assert.equal(stats.activeRecurringDonationsCount, 2); - assert.equal(stats.totalStreamedUsdValue, 1100); - }); - - it('should return the correct stats for the given date range where beginDate', async () => { - const lastYear15thOfJanuary = new Date(`${lastYear}-01-15T09:00:00`); - - const donor = await saveUserDirectlyToDb(generateRandomEtheriumAddress()); - await saveRecurringDonationDirectlyToDb({ - donationData: { - donorId: donor.id, - totalUsdStreamed: 400, - status: RECURRING_DONATION_STATUS.ACTIVE, - createdAt: lastYear15thOfJanuary, - }, - }); - await saveRecurringDonationDirectlyToDb({ - donationData: { - donorId: donor.id, - totalUsdStreamed: 100, - createdAt: lastYear15thOfJanuary, - }, - }); - - const result = await axios.post(graphqlUrl, { - query: fetchRecurringDonationStatsQuery, - variables: { - beginDate: `${lastYear}-01-15T09:00:00`, - endDate: `${lastYear}-01-15T09:00:00`, - }, - }); - - const stats = result.data.data.getRecurringDonationStats; - - assert.equal(stats.activeRecurringDonationsCount, 1); - assert.equal(stats.totalStreamedUsdValue, 500); - }); - - it(`should return empty stats for the given date range where beginDate is same as endDate`, async () => { - const result = await axios.post(graphqlUrl, { - query: fetchRecurringDonationStatsQuery, - variables: { - beginDate: `${lastYear}-04-01`, - endDate: `${lastYear}-05-01`, - }, - }); - - const stats = result.data.data.getRecurringDonationStats; - assert.equal(stats.activeRecurringDonationsCount, 0); - assert.equal(stats.totalStreamedUsdValue, 0); - }); - - it('should return an error for the given an empty date range', async () => { - const donor = await saveUserDirectlyToDb(generateRandomEtheriumAddress()); - await saveRecurringDonationDirectlyToDb({ - donationData: { - donorId: donor.id, - totalUsdStreamed: 400, - status: RECURRING_DONATION_STATUS.ACTIVE, - createdAt: new Date(), - }, - }); - await saveRecurringDonationDirectlyToDb({ - donationData: { - donorId: donor.id, - totalUsdStreamed: 100, - createdAt: new Date(), - }, - }); - - const result = await axios.post(graphqlUrl, { - query: fetchRecurringDonationStatsQuery, - variables: { - beginDate: '', - endDate: '', - }, - }); - - assert.isNotNull(result.data.errors); - }); - - it('should return an error for the given an invalid date range', async () => { - const donor = await saveUserDirectlyToDb(generateRandomEtheriumAddress()); - await saveRecurringDonationDirectlyToDb({ - donationData: { - donorId: donor.id, - totalUsdStreamed: 400, - status: RECURRING_DONATION_STATUS.ACTIVE, - createdAt: new Date(), - }, - }); - await saveRecurringDonationDirectlyToDb({ - donationData: { - donorId: donor.id, - totalUsdStreamed: 100, - createdAt: new Date(), - }, - }); - - const result = await axios.post(graphqlUrl, { - query: fetchRecurringDonationStatsQuery, - variables: { - beginDate: 'invalid date', - endDate: 'invalid date', - }, - }); - - assert.isNotNull(result.data.errors); - }); -} diff --git a/src/resolvers/recurringDonationResolver.ts b/src/resolvers/recurringDonationResolver.ts index 0608a7ea1..6d1c5719b 100644 --- a/src/resolvers/recurringDonationResolver.ts +++ b/src/resolvers/recurringDonationResolver.ts @@ -4,7 +4,6 @@ import { ArgsType, Ctx, Field, - Float, InputType, Int, Mutation, @@ -40,15 +39,23 @@ import { import { detectAddressChainType } from '../utils/networks'; import { logger } from '../utils/logger'; import { - getRecurringDonationStatsArgsValidator, + resourcePerDateReportValidator, updateDonationQueryValidator, validateWithJoiSchema, } from '../utils/validators/graphqlQueryValidators'; import { sleep } from '../utils/utils'; import SentryLogger from '../sentryLogger'; -import { updateRecurringDonationStatusWithNetwork } from '../services/recurringDonationService'; +import { + updateRecurringDonationStatusWithNetwork, + recurringDonationsCountPerDateRange, + recurringDonationsCountPerDateRangePerMonth, + recurringDonationsStreamedCUsdTotal, + recurringDonationsStreamedCUsdTotalPerMonth, + recurringDonationsTotalPerToken, + recurringDonationsCountPerToken, +} from '../services/recurringDonationService'; import { markDraftRecurringDonationStatusMatched } from '../repositories/draftRecurringDonationRepository'; - +import { ResourcePerDateRange } from './donationResolver'; @InputType() class RecurringDonationSortBy { @Field(_type => RecurringDonationSortField) @@ -67,6 +74,21 @@ class FinishStatus { ended: boolean; } +@ObjectType() +class RDTataPerToken { + @Field(_type => String) + token: string; + + @Field(_type => Number) + total: number; +} + +@ObjectType() +class RDRessourcePerDateRange extends ResourcePerDateRange { + @Field(_type => [RDTataPerToken], { nullable: true }) + totalPerToken: RDTataPerToken[]; +} + export enum RecurringDonationSortField { createdAt = 'createdAt', flowRate = 'flowRate', @@ -156,28 +178,6 @@ class UserRecurringDonations { totalCount: number; } -@Service() -@ArgsType() -class GetRecurringDonationStatsArgs { - @Field(_type => String) - beginDate: string; - - @Field(_type => String) - endDate: string; - - @Field(_type => String, { nullable: true }) - currency?: string; -} - -@ObjectType() -class RecurringDonationStats { - @Field(_type => Float) - activeRecurringDonationsCount: number; - - @Field(_type => Float) - totalStreamedUsdValue: number; -} - @Resolver(_of => AnchorContractAddress) export class RecurringDonationResolver { @Mutation(_returns => RecurringDonation, { nullable: true }) @@ -662,40 +662,90 @@ export class RecurringDonationResolver { } } - @Query(_returns => RecurringDonationStats) - async getRecurringDonationStats( - @Args() { beginDate, endDate, currency }: GetRecurringDonationStatsArgs, - ): Promise { + @Query(_returns => RDRessourcePerDateRange, { nullable: true }) + async recurringDonationsCountPerDate( + // fromDate and toDate should be in this format YYYYMMDD HH:mm:ss + @Arg('fromDate', { nullable: true }) fromDate?: string, + @Arg('toDate', { nullable: true }) toDate?: string, + @Arg('networkId', { nullable: true }) networkId?: number, + @Arg('onlyVerified', { nullable: true }) onlyVerified?: boolean, + ): Promise { try { validateWithJoiSchema( - { beginDate, endDate }, - getRecurringDonationStatsArgsValidator, + { fromDate, toDate }, + resourcePerDateReportValidator, ); - - const query = RecurringDonation.createQueryBuilder('recurring_donation') - .select([ - 'COUNT(CASE WHEN recurring_donation.status = :active THEN 1 END)', - 'SUM(recurring_donation.totalUsdStreamed)', - ]) - .setParameter('active', 'active') - .where( - `recurring_donation.createdAt >= :beginDate AND recurring_donation.createdAt <= :endDate`, - { beginDate, endDate }, + const total = await recurringDonationsCountPerDateRange( + fromDate, + toDate, + networkId, + onlyVerified, + ); + const totalPerMonthAndYear = + await recurringDonationsCountPerDateRangePerMonth( + fromDate, + toDate, + networkId, + onlyVerified, ); + const totalPerToken = await recurringDonationsCountPerToken({ + fromDate, + toDate, + networkId, + onlyVerified, + }); - if (currency) { - query.andWhere(`recurring_donation.currency = :currency`, { currency }); - } + return { + total, + totalPerMonthAndYear, + totalPerToken, + }; + } catch (e) { + logger.error('recurringDonationsCountPerDate query error', e); + throw e; + } + } - const [result] = await query.getRawMany(); + @Query(_returns => RDRessourcePerDateRange, { nullable: true }) + async recurringDonationsTotalStreamedUsdPerDate( + // fromDate and toDate should be in this format YYYYMMDD HH:mm:ss + @Arg('fromDate', { nullable: true }) fromDate?: string, + @Arg('toDate', { nullable: true }) toDate?: string, + @Arg('networkId', { nullable: true }) networkId?: number, + @Arg('onlyVerified', { nullable: true }) onlyVerified?: boolean, + ): Promise { + try { + validateWithJoiSchema( + { fromDate, toDate }, + resourcePerDateReportValidator, + ); + const total = await recurringDonationsStreamedCUsdTotal( + fromDate, + toDate, + networkId, + onlyVerified, + ); + const totalPerMonthAndYear = + await recurringDonationsStreamedCUsdTotalPerMonth( + fromDate, + toDate, + networkId, + onlyVerified, + ); + const totalPerToken = await recurringDonationsTotalPerToken({ + fromDate, + toDate, + networkId, + onlyVerified, + }); return { - activeRecurringDonationsCount: parseInt(result.count), - totalStreamedUsdValue: parseFloat(result.sum) || 0, + total, + totalPerMonthAndYear, + totalPerToken, }; } catch (e) { - SentryLogger.captureException(e); - logger.error('getRecurringDonationStats() error ', e); + logger.error('recurringDonationsTotalStreamedUsdPerDate query error', e); throw e; } } diff --git a/src/services/recurringDonationService.ts b/src/services/recurringDonationService.ts index 31c6c2140..3e2d52d41 100644 --- a/src/services/recurringDonationService.ts +++ b/src/services/recurringDonationService.ts @@ -38,6 +38,7 @@ import { User } from '../entities/user'; import { NOTIFICATIONS_EVENT_NAMES } from '../analytics/analytics'; import { relatedActiveQfRoundForProject } from './qfRoundService'; import { updateProjectStatistics } from './projectService'; +import { ResourcesTotalPerMonthAndYear } from '../resolvers/donationResolver'; // Initially it will only be monthly data export const priceDisplay = 'month'; @@ -418,3 +419,297 @@ export const updateRecurringDonationStatusWithNetwork = async (params: { return recurringDonation; } }; + +export const recurringDonationsCountPerDateRange = async ( + fromDate?: string, + toDate?: string, + networkId?: number, + onlyVerified?: boolean, +): Promise => { + const query = RecurringDonation.createQueryBuilder('recurringDonation') + .select('COALESCE(COUNT(recurringDonation.id), 0)', 'count') + .where('recurringDonation.status = :status', { + status: RECURRING_DONATION_STATUS.ACTIVE, + }); + + if (fromDate) { + query.andWhere('recurringDonation.createdAt >= :fromDate', { + fromDate: new Date(fromDate), + }); + } + + if (toDate) { + query.andWhere('recurringDonation.createdAt <= :toDate', { + toDate: new Date(toDate), + }); + } + + if (networkId) { + query.andWhere('recurringDonation.networkId = :networkId', { + networkId, + }); + } + + if (onlyVerified) { + query + .leftJoin('recurringDonation.project', 'project') + .andWhere('project.verified = :verified', { + verified: true, + }); + } + + const recurringDonationsCount = await query + .cache( + `recurringDonationsCountPerDateRange-${fromDate || ''}-${toDate || ''}-${networkId || 'all'}-${onlyVerified || 'all'}`, + 300000, + ) + .getRawOne(); + + return recurringDonationsCount.count; +}; + +export const recurringDonationsCountPerDateRangePerMonth = async ( + fromDate?: string, + toDate?: string, + networkId?: number, + onlyVerified?: boolean, +): Promise => { + const query = RecurringDonation.createQueryBuilder('recurringDonation') + .select('COUNT(recurringDonation.id)', 'total') + .addSelect("TO_CHAR(recurringDonation.createdAt, 'YYYY/MM')", 'date') + .where('recurringDonation.status = :status', { + status: RECURRING_DONATION_STATUS.ACTIVE, + }); + + if (fromDate) { + query.andWhere('recurringDonation.createdAt >= :fromDate', { + fromDate: new Date(fromDate), + }); + } + + if (toDate) { + query.andWhere('recurringDonation.createdAt <= :toDate', { + toDate: new Date(toDate), + }); + } + + if (networkId) { + query.andWhere('recurringDonation.networkId = :networkId', { + networkId, + }); + } + + if (onlyVerified) { + query + .leftJoin('recurringDonation.project', 'project') + .andWhere('project.verified = :verified', { + verified: true, + }); + } + + query.groupBy('date'); + query.orderBy('date', 'ASC'); + + query.cache( + `recurringDonationsCountPerDateRangePerMonthAndYear-${fromDate || ''}-${toDate || ''}-${networkId || 'all'}-${onlyVerified || 'all'}`, + 300000, + ); + + return query.getRawMany(); +}; + +export const recurringDonationsStreamedCUsdTotal = async ( + fromDate?: string, + toDate?: string, + networkId?: number, + onlyVerified?: boolean, +): Promise => { + const query = RecurringDonation.createQueryBuilder( + 'recurringDonation', + ).select('COALESCE(SUM(recurringDonation.totalUsdStreamed), 0)', 'total'); + + if (fromDate) { + query.andWhere('recurringDonation.createdAt >= :fromDate', { + fromDate: new Date(fromDate), + }); + } + + if (toDate) { + query.andWhere('recurringDonation.createdAt <= :toDate', { + toDate: new Date(toDate), + }); + } + + if (networkId) { + query.andWhere('recurringDonation.networkId = :networkId', { + networkId, + }); + } + + if (onlyVerified) { + query + .leftJoin('recurringDonation.project', 'project') + .andWhere('project.verified = :verified', { + verified: true, + }); + } + + const recurringDonationsTotal = await query + .cache( + `recurringDonationsStreamedCUsdTotal-${fromDate || ''}-${toDate || ''}-${networkId || 'all'}-${onlyVerified || 'all'}`, + 300000, + ) + .getRawOne(); + + return recurringDonationsTotal.total; +}; + +export const recurringDonationsStreamedCUsdTotalPerMonth = async ( + fromDate?: string, + toDate?: string, + networkId?: number, + onlyVerified?: boolean, +): Promise => { + const query = RecurringDonation.createQueryBuilder('recurringDonation') + .select('SUM(recurringDonation.totalUsdStreamed)', 'total') + .addSelect("TO_CHAR(recurringDonation.createdAt, 'YYYY/MM')", 'date'); + + if (fromDate) { + query.andWhere('recurringDonation.createdAt >= :fromDate', { + fromDate: new Date(fromDate), + }); + } + + if (toDate) { + query.andWhere('recurringDonation.createdAt <= :toDate', { + toDate: new Date(toDate), + }); + } + + if (networkId) { + query.andWhere('recurringDonation.networkId = :networkId', { + networkId, + }); + } + + if (onlyVerified) { + query + .leftJoin('recurringDonation.project', 'project') + .andWhere('project.verified = :verified', { + verified: true, + }); + } + + query.groupBy('date'); + query.orderBy('date', 'ASC'); + + const recurringDonationsTotal = await query + .cache( + `recurringDonationsStreamedCUsdTotalPerMonth-${fromDate || ''}-${toDate || ''}-${networkId || 'all'}-${onlyVerified || 'all'}`, + 300000, + ) + .getRawMany(); + + return recurringDonationsTotal; +}; + +export const recurringDonationsTotalPerToken = async (params: { + fromDate?: string; + toDate?: string; + networkId?: number; + onlyVerified?: boolean; +}): Promise<{ token: string; total: number }[]> => { + const { fromDate, toDate, networkId, onlyVerified } = params; + const query = RecurringDonation.createQueryBuilder('recurringDonation') + .select('recurringDonation.currency', 'token') + .addSelect('COALESCE(SUM(recurringDonation.totalUsdStreamed), 0)', 'total') + .groupBy('recurringDonation.currency') + .having('SUM(recurringDonation.totalUsdStreamed) > 0'); + + if (fromDate) { + query.andWhere('recurringDonation.createdAt >= :fromDate', { + fromDate: new Date(fromDate), + }); + } + + if (toDate) { + query.andWhere('recurringDonation.createdAt <= :toDate', { + toDate: new Date(toDate), + }); + } + + if (networkId) { + query.andWhere('recurringDonation.networkId = :networkId', { + networkId, + }); + } + + if (onlyVerified) { + query + .leftJoin('recurringDonation.project', 'project') + .andWhere('project.verified = :verified', { + verified: true, + }); + } + + const recurringDonationsTotal = await query + .cache( + `recurringDonationsTotalPerToken-${fromDate || ''}-${toDate || ''}-${networkId || 'all'}-${onlyVerified || 'all'}`, + 300000, + ) + .getRawMany(); + + return recurringDonationsTotal; +}; + +export const recurringDonationsCountPerToken = async (params: { + fromDate?: string; + toDate?: string; + networkId?: number; + onlyVerified?: boolean; +}): Promise<{ token: string; total: number }[]> => { + const { fromDate, toDate, networkId, onlyVerified } = params; + const query = RecurringDonation.createQueryBuilder('recurringDonation') + .select('recurringDonation.currency', 'token') + .addSelect('COALESCE(COUNT(recurringDonation.id), 0)', 'total') + .where('recurringDonation.status = :status', { + status: RECURRING_DONATION_STATUS.ACTIVE, + }) + .groupBy('recurringDonation.currency') + .having('COUNT(recurringDonation.id) > 0'); + + if (fromDate) { + query.andWhere('recurringDonation.createdAt >= :fromDate', { + fromDate: new Date(fromDate), + }); + } + + if (toDate) { + query.andWhere('recurringDonation.createdAt <= :toDate', { + toDate: new Date(toDate), + }); + } + + if (networkId) { + query.andWhere('recurringDonation.networkId = :networkId', { + networkId, + }); + } + + if (onlyVerified) { + query + .leftJoin('recurringDonation.project', 'project') + .andWhere('project.verified = :verified', { + verified: true, + }); + } + + const recurringDonationsTotal = await query + .cache( + `recurringDonationsCountPerToken-${fromDate || ''}-${toDate || ''}-${networkId || 'all'}-${onlyVerified || 'all'}`, + 300000, + ) + .getRawMany(); + + return recurringDonationsTotal; +}; diff --git a/src/utils/validators/graphqlQueryValidators.ts b/src/utils/validators/graphqlQueryValidators.ts index 80e5d4444..0d0f6f0a0 100644 --- a/src/utils/validators/graphqlQueryValidators.ts +++ b/src/utils/validators/graphqlQueryValidators.ts @@ -170,17 +170,6 @@ export const updateDonationQueryValidator = Joi.object({ status: Joi.string().valid(DONATION_STATUS.VERIFIED, DONATION_STATUS.FAILED), }); -export const getRecurringDonationStatsArgsValidator = Joi.object({ - beginDate: Joi.string().pattern(resourcePerDateRegex).messages({ - 'string.base': errorMessages.INVALID_FROM_DATE, - 'string.pattern.base': errorMessages.INVALID_DATE_FORMAT, - }), - endDate: Joi.string().pattern(resourcePerDateRegex).messages({ - 'string.base': errorMessages.INVALID_FROM_DATE, - 'string.pattern.base': errorMessages.INVALID_DATE_FORMAT, - }), -}); - export const createProjectVerificationRequestValidator = Joi.object({ slug: Joi.string().required(), }); diff --git a/test/graphqlQueries.ts b/test/graphqlQueries.ts index c0075e37e..b4d474f8b 100644 --- a/test/graphqlQueries.ts +++ b/test/graphqlQueries.ts @@ -2400,20 +2400,55 @@ export const updateRecurringDonationQuery = ` } `; -export const fetchRecurringDonationStatsQuery = ` +export const fetchRecurringDonationsCount = ` query ( - $beginDate: String! - $endDate: String! - $currency: String + $fromDate: String + $toDate: String + $networkId: Float + $onlyVerified: Boolean + ) { + recurringDonationsCountPerDate ( + fromDate: $fromDate + toDate: $toDate + networkId: $networkId + onlyVerified: $onlyVerified ) { - getRecurringDonationStats( - beginDate: $beginDate - endDate: $endDate - currency: $currency - ) { - totalStreamedUsdValue, - activeRecurringDonationsCount, + total + totalPerMonthAndYear { + total + date + } + totalPerToken { + token + total + } + } + } +`; + +export const fetchRecurringDonationsTotalUSD = ` + query ( + $fromDate: String + $toDate: String + $networkId: Float + $onlyVerified: Boolean + ) { + recurringDonationsTotalStreamedUsdPerDate ( + fromDate: $fromDate + toDate: $toDate + networkId: $networkId + onlyVerified: $onlyVerified + ) { + total + totalPerMonthAndYear { + total + date } + totalPerToken { + token + total + } + } } `;