Ensure short_code column is case sensitive in Microsoft SQL server

This commit is contained in:
Alejandro Celaya 2023-01-30 10:49:47 +01:00
parent 0080ab5132
commit a52d0cd419
3 changed files with 59 additions and 18 deletions

View file

@ -0,0 +1,49 @@
<?php
declare(strict_types=1);
namespace ShlinkMigrations;
use Doctrine\DBAL\Platforms\SQLServerPlatform;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
final class Version20230130090946 extends AbstractMigration
{
public function up(Schema $schema): void
{
$this->skipIf(! $this->isMsSql(), 'This only sets MsSQL-specific database options');
$shortUrls = $schema->getTable('short_urls');
$shortCode = $shortUrls->getColumn('short_code');
// Drop the unique index before changing the collation, as the field is part of this index
$shortUrls->dropIndex('unique_short_code_plus_domain');
$shortCode->setPlatformOption('collation', 'Latin1_General_CS_AS');
}
public function postUp(Schema $schema): void
{
if ($this->isMsSql()) {
// The index needs to be re-created in postUp, but here, we can only use statements run against the
// connection directly
$this->connection->executeStatement(
'CREATE INDEX unique_short_code_plus_domain ON short_urls (domain_id, short_code);',
);
}
}
public function down(Schema $schema): void
{
// No down
}
public function isTransactional(): bool
{
return false;
}
private function isMsSql(): bool
{
return $this->connection->getDatabasePlatform() instanceof SQLServerPlatform;
}
}

View file

@ -39,8 +39,8 @@ class ShortUrl extends AbstractEntity
private string $longUrl;
private string $shortCode;
private Chronos $dateCreated;
/** @var Collection<int, Visit> */
private Collection $visits;
/** @var Collection<int, Visit> & Selectable */
private Collection & Selectable $visits;
/** @var Collection<string, DeviceLongUrl> */
private Collection $deviceLongUrls;
/** @var Collection<int, Tag> */
@ -255,23 +255,19 @@ class ShortUrl extends AbstractEntity
public function mostRecentImportedVisitDate(): ?Chronos
{
/** @var Selectable $visits */
$visits = $this->visits;
$criteria = Criteria::create()->where(Criteria::expr()->eq('type', VisitType::IMPORTED))
->orderBy(['id' => 'DESC'])
->setMaxResults(1);
$visit = $this->visits->matching($criteria)->last();
/** @var Visit|false $visit */
$visit = $visits->matching($criteria)->last();
return $visit === false ? null : $visit->getDate();
return $visit instanceof Visit ? $visit->getDate() : null;
}
/**
* @param Collection<int, Visit> $visits
* @param Collection<int, Visit> & Selectable $visits
* @internal
*/
public function setVisits(Collection $visits): self
public function setVisits(Collection & Selectable $visits): self
{
$this->visits = $visits;
return $this;

View file

@ -5,7 +5,6 @@ declare(strict_types=1);
namespace ShlinkioDbTest\Shlink\Core\ShortUrl\Repository;
use Cake\Chronos\Chronos;
use Doctrine\DBAL\Platforms\SQLServerPlatform;
use Shlinkio\Shlink\Core\Domain\Entity\Domain;
use Shlinkio\Shlink\Core\ShortUrl\Entity\ShortUrl;
use Shlinkio\Shlink\Core\ShortUrl\Model\ShortUrlCreation;
@ -61,13 +60,10 @@ class ShortUrlRepositoryTest extends DatabaseTestCase
ShortUrlIdentifier::fromShortCodeAndDomain('fOo'),
ShortUrlMode::LOOSE,
));
// TODO MS is doing loose checks always, making this fail.
if (! $this->getEntityManager()->getConnection()->getDatabasePlatform() instanceof SQLServerPlatform) {
self::assertNull($this->repo->findOneWithDomainFallback(
ShortUrlIdentifier::fromShortCodeAndDomain('foo'),
ShortUrlMode::STRICT,
));
}
self::assertNull($this->repo->findOneWithDomainFallback(
ShortUrlIdentifier::fromShortCodeAndDomain('foo'),
ShortUrlMode::STRICT,
));
self::assertSame($regularOne, $this->repo->findOneWithDomainFallback(
ShortUrlIdentifier::fromShortCodeAndDomain($withDomainDuplicatingRegular->getShortCode()),
ShortUrlMode::STRICT,