Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/Database/Adapter.php
Original file line number Diff line number Diff line change
Expand Up @@ -578,10 +578,11 @@ abstract public function createAttributes(string $collection, array $attributes)
* @param bool $signed
* @param bool $array
* @param string|null $newKey
* @param bool $required
*
* @return bool
*/
abstract public function updateAttribute(string $collection, string $id, string $type, int $size, bool $signed = true, bool $array = false, ?string $newKey = null): bool;
abstract public function updateAttribute(string $collection, string $id, string $type, int $size, bool $signed = true, bool $array = false, ?string $newKey = null, bool $required = false): bool;

/**
* Delete Attribute
Expand Down
9 changes: 5 additions & 4 deletions src/Database/Adapter/MariaDB.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
use Utopia\Database\Exception as DatabaseException;
use Utopia\Database\Exception\Duplicate as DuplicateException;
use Utopia\Database\Exception\NotFound as NotFoundException;
use Utopia\Database\Exception\Query as QueryException;
use Utopia\Database\Exception\Timeout as TimeoutException;
use Utopia\Database\Exception\Truncate as TruncateException;
use Utopia\Database\Helpers\ID;
Expand Down Expand Up @@ -409,16 +410,16 @@ public function getSchemaAttributes(string $collection): array
* @param bool $signed
* @param bool $array
* @param string|null $newKey
* @param bool $required
* @return bool
* @throws DatabaseException
*/
public function updateAttribute(string $collection, string $id, string $type, int $size, bool $signed = true, bool $array = false, ?string $newKey = null): bool
public function updateAttribute(string $collection, string $id, string $type, int $size, bool $signed = true, bool $array = false, ?string $newKey = null, bool $required = false): bool
{
$name = $this->filter($collection);
$id = $this->filter($id);
$newKey = empty($newKey) ? null : $this->filter($newKey);
$type = $this->getSQLType($type, $size, $signed, $array, false);

$type = $this->getSQLType($type, $size, $signed, $array, $required);
if (!empty($newKey)) {
$sql = "ALTER TABLE {$this->getSQLTable($name)} CHANGE COLUMN `{$id}` `{$newKey}` {$type};";
} else {
Expand Down Expand Up @@ -1393,7 +1394,7 @@ protected function handleDistanceSpatialQueries(Query $query, array &$binds, str
$wktType = $this->getSpatialTypeFromWKT($wkt);
$attrType = strtolower($type);
if ($wktType != Database::VAR_POINT || $attrType != Database::VAR_POINT) {
throw new DatabaseException('Distance in meters is not supported between '.$attrType . ' and '. $wktType);
throw new QueryException('Distance in meters is not supported between '.$attrType . ' and '. $wktType);
}
return "ST_DISTANCE_SPHERE({$alias}.{$attribute}, ST_GeomFromText(:{$placeholder}_0), 6371000) {$operator} :{$placeholder}_1";
}
Expand Down
2 changes: 1 addition & 1 deletion src/Database/Adapter/Pool.php
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ public function createAttributes(string $collection, array $attributes): bool
return $this->delegate(__FUNCTION__, \func_get_args());
}

public function updateAttribute(string $collection, string $id, string $type, int $size, bool $signed = true, bool $array = false, ?string $newKey = null): bool
public function updateAttribute(string $collection, string $id, string $type, int $size, bool $signed = true, bool $array = false, ?string $newKey = null, bool $required = false): bool
{
return $this->delegate(__FUNCTION__, \func_get_args());
}
Expand Down
5 changes: 3 additions & 2 deletions src/Database/Adapter/Postgres.php
Original file line number Diff line number Diff line change
Expand Up @@ -535,16 +535,17 @@ public function renameAttribute(string $collection, string $old, string $new): b
* @param bool $signed
* @param bool $array
* @param string|null $newKey
* @param bool $required
* @return bool
* @throws Exception
* @throws PDOException
*/
public function updateAttribute(string $collection, string $id, string $type, int $size, bool $signed = true, bool $array = false, ?string $newKey = null): bool
public function updateAttribute(string $collection, string $id, string $type, int $size, bool $signed = true, bool $array = false, ?string $newKey = null, bool $required = false): bool
{
$name = $this->filter($collection);
$id = $this->filter($id);
$newKey = empty($newKey) ? null : $this->filter($newKey);
$type = $this->getSQLType($type, $size, $signed, $array, false);
$type = $this->getSQLType($type, $size, $signed, $array, $required);

if ($type == 'TIMESTAMP(3)') {
$type = "TIMESTAMP(3) without time zone USING TO_TIMESTAMP(\"$id\", 'YYYY-MM-DD HH24:MI:SS.MS')";
Expand Down
3 changes: 2 additions & 1 deletion src/Database/Adapter/SQLite.php
Original file line number Diff line number Diff line change
Expand Up @@ -327,11 +327,12 @@ public function analyzeCollection(string $collection): bool
* @param bool $signed
* @param bool $array
* @param string|null $newKey
* @param bool $required
* @return bool
* @throws Exception
* @throws PDOException
*/
public function updateAttribute(string $collection, string $id, string $type, int $size, bool $signed = true, bool $array = false, ?string $newKey = null): bool
public function updateAttribute(string $collection, string $id, string $type, int $size, bool $signed = true, bool $array = false, ?string $newKey = null, bool $required = false): bool
{
if (!empty($newKey) && $newKey !== $id) {
return $this->renameAttribute($collection, $id, $newKey);
Expand Down
6 changes: 5 additions & 1 deletion src/Database/Database.php
Original file line number Diff line number Diff line change
Expand Up @@ -2161,6 +2161,10 @@ public function updateAttribute(string $collection, string $id, ?string $type =
$default = null;
}

if ($required === true && in_array($type, Database::SPATIAL_TYPES)) {
$altering = true;
}

switch ($type) {
case self::VAR_STRING:
if (empty($size)) {
Expand Down Expand Up @@ -2322,7 +2326,7 @@ public function updateAttribute(string $collection, string $id, ?string $type =
}
}

$updated = $this->adapter->updateAttribute($collection, $id, $type, $size, $signed, $array, $newKey);
$updated = $this->adapter->updateAttribute($collection, $id, $type, $size, $signed, $array, $newKey, $required);

if (!$updated) {
throw new DatabaseException('Failed to update attribute');
Expand Down
51 changes: 49 additions & 2 deletions tests/e2e/Adapter/Scopes/SpatialTests.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
use Utopia\Database\Database;
use Utopia\Database\Document;
use Utopia\Database\Exception;
use Utopia\Database\Exception\Query as QueryException;
use Utopia\Database\Exception\Structure as StructureException;
use Utopia\Database\Helpers\ID;
use Utopia\Database\Helpers\Permission;
Expand Down Expand Up @@ -840,6 +841,53 @@ public function testSpatialIndex(): void
} finally {
$database->deleteCollection($collNullIndex);
}

$collUpdateNull = 'spatial_idx_req';
try {
$database->createCollection($collUpdateNull);

$database->createAttribute($collUpdateNull, 'loc', Database::VAR_POINT, 0, false);
if (!$nullSupported) {
try {
$database->createIndex($collUpdateNull, 'idx_loc_required', Database::INDEX_SPATIAL, ['loc']);
$this->fail('Expected exception when creating spatial index on NULL-able attribute');
} catch (\Throwable $e) {
$this->assertInstanceOf(Exception::class, $e);
}
} else {
$this->assertTrue($database->createIndex($collUpdateNull, 'idx_loc', Database::INDEX_SPATIAL, ['loc']));
}

$database->updateAttribute($collUpdateNull, 'loc', required: true);

$this->assertTrue($database->createIndex($collUpdateNull, 'idx_loc_req', Database::INDEX_SPATIAL, ['loc']));
} finally {
$database->deleteCollection($collUpdateNull);
}


$collUpdateNull = 'spatial_idx_index_null_required_true';
try {
$database->createCollection($collUpdateNull);

$database->createAttribute($collUpdateNull, 'loc', Database::VAR_POINT, 0, false);
if (!$nullSupported) {
try {
$database->createIndex($collUpdateNull, 'idx_loc', Database::INDEX_SPATIAL, ['loc']);
$this->fail('Expected exception when creating spatial index on NULL-able attribute');
} catch (\Throwable $e) {
$this->assertInstanceOf(Exception::class, $e);
}
} else {
$this->assertTrue($database->createIndex($collUpdateNull, 'idx_loc', Database::INDEX_SPATIAL, ['loc']));
}

$database->updateAttribute($collUpdateNull, 'loc', required: true);

$this->assertTrue($database->createIndex($collUpdateNull, 'new index', Database::INDEX_SPATIAL, ['loc']));
} finally {
$database->deleteCollection($collUpdateNull);
}
}

public function testComplexGeometricShapes(): void
Expand Down Expand Up @@ -2335,11 +2383,10 @@ public function testSpatialDistanceInMeterError(): void
]);
$this->fail('Expected Exception not thrown for ' . implode(' vs ', $case['expected']));
} catch (\Exception $e) {
$this->assertInstanceOf(\Exception::class, $e);
$this->assertInstanceOf(QueryException::class, $e);

// Validate exception message contains correct type names
$msg = strtolower($e->getMessage());
var_dump($msg);
$this->assertStringContainsString($case['expected'][0], $msg, 'Attr type missing in exception');
$this->assertStringContainsString($case['expected'][1], $msg, 'Geom type missing in exception');
}
Expand Down