Skip to content

Commit

Permalink
feat: make graphql queries compatible with new Squid
Browse files Browse the repository at this point in the history
  • Loading branch information
juanmahidalgo committed Aug 5, 2024
1 parent d8e615c commit 2f1d431
Show file tree
Hide file tree
Showing 11 changed files with 151 additions and 75 deletions.
4 changes: 4 additions & 0 deletions src/adapters/handlers/nfts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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>(
'wearableCategory',
Expand Down
14 changes: 7 additions & 7 deletions src/adapters/handlers/prices.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ export function createPricesHandler(
const params = new Params(context.url.searchParams)
const category = params.getString('category') as PriceFilterCategory
const assetType = params.getString('assetType') as AssetType
const isWearableHead = params.getBoolean('isWearableHead')
const isWearableAccessory = params.getBoolean('isWearableAccessory')
const isWearableSmart = params.getBoolean('isWearableSmart')
const isWearableHead = params.getBooleanValue('isWearableHead')
const isWearableAccessory = params.getBooleanValue('isWearableAccessory')
const isWearableSmart = params.getBooleanValue('isWearableSmart')
const wearableCategory = params.getValue<WearableCategory>(
'wearableCategory',
WearableCategory
Expand All @@ -51,13 +51,13 @@ export function createPricesHandler(
const itemRarities = params.getList<Rarity>('itemRarity', Rarity)
const network = params.getValue<Network>('network', Network)

const adjacentToRoad = params.getBoolean('adjacentToRoad')
const adjacentToRoad = params.getBooleanValue('adjacentToRoad')
const minDistanceToPlaza = params.getNumber('minDistanceToPlaza')
const maxDistanceToPlaza = params.getNumber('maxDistanceToPlaza')
const maxEstateSize = params.getNumber('maxEstateSize')
const minEstateSize = params.getNumber('minEstateSize')
const emoteHasSound = params.getBoolean('emoteHasSound')
const emoteHasGeometry = params.getBoolean('emoteHasGeometry')
const emoteHasSound = params.getBooleanValue('emoteHasSound')
const emoteHasGeometry = params.getBooleanValue('emoteHasGeometry')

return asJSON(
async () => ({
Expand All @@ -81,7 +81,7 @@ export function createPricesHandler(
maxEstateSize,
minEstateSize,
emoteHasGeometry,
emoteHasSound
emoteHasSound,
}),
}),
{
Expand Down
5 changes: 5 additions & 0 deletions src/logic/http/params.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@ export class Params {
return value !== null
}

getBooleanValue(key: string) {
const value = this.params.get(key)
return value !== null ? value === 'true' : undefined
}

getValue<T extends string>(
key: string,
values: Values = {},
Expand Down
2 changes: 1 addition & 1 deletion src/logic/nfts/collections.ts
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ export function fromCollectionsFragment(
break
}
default: {
throw new Error(`Uknown itemType=${fragment.itemType}`)
throw new Error(`Unknown itemType=${fragment.itemType}`)
}
}

Expand Down
76 changes: 53 additions & 23 deletions src/logic/prices/collections.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,18 @@ import { AssetType, PriceFilters } from '../../ports/prices/types'

const MAX_RESULTS = 1000

const PRICES_ITEMS_FILTERS_DICT: Record<string, string> = {
wearableCategory: '$wearableCategory: String',
emoteCategory: '$emoteCategory: String',
isWearableHead: '$isWearableHead: Boolean',
isWearableAccessory: '$isWearableAccessory: Boolean',
}

const PRICES_FILTERS_DICT: Record<string, string> = {
expiresAt: '$expiresAt: BigInt',
...PRICES_ITEMS_FILTERS_DICT,
}

export function collectionsShouldFetch(filters: PriceFilters) {
const isCorrectNetworkFilter =
!filters.network || !!(filters.network && filters.network === Network.MATIC)
Expand Down Expand Up @@ -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,
Expand All @@ -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},
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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},
Expand Down
44 changes: 30 additions & 14 deletions src/logic/prices/marketplace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,14 @@ import {

const MAX_RESULTS = 1000

const PRICES_FILTERS_DICT: Record<string, string> = {
expiresAt: '$expiresAt: BigInt',
wearableCategory: '$wearableCategory: String',
emoteCategory: '$emoteCategory: String',
isWearableHead: '$isWearableHead: Boolean',
isWearableAccessory: '$isWearableAccessory: Boolean',
}

export function marketplaceShouldFetch(filters: PriceFilters) {
const isCorrectNetworkFilter =
!filters.network ||
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down
4 changes: 2 additions & 2 deletions src/ports/nfts/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ export type NFTResult = {
export type QueryVariables = Omit<NFTFilters, 'sortBy' | 'rentalDays'> & {
orderBy: string
orderDirection: 'asc' | 'desc'
expiresAt: string
expiresAtSec: string
expiresAt?: string
expiresAtSec?: string
}

export interface INFTsComponent {
Expand Down
61 changes: 37 additions & 24 deletions src/ports/nfts/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<string, string> = {
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}
Expand Down Expand Up @@ -46,14 +44,21 @@ export function getQueryVariables<T>(
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(),
}
}

Expand Down Expand Up @@ -208,7 +213,7 @@ export function getFetchQuery(
}

if (filters.owner) {
where.push('owner: $owner')
where.push('owner_: {address: $owner}')
}

if (
Expand Down Expand Up @@ -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(
Expand All @@ -312,18 +320,19 @@ export function getFetchQuery(
}
}`

return `
const result = `
${query}
${isCount ? '' : getNFTFragment()}
`
return result
}

export function getFetchOneQuery(
fragmentName: string,
getFragment: () => string
) {
return `
query NFTByTokenId($contractAddress: String, $tokenId: String) {
query NFTByTokenId($contractAddress: String, $tokenId: BigInt) {
nfts(
where: { contractAddress: $contractAddress, tokenId: $tokenId }
first: 1
Expand All @@ -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
Expand All @@ -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
}
2 changes: 1 addition & 1 deletion src/ports/prices/component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand All @@ -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)
Expand Down
Loading

0 comments on commit 2f1d431

Please sign in to comment.