Skip to content

Commit

Permalink
Merge pull request #194 from decentraland/fix/sales-and-bids-queries
Browse files Browse the repository at this point in the history
feat: fix bids and sales queries
  • Loading branch information
juanmahidalgo authored Dec 10, 2024
2 parents 614898b + 06f0022 commit 12ad595
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 190 deletions.
2 changes: 1 addition & 1 deletion src/ports/bids/queries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ export function getBidsQuery(options: GetBidsParameters) {

const FILTER_BY_BIDDER = options.bidder ? SQL` LOWER(bidder) = LOWER(${options.bidder}) ` : null
const FILTER_BY_SELLER = options.seller ? SQL` LOWER(seller) = LOWER(${options.seller}) ` : null
const FILTER_BY_CONTRACT_ADDRESS = options.contractAddress ? SQL` LOWER(contract_address) = LOWER(${options.contractAddress}) ` : null
const FILTER_BY_CONTRACT_ADDRESS = options.contractAddress ? SQL` contract_address = ${options.contractAddress.toLowerCase()} ` : null
const FILTER_BY_TOKEN_ID = options.tokenId ? SQL` LOWER(token_id) = LOWER(${options.tokenId}) ` : null
const FILTER_BY_ITEM_ID = options.itemId ? SQL` LOWER(item_id) = LOWER(${options.itemId}) ` : null
const FILTER_BY_NETWORK = options.network ? SQL` network = ANY (${getDBNetworks(options.network)}) ` : null
Expand Down
219 changes: 31 additions & 188 deletions src/ports/sales/queries.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import SQL, { SQLStatement } from 'sql-template-strings'
import { NFTCategory, SaleFilters, SaleSortBy, SaleType, TradeAssetType, TradeType } from '@dcl/schemas'
import { SaleFilters, SaleSortBy } from '@dcl/schemas'
import { getDBNetworks } from '../../utils'
import { ItemType } from '../items'
import { getWhereStatementFromFilters } from '../utils'

const DEFAULT_LIMIT = 100
Expand All @@ -24,7 +23,7 @@ function getSalesSortByStatement(sortBy?: SaleSortBy) {
}
}

function getLegacySalesQuery(filters: SaleFilters): SQLStatement {
function getLegacySalesQueryWhereStatement(filters: SaleFilters): SQLStatement {
const FILTER_BY_TYPE = filters.type ? SQL` type = ${filters.type} ` : null
const FILTER_BY_BUYER = filters.buyer ? SQL` buyer = ${filters.buyer} ` : null
const FILTER_BY_SELLER = filters.seller ? SQL` seller = ${filters.seller.toLowerCase()} ` : null
Expand All @@ -40,7 +39,7 @@ function getLegacySalesQuery(filters: SaleFilters): SQLStatement {
const FILTER_FROM_TIMESTAMP = filters.from ? SQL` (timestamp * 1000) >= ${filters.from} ` : null
const FILTER_TO_TIMESTAMP = filters.to ? SQL` (timestamp * 1000) <= ${filters.to} ` : null

const where = getWhereStatementFromFilters([
return getWhereStatementFromFilters([
FILTER_BY_TYPE,
FILTER_BY_BUYER,
FILTER_BY_SELLER,
Expand All @@ -54,7 +53,9 @@ function getLegacySalesQuery(filters: SaleFilters): SQLStatement {
FILTER_FROM_TIMESTAMP,
FILTER_TO_TIMESTAMP
])
}

function getLegacySalesQuery(filters: SaleFilters): SQLStatement {
return SQL`
SELECT
id,
Expand All @@ -71,202 +72,44 @@ function getLegacySalesQuery(filters: SaleFilters): SQLStatement {
search_category as category
FROM squid_marketplace.sale
`
.append(where)
.append(getLegacySalesQueryWhereStatement(filters))
.append(getSalesSortByStatement(filters.sortBy))
.append(getSalesLimitAndOffsetStatement(filters))
// .append(SQL` LIMIT ${filters.first} OFFSET ${filters.skip} `)
}

function getTradeSalesQuery(filters: SaleFilters): SQLStatement {
const FILTER_BY_TYPE = filters.type
? filters.type == SaleType.ORDER
? SQL` trade.type = '`.append(TradeType.PUBLIC_NFT_ORDER).append(SQL`'`)
: filters.type == SaleType.BID
? SQL` c'`.append(TradeType.PUBLIC_NFT_ORDER).append(SQL`'`)
: SQL` `
: null

const FILTER_BY_BUYER = filters.buyer ? SQL` trade_status.sent_beneficiary = ${filters.buyer} ` : null
const FILTER_BY_SELLER = filters.seller ? SQL` trade_status.received_beneficiary = ${filters.seller.toLowerCase()} ` : null
const HAVING_BY_CONTRACT_ADDRESS = filters.contractAddress
? SQL` (
array_agg(assets_with_values.contract_address) FILTER (
WHERE
assets_with_values.asset_type = '3'
OR assets_with_values.asset_type = '4'
)
) [1] = ${filters.contractAddress.toLowerCase()} `
: null
const HAVING_BY_ITEM_ID = filters.itemId
? SQL` (
array_agg(assets_with_values.item_id) FILTER (
WHERE
assets_with_values.item_id IS NOT NULL
)
) [1] = ${filters.itemId} `
: null
const HAVING_BY_TOKEN_ID = filters.tokenId
? SQL` (
array_agg(assets_with_values.token_id) FILTER (
WHERE
assets_with_values.token_id IS NOT NULL
)
) [1] = ${filters.tokenId} `
: null
const FILTER_BY_NETWORK = filters.network ? SQL` trade_status.network = ANY (${getDBNetworks(filters.network)}) ` : null
const HAVING_BY_MIN_PRICE = filters.minPrice
? SQL` (
array_agg(assets_with_values.amount) FILTER (
WHERE
assets_with_values.asset_type = '1'
)
) [1] >= ${filters.minPrice} `
: null
const HAVING_BY_MAX_PRICE = filters.maxPrice
? SQL` (
array_agg(assets_with_values.amount) FILTER (
WHERE
assets_with_values.asset_type = '1'
)
) [1] <= ${filters.maxPrice} `
: null
const HAVING_BY_CATEGORY =
filters.categories && filters.categories.length
? SQL` (
array_agg(assets_with_values.category) FILTER (
WHERE
assets_with_values.category IS NOT NULL
)
) [1] = ANY (${filters.categories}) `
: null
const FILTER_FROM_TIMESTAMP = filters.from ? SQL` trade_status.timestamp >= ${filters.from} ` : null
const FILTER_TO_TIMESTAMP = filters.to ? SQL` trade_status.timestamp <= ${filters.to} ` : null
const getNFTCTE = (filters: SaleFilters) => {
console.log('filters', filters)
const FILTER_BY_CONTRACT_ADDRESS = filters.contractAddress ? SQL` contract_address = ${filters.contractAddress.toLowerCase()} ` : null
const FILTER_BY_ITEM_ID = filters.itemId ? SQL` item_id = ${filters.itemId} ` : null
const FILTER_BY_TOKEN_ID = filters.tokenId ? SQL` token_id = ${filters.tokenId} ` : null
const FILTER_BY_NETWORK = filters.network ? SQL` network = ANY (${getDBNetworks(filters.network)}) ` : null
const FILTER_BY_CATEGORY = filters.categories && filters.categories.length ? SQL` category = ANY (${filters.categories}) ` : null

const where = getWhereStatementFromFilters([
SQL`trade_status.action = 'executed' AND trade.type != '`.append(TradeType.PUBLIC_ITEM_ORDER).append(SQL`'`),
FILTER_BY_TYPE,
FILTER_BY_BUYER,
FILTER_BY_SELLER,
FILTER_BY_CONTRACT_ADDRESS,
FILTER_BY_ITEM_ID,
FILTER_BY_TOKEN_ID,
FILTER_BY_NETWORK,
FILTER_FROM_TIMESTAMP,
FILTER_TO_TIMESTAMP
FILTER_BY_CATEGORY
])

const having = getWhereStatementFromFilters(
[HAVING_BY_CONTRACT_ADDRESS, HAVING_BY_ITEM_ID, HAVING_BY_TOKEN_ID, HAVING_BY_MIN_PRICE, HAVING_BY_MAX_PRICE, HAVING_BY_CATEGORY],
true
)

return SQL`
SELECT
trade_status.id as id,
CASE
WHEN trade.type = '`
.append(TradeType.PUBLIC_NFT_ORDER)
.append(SQL`' THEN '`)
.append(SaleType.ORDER)
.append(
SQL`'
ELSE '`
.append(SaleType.BID)
.append(
SQL`' END as type,
trade_status.received_beneficiary as seller,
trade_status.sent_beneficiary as buyer,
trade_status.timestamp,
trade_status.network,
trade_status.tx_hash,
(array_agg(assets_with_values.amount) FILTER (WHERE assets_with_values.asset_type = '`
.append(TradeAssetType.ERC20)
.append(
SQL`'))[1] as price,
(array_agg(assets_with_values.item_id) FILTER (WHERE assets_with_values.item_id IS NOT NULL))[1] as item_id,
(array_agg(assets_with_values.token_id) FILTER (WHERE assets_with_values.token_id IS NOT NULL))[1] as token_id,
(array_agg(assets_with_values.contract_address) FILTER (WHERE assets_with_values.asset_type = '`
.append(TradeAssetType.ERC721)
.append(
SQL`' OR assets_with_values.asset_type = '`.append(TradeAssetType.COLLECTION_ITEM).append(
SQL`'))[1] as contract_address,
(array_agg(assets_with_values.category) FILTER (WHERE assets_with_values.category IS NOT NULL))[1] as category
FROM squid_trades.trade as trade_status
JOIN marketplace.trades as trade ON trade_status.signature = trade.hashed_signature
JOIN (
SELECT
ta.trade_id,
ta.contract_address,
ta.direction,
ta.beneficiary,
ta.asset_type,
ta.extra,
erc721_asset.token_id,
coalesce(item_asset.item_id, nft.item_blockchain_id::text) as item_id,
erc20_asset.amount,
item.creator,
item.item_type,
account.address as owner,
CASE
WHEN item.item_type = '`
.append(ItemType.WEARABLE_V1)
.append(
SQL`' THEN '`.append(NFTCategory.WEARABLE).append(
SQL`'
WHEN item.item_type = '`
.append(ItemType.WEARABLE_V2)
.append(
SQL`' THEN '`.append(NFTCategory.WEARABLE).append(
SQL`'
WHEN item.item_type = '`
.append(ItemType.SMART_WEARABLE_V1)
.append(
SQL`' THEN '`.append(NFTCategory.WEARABLE).append(
SQL`'
WHEN item.item_type = '`
.append(ItemType.EMOTE_V1)
.append(
SQL`' THEN '`.append(NFTCategory.EMOTE).append(
SQL`'
ELSE nft.category
END as category,
nft.id as nft_id,
nft.issued_id as issued_id,
nft.name as nft_name
FROM marketplace.trade_assets as ta
LEFT JOIN marketplace.trade_assets_erc721 as erc721_asset ON ta.id = erc721_asset.asset_id
LEFT JOIN marketplace.trade_assets_erc20 as erc20_asset ON ta.id = erc20_asset.asset_id
LEFT JOIN marketplace.trade_assets_item as item_asset ON ta.id = item_asset.asset_id
LEFT JOIN squid_marketplace.item as item ON (ta.contract_address = item.collection_id AND item_asset.item_id = item.blockchain_id::text)
LEFT JOIN squid_marketplace.nft as nft ON (ta.contract_address = nft.contract_address AND erc721_asset.token_id = nft.token_id::text)
LEFT JOIN squid_marketplace.account as account ON (account.id = nft.owner_id)
) as assets_with_values ON trade.id = assets_with_values.trade_id
`
.append(where)
.append(
SQL` GROUP BY trade_status.id, trade_status.timestamp, trade_status.network, trade_status.tx_hash, trade_status.sent_beneficiary, trade_status.received_beneficiary, trade.type `
)
.append(having)
)
)
)
)
)
)
)
)
)
)
)
)
)
WITH filtered_nfts AS (
SELECT *
FROM squid_marketplace.nft
`.append(where).append(SQL`
)
`)
}

export function getSalesQuery(filters: SaleFilters = {}) {
const LEGACY_SALES = SQL`(`.append(getLegacySalesQuery(filters)).append(SQL` ) as legacy_sales `)
const TRADE_SALES = SQL`(`.append(getTradeSalesQuery(filters)).append(SQL` ) as trade_sales `)

return SQL`SELECT *, COUNT(*) OVER() as count`
.append(SQL` FROM `)
.append(LEGACY_SALES)
.append(SQL` NATURAL FULL OUTER JOIN `)
.append(TRADE_SALES)
.append(getSalesSortByStatement(filters.sortBy))
.append(getSalesLimitAndOffsetStatement(filters))
return getNFTCTE(filters).append(
SQL`SELECT *, COUNT(*) OVER() as count`
.append(SQL` FROM `)
.append(LEGACY_SALES)
.append(getSalesSortByStatement(filters.sortBy))
.append(getSalesLimitAndOffsetStatement(filters))
)
}
2 changes: 1 addition & 1 deletion test/unit/bids-queries.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ describe('when querying for bids', () => {
describe('and the contract address filter is defined', () => {
it('should add the filter to the query', () => {
const query = getBidsQuery({ contractAddress: '0x123', offset: 1, limit: 1 })
expect(query.text).toContain('LOWER(contract_address) = LOWER($1)')
expect(query.text).toContain('contract_address = $1')
expect(query.values).toEqual(expect.arrayContaining(['0x123']))
})
})
Expand Down

0 comments on commit 12ad595

Please sign in to comment.