diff --git a/README.md b/README.md index 34e581e..fb28934 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,9 @@ # Async ORM [![codecov](https://codecov.io/gh/danog/AsyncOrm/branch/master/graph/badge.svg)](https://codecov.io/gh/danog/AsyncOrm) -[![Mutation testing badge](https://img.shields.io/endpoint?style=flat&url=https%3A%2F%2Fbadge-api.stryker-mutator.io%2Fgithub.com%2Fdanog%2Floop%2Fmaster)](https://dashboard.stryker-mutator.io/r> [![Psalm coverage](https://shepherd.dev/github/danog/AsyncOrm/coverage.svg)](https://shepherd.dev/github/danog/AsyncOrm) [![Psalm level 1](https://shepherd.dev/github/danog/AsyncOrm/level.svg)](https://shepherd.dev/github/danog/AsyncOrm) -![License](https://img.shields.io/badge/license-MIT-blue.svg) +![License](https://img.shields.io/badge/license-Apache-2.0-blue.svg) Async ORM based on AMPHP v3 and fibers, created by Daniil Gentili and Alexander Pankratov . diff --git a/psalm-baseline.xml b/psalm-baseline.xml new file mode 100644 index 0000000..b084ce2 --- /dev/null +++ b/psalm-baseline.xml @@ -0,0 +1,33 @@ + + + + + + + + ]]> + + + + + + + + + + + + + + + + + + + + + + cache->inner)]]> + + + diff --git a/psalm.xml b/psalm.xml index 8e05c23..26d5b31 100644 --- a/psalm.xml +++ b/psalm.xml @@ -6,7 +6,9 @@ xmlns="https://getpsalm.org/schema/config" xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd" findUnusedBaselineEntry="true" + findUnusedPsalmSuppress="true" findUnusedCode="true" + errorBaseline="psalm-baseline.xml" > diff --git a/src/DbArray.php b/src/DbArray.php index c360c66..a0850e9 100644 --- a/src/DbArray.php +++ b/src/DbArray.php @@ -118,6 +118,12 @@ abstract class DbArray implements Countable, ArrayAccess, Traversable, IteratorA /** * Get instance. + * + * @template TTKey as array-key + * @template TTValue as DbObject + * + * @param DbArray|null $previous + * @return DbArray */ abstract public static function getInstance(DbArrayBuilder $config, self|null $previous): self; } diff --git a/src/DbArrayBuilder.php b/src/DbArrayBuilder.php index a008215..13857d1 100644 --- a/src/DbArrayBuilder.php +++ b/src/DbArrayBuilder.php @@ -58,6 +58,12 @@ final readonly class DbArrayBuilder /** * Build database array. + * + * @template TKey as array-key + * @template TValue + * + * @param DbArray|null $previous + * @return DbArray */ public function build(?DbArray $previous = null): DbArray { @@ -68,6 +74,7 @@ final readonly class DbArrayBuilder if ($this->settings->serializer instanceof Json) { throw new AssertionError("The JSON backend cannot be used when serializing objects!"); } + /** @psalm-suppress MixedArgumentTypeCoercion */ return ObjectArray::getInstance($this, $previous); } if ($this->settings instanceof MemorySettings diff --git a/src/Driver/DriverArray.php b/src/Driver/DriverArray.php index 0376214..bbdc1f2 100644 --- a/src/Driver/DriverArray.php +++ b/src/Driver/DriverArray.php @@ -58,9 +58,16 @@ abstract class DriverArray extends DbArray $this->inited = true; } + /** + * @template TTKey as array-key + * @template TTValue + * @param DbArray $previous + * @return DbArray + */ public static function getInstance(DbArrayBuilder $config, DbArray|null $previous): DbArray { $migrate = true; + /** @psalm-suppress DocblockTypeContradiction TODO fix in psalm */ if ($previous !== null && $previous::class === static::class && $previous->config == $config @@ -72,12 +79,14 @@ abstract class DriverArray extends DbArray } \assert($config->settings instanceof DriverSettings); + /** @var DbArray */ $instance = new static($config, $config->settings->serializer); if ($previous === null || !$migrate) { return $instance; } + /** @psalm-suppress DocblockTypeContradiction TODO fix in psalm */ if ($previous instanceof SqlArray && $instance instanceof SqlArray && $previous::class === $instance::class @@ -85,7 +94,6 @@ abstract class DriverArray extends DbArray $instance->importFromTable($previous->config->table); } else { $promises = []; - /** @psalm-suppress MixedAssignment */ foreach ($previous->getIterator() as $key => $value) { $promises []= async($previous->unset(...), $key) ->map(static fn () => $instance->set($key, $value)); diff --git a/src/Driver/SqlArray.php b/src/Driver/SqlArray.php index a6f02ae..2e8b752 100644 --- a/src/Driver/SqlArray.php +++ b/src/Driver/SqlArray.php @@ -88,12 +88,14 @@ abstract class SqlArray extends DriverArray public function set(string|int $key, mixed $value): void { $key = (string) $key; + /** @var scalar */ + $value = $this->serializer->serialize($value); $this->execute( $this->set, [ 'index' => $key, - 'value' => $this->serializer->serialize($value), + 'value' => $value, ], ); } @@ -124,8 +126,7 @@ abstract class SqlArray extends DriverArray { $row = $this->execute($this->count); $res = $row->fetchRow(); - \assert($res !== null); - /** @var int */ + \assert($res !== null && isset($res['count']) && \is_int($res['count'])); return $res['count']; } @@ -139,7 +140,7 @@ abstract class SqlArray extends DriverArray /** * Perform async request to db. - * + * @param array $params */ protected function execute(string $sql, array $params = []): SqlResult { diff --git a/src/Internal/Driver/MysqlArray.php b/src/Internal/Driver/MysqlArray.php index ca75b5e..374a5cb 100644 --- a/src/Internal/Driver/MysqlArray.php +++ b/src/Internal/Driver/MysqlArray.php @@ -82,8 +82,10 @@ final class MysqlArray extends SqlArray COLLATE 'utf8mb4_general_ci' "); try { - /** @psalm-suppress PossiblyNullArrayAccess */ - $max = (int) $connection->query("SHOW VARIABLES LIKE 'max_connections'")->fetchRow()['Value']; + $max = $connection->query("SHOW VARIABLES LIKE 'max_connections'")->fetchRow(); + \assert(\is_array($max)); + $max = $max['Value'] ?? null; + \assert(\is_int($max)); if ($max < 100000) { $connection->query("SET GLOBAL max_connections = 100000"); } @@ -219,11 +221,9 @@ final class MysqlArray extends SqlArray /** * Perform async request to db. - * */ protected function execute(string $sql, array $params = []): SqlResult { - /** @psalm-suppress MixedAssignment */ foreach ($params as $key => $value) { if (\is_string($value)) { $value = $this->pdo->quote($value); diff --git a/src/Internal/Driver/ObjectArray.php b/src/Internal/Driver/ObjectArray.php index 3647df3..1de4cd4 100644 --- a/src/Internal/Driver/ObjectArray.php +++ b/src/Internal/Driver/ObjectArray.php @@ -50,28 +50,33 @@ final class ObjectArray extends DbArray /** * Get instance. + * + * @template TTKey as array-key + * @template TTValue as DbObject + * + * @param DbArray|null $previous + * @return DbArray */ public static function getInstance(DbArrayBuilder $config, DbArray|null $previous): DbArray { $new = $config->settings->getDriverClass(); \assert($config->settings instanceof DriverSettings); if ($previous === null) { - /** @psalm-suppress MixedArgumentTypeCoercion */ $previous = new self($new::getInstance($config, null), $config, $config->settings->cacheTtl); } elseif ($previous instanceof self) { - /** @psalm-suppress MixedPropertyTypeCoercion, InvalidArgument */ $previous->cache->inner = $new::getInstance($config, $previous->cache->inner); $previous->cache->config = $config; $previous->cache->cacheTtl = $config->settings->cacheTtl; } else { - /** @psalm-suppress MixedArgumentTypeCoercion */ $previous = new self($new::getInstance($config, $previous), $config, $config->settings->cacheTtl); } if ($previous->cache->inner instanceof MemoryArray) { $previous->cache->flushCache(); + /** @var DbArray */ return $previous->cache->inner; } $previous->cache->startCacheCleanupLoop(); + /** @var DbArray */ return $previous; } diff --git a/src/Internal/Driver/RedisArray.php b/src/Internal/Driver/RedisArray.php index c54fe01..afa6a19 100644 --- a/src/Internal/Driver/RedisArray.php +++ b/src/Internal/Driver/RedisArray.php @@ -95,8 +95,9 @@ final class RedisArray extends DriverArray public function set(string|int $key, mixed $value): void { - /** @psalm-suppress MixedArgument The serializer always produces a string */ - $this->db->set($this->config->table.':'.(string) $key, $this->serializer->serialize($value)); + /** @var string */ + $value = $this->serializer->serialize($value); + $this->db->set($this->config->table.':'.(string) $key, $value); } public function get(string|int $key): mixed diff --git a/src/Internal/Serializer/ByteaSerializer.php b/src/Internal/Serializer/ByteaSerializer.php index 4cc118e..2d24a6c 100644 --- a/src/Internal/Serializer/ByteaSerializer.php +++ b/src/Internal/Serializer/ByteaSerializer.php @@ -45,8 +45,7 @@ final class ByteaSerializer implements Serializer } public function serialize(mixed $value): mixed { - /** @psalm-suppress MixedArgument */ - return new PostgresByteA($this->inner->serialize($value)); + return new PostgresByteA((string) $this->inner->serialize($value)); } public function deserialize(mixed $value): mixed {