diff --git a/src/adapters/handlers/nfts.ts b/src/adapters/handlers/nfts.ts index b67ae649..82778537 100644 --- a/src/adapters/handlers/nfts.ts +++ b/src/adapters/handlers/nfts.ts @@ -33,7 +33,11 @@ export function createNFTsHandler( const isLand = params.getBoolean('isLand') const isOnRent = params.getBoolean('isOnRent') const isWearableHead = params.getBoolean('isWearableHead') + ? params.getString('isWearableHead') === 'true' + : undefined const isWearableAccessory = params.getBoolean('isWearableAccessory') + ? params.getString('isWearableAccessory') === 'true' + : undefined const isWearableSmart = params.getBoolean('isWearableSmart') const wearableCategory = params.getValue( 'wearableCategory', diff --git a/src/adapters/handlers/prices.ts b/src/adapters/handlers/prices.ts index 821d3c1a..8d1a9498 100644 --- a/src/adapters/handlers/prices.ts +++ b/src/adapters/handlers/prices.ts @@ -25,7 +25,11 @@ export function createPricesHandler( const category = params.getString('category') as PriceFilterCategory const assetType = params.getString('assetType') as AssetType const isWearableHead = params.getBoolean('isWearableHead') + ? params.getString('isWearableAccessory') === 'true' + : undefined const isWearableAccessory = params.getBoolean('isWearableAccessory') + ? params.getString('isWearableAccessory') === 'true' + : undefined const isWearableSmart = params.getBoolean('isWearableSmart') const wearableCategory = params.getValue( 'wearableCategory', @@ -81,7 +85,7 @@ export function createPricesHandler( maxEstateSize, minEstateSize, emoteHasGeometry, - emoteHasSound + emoteHasSound, }), }), { diff --git a/src/logic/nfts/collections.ts b/src/logic/nfts/collections.ts index 8e48b50b..c814bdab 100644 --- a/src/logic/nfts/collections.ts +++ b/src/logic/nfts/collections.ts @@ -188,7 +188,7 @@ export function fromCollectionsFragment( break } default: { - throw new Error(`Uknown itemType=${fragment.itemType}`) + throw new Error(`Unknown itemType=${fragment.itemType}`) } } diff --git a/src/logic/prices/collections.ts b/src/logic/prices/collections.ts index 47e8d500..ff22a4b8 100644 --- a/src/logic/prices/collections.ts +++ b/src/logic/prices/collections.ts @@ -7,6 +7,18 @@ import { AssetType, PriceFilters } from '../../ports/prices/types' const MAX_RESULTS = 1000 +const PRICES_ITEMS_FILTERS_DICT: Record = { + wearableCategory: '$wearableCategory: String', + emoteCategory: '$emoteCategory: String', + isWearableHead: '$isWearableHead: Boolean', + isWearableAccessory: '$isWearableAccessory: Boolean', +} + +const PRICES_FILTERS_DICT: Record = { + expiresAt: '$expiresAt: BigInt', + ...PRICES_ITEMS_FILTERS_DICT, +} + export function collectionsShouldFetch(filters: PriceFilters) { const isCorrectNetworkFilter = !filters.network || !!(filters.network && filters.network === Network.MATIC) @@ -72,12 +84,17 @@ export function collectionsNFTsPricesQuery(filters: PriceFilters) { }, AssetType.NFT ) - return `query NFTPrices( - $expiresAt: String, - $wearableCategory: String - $emoteCategory: String - $isWearableHead: Boolean - $isWearableAccessory: Boolean) { + + const variablesBasedOnFilters = Object.entries(filters) + .filter(([key, value]) => value !== undefined && key in PRICES_FILTERS_DICT) + .map(([key]) => (PRICES_FILTERS_DICT[key] ? PRICES_FILTERS_DICT[key] : '')) + + const variablesDefinition = variablesBasedOnFilters.length + ? `query NFTPrices(${variablesBasedOnFilters.join('\n')})` + : `query NFTPrices` + + return ` + ${variablesDefinition} { prices: nfts ( first: ${MAX_RESULTS}, orderBy: id, @@ -103,12 +120,15 @@ export function collectionsNFTsPricesQueryById(filters: PriceFilters) { AssetType.NFT ) return `query NFTPrices( - $lastId: ID, - $expiresAt: String - $wearableCategory: String - $emoteCategory: String - $isWearableHead: Boolean - $isWearableAccessory: Boolean + $lastId: String, + ${Object.entries(filters) + .filter( + ([key, value]) => value !== undefined && key in PRICES_FILTERS_DICT + ) + .map(([key]) => + PRICES_FILTERS_DICT[key] ? PRICES_FILTERS_DICT[key] : '' + ) + .join('\n')} ) { prices: nfts( first: ${MAX_RESULTS}, @@ -141,12 +161,18 @@ export function collectionsItemsPricesQuery(filters: PriceFilters) { ? '[wearable_v1, wearable_v2, smart_wearable_v1]' : '[emote_v1]' - return `query ItemPrices( - $wearableCategory: String - $emoteCategory: String - $isWearableHead: Boolean - $isWearableAccessory: Boolean - ) { + const variablesBasedOnFilters = Object.entries(filters) + .filter( + ([key, value]) => value !== undefined && key in PRICES_ITEMS_FILTERS_DICT + ) + .map(([key]) => (PRICES_FILTERS_DICT[key] ? PRICES_FILTERS_DICT[key] : '')) + + const variablesDefinition = variablesBasedOnFilters.length + ? `query ItemPrices(${variablesBasedOnFilters.join('\n')})` + : `query ItemPrices` + + return ` + ${variablesDefinition} { prices: items ( first: ${MAX_RESULTS}, orderBy: id, @@ -179,11 +205,15 @@ export function collectionsItemsPricesQueryById(filters: PriceFilters) { : '[emote_v1]' return `query ItemPrices( - $lastId: ID, - $wearableCategory: String - $emoteCategory: String - $isWearableHead: Boolean - $isWearableAccessory: Boolean + $lastId: String, + ${Object.entries(filters) + .filter( + ([key, value]) => value !== undefined && key in PRICES_FILTERS_DICT + ) + .map(([key]) => + PRICES_FILTERS_DICT[key] ? PRICES_FILTERS_DICT[key] : '' + ) + .join('\n')} ) { prices: items ( first: ${MAX_RESULTS}, diff --git a/src/logic/prices/marketplace.ts b/src/logic/prices/marketplace.ts index e6205e10..e1a452d4 100644 --- a/src/logic/prices/marketplace.ts +++ b/src/logic/prices/marketplace.ts @@ -16,6 +16,14 @@ import { const MAX_RESULTS = 1000 +const PRICES_FILTERS_DICT: Record = { + expiresAt: '$expiresAt: BigInt', + wearableCategory: '$wearableCategory: String', + emoteCategory: '$emoteCategory: String', + isWearableHead: '$isWearableHead: Boolean', + isWearableAccessory: '$isWearableAccessory: Boolean', +} + export function marketplaceShouldFetch(filters: PriceFilters) { const isCorrectNetworkFilter = !filters.network || @@ -96,13 +104,18 @@ export function marketplacePricesQuery(filters: PriceFilters) { searchEstateSize_gt: 0, ${additionalWheres.join('\n')} ` - return `query NFTPrices( - $expiresAt: String - $expiresAtSec: String - $wearableCategory: String - $isWearableHead: Boolean - $isWearableAccessory: Boolean - ) { + + const variablesBasedOnFilters = Object.entries(filters) + .filter(([key, value]) => value !== undefined && key in PRICES_FILTERS_DICT) + .map(([key]) => (PRICES_FILTERS_DICT[key] ? PRICES_FILTERS_DICT[key] : '')) + + const variablesDefinition = variablesBasedOnFilters.length + ? `query NFTPrices($expiresAtSec: BigInt, ${variablesBasedOnFilters.join( + '\n' + )})` + : `query NFTPrices($expiresAtSec: BigInt, $expiresAt: BigInt)` + + return `${variablesDefinition} { prices: nfts( first: ${MAX_RESULTS}, orderBy: tokenId, @@ -130,13 +143,16 @@ export function marketplacePricesQueryById(filters: PriceFilters) { const { category, ...rest } = filters const additionalWheres: string[] = getExtraWheres(rest) const categories = getNFTCategoryFromPriceCategory(category) - return `query NFTPrices( - $lastId: ID, - $expiresAt: String - $wearableCategory: String - $isWearableHead: Boolean - $isWearableAccessory: Boolean - ) { + const variablesBasedOnFilters = Object.entries(filters) + .filter(([key, value]) => value !== undefined && key in PRICES_FILTERS_DICT) + .map(([key]) => (PRICES_FILTERS_DICT[key] ? PRICES_FILTERS_DICT[key] : '')) + + const variablesDefinition = variablesBasedOnFilters.length + ? `query NFTPrices($lastId: BigInt, ${variablesBasedOnFilters.join('\n')})` + : `query NFTPrices($lastId: BigInt)` + + return ` + ${variablesDefinition} { prices: nfts( orderBy: tokenId, orderDirection: asc, diff --git a/src/ports/nfts/types.ts b/src/ports/nfts/types.ts index 391418fc..aec37a2e 100644 --- a/src/ports/nfts/types.ts +++ b/src/ports/nfts/types.ts @@ -9,8 +9,8 @@ export type NFTResult = { export type QueryVariables = Omit & { orderBy: string orderDirection: 'asc' | 'desc' - expiresAt: string - expiresAtSec: string + expiresAt?: string + expiresAtSec?: string } export interface INFTsComponent { diff --git a/src/ports/nfts/utils.ts b/src/ports/nfts/utils.ts index 25ecabd2..50b067b4 100644 --- a/src/ports/nfts/utils.ts +++ b/src/ports/nfts/utils.ts @@ -5,18 +5,16 @@ import { QueryVariables } from './types' export const NFT_DEFAULT_SORT_BY = NFTSortBy.NEWEST -const NFTS_FILTERS = ` - $first: Int - $skip: Int - $orderBy: String - $orderDirection: String - $expiresAt: String - $expiresAtSec: String - $owner: String - $wearableCategory: String - $isWearableHead: Boolean - $isWearableAccessory: Boolean -` +const NFT_FILTERS_DICT: Record = { + orderBy: '$orderBy: NFT_orderBy', + orderDirection: '$orderDirection: OrderDirection', + expiresAt: '$expiresAt: BigInt', + expiresAtSec: '$expiresAtSec: BigInt', + owner: '$owner: String', + wearableCategory: '$wearableCategory: String', + isWearableHead: '$isWearableHead: Boolean', + isWearableAccessory: '$isWearableAccessory: Boolean', +} const getArguments = (total: number) => ` first: ${total} @@ -46,14 +44,21 @@ export function getQueryVariables( const { sortBy, ...variables } = options const orderBy = getOrderBy(sortBy) as string const orderDirection = getOrderDirection(sortBy) - const expiresAt = Date.now() - const expiresAtSec = Math.trunc(expiresAt / 1000) + if (options.isOnSale) { + const expiresAt = Date.now() + const expiresAtSec = Math.trunc(expiresAt / 1000) + return { + ...variables, + orderBy, + orderDirection, + expiresAt: expiresAt.toString(), + expiresAtSec: expiresAtSec.toString(), + } + } return { ...variables, orderBy, orderDirection, - expiresAt: expiresAt.toString(), - expiresAtSec: expiresAtSec.toString(), } } @@ -208,7 +213,7 @@ export function getFetchQuery( } if (filters.owner) { - where.push('owner: $owner') + where.push('owner_: {address: $owner}') } if ( @@ -302,7 +307,10 @@ export function getFetchQuery( } const query = `query NFTs( - ${NFTS_FILTERS} + ${Object.entries(filters) + .filter(([key, value]) => value !== undefined && key in NFT_FILTERS_DICT) + .map(([key]) => (NFT_FILTERS_DICT[key] ? NFT_FILTERS_DICT[key] : '')) + .join('\n')} ${getExtraVariables ? getExtraVariables(filters).join('\n') : ''} ) { nfts( @@ -312,10 +320,11 @@ export function getFetchQuery( } }` - return ` + const result = ` ${query} ${isCount ? '' : getNFTFragment()} ` + return result } export function getFetchOneQuery( @@ -323,7 +332,7 @@ export function getFetchOneQuery( getFragment: () => string ) { return ` - query NFTByTokenId($contractAddress: String, $tokenId: String) { + query NFTByTokenId($contractAddress: String, $tokenId: BigInt) { nfts( where: { contractAddress: $contractAddress, tokenId: $tokenId } first: 1 @@ -340,7 +349,7 @@ export function getByTokenIdQuery( getFragment: () => string ) { return ` - query NFTByTokenId($tokenIds: [String!]) { + query NFTByTokenId($tokenIds: [BigInt!]) { nfts( where: { id_in: $tokenIds } first: 1000 @@ -357,7 +366,11 @@ export function getId(contractAddress: string, tokenId: string) { } export function getFuzzySearchQueryForENS(schema: string, searchTerm: string) { - return SQL`SELECT id from ` - .append(schema) - .append(SQL`.ens_active WHERE subdomain % ${searchTerm}`) + const query = + SQL`SELECT subdomain, id, similarity(subdomain, ${searchTerm}) AS match_similarity from ` + .append(schema) + .append( + SQL`.ens_active WHERE subdomain % ${searchTerm} ORDER BY match_similarity DESC;` + ) + return query } diff --git a/src/ports/prices/component.ts b/src/ports/prices/component.ts index b44273ba..4d70c2db 100644 --- a/src/ports/prices/component.ts +++ b/src/ports/prices/component.ts @@ -41,7 +41,6 @@ export function createPricesComponent(options: { let lastId = '' let priceFragments: PriceFragment[] = [] while (true) { - const query = getPricesQuery(queryGetter, filters, lastId) const expiresAt = Date.now() const expiresAtSec = Math.trunc(expiresAt / 1000) const queryVariables = { @@ -50,6 +49,7 @@ export function createPricesComponent(options: { expiresAt: expiresAt.toString(), expiresAtSec: expiresAtSec.toString(), } + const query = getPricesQuery(queryGetter, queryVariables, lastId) const { prices: fragments } = await subgraph.query<{ prices: PriceFragment[] }>(query, queryVariables) diff --git a/src/ports/sales/utils.ts b/src/ports/sales/utils.ts index eb8e1974..e5bc0c1b 100644 --- a/src/ports/sales/utils.ts +++ b/src/ports/sales/utils.ts @@ -1,4 +1,4 @@ -import { ChainId, Sale, SaleFilters, SaleSortBy } from '@dcl/schemas' +import { ChainId, Network, Sale, SaleFilters, SaleSortBy } from '@dcl/schemas' import { AssetsNetworks } from '../../types' import { SaleFragment } from './types' @@ -10,7 +10,11 @@ export function fromSaleFragment( chainId: ChainId ): Sale { const sale: Sale = { - id: 'sale-' + network.toLowerCase() + '-' + fragment.id, + id: + // squid fragments will already have the network as part of the id + fragment.id.includes(Network.ETHEREUM) || fragment.id.includes('POLYGON') + ? `sale-${fragment.id.toLowerCase()}` + : 'sale-' + network.toLowerCase() + '-' + fragment.id, type: fragment.type, buyer: fragment.buyer, seller: fragment.seller, diff --git a/src/ports/stats/utils.ts b/src/ports/stats/utils.ts index b3691fc7..bfcf8619 100644 --- a/src/ports/stats/utils.ts +++ b/src/ports/stats/utils.ts @@ -43,8 +43,12 @@ export function getEstatesSizesQuery(filters: StatsEstateFilters) { ]` } + const variables = wrapWhere + ? `$lastId: String, $expiresAt: BigInt, $expiresAtSec: BigInt` + : `$lastId: String` + return ` - query EstateSizesQuery($lastId: ID, $expiresAt: String, $expiresAtSec: String) { + query EstateSizesQuery(${variables}) { nfts ( first: ${MAX_RESULTS}, where: {