diff --git a/src/Database/Adapter.php b/src/Database/Adapter.php index f5748e460..6e7cc9f9e 100644 --- a/src/Database/Adapter.php +++ b/src/Database/Adapter.php @@ -781,6 +781,13 @@ abstract public function getSupportForSchemas(): bool; */ abstract public function getSupportForAttributes(): bool; + /** + * Are schema attributes supported? + * + * @return bool + */ + abstract public function getSupportForSchemaAttributes(): bool; + /** * Is index supported? * @@ -1022,4 +1029,13 @@ abstract public function getConnectionId(): string; * @return array */ abstract public function getInternalIndexesKeys(): array; + + /** + * Get Schema Attributes + * + * @param string $collection + * @return array + * @throws DatabaseException + */ + abstract public function getSchemaAttributes(string $collection): array; } diff --git a/src/Database/Adapter/MariaDB.php b/src/Database/Adapter/MariaDB.php index b616247ab..b5d2956f1 100644 --- a/src/Database/Adapter/MariaDB.php +++ b/src/Database/Adapter/MariaDB.php @@ -1457,6 +1457,7 @@ public function updateDocuments(string $collection, Document $updates, array $do $permissionsStmt->execute(); $permissions = $permissionsStmt->fetchAll(); + $permissionsStmt->closeCursor(); $initial = []; foreach (Database::PERMISSIONS as $type) { @@ -2433,4 +2434,55 @@ protected function processException(PDOException $e): \Exception return $e; } + + /** + * Get Schema Attributes + * + * @param string $collection + * @return array + * @throws DatabaseException + */ + public function getSchemaAttributes(string $collection): array + { + $schema = $this->getDatabase(); + $collection = $this->getNamespace().'_'.$this->filter($collection); + + try { + $stmt = $this->getPDO()->prepare(' + SELECT + COLUMN_NAME as columnName, + COLUMN_DEFAULT as columnDefault, + IS_NULLABLE as isNullable, + DATA_TYPE as dataType, + CHARACTER_MAXIMUM_LENGTH as characterMaximumLength, + NUMERIC_PRECISION as numericPrecision, + NUMERIC_SCALE as numericScale, + DATETIME_PRECISION as datetimePrecision, + COLUMN_TYPE as columnType, + COLUMN_KEY as columnKey, + EXTRA as extra + FROM INFORMATION_SCHEMA.COLUMNS + WHERE TABLE_SCHEMA = :schema AND TABLE_NAME = :table + '); + $stmt->bindParam(':schema', $schema); + $stmt->bindParam(':table', $collection); + $stmt->execute(); + $results = $stmt->fetchAll(); + $stmt->closeCursor(); + + foreach ($results as $index => $document) { + $results[$index] = new Document($document); + } + + return $results; + + } catch (PDOException $e) { + throw new DatabaseException('Failed to get schema attributes', $e->getCode(), $e); + } + } + + public function getSupportForSchemaAttributes(): bool + { + return true; + } } diff --git a/src/Database/Adapter/Mongo.php b/src/Database/Adapter/Mongo.php index 4a54c473b..2e35a74e0 100644 --- a/src/Database/Adapter/Mongo.php +++ b/src/Database/Adapter/Mongo.php @@ -1787,6 +1787,16 @@ public function getSupportForGetConnectionId(): bool return false; } + /** + * Is get schema attributes supported? + * + * @return bool + */ + public function getSupportForSchemaAttributes(): bool + { + return false; + } + /** * Get current attribute count from collection document * @@ -1942,4 +1952,9 @@ public function getInternalIndexesKeys(): array { return []; } + + public function getSchemaAttributes(string $collection): array + { + return []; + } } diff --git a/src/Database/Adapter/Postgres.php b/src/Database/Adapter/Postgres.php index c679a9414..378d77cdf 100644 --- a/src/Database/Adapter/Postgres.php +++ b/src/Database/Adapter/Postgres.php @@ -2397,6 +2397,16 @@ public function getSupportForJSONOverlaps(): bool return false; } + /** + * Is get schema attributes supported? + * + * @return bool + */ + public function getSupportForSchemaAttributes(): bool + { + return false; + } + /** * @return string */ diff --git a/src/Database/Adapter/SQL.php b/src/Database/Adapter/SQL.php index a0b6a3c6a..ee69d5919 100644 --- a/src/Database/Adapter/SQL.php +++ b/src/Database/Adapter/SQL.php @@ -1151,4 +1151,9 @@ protected function processException(PDOException $e): \Exception { return $e; } + + public function getSchemaAttributes(string $collection): array + { + return []; + } } diff --git a/src/Database/Adapter/SQLite.php b/src/Database/Adapter/SQLite.php index a52ce1332..8442367ff 100644 --- a/src/Database/Adapter/SQLite.php +++ b/src/Database/Adapter/SQLite.php @@ -934,6 +934,16 @@ public function getSupportForGetConnectionId(): bool return false; } + /** + * Is get schema attributes supported? + * + * @return bool + */ + public function getSupportForSchemaAttributes(): bool + { + return false; + } + /** * Get SQL Index Type * diff --git a/src/Database/Database.php b/src/Database/Database.php index 95a499df2..b37f821bc 100644 --- a/src/Database/Database.php +++ b/src/Database/Database.php @@ -6037,4 +6037,16 @@ public function analyzeCollection(string $collection): bool { return $this->adapter->analyzeCollection($collection); } + + /** + * Get Schema Attributes + * + * @param string $collection + * @return array + * @throws DatabaseException + */ + public function getSchemaAttributes(string $collection): array + { + return $this->adapter->getSchemaAttributes($collection); + } } diff --git a/tests/e2e/Adapter/Base.php b/tests/e2e/Adapter/Base.php index 943eb458e..d56a987df 100644 --- a/tests/e2e/Adapter/Base.php +++ b/tests/e2e/Adapter/Base.php @@ -1300,6 +1300,69 @@ public function testPurgeCollectionCache(): void $this->assertArrayHasKey('age', $document); } + public function testSchemaAttribute(): void + { + if (!$this->getDatabase()->getAdapter()->getSupportForSchemaAttributes()) { + $this->expectNotToPerformAssertions(); + return; + } + + $collection = 'schema_attributes'; + $db = static::getDatabase(); + + $this->assertEmpty($db->getSchemaAttributes('no_such_collection')); + + $db->createCollection($collection); + + $db->createAttribute($collection, 'username', Database::VAR_STRING, 128, true); + $db->createAttribute($collection, 'story', Database::VAR_STRING, 20000, true); + $db->createAttribute($collection, 'string_list', Database::VAR_STRING, 128, true, null, true, true); + $db->createAttribute($collection, 'dob', Database::VAR_DATETIME, 0, false, '2000-06-12T14:12:55.000+00:00', true, false, null, [], ['datetime']); + + $attributes = []; + foreach ($db->getSchemaAttributes($collection) as $attribute) { + /** + * @var Document $attribute + */ + $attributes[$attribute->getAttribute('columnName')] = $attribute; + } + + $attribute = $attributes['username']; + $this->assertEquals('username', $attribute['columnName']); + $this->assertEquals('varchar', $attribute['dataType']); + $this->assertEquals('varchar(128)', $attribute['columnType']); + $this->assertEquals('128', $attribute['characterMaximumLength']); + $this->assertEquals('YES', $attribute['isNullable']); + + $attribute = $attributes['story']; + $this->assertEquals('story', $attribute['columnName']); + $this->assertEquals('text', $attribute['dataType']); + $this->assertEquals('text', $attribute['columnType']); + $this->assertEquals('65535', $attribute['characterMaximumLength']); + + $attribute = $attributes['string_list']; + $this->assertEquals('string_list', $attribute['columnName']); + $this->assertTrue(in_array($attribute['dataType'], ['json', 'longtext'])); // mysql vs maria + $this->assertTrue(in_array($attribute['columnType'], ['json', 'longtext'])); + $this->assertTrue(in_array($attribute['characterMaximumLength'], [null, '4294967295'])); + $this->assertEquals('YES', $attribute['isNullable']); + + $attribute = $attributes['dob']; + $this->assertEquals('dob', $attribute['columnName']); + $this->assertEquals('datetime', $attribute['dataType']); + $this->assertEquals('datetime(3)', $attribute['columnType']); + $this->assertEquals(null, $attribute['characterMaximumLength']); + $this->assertEquals('3', $attribute['datetimePrecision']); + + if ($db->getSharedTables()) { + $attribute = $attributes['_tenant']; + $this->assertEquals('_tenant', $attribute['columnName']); + $this->assertEquals('int', $attribute['dataType']); + $this->assertEquals('10', $attribute['numericPrecision']); + $this->assertTrue(in_array($attribute['columnType'], ['int unsigned', 'int(11) unsigned'])); + } + } + public function testCreateDeleteAttribute(): void { static::getDatabase()->createCollection('attributes');