Skip to content

Commit b7f57e7

Browse files
committed
Working tests for sorting strategies.
1 parent add3072 commit b7f57e7

18 files changed

Lines changed: 471 additions & 42 deletions

.env.testing

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
APP_NAME="Computer Science Resources"
2+
APP_ENV=testing
3+
APP_KEY=base64:7aYe15aBsSh6a2ScVwj1JfYjQKUmz9Z5X/GSe64joHA=
4+
APP_DEBUG=true
5+
APP_TIMEZONE=UTC
6+
APP_URL=http://localhost
7+
8+
APP_LOCALE=en
9+
APP_FALLBACK_LOCALE=en
10+
APP_FAKER_LOCALE=en_US
11+
12+
APP_MAINTENANCE_DRIVER=file
13+
# APP_MAINTENANCE_STORE=database
14+
15+
PHP_CLI_SERVER_WORKERS=4
16+
17+
BCRYPT_ROUNDS=12
18+
19+
LOG_CHANNEL=stack
20+
LOG_STACK=single
21+
LOG_DEPRECATIONS_CHANNEL=null
22+
LOG_LEVEL=debug
23+
24+
DB_CONNECTION=mysql
25+
DB_HOST=mysql
26+
DB_PORT=3306
27+
DB_DATABASE=computer_science_resources_testing
28+
DB_USERNAME=root
29+
DB_PASSWORD=password
30+
31+
SESSION_DRIVER=database
32+
SESSION_LIFETIME=120
33+
SESSION_ENCRYPT=false
34+
SESSION_PATH=/
35+
SESSION_DOMAIN=null
36+
37+
GITHUB_CLIENT_ID=Ov23liEEEW7WLTpaC688
38+
GITHUB_CLIENT_SECRET=5a60158c32fc6ef2b6ac8d9771012a6ac4440eba
39+
40+
BROADCAST_CONNECTION=log
41+
FILESYSTEM_DISK=local
42+
QUEUE_CONNECTION=database
43+
44+
CACHE_STORE=database
45+
CACHE_PREFIX=
46+
47+
MEMCACHED_HOST=127.0.0.1
48+
49+
REDIS_CLIENT=phpredis
50+
REDIS_HOST=127.0.0.1
51+
REDIS_PASSWORD=null
52+
REDIS_PORT=6379
53+
54+
MAIL_MAILER=smtp
55+
MAIL_HOST=mailpit
56+
MAIL_PORT=1025
57+
MAIL_USERNAME=null
58+
MAIL_PASSWORD=null
59+
MAIL_ENCRYPTION=null
60+
MAIL_FROM_ADDRESS="hello@example.com"
61+
MAIL_FROM_NAME="${APP_NAME}"
62+
63+
AWS_ACCESS_KEY_ID=
64+
AWS_SECRET_ACCESS_KEY=
65+
AWS_DEFAULT_REGION=us-east-1
66+
AWS_BUCKET=
67+
AWS_USE_PATH_STYLE_ENDPOINT=false
68+
69+
VITE_APP_NAME="${APP_NAME}"
70+
71+
SAIL_XDEBUG_MODE=develop,debug,coverage
72+
SSAIL_XDEBUG_CONFIG="discover_client_host=1 client_port=9003"
73+

app/Http/Controllers/ComputerScienceResourceController.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -144,13 +144,13 @@ public function index(Request $request)
144144

145145
// Filter by reviews
146146
$ratingFilters = [
147-
'community_rating',
147+
'community',
148148
'teaching_clarity',
149149
'engagement',
150150
'practicality',
151151
'user_friendliness',
152152
'updates',
153-
'overall_rating',
153+
'overall',
154154
];
155155

156156
foreach ($ratingFilters as $field) {
@@ -180,7 +180,7 @@ public function index(Request $request)
180180
/// Handle Sorting
181181
$sortBy = $request->query('sort_by', 'top');
182182
$query = $this->resourceSortingManager->applySort($query, $sortBy);
183-
if ($request->query('reverse', '0') == '1') {
183+
if ($request->query('reverse', 'false') == 'true') {
184184
$query = $this->resourceSortingManager->reverse($query);
185185
}
186186

app/Models/ResourceReview.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ class ResourceReview extends Model
1414
use HasFactory;
1515
use HasVotes;
1616
use HasComments;
17-
17+
1818
protected $guarded = [];
1919

2020
protected $with = ['votes', 'upvoteSummary', 'commentsCountRelationship'];

app/Models/UpvoteSummary.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,12 @@
44

55
use Illuminate\Database\Eloquent\Casts\Attribute;
66
use Illuminate\Database\Eloquent\Model;
7+
use Illuminate\Database\Eloquent\Factories\HasFactory;
78

89
class UpvoteSummary extends Model
910
{
11+
use HasFactory;
12+
1013
public $timestamps = false;
1114
protected $fillable = ['upvotable_id', 'upvotable_type'];
1215

app/SortingStrategies/ResourceReviewsSortingStrategy.php

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,12 @@ public static function supports(string $sortBy): bool
1818
public static function apply(Builder $query, string $sortBy): Builder
1919
{
2020
$instance = new self();
21+
$resourceTable = $query->getModel()->getTable();
2122
$query = $instance->ensureReviewSummaryJoined($query);
2223
$reviewTable = $instance->getReviewSummaryTable();
2324

24-
return $query->orderByRaw(
25-
"{$reviewTable}.{$sortBy} / NULLIF({$reviewTable}.review_count, 1) DESC"
26-
);
25+
return $query
26+
->orderByDesc("{$reviewTable}.{$sortBy}_rating")
27+
->addSelect("{$resourceTable}.*");
2728
}
2829
}

app/SortingStrategies/VoteSortingStrategy.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ public static function apply(Builder $query, string $sortBy): Builder
3333
break;
3434

3535
case 'controversial':
36-
$query->orderBy('upvote_summaries.controversy', 'ASC');
36+
$query->orderBy('upvote_summaries.controversy', 'DESC');
3737
break;
3838

3939
case 'total_votes':

app/Traits/HandlesResourceReviewJoins.php

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,12 @@ trait HandlesResourceReviewJoins
1010
protected function ensureReviewSummaryJoined(Builder $query): Builder
1111
{
1212
$reviewTable = (new ResourceReviewSummary())->getTable();
13+
1314
$joins = $query->getQuery()->joins ?? [];
1415

15-
$already = collect($joins)->pluck('table')->contains($reviewTable);
16+
$already = collect($joins)->contains(function ($join) use ($reviewTable) {
17+
return $join->table === $reviewTable;
18+
});
1619

1720
if (! $already) {
1821
$resourceTable = $query->getModel()->getTable();
@@ -21,7 +24,7 @@ protected function ensureReviewSummaryJoined(Builder $query): Builder
2124
"{$reviewTable}.computer_science_resource_id",
2225
'=',
2326
"{$resourceTable}.id"
24-
)->select("{$resourceTable}.*");
27+
);
2528
}
2629

2730
return $query;
@@ -41,7 +44,7 @@ protected function getAllowedReviewFields(): array
4144
'practicality',
4245
'user_friendliness',
4346
'updates',
44-
'overall_rating',
47+
'overall',
4548
];
4649
}
4750
}

config/database.php

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -30,18 +30,6 @@
3030
*/
3131

3232
'connections' => [
33-
34-
'sqlite' => [
35-
'driver' => 'sqlite',
36-
'url' => env('DB_URL'),
37-
'database' => env('DB_DATABASE', database_path('database.sqlite')),
38-
'prefix' => '',
39-
'foreign_key_constraints' => env('DB_FOREIGN_KEYS', true),
40-
'busy_timeout' => null,
41-
'journal_mode' => null,
42-
'synchronous' => null,
43-
],
44-
4533
'mysql' => [
4634
'driver' => 'mysql',
4735
'url' => env('DB_URL'),
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<?php
2+
3+
namespace Database\Factories;
4+
5+
use App\Models\UpvoteSummary;
6+
use Illuminate\Database\Eloquent\Factories\Factory;
7+
use Illuminate\Database\Eloquent\Model;
8+
9+
class UpvoteSummaryFactory extends Factory
10+
{
11+
protected $model = UpvoteSummary::class;
12+
13+
public function definition(): array
14+
{
15+
$upvotes = $this->faker->numberBetween(0, 100);
16+
$downvotes = $this->faker->numberBetween(0, 100);
17+
18+
return [
19+
'upvotes' => $upvotes,
20+
'downvotes' => $downvotes,
21+
];
22+
}
23+
24+
/**
25+
* Link the summary to a given upvotable model.
26+
*/
27+
public function forUpvotable(Model $model): static
28+
{
29+
return $this->state([
30+
'upvotable_id' => $model->getKey(),
31+
'upvotable_type' => $model::class,
32+
]);
33+
}
34+
}

database/migrations/2025_02_18_225525_create_resource_review_summaries_table.php

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,37 @@ public function up(): void
2323
$table->bigInteger('user_friendliness')->default(0);
2424
$table->bigInteger('updates')->default(0);
2525

26+
$table->decimal('community_rating')->storedAs("
27+
CASE WHEN review_count = 0 THEN 0 ELSE community / review_count END
28+
")->index();
29+
30+
$table->decimal('teaching_clarity_rating')->storedAs("
31+
CASE WHEN review_count = 0 THEN 0 ELSE teaching_clarity / review_count END
32+
")->index();
33+
34+
$table->decimal('engagement_rating')->storedAs("
35+
CASE WHEN review_count = 0 THEN 0 ELSE engagement / review_count END
36+
")->index();
37+
38+
$table->decimal('practicality_rating')->storedAs("
39+
CASE WHEN review_count = 0 THEN 0 ELSE practicality / review_count END
40+
")->index();
41+
42+
$table->decimal('user_friendliness_rating')->storedAs("
43+
CASE WHEN review_count = 0 THEN 0 ELSE user_friendliness / review_count END
44+
")->index();
45+
46+
$table->decimal('updates_rating')->storedAs("
47+
CASE WHEN review_count = 0 THEN 0 ELSE updates / review_count END
48+
")->index();
49+
2650
$table->decimal('overall_rating')
27-
->storedAs('(community + teaching_clarity + engagement + practicality
28-
+ user_friendliness + updates) / 6')
51+
->storedAs('(community_rating +
52+
teaching_clarity_rating +
53+
engagement_rating +
54+
practicality_rating +
55+
user_friendliness_rating +
56+
updates_rating)/6')
2957
->index();
3058

3159
$table->integer('review_count')->default(0);

0 commit comments

Comments
 (0)