diff --git a/src/Database/Database.php b/src/Database/Database.php index 74e75d883..4fbac8d3a 100644 --- a/src/Database/Database.php +++ b/src/Database/Database.php @@ -8584,7 +8584,8 @@ public function find(string $collection, array $queries = [], string $forPermiss * @param string|null $namespace * @return bool */ - public function purgeCachedQueries(string $collection, ?string $namespace = null): bool + /** @phpstan-ignore-next-line exercised through query cache tests */ + private function purgeCachedQueries(string $collection, ?string $namespace = null): bool { $collectionDocument = $this->silent(fn () => $this->getCollection($collection)); $collection = $collectionDocument->isEmpty() ? $collection : $collectionDocument->getId(); @@ -9719,7 +9720,7 @@ public function getCacheKeys(string $collectionId, ?string $documentId = null, a * @param string|null $namespace * @return string */ - public function getQueryCacheKey(string $collectionId, ?string $namespace = null): string + private function getQueryCacheKey(string $collectionId, ?string $namespace = null): string { $hostname = $this->adapter->getSupportForHostname() ? $this->adapter->getHostname() @@ -9744,7 +9745,8 @@ public function getQueryCacheKey(string $collectionId, ?string $namespace = null * @param string $forPermission * @return string|null */ - public function getQueryCacheField( + /** @phpstan-ignore-next-line exercised through query cache tests */ + private function getQueryCacheField( ?Document $collection = null, array $queries = [], string $field = 'documents', diff --git a/tests/unit/CacheKeyTest.php b/tests/unit/CacheKeyTest.php index 92c3bc608..2958f3a16 100644 --- a/tests/unit/CacheKeyTest.php +++ b/tests/unit/CacheKeyTest.php @@ -13,6 +13,8 @@ class CacheKeyTest extends TestCase { + use QueryCacheTestHelpers; + /** * @param array $instanceFilters */ @@ -147,7 +149,7 @@ public function testQueryCacheKeyUsesQueryCacheShape(): void $this->assertSame( 'default-cache-mysql-console:_39::collection:ttl_cache_table:query', - $db->getQueryCacheKey('ttl_cache_table'), + $this->getQueryCacheKey($db, 'ttl_cache_table'), ); } @@ -163,7 +165,7 @@ public function testQueryCacheKeyCanOverrideNamespaceSegment(): void $this->assertSame( 'default-cache-mysql-console:_39::collection:wafrules:query', - $db->getQueryCacheKey('wafrules', '_39'), + $this->getQueryCacheKey($db, 'wafrules', '_39'), ); } @@ -192,7 +194,7 @@ public function testQueryCacheFieldUsesQueryCacheShape(): void . (\json_encode($collection->getAttribute('$permissions', [])) ?: '') . (\json_encode($collection->getAttribute('documentSecurity', false)) ?: '') ); - $field = $db->getQueryCacheField($collection, $queries); + $field = $this->getQueryCacheField($db, $collection, $queries); $this->assertStringStartsWith("{$schemaHash}:", $field); $this->assertStringEndsWith(':documents', $field); @@ -203,7 +205,8 @@ public function testQueryCacheFieldChangesWithInputs(): void { $db = $this->createDatabase(); - $field = $db->getQueryCacheField( + $field = $this->getQueryCacheField( + $db, new Document([ 'attributes' => [new Document(['$id' => 'name', 'type' => Database::VAR_STRING])], 'indexes' => [], @@ -213,7 +216,8 @@ public function testQueryCacheFieldChangesWithInputs(): void $this->assertNotSame( $field, - $db->getQueryCacheField( + $this->getQueryCacheField( + $db, new Document([ 'attributes' => [new Document(['$id' => 'status', 'type' => Database::VAR_STRING])], 'indexes' => [], @@ -221,26 +225,26 @@ public function testQueryCacheFieldChangesWithInputs(): void [Query::limit(10)], ), ); - $this->assertNotSame($field, $db->getQueryCacheField(null, [Query::limit(20)])); - $this->assertStringEndsWith(':total', $db->getQueryCacheField(null, [Query::limit(10)], 'total')); + $this->assertNotSame($field, $this->getQueryCacheField($db, null, [Query::limit(20)])); + $this->assertStringEndsWith(':total', $this->getQueryCacheField($db, null, [Query::limit(10)], 'total')); } public function testQueryCacheFieldChangesWithActiveAuthorizationContext(): void { $db = $this->createDatabase(); - $field = $db->getQueryCacheField(null, [Query::limit(10)]); + $field = $this->getQueryCacheField($db, null, [Query::limit(10)]); $this->assertNotSame( $field, - $db->getAuthorization()->skip(fn () => $db->getQueryCacheField(null, [Query::limit(10)])), + $db->getAuthorization()->skip(fn () => $this->getQueryCacheField($db, null, [Query::limit(10)])), ); $db->getAuthorization()->addRole('user:1'); $this->assertNotSame( $field, - $db->getQueryCacheField(null, [Query::limit(10)]), + $this->getQueryCacheField($db, null, [Query::limit(10)]), ); } @@ -248,21 +252,21 @@ public function testQueryCacheFieldReturnsNullForNonReadPermission(): void { $db = $this->createDatabase(); - $this->assertNull($db->getQueryCacheField(forPermission: Database::PERMISSION_UPDATE)); + $this->assertNull($this->getQueryCacheField($db, forPermission: Database::PERMISSION_UPDATE)); } public function testQueryCacheFieldIncludesCursorDocumentPayload(): void { $db = $this->createDatabase(); - $fieldA = $db->getQueryCacheField(null, [ + $fieldA = $this->getQueryCacheField($db, null, [ Query::orderAsc('name'), Query::cursorAfter(new Document([ '$id' => 'cursor', 'name' => 'alpha', ])), ]); - $fieldB = $db->getQueryCacheField(null, [ + $fieldB = $this->getQueryCacheField($db, null, [ Query::orderAsc('name'), Query::cursorAfter(new Document([ '$id' => 'cursor', @@ -277,15 +281,15 @@ public function testQueryCacheFieldIncludesAmbientState(): void { $db = $this->createDatabase(); - $field = $db->getQueryCacheField(null, [Query::limit(10)]); + $field = $this->getQueryCacheField($db, null, [Query::limit(10)]); $this->assertNotSame( $field, - $db->skipFilters(fn () => $db->getQueryCacheField(null, [Query::limit(10)]), ['json']), + $db->skipFilters(fn () => $this->getQueryCacheField($db, null, [Query::limit(10)]), ['json']), ); $this->assertNotSame( $field, - $db->skipRelationships(fn () => $db->getQueryCacheField(null, [Query::limit(10)])), + $db->skipRelationships(fn () => $this->getQueryCacheField($db, null, [Query::limit(10)])), ); } @@ -297,7 +301,7 @@ public function testQueryCacheFieldValidatesQueryTypes(): void $queries = ['invalid']; /** @phpstan-ignore-next-line intentionally passing invalid query type */ - $db->getQueryCacheField(null, $queries); + $this->getQueryCacheField($db, null, $queries); } diff --git a/tests/unit/QueryCacheTest.php b/tests/unit/QueryCacheTest.php index 8103a0dd2..573c4083a 100644 --- a/tests/unit/QueryCacheTest.php +++ b/tests/unit/QueryCacheTest.php @@ -14,6 +14,8 @@ class QueryCacheTest extends TestCase { + use QueryCacheTestHelpers; + /** * @param array $filters */ @@ -46,8 +48,8 @@ private function findWithCache( } $collectionDocument = $database->getCollection($collection); - $cacheKey = $database->getQueryCacheKey($collectionDocument->getId(), $namespace); - $cacheHash = $database->getQueryCacheField($collectionDocument, $queries); + $cacheKey = $this->getQueryCacheKey($database, $collectionDocument->getId(), $namespace); + $cacheHash = $this->getQueryCacheField($database, $collectionDocument, $queries); return $database->withCache( key: $cacheKey, @@ -326,8 +328,8 @@ public function testWithCacheCachesSingleDocument(): void $callbackCalls = 0; $collection = $database->getCollection('wafRules'); - $key = $database->getQueryCacheKey($collection->getId(), '_39'); - $hash = $database->getQueryCacheField($collection, field: 'document'); + $key = $this->getQueryCacheKey($database, $collection->getId(), '_39'); + $hash = $this->getQueryCacheField($database, $collection, field: 'document'); $first = $database->withCache( key: $key, @@ -361,8 +363,8 @@ public function testWithCacheCachesStaticQueryValues(): void $callbackCalls = 0; $collection = $database->getCollection('wafRules'); - $key = $database->getQueryCacheKey($collection->getId(), '_39'); - $hash = $database->getQueryCacheField($collection, field: 'count'); + $key = $this->getQueryCacheKey($database, $collection->getId(), '_39'); + $hash = $this->getQueryCacheField($database, $collection, field: 'count'); $first = $database->withCache( key: $key, @@ -429,7 +431,7 @@ public function testQueryCacheUsesCacheUntilPurged(): void $this->assertCount(1, $cached); $this->assertSame('rule-a', $cached[0]->getId()); - $this->assertTrue($database->purgeCachedQueries('wafRules', '_39')); + $this->assertTrue($this->purgeCachedQueries($database, 'wafRules', '_39')); $fresh = $this->findWithCache($database, 'wafRules', $queries, '_39'); $this->assertCount(2, $fresh); @@ -659,7 +661,7 @@ public function testQueryCacheReliesOnPurgeForDocumentSecurityCollections(): voi $this->assertCount(1, $cached); - $this->assertTrue($database->purgeCachedQueries('secureRules', '_39')); + $this->assertTrue($this->purgeCachedQueries($database, 'secureRules', '_39')); $fresh = $this->findWithCache($database, 'secureRules', $queries, '_39'); $this->assertSame([], $fresh); @@ -678,8 +680,8 @@ public function testQueryCacheFiltersDocumentSecurityPayloadsOnHit(): void $database->getAuthorization()->addRole(Role::user('user-1')->toString()); $collection = $database->getCollection('secureRules'); - $key = $database->getQueryCacheKey($collection->getId(), '_39'); - $hash = $database->getQueryCacheField($collection); + $key = $this->getQueryCacheKey($database, $collection->getId(), '_39'); + $hash = $this->getQueryCacheField($database, $collection); $database->getCache()->save($key, [ 'collection' => $collection->getId(), 'type' => 'documents', @@ -725,7 +727,7 @@ public function testQueryCacheRehydratesNestedDocumentPayloads(): void $collection = $database->getCollection('parents'); $cache->save( - $database->getQueryCacheKey($collection->getId(), '_39'), + $this->getQueryCacheKey($database, $collection->getId(), '_39'), [ 'collection' => $collection->getId(), 'type' => 'documents', @@ -740,7 +742,7 @@ public function testQueryCacheRehydratesNestedDocumentPayloads(): void ], ], ], - $database->getQueryCacheField($collection, $queries), + $this->getQueryCacheField($database, $collection, $queries), ); $parents = $this->findWithCache($database, 'parents', $queries, '_39'); @@ -782,13 +784,13 @@ public function testQueryCacheRefreshesInvalidPayload(): void $collection = $database->getCollection('wafRules'); $cache->save( - $database->getQueryCacheKey($collection->getId(), '_39'), + $this->getQueryCacheKey($database, $collection->getId(), '_39'), [ 'collection' => $collection->getId(), 'type' => 'documents', 'value' => 'invalid', ], - $database->getQueryCacheField($collection, $queries), + $this->getQueryCacheField($database, $collection, $queries), ); $rules = $this->findWithCache($database, 'wafRules', $queries, '_39'); @@ -833,7 +835,7 @@ public function testQueryCacheRefreshesInvalidPayloadEntry(): void $collection = $database->getCollection('wafRules'); $cache->save( - $database->getQueryCacheKey($collection->getId(), '_39'), + $this->getQueryCacheKey($database, $collection->getId(), '_39'), [ 'collection' => $collection->getId(), 'type' => 'documents', @@ -845,7 +847,7 @@ public function testQueryCacheRefreshesInvalidPayloadEntry(): void 'invalid', ], ], - $database->getQueryCacheField($collection, $queries), + $this->getQueryCacheField($database, $collection, $queries), ); $rules = $this->findWithCache($database, 'wafRules', $queries, '_39'); diff --git a/tests/unit/QueryCacheTestHelpers.php b/tests/unit/QueryCacheTestHelpers.php new file mode 100644 index 000000000..78ef999fd --- /dev/null +++ b/tests/unit/QueryCacheTestHelpers.php @@ -0,0 +1,39 @@ +invoke($database, $collection, $namespace); + } + + private function getQueryCacheKey(Database $database, string $collectionId, ?string $namespace = null): string + { + $method = new \ReflectionMethod(Database::class, 'getQueryCacheKey'); + + return $method->invoke($database, $collectionId, $namespace); + } + + /** + * @param array $queries + */ + private function getQueryCacheField( + Database $database, + ?Document $collection = null, + array $queries = [], + string $field = 'documents', + string $forPermission = Database::PERMISSION_READ, + ): ?string { + $method = new \ReflectionMethod(Database::class, 'getQueryCacheField'); + + return $method->invoke($database, $collection, $queries, $field, $forPermission); + } +} diff --git a/tests/unit/WithCacheLeaseTest.php b/tests/unit/WithCacheLeaseTest.php index 8eafd3540..e97c2d7bd 100644 --- a/tests/unit/WithCacheLeaseTest.php +++ b/tests/unit/WithCacheLeaseTest.php @@ -14,6 +14,8 @@ class WithCacheLeaseTest extends TestCase { + use QueryCacheTestHelpers; + private LeasableMemoryCache $cacheAdapter; private Database $database; @@ -39,7 +41,7 @@ protected function setUp(): void 'name' => 'fresh', ])); - $this->key = $this->database->getQueryCacheKey('projects'); + $this->key = $this->getQueryCacheKey($this->database, 'projects'); } public function testStaleListWriteAfterConcurrentPurgeIsRejected(): void