Skip to content

Commit

Permalink
Merge pull request capsule-corp-ternoa#171 from capsule-corp-ternoa/f…
Browse files Browse the repository at this point in the history
…eat-getTotalFilteredNFTs

feat: New countTotalFilteredNFTs graphQL querie created.
  • Loading branch information
ipapandinas authored Feb 21, 2022
2 parents 5943233 + 396a567 commit 92830a0
Show file tree
Hide file tree
Showing 6 changed files with 131 additions and 13 deletions.
15 changes: 14 additions & 1 deletion src/api/controllers/nfts/controller.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import NFTService from "../../services/nft";
import { NextFunction, Request, Response } from "express";
import { validationGetNFTs, validationGetNFT, validationGetStatNFTsUser, validationNFTsBySeries, validationGetSeries, validationCanAddToSeries, validationGetHistory, validationAddCategoriesNFTs, validationGetTotalOnSale, validationLikeUnlike, validationGetFilters } from "../../validators/nftValidators";
import { validationGetNFTs, validationGetNFT, validationGetStatNFTsUser, validationNFTsBySeries, validationGetSeries, validationCanAddToSeries, validationGetHistory, validationAddCategoriesNFTs, validationGetTotalOnSale, validationGetTotalFilteredNFTs, validationLikeUnlike, validationGetFilters } from "../../validators/nftValidators";
import { decryptCookie } from "../../../utils";

export class Controller {
Expand Down Expand Up @@ -117,6 +117,19 @@ export class Controller {
}
}

async getTotalFiltered(
req: Request,
res: Response,
next: NextFunction
): Promise<void>{
try {
const queryValues = validationGetTotalFilteredNFTs(req.query)
res.json(await NFTService.getTotalFilteredNFTs(queryValues));
} catch (err) {
next(err);
}
}

async likeNft(
req: Request,
res: Response,
Expand Down
1 change: 1 addition & 0 deletions src/api/controllers/nfts/router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export default express
.get("/most-sold-series", controller.getMostSoldSeries)
.get("/history", controller.getHistory)
.get("/total-on-sale", controller.getTotalOnSale)
.get("/total-filtered", controller.getTotalFiltered)
.get("/:id", controller.getNFT)
.get("/stat/:id", controller.getStatNFTsUser)
.get("/series/data", controller.getNFTsBySeries)
Expand Down
5 changes: 2 additions & 3 deletions src/api/helpers/nftHelpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,15 +44,14 @@ export async function populateStat(
): Promise<{
totalNft: number,
totalListedNft: number,
totalFiltered: number | null,
totalListedInMarketplace: number,
totalOwnedByRequestingUser: number,
totalOwnedListedByRequestingUser: number,
smallestPrice: string
}> {
try {
const marketplaceId = query.filter?.marketplaceId;
const owner = query.filter?.owner;
const stat = await NFTService.getStatNFT(NFT.serieId, marketplaceId, owner)
const stat = await NFTService.getStatNFT(NFT.serieId, query)
return stat
} catch (err) {
L.error({ err }, "NFTs stats could not have been fetched");
Expand Down
51 changes: 50 additions & 1 deletion src/api/services/gqlQueriesBuilder.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { gql } from "graphql-request";
import { convertSortString, convertSortStringDistinct, LIMIT_MAX_PAGINATION } from "../../utils";
import { getFiltersQuery, getHistoryQuery, getSeriesStatusQuery, NFTBySeriesQuery, NFTQuery, NFTsQuery, statNFTsUserQuery } from "../validators/nftValidators";
import { getFiltersQuery, getHistoryQuery, getSeriesStatusQuery, NFTBySeriesQuery, NFTQuery, NFTsQuery, statNFTsUserQuery, getTotalFilteredNFTsQuery } from "../validators/nftValidators";
// import L from '../../common/logger';

const nodes = `
Expand Down Expand Up @@ -427,6 +427,55 @@ countAllListedInMarketplace = (marketplaceId: number) => gql`
}
`;

countTotalFilteredNFTs = (query: getTotalFilteredNFTsQuery, seriesId?: string) => {
const {
idsCategories,
idsToExcludeCategories,
marketplaceId,
listed,
priceStartRange,
priceEndRange,
timestampCreateStartRange,
timestampCreateEndRange,
} = query.filter ?? {};

return gql`
{
nftEntities(
filter: {
and: [
{ timestampBurn: { isNull: true } }
${seriesId!==undefined ? `{ serieId: { equalTo: "${seriesId}" } }` : ""}
${listed!==undefined ? `{ listed: { equalTo: ${!listed ? 0 : 1} } }` : ""}
${marketplaceId!==undefined ? `{ marketplaceId: { equalTo: "${marketplaceId}" } }` : ""}
${idsCategories ? `{id: { in: ${JSON.stringify(idsCategories.map(x => String(x)))} }}` : ""}
${idsToExcludeCategories ? `{id: { notIn: ${JSON.stringify(idsToExcludeCategories.map(x => String(x)))} }}` : ""}
]
${
priceStartRange !== undefined ||
priceEndRange !== undefined
? `priceRounded: {
${priceStartRange!==undefined ? `greaterThanOrEqualTo: ${priceStartRange}` : ""}
${priceStartRange!==undefined ? `lessThanOrEqualTo: ${priceEndRange}` : ""}
}`
: ""
}
${
timestampCreateStartRange !== undefined ||
timestampCreateEndRange !== undefined
? `timestampCreate: {
${timestampCreateStartRange!==undefined ? `greaterThanOrEqualTo: "${timestampCreateStartRange}"` : ""}
${timestampCreateEndRange!==undefined ? `lessThanOrEqualTo: "${timestampCreateEndRange}"` : ""}
}`
: ""
}
}
) {
totalCount
}
}`;
};

getMostSold = (query: getFiltersQuery) => gql`
{
mostSold(
Expand Down
42 changes: 34 additions & 8 deletions src/api/services/nft.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import CategoryService from "./category"
import { populateNFT } from "../helpers/nftHelpers";
import QueriesBuilder from "./gqlQueriesBuilder";
import { decryptCookie, TIME_BETWEEN_SAME_USER_VIEWS } from "../../utils";
import { canAddToSeriesQuery, addCategoriesNFTsQuery, getHistoryQuery, getSeriesStatusQuery, NFTBySeriesQuery, NFTQuery, NFTsQuery, statNFTsUserQuery, getTotalOnSaleQuery, likeUnlikeQuery, getFiltersQuery } from "../validators/nftValidators";
import { canAddToSeriesQuery, addCategoriesNFTsQuery, getHistoryQuery, getSeriesStatusQuery, NFTBySeriesQuery, NFTQuery, NFTsQuery, statNFTsUserQuery, getTotalOnSaleQuery, getTotalFilteredNFTsQuery, likeUnlikeQuery, getFiltersQuery } from "../validators/nftValidators";
import CategoryModel from "../../models/category";
import { ICategory } from "../../interfaces/ICategory";
import { INftLike } from "../../interfaces/INftLike";
Expand Down Expand Up @@ -147,30 +147,37 @@ export class NFTService {
* @param seriesId - Series Id of nft to get stat for
* @param marketplaceId - marketplace id (optional)
* @param owner - owner (optional)
* @param filterOptionsQuery - filter options (optional)
* @throws Will throw an error if can't request indexer
*/
async getStatNFT(seriesId:string, marketplaceId:number=null, owner:string=null): Promise<{
async getStatNFT(seriesId:string, query:NFTsQuery=null): Promise<{
totalNft: number,
totalListedNft: number,
totalFiltered: number | null,
totalListedInMarketplace: number,
totalOwnedByRequestingUser: number,
totalOwnedListedByRequestingUser: number,
totalOwnedListedInMarketplaceByRequestingUser: number,
smallestPrice: string
}> {
const marketplaceId = query.filter.marketplaceId ?? null;
const owner = query.filter.owner ?? null;

try {
const [totalRequest, totalListedRequest, totalListedInMarketplaceRequest, totalOwnedByRequestingUserRequest, totalOwnedListedByRequestingUserRequest, totalOwnedListedInMarketplaceByRequestingUserRequest, smallestPriceRequest] = await Promise.all([
const [totalRequest, totalListedRequest, totalFilteredRequest, totalListedInMarketplaceRequest, totalOwnedByRequestingUserRequest, totalOwnedListedByRequestingUserRequest, totalOwnedListedInMarketplaceByRequestingUserRequest, smallestPriceRequest] = await Promise.all([
request(indexerUrl, QueriesBuilder.countTotal(seriesId)),
request(indexerUrl, QueriesBuilder.countTotalListed(seriesId)),
marketplaceId!==null ? request(indexerUrl, QueriesBuilder.countTotalListedInMarketplace(seriesId, marketplaceId)) : 0,
owner ? request(indexerUrl, QueriesBuilder.countTotalOwned(seriesId, owner)) : null,
owner ? request(indexerUrl, QueriesBuilder.countTotalOwnedListed(seriesId, owner)) : null,
owner && marketplaceId!==null ? request(indexerUrl, QueriesBuilder.countTotalOwnedListedInMarketplace(seriesId, owner, marketplaceId)) : null,
query ? request(indexerUrl, QueriesBuilder.countTotalFilteredNFTs(query, seriesId)) : null,
marketplaceId !== null ? request(indexerUrl, QueriesBuilder.countTotalListedInMarketplace(seriesId, marketplaceId)) : 0,
owner !== null ? request(indexerUrl, QueriesBuilder.countTotalOwned(seriesId, owner)) : null,
owner !== null ? request(indexerUrl, QueriesBuilder.countTotalOwnedListed(seriesId, owner)) : null,
owner !== null && marketplaceId !== null ? request(indexerUrl, QueriesBuilder.countTotalOwnedListedInMarketplace(seriesId, owner, marketplaceId)) : null,
request(indexerUrl, QueriesBuilder.countSmallestPrice(seriesId, marketplaceId)),
])
const totalNft: number = totalRequest.nftEntities.totalCount;
const totalListedNft: number = totalListedRequest.nftEntities.totalCount;
const totalListedInMarketplace: number = totalListedInMarketplaceRequest ? totalListedInMarketplaceRequest.nftEntities.totalCount : 0;
const totalFiltered: number = totalFilteredRequest ? totalFilteredRequest.nftEntities.totalCount : null;
const totalOwnedByRequestingUser: number = totalOwnedByRequestingUserRequest ? totalOwnedByRequestingUserRequest.nftEntities.totalCount : 0;
const totalOwnedListedByRequestingUser: number = totalOwnedListedByRequestingUserRequest ? totalOwnedListedByRequestingUserRequest.nftEntities.totalCount : 0;
const totalOwnedListedInMarketplaceByRequestingUser: number = totalOwnedListedInMarketplaceByRequestingUserRequest ? totalOwnedListedInMarketplaceByRequestingUserRequest.nftEntities.totalCount : 0;
Expand All @@ -179,7 +186,7 @@ export class NFTService {
:
"0"
;
return { totalNft, totalListedNft, totalListedInMarketplace, totalOwnedByRequestingUser, totalOwnedListedByRequestingUser, totalOwnedListedInMarketplaceByRequestingUser, smallestPrice }
return { totalNft, totalListedNft, totalListedInMarketplace, totalFiltered, totalOwnedByRequestingUser, totalOwnedListedByRequestingUser, totalOwnedListedInMarketplaceByRequestingUser, smallestPrice }
} catch (err) {
throw new Error("Couldn't get NFT stat");
}
Expand Down Expand Up @@ -354,6 +361,25 @@ export class NFTService {
}
}

/**
* Returns the totalCount for the specified filters
* @param query - query (see getTotalFilteredNFTsQuery)
* @throws Will throw an error if indexer is not reachable
*/
async getTotalFilteredNFTs(query: getTotalFilteredNFTsQuery): Promise<boolean> {
try {
// Categories
if (query.filter?.categories) await this.handleFilterCategory(query);

const gqlQuery = QueriesBuilder.countTotalFilteredNFTs(query);
const res = await request(indexerUrl, gqlQuery);
if (!res.nftEntities.totalCount) throw new Error();
return res.nftEntities.totalCount;
} catch (err) {
throw new Error("Filtered count could not have been fetched");
}
}

/**
* Like an NFT
* @param query - see likeUnlikeQuery
Expand Down
30 changes: 30 additions & 0 deletions src/api/validators/nftValidators.ts
Original file line number Diff line number Diff line change
Expand Up @@ -273,4 +273,34 @@ export const validationGetFilters = (query: any) => {
}).required()
})
return validateQuery(validationSchema, { pagination }) as getFiltersQuery;
}

export type getTotalFilteredNFTsQuery = {
filter?: {
idsCategories?: string[],
idsToExcludeCategories?: string[],
categories?: string[],
listed?: boolean,
marketplaceId?: number,
priceStartRange?: number,
priceEndRange?: number,
timestampCreateStartRange?: Date,
timestampCreateEndRange?: Date
}
}
export const validationGetTotalFilteredNFTs = (query: any) => {
let { filter } = query;
if (filter) filter = JSON.parse(filter);
const validationSchema = Joi.object({
filter: Joi.object({
categories: Joi.array().items(Joi.string()),
listed: Joi.boolean(),
marketplaceId: Joi.number().integer().min(0),
priceStartRange: Joi.number(),
priceEndRange: Joi.number(),
timestampCreateStartRange: Joi.date().raw(),
timestampCreateEndRange: Joi.date().raw(),
}),
})
return validateQuery(validationSchema, { filter }) as getTotalFilteredNFTsQuery;
}

0 comments on commit 92830a0

Please sign in to comment.