diff --git a/app/Http/Controllers/CollectionController.php b/app/Http/Controllers/CollectionController.php index 5b55f9bd7..04ae98259 100644 --- a/app/Http/Controllers/CollectionController.php +++ b/app/Http/Controllers/CollectionController.php @@ -149,9 +149,15 @@ private function getPopularCollections(Request $request): Paginator $currency = $user ? $user->currency() : CurrencyCode::USD; + $volumeColumn = match ($request->query('period')) { + '7d' => 'avg_volume_7d', + '30d' => 'avg_volume_30d', + default => 'avg_volume_1d', + }; + /** @var Paginator $collections */ $collections = Collection::query() - ->when($request->query('sort') !== 'floor-price', fn ($q) => $q->orderBy('volume', 'desc')) // TODO: order by top... + ->when($request->query('sort') !== 'floor-price', fn ($q) => $q->orderByWithNulls($volumeColumn.'::numeric', 'desc')) ->filterByChainId($chainId) ->orderByFloorPrice('desc', $currency) ->with([ diff --git a/app/Models/Collection.php b/app/Models/Collection.php index 11aacedca..1be14691e 100644 --- a/app/Models/Collection.php +++ b/app/Models/Collection.php @@ -235,8 +235,6 @@ public function scopeErc721(Builder $query): Builder */ public function scopeOrderByValue(Builder $query, ?Wallet $wallet, ?string $direction, ?CurrencyCode $currency = CurrencyCode::USD): Builder { - $nullsPosition = strtolower($direction) === 'asc' ? 'NULLS FIRST' : 'NULLS LAST'; - $walletFilter = $wallet ? "WHERE nfts.wallet_id = $wallet->id" : ''; return $query->selectRaw( @@ -251,7 +249,7 @@ public function scopeOrderByValue(Builder $query, ?Wallet $wallet, ?string $dire GROUP BY collection_id ) nc"), 'collections.id', '=', 'nc.collection_id') ->groupBy('collections.id') - ->orderByRaw("total_value {$direction} {$nullsPosition}") + ->orderByWithNulls('total_value', $direction) ->orderBy('collections.id', $direction); } @@ -262,11 +260,9 @@ public function scopeOrderByValue(Builder $query, ?Wallet $wallet, ?string $dire */ public function scopeOrderByFloorPrice(Builder $query, string $direction, CurrencyCode $currency = CurrencyCode::USD): Builder { - $nullsPosition = $direction === 'asc' ? 'NULLS FIRST' : 'NULLS LAST'; - return $query->selectRaw( sprintf('collections.*, CAST(collections.fiat_value->>\'%s\' AS float) as total_floor_price', $currency->value) - )->orderByRaw("total_floor_price {$direction} {$nullsPosition}"); + )->orderByWithNulls('total_floor_price', $direction); } /** @@ -276,9 +272,7 @@ public function scopeOrderByFloorPrice(Builder $query, string $direction, Curren */ public function scopeOrderByName(Builder $query, string $direction): Builder { - $nullsPosition = $direction === 'asc' ? 'NULLS FIRST' : 'NULLS LAST'; - - return $query->orderByRaw("lower(collections.name) {$direction} {$nullsPosition}"); + return $query->orderByWithNulls('lower(collections.name)', $direction); } /** @@ -288,11 +282,7 @@ public function scopeOrderByName(Builder $query, string $direction): Builder */ public function scopeOrderByMintDate(Builder $query, string $direction): Builder { - if ($direction === 'asc') { - return $query->orderByRaw('minted_at ASC NULLS FIRST'); - } - - return $query->orderByRaw('minted_at DESC NULLS LAST'); + return $query->orderByWithNulls('minted_at', $direction); } /** @@ -314,11 +304,7 @@ public function scopeOrderByReceivedDate(Builder $query, Wallet $wallet, string ->addSelect(DB::raw('MAX(nft_activity.timestamp) as received_at')) ->groupBy('collections.id'); - if ($direction === 'asc') { - return $query->orderByRaw('received_at ASC NULLS FIRST'); - } - - return $query->orderByRaw('received_at DESC NULLS LAST'); + return $query->orderByWithNulls('received_at', $direction); } /** @@ -581,7 +567,7 @@ public function isBlacklisted(): bool */ public function scopeOrderByOldestNftLastFetchedAt(Builder $query): Builder { - return $query->orderByRaw('extra_attributes->>\'nft_last_fetched_at\' ASC NULLS FIRST'); + return $query->orderByWithNulls('extra_attributes->>\'nft_last_fetched_at\'', 'asc'); } /** @@ -590,7 +576,7 @@ public function scopeOrderByOldestNftLastFetchedAt(Builder $query): Builder */ public function scopeOrderByFloorPriceLastFetchedAt(Builder $query): Builder { - return $query->orderByRaw('extra_attributes->>\'floor_price_last_fetched_at\' ASC NULLS FIRST'); + return $query->orderByWithNulls('extra_attributes->>\'floor_price_last_fetched_at\'', 'asc'); } /** @@ -599,7 +585,7 @@ public function scopeOrderByFloorPriceLastFetchedAt(Builder $query): Builder */ public function scopeOrderByOpenseaSlugLastFetchedAt(Builder $query): Builder { - return $query->orderByRaw('extra_attributes->>\'opensea_slug_last_fetched_at\' ASC NULLS FIRST'); + return $query->orderByWithNulls('extra_attributes->>\'opensea_slug_last_fetched_at\'', 'asc'); } public function isSpam(): bool @@ -731,4 +717,21 @@ public function averageVolumeSince(Carbon $date): string ->where('created_at', '>', $date) ->value('aggregate'); } + + /** + * Modify the query to apply ORDER BY, but with respect to NULL values. + * If direction is ascending, the query will order NULL values first, + * otherwise it will order NULL values last. + * + * @param Builder $query + * @return Builder + */ + public function scopeOrderByWithNulls(Builder $query, string $column, string $direction): Builder + { + $nullsPosition = strtolower($direction) === 'asc' + ? 'NULLS FIRST' + : 'NULLS LAST'; + + return $query->orderByRaw("{$column} {$direction} {$nullsPosition}"); + } }