diff --git a/src/Appwrite/Docker/Env.php b/src/Appwrite/Docker/Env.php index 51ec9e167c..3bf6fb2d50 100644 --- a/src/Appwrite/Docker/Env.php +++ b/src/Appwrite/Docker/Env.php @@ -19,7 +19,16 @@ class Env foreach ($data as &$row) { $row = explode('=', $row, 2); $key = (isset($row[0])) ? trim($row[0]) : null; - $value = (isset($row[1])) ? trim($row[1]) : null; + $value = (isset($row[1])) ? (function (string $v): string { + $v = trim($v); + if ( + (\str_starts_with($v, '"') && \str_ends_with($v, '"')) || + (\str_starts_with($v, "'") && \str_ends_with($v, "'")) + ) { + return \substr($v, 1, -1); + } + return $v; + })(trim($row[1])) : null; if ($key) { $this->vars[$key] = $value; diff --git a/src/Appwrite/Platform/Tasks/Install.php b/src/Appwrite/Platform/Tasks/Install.php index 59a60062eb..af768444f2 100644 --- a/src/Appwrite/Platform/Tasks/Install.php +++ b/src/Appwrite/Platform/Tasks/Install.php @@ -33,6 +33,7 @@ class Install extends Action private const string APPWRITE_API_URL = 'http://appwrite'; private const string GROWTH_API_URL = 'https://growth.appwrite.io/v1'; + protected bool $isUpgrade = false; protected string $hostPath = ''; protected ?bool $isLocalInstall = null; protected ?array $installerConfig = null; @@ -66,7 +67,7 @@ class Install extends Action bool $noStart, string $database ): void { - $isUpgrade = false; + $isUpgrade = $this->isUpgrade; $defaultHttpPort = '80'; $defaultHttpsPort = '443'; $config = Config::getParam('variables'); @@ -508,7 +509,7 @@ class Install extends Action $this->applyLocalPaths($isLocalInstall, false); $isCLI = php_sapi_name() === 'cli'; - if ($isLocalInstall) { + if ($isLocalInstall || $isUpgrade) { $useExistingConfig = false; } else { $useExistingConfig = file_exists($this->path . '/' . $this->getComposeFileName()) diff --git a/src/Appwrite/Platform/Tasks/Upgrade.php b/src/Appwrite/Platform/Tasks/Upgrade.php index 7214ca2e8c..1d61180963 100644 --- a/src/Appwrite/Platform/Tasks/Upgrade.php +++ b/src/Appwrite/Platform/Tasks/Upgrade.php @@ -42,6 +42,7 @@ class Upgrade extends Install bool $noStart, string $database ): void { + $this->isUpgrade = true; $isLocalInstall = $this->isLocalInstall(); $this->applyLocalPaths($isLocalInstall, true); @@ -72,7 +73,7 @@ class Upgrade extends Install } if ($database === null) { - $envData = @file_get_contents($this->path . '/.env'); + $envData = @file_get_contents($this->path . '/' . $this->getEnvFileName()); if ($envData !== false) { $envFile = new Env($envData); $database = $envFile->list()['_APP_DB_ADAPTER'] ?? null; diff --git a/tests/e2e/Services/Databases/DatabasesBase.php b/tests/e2e/Services/Databases/DatabasesBase.php index aecad983de..5f8ac7dd94 100644 --- a/tests/e2e/Services/Databases/DatabasesBase.php +++ b/tests/e2e/Services/Databases/DatabasesBase.php @@ -3518,6 +3518,62 @@ trait DatabasesBase $this->assertEquals(200, $response['headers']['status-code']); } + public function testQueryBySequenceType(): void + { + $data = $this->setupDocuments(); + $databaseId = $data['databaseId']; + + $documents = $this->client->call(Client::METHOD_GET, $this->getRecordUrl($databaseId, $data['moviesId']), array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'queries' => [ + Query::equal('$id', $data['documentIds'])->toString(), + ], + ]); + + $this->assertEquals(200, $documents['headers']['status-code']); + $this->assertGreaterThan(0, count($documents['body'][$this->getRecordResource()])); + + $sequence = $documents['body'][$this->getRecordResource()][0]['$sequence']; + $this->assertIsString($sequence); + + // Query with string $sequence value (supported by all adapters) + $response = $this->client->call(Client::METHOD_GET, $this->getRecordUrl($databaseId, $data['moviesId']), array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'queries' => [ + Query::equal('$sequence', [$sequence])->toString(), + ], + ]); + + $this->assertEquals(200, $response['headers']['status-code']); + $this->assertCount(1, $response['body'][$this->getRecordResource()]); + $this->assertIsString($response['body'][$this->getRecordResource()][0]['$sequence']); + $this->assertSame($sequence, $response['body'][$this->getRecordResource()][0]['$sequence']); + + // Query with int $sequence value (supported by SQL adapters, rejected by MongoDB) + $intSequence = (int)$sequence; + $response = $this->client->call(Client::METHOD_GET, $this->getRecordUrl($databaseId, $data['moviesId']), array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'queries' => [ + Query::equal('$sequence', [$intSequence])->toString(), + ], + ]); + + $adapter = getenv('_APP_DB_ADAPTER'); + if ($adapter === 'mongodb') { + $this->assertEquals(400, $response['headers']['status-code']); + } else { + $this->assertEquals(200, $response['headers']['status-code']); + $this->assertCount(1, $response['body'][$this->getRecordResource()]); + $this->assertIsString($response['body'][$this->getRecordResource()][0]['$sequence']); + } + } + public function testListDocumentsAfterPagination(): void { $data = $this->setupDocuments(); diff --git a/tests/unit/Utopia/Response/Filters/V21Test.php b/tests/unit/Utopia/Response/Filters/V21Test.php index fdff7fdf3f..a049b70d84 100644 --- a/tests/unit/Utopia/Response/Filters/V21Test.php +++ b/tests/unit/Utopia/Response/Filters/V21Test.php @@ -430,7 +430,7 @@ class V21Test extends TestCase { $result = $this->filter->parse($content, Response::MODEL_DOCUMENT); - $this->assertEquals($expected, $result); + $this->assertSame($expected, $result); } #[DataProvider('documentProvider')] @@ -438,7 +438,76 @@ class V21Test extends TestCase { $result = $this->filter->parse($content, Response::MODEL_ROW); - $this->assertEquals($expected, $result); + $this->assertSame($expected, $result); + } + + public static function documentListProvider(): array + { + return [ + 'cast $sequence in document list' => [ + [ + 'total' => 2, + 'documents' => [ + [ + '$id' => 'doc1', + '$sequence' => '10', + 'name' => 'first', + ], + [ + '$id' => 'doc2', + '$sequence' => '20', + 'name' => 'second', + ], + ], + ], + [ + 'total' => 2, + 'documents' => [ + [ + '$id' => 'doc1', + '$sequence' => 10, + 'name' => 'first', + ], + [ + '$id' => 'doc2', + '$sequence' => 20, + 'name' => 'second', + ], + ], + ] + ], + 'handle empty document list' => [ + [ + 'total' => 0, + 'documents' => [], + ], + [ + 'total' => 0, + 'documents' => [], + ] + ], + ]; + } + + #[DataProvider('documentListProvider')] + public function testDocumentList(array $content, array $expected): void + { + $result = $this->filter->parse($content, Response::MODEL_DOCUMENT_LIST); + + $this->assertSame($expected, $result); + } + + #[DataProvider('documentListProvider')] + public function testRowList(array $content, array $expected): void + { + $content['rows'] = $content['documents']; + unset($content['documents']); + $expected['rows'] = $expected['documents']; + unset($expected['documents']); + + $result = $this->filter->parse($content, Response::MODEL_ROW_LIST); + + $this->assertSame($expected, $result); } public static function defaultPassthroughProvider(): array