Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: fix unified markets query to include proper owner count #276

Merged
merged 3 commits into from
May 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion src/adapters/handlers/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@ export const getItemsParams = (params: Params) => {
category: params.getValue<NFTCategory>('category', NFTCategory),
creator: params.getList('creator'),
isSoldOut: params.getBoolean('isSoldOut'),
isOnSale: params.getBoolean('isOnSale'),
isOnSale: params.getBoolean('isOnSale')
? params.getString('isOnSale') === 'true'
: undefined,
search: params.getString('search'),
isWearableHead: params.getBoolean('isWearableHead'),
isWearableAccessory: params.getBoolean('isWearableAccessory'),
Expand Down
44 changes: 27 additions & 17 deletions src/ports/catalog/queries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export const getLatestSubgraphSchema = (subgraphName: string) =>
`

export function getOrderBy(filters: CatalogFilters) {
const { sortBy, sortDirection, onlyListing, isOnSale } = filters
const { sortBy, sortDirection, isOnSale } = filters
const sortByParam = sortBy ?? CatalogSortBy.NEWEST
const sortDirectionParam = sortDirection ?? CatalogSortDirection.DESC

Expand All @@ -51,13 +51,13 @@ export function getOrderBy(filters: CatalogFilters) {
sortByQuery = `ORDER BY max_price desc \n`
break
case CatalogSortBy.RECENTLY_LISTED:
sortByQuery = onlyListing ? `ORDER BY max_order_created_at desc \n` : ``
sortByQuery = `ORDER BY GREATEST(max_order_created_at, first_listed_at) desc \n`
break
case CatalogSortBy.RECENTLY_SOLD:
sortByQuery = `ORDER BY sold_at desc \n`
break
case CatalogSortBy.CHEAPEST:
sortByQuery = `ORDER BY min_price asc \n`
sortByQuery = `ORDER BY min_price asc, first_listed_at desc \n`
break
}

Expand Down Expand Up @@ -138,8 +138,10 @@ export const getIsSoldOutWhere = () => {
return SQL`items.available = 0`
}

export const getIsOnSale = () => {
return SQL`((search_is_store_minter = true AND available > 0) OR listings_count > 0)`
export const getIsOnSale = (filters: CatalogFilters) => {
return filters.isOnSale
? SQL`((search_is_store_minter = true AND available > 0) OR listings_count IS NOT NULL)`
: SQL`((search_is_store_minter = false OR available = 0) AND listings_count IS NULL)`
}

export const getisWearableHeadAccessoryWhere = () => {
Expand Down Expand Up @@ -200,7 +202,7 @@ export const getCollectionsQueryWhere = (filters: CatalogFilters) => {
filters.rarities?.length ? getRaritiesWhere(filters) : undefined,
filters.creator?.length ? getCreatorWhere(filters) : undefined,
filters.isSoldOut ? getIsSoldOutWhere() : undefined,
filters.isOnSale ? getIsOnSale() : undefined,
filters.isOnSale !== undefined ? getIsOnSale(filters) : undefined,
filters.search ? getSearchWhere(filters) : undefined,
filters.isWearableHead ? getisWearableHeadAccessoryWhere() : undefined,
filters.isWearableAccessory ? getWearableAccessoryWhere() : undefined,
Expand Down Expand Up @@ -269,23 +271,31 @@ export const getCollectionsItemsCatalogQuery = (
items.sold_at,
${filters.network} as network,
items.first_listed_at,
nfts.min_price AS min_listing_price,
nfts.max_price AS max_listing_price,
nfts.listings_count as listings_count,
nfts.owners_count as owners_count,
nfts.max_order_created_at as max_order_created_at,
nfts_with_orders.min_price AS min_listing_price,
nfts_with_orders.max_price AS max_listing_price,
COALESCE(nfts_with_orders.listings_count,0) as listings_count,
nfts.owners_count,
nfts_with_orders.max_order_created_at as max_order_created_at,
CASE
WHEN items.available > 0 AND items.search_is_store_minter = true THEN LEAST(items.price, nfts.min_price)
ELSE nfts.min_price
WHEN items.available > 0 AND items.search_is_store_minter = true THEN LEAST(items.price, nfts_with_orders.min_price)
ELSE nfts_with_orders.min_price
END AS min_price,
CASE
WHEN available > 0 AND items.search_is_store_minter = true THEN GREATEST(items.price, nfts.max_price)
ELSE nfts.max_price END
WHEN available > 0 AND items.search_is_store_minter = true THEN GREATEST(items.price, nfts_with_orders.max_price)
ELSE nfts_with_orders.max_price END
AS max_price
FROM `
.append(schemaVersion)
.append(
`.item_active AS items
`.item_active AS items
LEFT JOIN (
SELECT item, COUNT(distinct owner) as owners_count FROM `
)
.append(schemaVersion)
.append(
`.nft_active as nfts GROUP BY nfts.item
) AS nfts ON nfts.item = items.id

LEFT JOIN (
SELECT
nft.item,
Expand Down Expand Up @@ -314,7 +324,7 @@ export const getCollectionsItemsCatalogQuery = (
`
AND to_timestamp(orders.expires_at / 100.0) > now()
GROUP BY nft.item
) AS nfts ON nfts.item = items.id
) AS nfts_with_orders ON nfts_with_orders.item = items.id
LEFT JOIN (
SELECT
metadata.id,
Expand Down
37 changes: 2 additions & 35 deletions src/ports/catalog/utils.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import SQL, { SQLStatement } from 'sql-template-strings'
import SQL from 'sql-template-strings'
import {
NFTCategory,
Item,
Expand All @@ -10,8 +10,6 @@ import {
ChainId,
CatalogFilters,
CatalogItem,
CatalogSortBy,
CatalogSortDirection,
} from '@dcl/schemas'
import {
getCollectionsChainId,
Expand All @@ -34,37 +32,6 @@ export const getSubgraphNameForNetwork = (
}`
}

export function getOrderBy(
sortBy: CatalogSortBy | null,
sortDirection: CatalogSortDirection | null
) {
const sortByParam = sortBy ?? CatalogSortBy.NEWEST
const sortDirectionParam = sortDirection ?? CatalogSortDirection.ASC

let sortByQuery:
| SQLStatement
| string = `ORDER BY created_at ${sortDirectionParam}\n`
switch (sortByParam) {
case CatalogSortBy.NEWEST:
sortByQuery = `ORDER BY created_at ${sortDirectionParam}\n`
break
case CatalogSortBy.MOST_EXPENSIVE:
sortByQuery = `ORDER BY max_price ${sortDirectionParam}\n`
break
case CatalogSortBy.RECENTLY_LISTED:
sortByQuery = `ORDER BY created_at ${sortDirectionParam}\n`
break
case CatalogSortBy.RECENTLY_SOLD:
sortByQuery = `ORDER BY sold_at ${sortDirectionParam}\n`
break
case CatalogSortBy.CHEAPEST:
sortByQuery = `ORDER BY min_price ${sortDirectionParam}\n`
break
}

return sortByQuery
}

const getMultiNetworkQuery = (
schemas: Record<string, string>,
filters: CatalogQueryFilters
Expand All @@ -85,8 +52,8 @@ const getMultiNetworkQuery = (
unionQuery.append(SQL`\n UNION ALL \n`)
}
})
addQuerySort(unionQuery, filters)
unionQuery.append(SQL`\n) as temp \n`)
addQuerySort(unionQuery, filters)
if (limit !== undefined && offset !== undefined) {
unionQuery.append(SQL`LIMIT ${limit} OFFSET ${offset}`)
}
Expand Down
2 changes: 1 addition & 1 deletion src/tests/adapters/handlers/utils.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ describe('getItemsParams', () => {
emoteCategory: undefined,
emoteGenders: [],
emotePlayMode: [],
isOnSale: false,
isOnSale: undefined,
isSoldOut: false,
isWearableAccessory: false,
isWearableHead: false,
Expand Down
56 changes: 32 additions & 24 deletions src/tests/ports/catalog-queries.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,16 +111,31 @@ test('catalog utils', function () {

describe('and passing the "isOnSale" filter', () => {
let isOnSale: boolean
beforeEach(() => {
isOnSale = true
filters = {
isOnSale,
}
describe('and is set to "true"', () => {
beforeEach(() => {
isOnSale = true
filters = {
isOnSale,
}
})
it('should add the is on sale definition to the WHERE', () => {
expect(getCollectionsQueryWhere(filters).text).toContain(
`((search_is_store_minter = true AND available > 0) OR listings_count IS NOT NULL)`
)
})
})
it('should add the is on sale definition to the WHERE', () => {
expect(getCollectionsQueryWhere(filters).text).toContain(
`((search_is_store_minter = true AND available > 0) OR listings_count > 0)`
)
describe('and is set to "false"', () => {
beforeEach(() => {
isOnSale = false
filters = {
isOnSale,
}
})
it('should add the is on sale definition to the WHERE', () => {
expect(getCollectionsQueryWhere(filters).text).toContain(
`items.search_is_collection_approved = true AND ((search_is_store_minter = false OR available = 0) AND listings_count IS NULL)`
)
})
})
})

Expand Down Expand Up @@ -331,20 +346,11 @@ test('catalog utils', function () {
beforeEach(() => {
sortBy = CatalogSortBy.RECENTLY_LISTED
})
describe('and the onlyListing filter is ON', () => {
beforeEach(() => {
onlyListing = true
})
it('should ORDER BY created_at field', () => {
expect(getOrderBy({ sortBy, onlyListing })).toContain(
`ORDER BY max_order_created_at desc`
)
})
})
describe('and the onlyListing filter is ON', () => {
it('should not ORDER BY any field since the combination is not valid', () => {
expect(getOrderBy({ sortBy })).toBe('')
})

it('should ORDER BY created_at field', () => {
expect(getOrderBy({ sortBy, onlyListing })).toContain(
`ORDER BY GREATEST(max_order_created_at, first_listed_at) desc`
)
})
})
describe('when sorting by RECENTLY_SOLD', () => {
Expand All @@ -360,7 +366,9 @@ test('catalog utils', function () {
sortBy = CatalogSortBy.CHEAPEST
})
it('should ORDER BY min_price field', () => {
expect(getOrderBy({ sortBy })).toContain(`ORDER BY min_price asc`)
expect(getOrderBy({ sortBy })).toContain(
`ORDER BY min_price asc, first_listed_at desc`
)
})
})
})
Expand Down