Skip to content

Commit 2b36cb3

Browse files
authored
Add PostgreSQL support with tests (#534)
- adds mysql8 and pgsql16 & pgsql17 tests - additional tests for slugs and order_column - adds explicit orderBy to getTypes in Tag.php
1 parent 85e662b commit 2b36cb3

File tree

6 files changed

+112
-18
lines changed

6 files changed

+112
-18
lines changed

.github/workflows/run-tests.yml

Lines changed: 47 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,12 @@ jobs:
88
test:
99
runs-on: ${{ matrix.os }}
1010
strategy:
11+
fail-fast: false
1112
matrix:
1213
php: [8.1, 8.2, 8.3, 8.4]
1314
laravel: [12.*, 11.*, 10.*]
1415
dependency-version: [prefer-lowest, prefer-stable]
16+
database: [mysql57, mysql8, pgsql16, pgsql17]
1517
os: [ubuntu-latest]
1618
include:
1719
- laravel: 12.*
@@ -21,21 +23,54 @@ jobs:
2123
- laravel: 10.*
2224
testbench: 8.*
2325
exclude:
24-
- laravel: 11.*
25-
php: 8.1
26+
- php: 8.4
27+
laravel: 10.*
28+
- php: 8.1
29+
laravel: 11.*
30+
- php: 8.1
31+
laravel: 12.*
2632

27-
name: P${{ matrix.php }} - L${{ matrix.laravel }} - ${{ matrix.dependency-version }} - ${{ matrix.os }}
33+
name: P${{ matrix.php }} - L${{ matrix.laravel }} - ${{ matrix.database }} - ${{ matrix.dependency-version }} - ${{ matrix.os }}
2834

2935
services:
30-
mysql:
36+
mysql57:
3137
image: mysql:5.7
3238
env:
3339
MYSQL_ALLOW_EMPTY_PASSWORD: yes
3440
MYSQL_DATABASE: laravel_tags
3541
ports:
36-
- 3306
42+
- 3306:3306
43+
options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3
44+
45+
mysql8:
46+
image: mysql:8.0
47+
env:
48+
MYSQL_ALLOW_EMPTY_PASSWORD: yes
49+
MYSQL_DATABASE: laravel_tags
50+
ports:
51+
- 3307:3306
3752
options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3
3853

54+
pgsql16:
55+
image: postgres:16
56+
env:
57+
POSTGRES_DB: laravel_tags
58+
POSTGRES_USER: postgres
59+
POSTGRES_PASSWORD: postgres
60+
ports:
61+
- 5432:5432
62+
options: --health-cmd=pg_isready --health-interval=10s --health-timeout=5s --health-retries=3
63+
64+
pgsql17:
65+
image: postgres:17
66+
env:
67+
POSTGRES_DB: laravel_tags
68+
POSTGRES_USER: postgres
69+
POSTGRES_PASSWORD: postgres
70+
ports:
71+
- 5433:5432
72+
options: --health-cmd=pg_isready --health-interval=10s --health-timeout=5s --health-retries=3
73+
3974
steps:
4075
- name: Checkout code
4176
uses: actions/checkout@v4
@@ -44,7 +79,7 @@ jobs:
4479
uses: shivammathur/setup-php@v2
4580
with:
4681
php-version: ${{ matrix.php }}
47-
extensions: dom, curl, libxml, mbstring, zip, pcntl, pdo, sqlite, pdo_sqlite, mysql, mysqli, pdo_mysql, bcmath, soap, intl, gd, exif, iconv, imagick
82+
extensions: dom, curl, libxml, mbstring, zip, pcntl, pdo, sqlite, pdo_sqlite, mysql, mysqli, pdo_mysql, pgsql, pdo_pgsql, bcmath, soap, intl, gd, exif, iconv, imagick
4883
coverage: none
4984

5085
- name: Setup Problem Matches
@@ -58,4 +93,9 @@ jobs:
5893
- name: Execute tests
5994
run: vendor/bin/pest
6095
env:
61-
DB_PORT: ${{ job.services.mysql.ports[3306] }}
96+
DB_CONNECTION: ${{ startsWith(matrix.database, 'mysql') && 'mysql' || 'pgsql' }}
97+
DB_PORT: ${{ matrix.database == 'mysql57' && 3306 || matrix.database == 'mysql8' && 3307 || matrix.database == 'pgsql16' && 5432 || matrix.database == 'pgsql17' && 5433 }}
98+
DB_HOST: 127.0.0.1
99+
DB_USERNAME: ${{ startsWith(matrix.database, 'pgsql') && 'postgres' || 'root' }}
100+
DB_PASSWORD: ${{ startsWith(matrix.database, 'pgsql') && 'postgres' || '' }}
101+
DB_DATABASE: laravel_tags

composer.json

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,13 @@
3939
}
4040
},
4141
"scripts": {
42-
"test": "vendor/bin/pest"
42+
"test": "@test:mysql",
43+
"test:mysql": "DB_CONNECTION=mysql vendor/bin/pest",
44+
"test:pgsql": "DB_CONNECTION=pgsql DB_PORT=5432 vendor/bin/pest",
45+
"test:all": [
46+
"@test:mysql",
47+
"@test:pgsql"
48+
]
4349
},
4450
"config": {
4551
"sort-packages": true,

src/Tag.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ public static function findOrCreateFromString(string $name, ?string $type = null
106106

107107
public static function getTypes(): Collection
108108
{
109-
return static::groupBy('type')->pluck('type');
109+
return static::groupBy('type')->orderBy('type')->pluck('type');
110110
}
111111

112112
public function setAttribute($key, $value)

tests/HasTagsScopesTest.php

Lines changed: 40 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -42,14 +42,14 @@
4242
it('provides a scope to get all models that have any of the given tags', function () {
4343
$testModels = TestModel::withAnyTags(['tagC', 'tagD'])->get();
4444

45-
expect($testModels->pluck('name')->toArray())->toEqual(['model3', 'model4']);
45+
expect($testModels->pluck('name')->toArray())->toContain('model3', 'model4');
4646
});
4747

4848

4949
test('the with any tags scopes will still items when passing a non existing tag', function () {
5050
$testModels = TestModel::withAnyTags(['tagB', 'tagC', 'nonExistingTag'])->get();
5151

52-
expect($testModels->pluck('name')->toArray())->toEqual(['model2', 'model3']);
52+
expect($testModels->pluck('name')->toArray())->toContain('model2', 'model3');
5353
});
5454

5555

@@ -72,11 +72,46 @@
7272
expect($testModels->pluck('name')->toArray())->toEqual(['model2', 'model3']);
7373
});
7474

75+
it('provides a scope to get all models from a slug of a tag', function () {
76+
$tagModel = Tag::findOrCreate('tag B');
77+
78+
$testModels = TestModel::create([
79+
'name' => 'model7',
80+
'tags' => ['tag B'],
81+
]);
82+
83+
$testModels = TestModel::withAllTags([$tagModel->slug])->get();
84+
85+
expect($testModels->pluck('name')->toArray())->toEqual(['model7']);
86+
expect($testModels->first()->tags->pluck('name')->toArray())->toEqual(['tag B']);
87+
expect($testModels->first()->tags->pluck('slug')->toArray())->toEqual(['tag-b']);
88+
});
89+
90+
it('returns tags attached to a model in the correct order', function () {
91+
$tag = Tag::findOrCreate('string');
92+
$tag->order_column = 10;
93+
$tag->save();
94+
95+
$tag2 = Tag::findOrCreate('string 2');
96+
$tag2->order_column = 20;
97+
$tag2->save();
98+
99+
$model = TestModel::create(['name' => 'test']);
100+
$model->attachTags([$tag2, $tag]);
101+
102+
expect($model->tags->pluck('name')->toArray())->toEqual(['string', 'string 2']);
103+
expect($model->tags->pluck('order_column')->toArray())->toEqual([10, 20]);
104+
105+
$foundModelAnyOrder = TestModel::withAnyTags(['string', 'string-2'])->first();
106+
expect($foundModelAnyOrder->tags->pluck('name')->toArray())->toEqual(['string', 'string 2']);
107+
expect($foundModelAnyOrder->tags->pluck('order_column')->toArray())->toEqual([10, 20]);
108+
});
109+
75110

76111
it('provides a scope to get all models that have any of the given tags with type', function () {
77112
$testModels = TestModel::withAnyTags(['tagE'], 'typedTag')->get();
78113

79-
expect($testModels->pluck('name')->toArray())->toEqual(['model5', 'model6']);
114+
expect($testModels->pluck('name')->toArray())->toContain('model5', 'model6');
80115

81116
$testModels = TestModel::withAnyTags(['tagF'], 'typedTag')->get();
82117

@@ -98,7 +133,7 @@
98133
it('provides a scope to get all models that have any of the given tags with any type', function () {
99134
$testModels = TestModel::withAnyTagsOfAnyType(['tagE', 'tagF'])->get();
100135

101-
expect($testModels->pluck('name')->toArray())->toEqual(['model5', 'model6']);
136+
expect($testModels->pluck('name')->toArray())->toContain('model5', 'model6');
102137
});
103138

104139

@@ -107,7 +142,7 @@
107142

108143
$testModels = TestModel::withAnyTagsOfAnyType([$tagD, 'tagE', 'tagF'])->get();
109144

110-
expect($testModels->pluck('name')->toArray())->toEqual(['model4', 'model5', 'model6']);
145+
expect($testModels->pluck('name')->toArray())->toContain('model4', 'model5', 'model6');
111146
});
112147

113148

tests/HasTagsTest.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@
186186

187187
$testModels = TestModel::withAnyTags(['tagB', 'tagC']);
188188

189-
expect($testModels->pluck('name')->toArray())->toEqual(['model2', 'model3']);
189+
expect($testModels->pluck('name')->toArray())->toContain('model2', 'model3');
190190
});
191191

192192

@@ -208,11 +208,11 @@
208208

209209
$testModels = TestModel::withAnyTags('tagB');
210210

211-
expect($testModels->pluck('name')->toArray())->toEqual(['model2', 'model3']);
211+
expect($testModels->pluck('name')->toArray())->toContain('model2', 'model3');
212212

213213
$testModels = TestModel::withAllTags('tagB');
214214

215-
expect($testModels->pluck('name')->toArray())->toEqual(['model2', 'model3']);
215+
expect($testModels->pluck('name')->toArray())->toContain('model2', 'model3');
216216
});
217217

218218

@@ -253,7 +253,7 @@
253253

254254
$testModels = TestModel::withoutTags(['tagC']);
255255

256-
expect($testModels->pluck('name')->toArray())->toEqual(['default', 'model1']);
256+
expect($testModels->pluck('name')->toArray())->toContain('default', 'model1');
257257

258258
$testModels = TestModel::withoutTags(['tagC', 'tagB']);
259259

tests/TagTest.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,19 @@
2222
expect($tag->order_column)->toBe(2);
2323
});
2424

25+
it('creates sortable tags with a custom order column', function () {
26+
$tag = Tag::findOrCreateFromString('string');
27+
$tag->order_column = 10;
28+
$tag->save();
29+
30+
$tag2 = Tag::findOrCreateFromString('string 2');
31+
$tag2->order_column = 20;
32+
$tag2->save();
33+
34+
expect($tag->order_column)->toBe(10);
35+
expect($tag2->order_column)->toBe(20);
36+
});
37+
2538
it('automatically generates a slug', function () {
2639
$tag = Tag::findOrCreateFromString('this is a tag');
2740

0 commit comments

Comments
 (0)